diff --git a/.travis.yml b/.travis.yml index d2979a48d40..aee4ecefeb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -79,6 +79,17 @@ matrix: packages: - google-chrome-stable + # Run tests (in zeppelin-web-angular) + - os: linux + sudo: false + dist: xenial + jdk: "openjdk8" + env: CI="true" BUILD_FLAG="clean -DskipTests -DskipRat" TEST_FLAG="package -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_MODULES="-pl zeppelin-web-angular" + addons: + apt: + packages: + - google-chrome-stable + # Test core modules # Several tests were excluded from this configuration due to the following issues: # HeliumApplicationFactoryTest - https://issues.apache.org/jira/browse/ZEPPELIN-2470 diff --git a/LICENSE b/LICENSE index add447eff74..2edb8a83245 100644 --- a/LICENSE +++ b/LICENSE @@ -236,16 +236,19 @@ The text of each license is also included at licenses/LICENSE-[project]-[version (The MIT License) jekyll-bootstrap 0.3.0 (https://github.com/plusjade/jekyll-bootstrap) - https://github.com/plusjade/jekyll-bootstrap (The MIT License) jekyll 1.3.0 (http://jekyllrb.com/) - https://github.com/jekyll/jekyll/blob/v1.3.0/LICENSE (The MIT License) ngInfiniteScroll 1.3.4 (https://github.com/sroze/ngInfiniteScroll) - https://github.com/sroze/ngInfiniteScroll/blob/master/LICENSE + (The MIT License) @antv/G2 3.5 (https://github.com/antvis/g2) - https://github.com/antvis/g2/blob/master/LICENSE + (The MIT License) Lodash (https://lodash.com) - https://github.com/lodash/lodash/blob/master/LICENSE + (The MIT License) Monaco Editor (https://github.com/microsoft/monaco-editor) - https://github.com/microsoft/monaco-editor/blob/master/LICENSE.md ======================================================================== MIT-style licenses ======================================================================== The following components are provided under the MIT-style license. See project link for details. The text of each license is also included at licenses/LICENSE-[project]-[version].txt. - + (MIT Style) jekyll-table-of-contents (https://github.com/ghiculescu/jekyll-table-of-contents) - https://github.com/ghiculescu/jekyll-table-of-contents/blob/master/LICENSE.txt (MIT Style) lunr.js (https://github.com/olivernn/lunr.js) - https://github.com/olivernn/lunr.js/blob/v0.7.1/LICENSE - + ======================================================================== Apache licenses ======================================================================== diff --git a/angular/src/main/resources/interpreter-setting.json b/angular/src/main/resources/interpreter-setting.json index 723348d25e9..957295f8322 100644 --- a/angular/src/main/resources/interpreter-setting.json +++ b/angular/src/main/resources/interpreter-setting.json @@ -9,5 +9,16 @@ "editOnDblClick": true, "completionSupport": false } + }, + { + "group": "angular", + "name": "ng", + "className": "org.apache.zeppelin.angular.AngularInterpreter", + "properties": { + }, + "editor": { + "editOnDblClick": true, + "completionSupport": false + } } ] diff --git a/bin/common.sh b/bin/common.sh index 0ebae660907..4e86ce94948 100644 --- a/bin/common.sh +++ b/bin/common.sh @@ -44,7 +44,15 @@ if [[ -z "${ZEPPELIN_WAR}" ]]; then if [[ -d "${ZEPPELIN_HOME}/zeppelin-web/dist" ]]; then export ZEPPELIN_WAR="${ZEPPELIN_HOME}/zeppelin-web/dist" else - export ZEPPELIN_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web*.war") + export ZEPPELIN_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web-[0-9]*.war") + fi +fi + +if [[ -z "${ZEPPELIN_ANGULAR_WAR}" ]]; then + if [[ -d "${ZEPPELIN_HOME}/zeppelin-web/dist" ]]; then + export ZEPPELIN_ANGULAR_WAR="${ZEPPELIN_HOME}/zeppelin-web-angular/dist/zeppelin" + else + export ZEPPELIN_ANGULAR_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web-angular*.war") fi fi @@ -102,7 +110,7 @@ function getZeppelinVersion(){ exit 0 } -# Text encoding for +# Text encoding for # read/write job into files, # receiving/displaying query/result. if [[ -z "${ZEPPELIN_ENCODING}" ]]; then diff --git a/bin/zeppelin-daemon.sh b/bin/zeppelin-daemon.sh index e8988497513..0ce9808e2d8 100755 --- a/bin/zeppelin-daemon.sh +++ b/bin/zeppelin-daemon.sh @@ -81,6 +81,7 @@ addJarInDir "${ZEPPELIN_HOME}/zeppelin-interpreter/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-zengine/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-server/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-web/target/lib" +addJarInDir "${ZEPPELIN_HOME}/zeppelin-web-angular/target/lib" CLASSPATH+=":${ZEPPELIN_CLASSPATH}" diff --git a/bin/zeppelin.sh b/bin/zeppelin.sh index a13f9db977d..5509e4f2f54 100755 --- a/bin/zeppelin.sh +++ b/bin/zeppelin.sh @@ -70,6 +70,7 @@ addJarInDir "${ZEPPELIN_HOME}/zeppelin-interpreter/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-zengine/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-server/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-web/target/lib" +addJarInDir "${ZEPPELIN_HOME}/zeppelin-web-angular/target/lib" ZEPPELIN_CLASSPATH="$CLASSPATH:$ZEPPELIN_CLASSPATH" diff --git a/dev/create_release.sh b/dev/create_release.sh index fdd33fb0bf0..cec81c0ecc5 100755 --- a/dev/create_release.sh +++ b/dev/create_release.sh @@ -98,8 +98,8 @@ function make_binary_release() { git_clone make_source_package -make_binary_release all "-Pspark-2.3 -Phadoop-2.6 -Pscala-${SCALA_VERSION}" -make_binary_release netinst "-Pspark-2.3 -Phadoop-2.6 -Pscala-${SCALA_VERSION} -pl zeppelin-interpreter,zeppelin-zengine,:zeppelin-display_${SCALA_VERSION},:zeppelin-spark-dependencies_${SCALA_VERSION},:zeppelin-spark_${SCALA_VERSION},zeppelin-web,zeppelin-server,zeppelin-distribution -am" +make_binary_release all "-Phadoop-2.6 -Pscala-${SCALA_VERSION}" +make_binary_release netinst "-Phadoop-2.6 -Pscala-${SCALA_VERSION} -pl zeppelin-interpreter,zeppelin-zengine,:zeppelin-display_${SCALA_VERSION},:zeppelin-spark-dependencies_${SCALA_VERSION},:zeppelin-spark_${SCALA_VERSION},zeppelin-web,zeppelin-server,zeppelin-distribution -am" # remove non release files and dirs rm -rf "${WORKING_DIR}/zeppelin" diff --git a/dev/publish_release.sh b/dev/publish_release.sh index 4745de99eb5..3519fdfa14c 100755 --- a/dev/publish_release.sh +++ b/dev/publish_release.sh @@ -46,7 +46,7 @@ if [[ $RELEASE_VERSION == *"SNAPSHOT"* ]]; then DO_SNAPSHOT="yes" fi -PUBLISH_PROFILES="-Ppublish-distr -Pspark-2.1 -Phadoop-2.6 -Pr" +PUBLISH_PROFILES="-Ppublish-distr -Phadoop-2.6 -Pr" PROJECT_OPTIONS="-pl !zeppelin-distribution" NEXUS_STAGING="https://repository.apache.org/service/local/staging" NEXUS_PROFILE="153446d1ac37c4" diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html index 68252efa8f1..a1796e70517 100644 --- a/docs/_includes/themes/zeppelin/_navigation.html +++ b/docs/_includes/themes/zeppelin/_navigation.html @@ -142,6 +142,7 @@
  • Hive
  • Ignite
  • Java
  • +
  • Jupyter
  • Kotlin
  • Kylin
  • Lens
  • diff --git a/docs/assets/themes/zeppelin/img/docs-img/ipython_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/ipython_kernel.png new file mode 100644 index 00000000000..eefe97e3612 Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/ipython_kernel.png differ diff --git a/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png new file mode 100644 index 00000000000..a1bf5ec188c Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png differ diff --git a/docs/assets/themes/zeppelin/img/docs-img/julia_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/julia_kernel.png new file mode 100644 index 00000000000..5c075dc28f0 Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/julia_kernel.png differ diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME16.png b/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME16.png new file mode 100644 index 00000000000..f925d47c17e Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME16.png differ diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME24.png b/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME24.png new file mode 100644 index 00000000000..0eaa063d608 Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME24.png differ diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_inline_configuration.png b/docs/assets/themes/zeppelin/img/docs-img/spark_inline_configuration.png new file mode 100644 index 00000000000..c02785b62b8 Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/spark_inline_configuration.png differ diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_user_impersonation.png b/docs/assets/themes/zeppelin/img/docs-img/spark_user_impersonation.png new file mode 100644 index 00000000000..f16f402f811 Binary files /dev/null and b/docs/assets/themes/zeppelin/img/docs-img/spark_user_impersonation.png differ diff --git a/docs/interpreter/jupyter.md b/docs/interpreter/jupyter.md new file mode 100644 index 00000000000..89586e6bf00 --- /dev/null +++ b/docs/interpreter/jupyter.md @@ -0,0 +1,134 @@ +--- +layout: page +title: "Jupyter Interpreter for Apache Zeppelin" +description: "Project Jupyter exists to develop open-source software, open-standards, and services for interactive computing across dozens of programming languages." +group: interpreter +--- + +{% include JB/setup %} + +# Jupyter Interpreter for Apache Zeppelin + +
    + +## Overview + +Project [Jupyter](https://jupyter.org/) exists to develop open-source software, open-standards, and services for interactive computing across dozens of programming languages. +Zeppelin's Jupyter interpreter is a bridge/adapter between Zeppelin interpreter and Jupyter kernel. You can use any of jupyter kernel as long as you installed the necessary dependencies. + +## Configuration + +To run any Jupyter kernel in Zeppelin you first need to install the following prerequisite: + +* pip install jupyter-client +* pip install grpcio +* pip install protobuf + +Then you need install the jupyter kernel you want to use. In the following sections, we will talk about how to use the following 3 jupyter kernels in Zeppelin: + +* ipython +* ir +* julia + +## Jupyter Python kernel + +In order to use Jupyter Python kernel in Zeppelin, you need to install `ipykernel` first. + +```bash + +pip install ipykernel +``` + +Then you can run python code in Jupyter interpreter like following. + +```python + +%jupyter(kernel=python) + +%matplotlib inline +import matplotlib.pyplot as plt +plt.plot([1, 2, 3]) +``` + + + +## Jupyter R kernel + +In order to use [IRKernel](https://github.com/IRkernel/IRkernel), you need to first install `IRkernel` package in R. + +```r +install.packages('IRkernel') +IRkernel::installspec() # to register the kernel in the current R installation +``` + +Then you can run r code in Jupyter interpreter like following. + +```r +%jupyter(kernel=ir) + +library(ggplot2) +ggplot(mpg, aes(x = displ, y = hwy)) + + geom_point() +``` + + + + +## Jupyter Julia kernel + +In order to use Julia in Zeppelin, you first need to install [IJulia](https://github.com/JuliaLang/IJulia.jl) first + +```julia +using Pkg +Pkg.add("IJulia") + +``` + +Then you can run julia code in Jupyter interpreter like following. + +```julia + +%jupyter(kernel=julia-1.3) + +using Pkg +Pkg.add("Plots") +using Plots +plotly() # Choose the Plotly.jl backend for web interactivity +plot(rand(5,5),linewidth=2,title="My Plot") +Pkg.add("PyPlot") # Install a different backend +pyplot() # Switch to using the PyPlot.jl backend +plot(rand(5,5),linewidth=2,title="My Plot") +``` + + + + +## Use any other kernel + +For any other jupyter kernel, you can follow the below steps to use it in Zeppelin. + +1. Install the specified jupyter kernel. you can find all the available jupyter kernels [here](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels) +2. Find its kernel name by run the following command + ```bash + jupyter kernelspec list + ``` +3. Run the kernel as following + +```python + +%jupyter(kernel=kernel_name) + +code +``` \ No newline at end of file diff --git a/docs/interpreter/shell.md b/docs/interpreter/shell.md index 9da2f091ad8..c38391b8e14 100644 --- a/docs/interpreter/shell.md +++ b/docs/interpreter/shell.md @@ -91,7 +91,7 @@ For changing the default behavior of when to renew Kerberos ticket following cha ```bash # Change Kerberos refresh interval (default value is 1d). Allowed postfix are ms, s, m, min, h, and d. -export LAUNCH_KERBEROS_REFRESH_INTERVAL=4h +export KERBEROS_REFRESH_INTERVAL=4h # Change kinit number retries (default value is 5), which means if the kinit command fails for 5 retries consecutively it will close the interpreter. export KINIT_FAIL_THRESHOLD=10 ``` diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md index bd50cb017b9..ef799593d26 100644 --- a/docs/interpreter/spark.md +++ b/docs/interpreter/spark.md @@ -37,18 +37,18 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist %spark SparkInterpreter - Creates a SparkContext and provides a Scala environment - - - %spark.kotlin - KotlinSparkInterpreter - Provides a Kotlin environment + Creates a SparkContext/SparkSession and provides a Scala environment %spark.pyspark PySparkInterpreter Provides a Python environment + + %spark.ipyspark + IPySparkInterpreter + Provides a IPython environment + %spark.r SparkRInterpreter @@ -60,9 +60,9 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist Provides a SQL environment - %spark.dep - DepInterpreter - Dependency loader + %spark.kotlin + KotlinSparkInterpreter + Provides a Kotlin environment @@ -76,42 +76,58 @@ You can also set other Spark properties which are not listed in the table. For a Description - args + `SPARK_HOME` - Spark commandline args - + Location of spark distribution + + master local[*] - Spark master uri.
    ex) spark://masterhost:7077 + Spark master uri.
    e.g. spark://master_host:7077 spark.app.name Zeppelin The name of spark application. - spark.cores.max - - Total number of cores to use.
    Empty value uses all available core. + spark.driver.cores + 1 + Number of cores to use for the driver process, only in cluster mode. - spark.executor.memory + spark.driver.memory 1g - Executor memory per worker instance.
    ex) 512m, 32g + Amount of memory to use for the driver process, i.e. where SparkContext is initialized, in the same format as JVM memory strings with a size unit suffix ("k", "m", "g" or "t") (e.g. 512m, 2g). - zeppelin.dep.additionalRemoteRepository - spark-packages,
    http://dl.bintray.com/spark-packages/maven,
    false; - A list of `id,remote-repository-URL,is-snapshot;`
    for each remote repository. + spark.executor.cores + 1 + The number of cores to use on each executor - zeppelin.dep.localrepo - local-repo - Local repository for dependency loader + spark.executor.memory + 1g + Executor memory per worker instance.
    e.g. 512m, 32g + + + spark.files + + Comma-separated list of files to be placed in the working directory of each executor. Globs are allowed. + + + spark.jars + + Comma-separated list of jars to include on the driver and executor classpaths. Globs are allowed. + + + spark.jars.packages + + Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories. `PYSPARK_PYTHON` python - Python binary executable to use for PySpark in both driver and workers (default is python). + Python binary executable to use for PySpark in both driver and executors (default is python). Property spark.pyspark.python take precedence if it is set @@ -120,6 +136,16 @@ You can also set other Spark properties which are not listed in the table. For a Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set + + zeppelin.pyspark.useIPython + false + Whether use IPython when the ipython prerequisites are met in `%spark.pyspark` + + + zeppelin.R.cmd + R + R binary executable path. + zeppelin.spark.concurrentSQL false @@ -133,22 +159,17 @@ You can also set other Spark properties which are not listed in the table. For a zeppelin.spark.maxResult 1000 - Max number of Spark SQL result to display. + Max number rows of Spark SQL result to display. zeppelin.spark.printREPLOutput true - Print REPL output + Print scala REPL output zeppelin.spark.useHiveContext true - Use HiveContext instead of SQLContext if it is true. - - - zeppelin.spark.importImplicit - true - Import implicits, UDF collection, and sql if set true. + Use HiveContext instead of SQLContext if it is true. Enable hive for SparkSession zeppelin.spark.enableSupportedVersionCheck @@ -158,47 +179,68 @@ You can also set other Spark properties which are not listed in the table. For a zeppelin.spark.sql.interpolation false - Enable ZeppelinContext variable interpolation into paragraph text + Enable ZeppelinContext variable interpolation into spark sql zeppelin.spark.uiWebUrl Overrides Spark UI default URL. Value should be a full URL (ex: http://{hostName}/{uniquePath} - zeppelin.spark.scala.color - true - Whether to enable color output of spark scala interpreter - Without any configuration, Spark interpreter works out of box in local mode. But if you want to connect to your Spark cluster, you'll need to follow below two simple steps. -### 1. Export SPARK_HOME -In `conf/zeppelin-env.sh`, export `SPARK_HOME` environment variable with your Spark installation path. +### Export SPARK_HOME -For example, +There are several options for setting `SPARK_HOME`. + +* Set `SPARK_HOME` in `zeppelin-env.sh` +* Set `SPARK_HOME` in Interpreter setting page +* Set `SPARK_HOME` via [inline generic configuration](../usage/interpreter/overview.html#inline-generic-confinterpreter) + +#### 1. Set `SPARK_HOME` in `zeppelin-env.sh` + +If you work with only one version of spark, then you can set `SPARK_HOME` in `zeppelin-env.sh` because any setting in `zeppelin-env.sh` is globally applied. + +e.g. ```bash export SPARK_HOME=/usr/lib/spark ``` -You can optionally set more environment variables +You can optionally set more environment variables in `zeppelin-env.sh` ```bash # set hadoop conf dir export HADOOP_CONF_DIR=/usr/lib/hadoop -# set options to pass spark-submit command -export SPARK_SUBMIT_OPTIONS="--packages com.databricks:spark-csv_2.10:1.2.0" - -# extra classpath. e.g. set classpath for hive-site.xml -export ZEPPELIN_INTP_CLASSPATH_OVERRIDES=/etc/hive/conf ``` -For Windows, ensure you have `winutils.exe` in `%HADOOP_HOME%\bin`. Please see [Problems running Hadoop on Windows](https://wiki.apache.org/hadoop/WindowsProblems) for the details. -### 2. Set master in Interpreter menu -After start Zeppelin, go to **Interpreter** menu and edit **master** property in your Spark interpreter setting. The value may vary depending on your Spark cluster deployment type. +#### 2. Set `SPARK_HOME` in Interpreter setting page + +If you want to use multiple versions of spark, then you need create multiple spark interpreters and set `SPARK_HOME` for each of them. e.g. +Create a new spark interpreter `spark24` for spark 2.4 and set `SPARK_HOME` in interpreter setting page +
    + +
    + +Create a new spark interpreter `spark16` for spark 1.6 and set `SPARK_HOME` in interpreter setting page +
    + +
    + + +#### 3. Set `SPARK_HOME` via [inline generic configuration](../usage/interpreter/overview.html#inline-generic-confinterpreter) + +Besides setting `SPARK_HOME` in interpreter setting page, you can also use inline generic configuration to put the +configuration with code together for more flexibility. e.g. +
    + +
    + +### Set master in Interpreter menu +After starting Zeppelin, go to **Interpreter** menu and edit **master** property in your Spark interpreter setting. The value may vary depending on your Spark cluster deployment type. For example, @@ -213,93 +255,132 @@ For the further information about Spark & Zeppelin version compatibility, please > Note that without exporting `SPARK_HOME`, it's running in local mode with included version of Spark. The included version may vary depending on the build profile. -### 3. Yarn mode -Zeppelin support both yarn client and yarn cluster mode (yarn cluster mode is supported from 0.8.0). For yarn mode, you must specify `SPARK_HOME` & `HADOOP_CONF_DIR`. -You can either specify them in `zeppelin-env.sh`, or in interpreter setting page. Specifying them in `zeppelin-env.sh` means you can use only one version of `spark` & `hadoop`. Specifying them -in interpreter setting page means you can use multiple versions of `spark` & `hadoop` in one zeppelin instance. - -### 4. New Version of SparkInterpreter -Starting from 0.9, we totally removed the old spark interpreter implementation, and make the new spark interpreter as the official spark interpreter. - ## SparkContext, SQLContext, SparkSession, ZeppelinContext -SparkContext, SQLContext and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext` and `z`, respectively, in Scala, Kotlin, Python and R environments. -Staring from 0.6.1 SparkSession is available as variable `spark` when you are using Spark 2.x. - -> Note that Scala/Python/R environment shares the same SparkContext, SQLContext and ZeppelinContext instance. - +SparkContext, SQLContext, SparkSession (for spark 2.x) and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext`, `spark` and `z`, respectively, in Scala, Kotlin, Python and R environments. -### How to pass property to SparkConf -There're 2 kinds of properties that would be passed to SparkConf +> Note that Scala/Python/R environment shares the same SparkContext, SQLContext, SparkSession and ZeppelinContext instance. - * Standard spark property (prefix with `spark.`). e.g. `spark.executor.memory` will be passed to `SparkConf` - * Non-standard spark property (prefix with `zeppelin.spark.`). e.g. `zeppelin.spark.property_1`, `property_1` will be passed to `SparkConf` +## YARN Mode +Zeppelin support both yarn client and yarn cluster mode (yarn cluster mode is supported from 0.8.0). For yarn mode, you must specify `SPARK_HOME` & `HADOOP_CONF_DIR`. +Usually you only have one hadoop cluster, so you can set `HADOOP_CONF_DIR` in `zeppelin-env.sh` which is applied to all spark interpreters. If you want to use spark against multiple hadoop cluster, then you need to define +`HADOOP_CONF_DIR` in interpreter setting or via inline generic configuration. ## Dependency Management -For spark interpreter, you should not use Zeppelin's [Dependency Management](../usage/interpreter/dependency_management.html) for managing -third party dependencies, (`%spark.dep` also is not the recommended approach starting from Zeppelin 0.8). Instead you should set spark properties (`spark.jars`, `spark.files`, `spark.jars.packages`) in 2 ways. +For spark interpreter, it is not recommended to use Zeppelin's [Dependency Management](../usage/interpreter/dependency_management.html) for managing +third party dependencies (`%spark.dep` is removed from Zeppelin 0.9 as well). Instead you should set the standard Spark properties. - - + + + + + + + - + - - - - - - +
    spark-defaults.confSPARK_SUBMIT_OPTIONSSpark PropertySpark Submit Argument Description
    spark.files--filesComma-separated list of files to be placed in the working directory of each executor. Globs are allowed.
    spark.jars --jarsComma-separated list of local jars to include on the driver and executor classpaths.Comma-separated list of jars to include on the driver and executor classpaths. Globs are allowed.
    spark.jars.packages --packagesComma-separated list of maven coordinates of jars to include on the driver and executor classpaths. Will search the local maven repo, then maven central and any additional remote repositories given by --repositories. The format for the coordinates should be groupId:artifactId:version.
    spark.files--filesComma-separated list of files to be placed in the working directory of each executor.Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories.
    -### 1. Set spark properties in zeppelin side. +You can either set Spark properties in interpreter setting page or set Spark submit arguments in `zeppelin-env.sh` via environment variable `SPARK_SUBMIT_OPTIONS`. +For examples: + +```bash +export SPARK_SUBMIT_OPTIONS="--files --jars --packages " +``` + +But it is not recommended to set them in `SPARK_SUBMIT_OPTIONS`. Because it will be shared by all spark interpreters, which means you can not set different dependencies for different users. -In zeppelin side, you can either set them in spark interpreter setting page or via [Generic ConfInterpreter](../usage/interpreter/overview.html). -It is not recommended to set them in `SPARK_SUBMIT_OPTIONS`. Because it will be shared by all spark interpreters, you can not set different dependencies for different users. -### 2. Set spark properties in spark side. +## PySpark -In spark side, you can set them in `spark-defaults.conf`. +There're 2 ways to use PySpark in Zeppelin: -e.g. +* Vanilla PySpark +* IPySpark - ``` - spark.jars /path/mylib1.jar,/path/mylib2.jar - spark.jars.packages com.databricks:spark-csv_2.10:1.2.0 - spark.files /path/mylib1.py,/path/mylib2.egg,/path/mylib3.zip - ``` +### Vanilla PySpark (Not Recommended) +Vanilla PySpark interpreter is almost the same as vanilla Python interpreter except Zeppelin inject SparkContext, SQLContext, SparkSession via variables `sc`, `sqlContext`, `spark`. +By default, Zeppelin would use IPython in `%spark.pyspark` when IPython is available, Otherwise it would fall back to the original PySpark implementation. +If you don't want to use IPython, then you can set `zeppelin.pyspark.useIPython` as `false` in interpreter setting. For the IPython features, you can refer doc +[Python Interpreter](python.html) -## ZeppelinContext -Zeppelin automatically injects `ZeppelinContext` as variable `z` in your Scala/Python environment. `ZeppelinContext` provides some additional functions and utilities. -See [Zeppelin-Context](../usage/other_features/zeppelin_context.html) for more details. +### IPySpark (Recommended) +You can use `IPySpark` explicitly via `%spark.ipyspark`. IPySpark interpreter is almost the same as IPython interpreter except Zeppelin inject SparkContext, SQLContext, SparkSession via variables `sc`, `sqlContext`, `spark`. +For the IPython features, you can refer doc [Python Interpreter](python.html) + +## SparkR + +Zeppelin support SparkR via `%spark.r`. Here's configuration for SparkR Interpreter. + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Spark PropertyDefaultDescription
    zeppelin.R.cmdRR binary executable path.
    zeppelin.R.knitrtrueWhether use knitr or not. (It is recommended to install knitr and use it in Zeppelin)
    zeppelin.R.image.width100%R plotting image width.
    zeppelin.R.render.optionsout.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2R plotting options.
    + + +## SparkSql -## Matplotlib Integration (pyspark) -Both the `python` and `pyspark` interpreters have built-in support for inline visualization using `matplotlib`, -a popular plotting library for python. More details can be found in the [python interpreter documentation](../interpreter/python.html), -since matplotlib support is identical. More advanced interactive plotting can be done with pyspark through -utilizing Zeppelin's built-in [Angular Display System](../usage/display_system/angular_backend.html), as shown below: +Spark Sql Interpreter share the same SparkContext/SparkSession with other Spark interpreter. That means any table registered in scala, python or r code can be accessed by Spark Sql. +For examples: - +```scala +%spark + +case class People(name: String, age: Int) +var df = spark.createDataFrame(List(People("jeff", 23), People("andy", 20))) +df.createOrReplaceTempView("people") +``` + +```sql + +%spark.sql + +select * from people +``` -## Running spark sql concurrently By default, each sql statement would run sequentially in `%spark.sql`. But you can run them concurrently by following setup. -1. set `zeppelin.spark.concurrentSQL` to true to enable the sql concurrent feature, underneath zeppelin will change to use fairscheduler for spark. And also set `zeppelin.spark.concurrentSQL.max` to control the max number of sql statements running concurrently. -2. configure pools by creating `fairscheduler.xml` under your `SPARK_CONF_DIR`, check the offical spark doc [Configuring Pool Properties](http://spark.apache.org/docs/latest/job-scheduling.html#configuring-pool-properties) -3. set pool property via setting paragraph property. e.g. +1. Set `zeppelin.spark.concurrentSQL` to true to enable the sql concurrent feature, underneath zeppelin will change to use fairscheduler for spark. And also set `zeppelin.spark.concurrentSQL.max` to control the max number of sql statements running concurrently. +2. Configure pools by creating `fairscheduler.xml` under your `SPARK_CONF_DIR`, check the official spark doc [Configuring Pool Properties](http://spark.apache.org/docs/latest/job-scheduling.html#configuring-pool-properties) +3. Set pool property via setting paragraph property. e.g. ``` %spark(pool=pool1) @@ -307,19 +388,44 @@ By default, each sql statement would run sequentially in `%spark.sql`. But you c sql statement ``` -This feature is available for both all versions of scala spark, pyspark. For sparkr, it is only available starting from 2.3.0. +This pool feature is also available for all versions of scala Spark, PySpark. For SparkR, it is only available starting from 2.3.0. -## Interpreter setting option +## Interpreter Setting Option -You can choose one of `shared`, `scoped` and `isolated` options wheh you configure Spark interpreter. -Spark interpreter creates separated Scala compiler per each notebook but share a single SparkContext in `scoped` mode (experimental). -It creates separated SparkContext per each notebook in `isolated` mode. +You can choose one of `shared`, `scoped` and `isolated` options when you configure Spark interpreter. +e.g. -## IPython support +* In `scoped` per user mode, Zeppelin creates separated Scala compiler for each user but share a single SparkContext. +* In `isolated` per user mode, Zeppelin creates separated SparkContext for each user. -By default, zeppelin would use IPython in `pyspark` when IPython is available, Otherwise it would fall back to the original PySpark implementation. -If you don't want to use IPython, then you can set `zeppelin.pyspark.useIPython` as `false` in interpreter setting. For the IPython features, you can refer doc -[Python Interpreter](python.html) +## ZeppelinContext +Zeppelin automatically injects `ZeppelinContext` as variable `z` in your Scala/Python environment. `ZeppelinContext` provides some additional functions and utilities. +See [Zeppelin-Context](../usage/other_features/zeppelin_context.html) for more details. + +## User Impersonation + +In yarn mode, the user who launch the zeppelin server will be used to launch the spark yarn application. This is not a good practise. +Most of time, you will enable shiro in Zeppelin and would like to use the login user to submit the spark yarn app. For this purpose, +you need to enable user impersonation for more security control. In order the enable user impersonation, you need to do the following steps + +**Step 1** Enable user impersonation setting hadoop's `core-site.xml`. E.g. if you are using user `zeppelin` to launch Zeppelin, then add the following to `core-site.xml`, then restart both hdfs and yarn. + +``` + + hadoop.proxyuser.zeppelin.groups + * + + + hadoop.proxyuser.zeppelin.hosts + * + +``` + +**Step 2** Enable interpreter user impersonation in Spark interpreter's interpreter setting. (Enable shiro first of course) + + +**Step 3(Optional)** If you are using kerberos cluster, then you need to set `zeppelin.server.kerberos.keytab` and `zeppelin.server.kerberos.principal` to the user(aka. user in Step 1) you want to +impersonate in `zeppelin-site.xml`. ## Setting up Zeppelin with Kerberos @@ -338,10 +444,7 @@ You can get rid of this message by setting `zeppelin.spark.deprecatedMsg.show` t 1. On the server that Zeppelin is installed, install Kerberos client modules and configuration, krb5.conf. This is to make the server communicate with KDC. -2. Set `SPARK_HOME` in `[ZEPPELIN_HOME]/conf/zeppelin-env.sh` to use spark-submit -(Additionally, you might have to set `export HADOOP_CONF_DIR=/etc/hadoop/conf`) - -3. Add the two properties below to Spark configuration (`[SPARK_HOME]/conf/spark-defaults.conf`): +2. Add the two properties below to Spark configuration (`[SPARK_HOME]/conf/spark-defaults.conf`): ``` spark.yarn.principal @@ -350,5 +453,5 @@ This is to make the server communicate with KDC. > **NOTE:** If you do not have permission to access for the above spark-defaults.conf file, optionally, you can add the above lines to the Spark Interpreter setting through the Interpreter tab in the Zeppelin UI. -4. That's it. Play with Zeppelin! +3. That's it. Play with Zeppelin! diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index 3fe0f5fe105..ef2eda95750 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -132,7 +132,7 @@ Before 0.8.0, Zeppelin didn't have lifecycle management for interpreters. Users Users can change this threshold via the `zeppelin.interpreter.lifecyclemanager.timeout.threshold` setting. `TimeoutLifecycleManager` is the default lifecycle manager, and users can change it via `zeppelin.interpreter.lifecyclemanager.class`. -## Generic ConfInterpreter +## Inline Generic ConfInterpreter Zeppelin's interpreter setting is shared by all users and notes, if you want to have different settings, you have to create a new interpreter, e.g. you can create `spark_jar1` for running Spark with dependency jar1 and `spark_jar2` for running Spark with dependency jar2. This approach works, but is not particularly convenient. `ConfInterpreter` can provide more fine-grained control on interpreter settings and more flexibility. diff --git a/kotlin/README.md b/kotlin/README.md index 0b71c240c1e..8e3420c4914 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -8,7 +8,7 @@ Here is the guide to its implementation and how it can be improved and tested. For interactive Kotlin execution, an instance of `KotlinRepl` is created. To set REPL properties (such as classpath, generated classes output directory, max result, etc.), pass `KotlinReplProperties` to its constructor. For example: -```$java +```java KotlinReplProperties replProperties = new KotlinReplProperties() .maxResult(1000) .shortenTypes(true); @@ -22,7 +22,7 @@ making the receiver's fields and methods accessible. To add your variables/functions, extend `KotlinReceiver` class (in separate file), declare your fields and methods, and pass an instance of it to `KotlinReplProperties`. Example: -```$java +```java // In separate file: class CustomReceiver extends KotlinReceiver { public int myValue = 1 // will be converted to Kotlin "var myValue: Int" @@ -80,4 +80,4 @@ can not use things like `forEach` because of ambiguity between `Iterable.forE (`foreach` from Spark's API does work, though). * The scoped mode for Kotlin Spark Interpreter currently has issues with having the same class output directory for different intepreters, leading to overwriting classes. Adding prefixes to generated classes or putting them - in separate directories leads to `ClassNotFoundException` on Spark executors. \ No newline at end of file + in separate directories leads to `ClassNotFoundException` on Spark executors. diff --git a/pom.xml b/pom.xml index bdcebe0118d..bfac15eaae1 100644 --- a/pom.xml +++ b/pom.xml @@ -96,6 +96,7 @@ zeppelin-jupyter zeppelin-plugins zeppelin-distribution + zeppelin-web-angular @@ -109,14 +110,14 @@ 1.12.5 - v8.9.3 - 5.5.1 + v12.3.1 + 6.9.0 1.6 1.7.10 1.2.17 - 0.12.0 + 0.13.0 2.2 0.2.1 9.4.18.v20190429 @@ -194,6 +195,12 @@ org.apache.thrift libthrift ${libthrift.version} + + + javax.annotation + javax.annotation-api + + @@ -1026,6 +1033,16 @@ **/e2e/**/**.spec.js package-lock.json + + **/*.json + **/browserslist + **/.prettierrc + **/.prettierignore + **/.editorconfig + **/src/**/*.svg + **/.gitkeep + + **/src/main/java/org/apache/zeppelin/jdbc/SqlCompleter.java diff --git a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java index 4d8a4b726a2..e4ea7321672 100644 --- a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java +++ b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java @@ -219,7 +219,7 @@ private void appendToPythonPath(Map env, String path) { if (!env.containsKey("PYTHONPATH")) { env.put("PYTHONPATH", path); } else { - env.put("PYTHONPATH", env.get("PYTHONPATH") + ":" + path); + env.put("PYTHONPATH", env.get("PYTHONPATH") + File.pathSeparator + path); } } diff --git a/rlang/pom.xml b/rlang/pom.xml index a8021b4851e..ff6b16b934a 100644 --- a/rlang/pom.xml +++ b/rlang/pom.xml @@ -37,7 +37,7 @@ r 1.12.1 - 2.4.3 + 2.4.4 1.15.0 spark-${spark.version} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java index d9076b4f6e2..949b1b1a722 100644 --- a/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java +++ b/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java @@ -73,7 +73,7 @@ protected boolean isSparkSupported() { * @return */ protected int sparkVersion() { - return 20403; + return 20404; } /** diff --git a/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java index b2dc5f331a7..3d0f24b582d 100644 --- a/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java +++ b/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java @@ -65,6 +65,7 @@ public void open() throws InterpreterException { this.z = new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), 1000); } + @Override public void close() throws InterpreterException { for (Map.Entry entry : shinyIRInterpreters.entrySet()) { @@ -133,7 +134,7 @@ private IRInterpreter getIRInterpreter(String shinyApp) throws InterpreterExcept synchronized (shinyIRInterpreters) { irInterpreter = shinyIRInterpreters.get(shinyApp); if (irInterpreter == null) { - irInterpreter = new IRInterpreter(properties); + irInterpreter = createIRInterpreter(); irInterpreter.setInterpreterGroup(getInterpreterGroup()); irInterpreter.open(); shinyIRInterpreters.put(shinyApp, irInterpreter); @@ -142,4 +143,12 @@ private IRInterpreter getIRInterpreter(String shinyApp) throws InterpreterExcept return irInterpreter; } + /** + * Subclass can overwrite this. e.g. SparkShinyInterpreter. + * @return + */ + protected IRInterpreter createIRInterpreter() { + return new IRInterpreter(properties); + } + } diff --git a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java index 5939f9917f8..2819ca51639 100644 --- a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java +++ b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java @@ -28,6 +28,7 @@ import org.apache.zeppelin.interpreter.InterpreterResult; import org.apache.zeppelin.interpreter.InterpreterResultMessage; import org.apache.zeppelin.interpreter.LazyOpenInterpreter; +import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -42,10 +43,11 @@ import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; public class ShinyInterpreterTest { - private ShinyInterpreter interpreter; + protected ShinyInterpreter interpreter; @Before public void setUp() throws InterpreterException { @@ -240,6 +242,7 @@ protected InterpreterContext getInterpreterContext() { .setInterpreterOut(new InterpreterOutput(null)) .setLocalProperties(new HashMap<>()) .setInterpreterClassName(ShinyInterpreter.class.getName()) + .setIntpEventClient(mock(RemoteInterpreterEventClient.class)) .build(); return context; } diff --git a/shell/src/main/resources/interpreter-setting.json b/shell/src/main/resources/interpreter-setting.json index 4a7dae5706d..1db6528457b 100644 --- a/shell/src/main/resources/interpreter-setting.json +++ b/shell/src/main/resources/interpreter-setting.json @@ -3,6 +3,7 @@ "group": "sh", "name": "sh", "className": "org.apache.zeppelin.shell.ShellInterpreter", + "defaultInterpreter": true, "properties": { "shell.command.timeout.millisecs": { "envName": "SHELL_COMMAND_TIMEOUT", diff --git a/spark/interpreter/pom.xml b/spark/interpreter/pom.xml index 86a5f754145..dfebec8965b 100644 --- a/spark/interpreter/pom.xml +++ b/spark/interpreter/pom.xml @@ -329,6 +329,14 @@ 0.4.4 test + + + com.mashape.unirest + unirest-java + 1.4.9 + test + + diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java index 004ce98ea24..ee16c7266ea 100644 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java +++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java @@ -58,8 +58,20 @@ protected boolean isSecretSupported() { return this.sparkVersion.isSecretSocketSupported(); } + /** + * We can inject SparkInterpreter in the case that SparkIRInterpreter is used by + * SparkShinyInterpreter in which case it is not in the same InterpreterGroup of + * SparkInterpreter. + * @param sparkInterpreter + */ + public void setSparkInterpreter(SparkInterpreter sparkInterpreter) { + this.sparkInterpreter = sparkInterpreter; + } + public void open() throws InterpreterException { - this.sparkInterpreter = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); + if (sparkInterpreter == null) { + this.sparkInterpreter = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); + } this.sc = sparkInterpreter.getSparkContext(); this.jsc = sparkInterpreter.getJavaSparkContext(); this.sparkVersion = new SparkVersion(sc.version()); diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java new file mode 100644 index 00000000000..c5dc1428d47 --- /dev/null +++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.spark; + +import org.apache.zeppelin.interpreter.InterpreterException; +import org.apache.zeppelin.r.IRInterpreter; +import org.apache.zeppelin.r.ShinyInterpreter; + +import java.util.Properties; + +/** + * The same function as ShinyInterpreter, but support Spark as well. + */ +public class SparkShinyInterpreter extends ShinyInterpreter { + public SparkShinyInterpreter(Properties properties) { + super(properties); + } + + protected IRInterpreter createIRInterpreter() { + SparkIRInterpreter interpreter = new SparkIRInterpreter(properties); + try { + interpreter.setSparkInterpreter(getInterpreterInTheSameSessionByClassName(SparkInterpreter.class)); + return interpreter; + } catch (InterpreterException e) { + throw new RuntimeException("Fail to set spark interpreter for SparkIRInterpreter", e); + } + } +} diff --git a/spark/interpreter/src/main/resources/interpreter-setting.json b/spark/interpreter/src/main/resources/interpreter-setting.json index 77392218e01..100c97c23b2 100644 --- a/spark/interpreter/src/main/resources/interpreter-setting.json +++ b/spark/interpreter/src/main/resources/interpreter-setting.json @@ -5,6 +5,48 @@ "className": "org.apache.zeppelin.spark.SparkInterpreter", "defaultInterpreter": true, "properties": { + "SPARK_HOME": { + "envName": "SPARK_HOME", + "propertyName": "SPARK_HOME", + "defaultValue": "", + "description": "Location of spark distribution", + "type": "string" + }, + "master": { + "envName": "", + "propertyName": "spark.master", + "defaultValue": "local[*]", + "description": "Spark master uri. ex) spark://master_host:7077", + "type": "string" + }, + "spark.app.name": { + "envName": "", + "propertyName": "spark.app.name", + "defaultValue": "Zeppelin", + "description": "The name of spark application.", + "type": "string" + }, + "spark.driver.cores": { + "envName": "", + "propertyName": "spark.driver.cores", + "defaultValue": "1", + "description": "Number of cores to use for the driver process, only in cluster mode.", + "type": "int" + }, + "spark.driver.memory": { + "envName": "", + "propertyName": "spark.driver.memory", + "defaultValue": "1g", + "description": "Amount of memory to use for the driver process, i.e. where SparkContext is initialized, in the same format as JVM memory strings with a size unit suffix (\"k\", \"m\", \"g\" or \"t\") (e.g. 512m, 2g).", + "type": "string" + }, + "spark.executor.cores": { + "envName": null, + "propertyName": "spark.executor.cores", + "defaultValue": "1", + "description": "The number of cores to use on each executor", + "type": "int" + }, "spark.executor.memory": { "envName": null, "propertyName": "spark.executor.memory", @@ -12,55 +54,50 @@ "description": "Executor memory per worker instance. ex) 512m, 32g", "type": "string" }, - "args": { + "spark.files": { "envName": null, - "propertyName": null, + "propertyName": "spark.files", "defaultValue": "", - "description": "spark commandline args", - "type": "textarea" + "description": "Comma-separated list of files to be placed in the working directory of each executor. Globs are allowed.", + "type": "string" + }, + "spark.jars": { + "envName": null, + "propertyName": "spark.jars", + "defaultValue": "", + "description": "Comma-separated list of jars to include on the driver and executor classpaths. Globs are allowed.", + "type": "string" + }, + "spark.jars.packages": { + "envName": null, + "propertyName": "spark.jars.packages", + "defaultValue": "", + "description": "Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories.", + "type": "string" }, "zeppelin.spark.useHiveContext": { - "envName": "ZEPPELIN_SPARK_USEHIVECONTEXT", + "envName": null, "propertyName": "zeppelin.spark.useHiveContext", "defaultValue": true, - "description": "Use HiveContext instead of SQLContext if it is true.", + "description": "Use HiveContext instead of SQLContext if it is true. Enable hive for SparkSession.", "type": "checkbox" }, - "spark.app.name": { - "envName": "SPARK_APP_NAME", - "propertyName": "spark.app.name", - "defaultValue": "Zeppelin", - "description": "The name of spark application.", - "type": "string" - }, + "zeppelin.spark.printREPLOutput": { "envName": null, "propertyName": "zeppelin.spark.printREPLOutput", "defaultValue": true, - "description": "Print REPL output", + "description": "Print scala REPL output", "type": "checkbox" }, - "spark.cores.max": { - "envName": null, - "propertyName": "spark.cores.max", - "defaultValue": "", - "description": "Total number of cores to use. Empty value uses all available core.", - "type": "number" - }, "zeppelin.spark.maxResult": { - "envName": "ZEPPELIN_SPARK_MAXRESULT", + "envName": null, "propertyName": "zeppelin.spark.maxResult", "defaultValue": "1000", "description": "Max number of Spark SQL result to display.", "type": "number" }, - "master": { - "envName": "MASTER", - "propertyName": "spark.master", - "defaultValue": "local[*]", - "description": "Spark master uri. ex) spark://masterhost:7077", - "type": "string" - }, + "zeppelin.spark.enableSupportedVersionCheck": { "envName": null, "propertyName": "zeppelin.spark.enableSupportedVersionCheck", @@ -110,21 +147,21 @@ "className": "org.apache.zeppelin.spark.SparkSqlInterpreter", "properties": { "zeppelin.spark.concurrentSQL": { - "envName": "ZEPPELIN_SPARK_CONCURRENTSQL", + "envName": null, "propertyName": "zeppelin.spark.concurrentSQL", "defaultValue": false, "description": "Execute multiple SQL concurrently if set true.", "type": "checkbox" }, "zeppelin.spark.concurrentSQL.max": { - "envName": "ZEPPELIN_SPARK_CONCURRENTSQL_MAX", + "envName": null, "propertyName": "zeppelin.spark.concurrentSQL.max", "defaultValue": 10, "description": "Max number of SQL concurrently executed", "type": "number" }, "zeppelin.spark.sql.stacktrace": { - "envName": "ZEPPELIN_SPARK_SQL_STACKTRACE", + "envName": null, "propertyName": "zeppelin.spark.sql.stacktrace", "defaultValue": false, "description": "Show full exception stacktrace for SQL queries if set to true.", @@ -134,18 +171,18 @@ "envName": null, "propertyName": "zeppelin.spark.sql.interpolation", "defaultValue": false, - "description": "Enable ZeppelinContext variable interpolation into paragraph text", + "description": "Enable ZeppelinContext variable interpolation into spark sql", "type": "checkbox" }, "zeppelin.spark.maxResult": { - "envName": "ZEPPELIN_SPARK_MAXRESULT", + "envName": null, "propertyName": "zeppelin.spark.maxResult", "defaultValue": "1000", "description": "Max number of Spark SQL result to display.", "type": "number" }, "zeppelin.spark.importImplicit": { - "envName": "ZEPPELIN_SPARK_IMPORTIMPLICIT", + "envName": null, "propertyName": "zeppelin.spark.importImplicit", "defaultValue": true, "description": "Import implicits, UDF collection, and sql if set true. true by default.", @@ -168,21 +205,21 @@ "envName": "PYSPARK_PYTHON", "propertyName": "PYSPARK_PYTHON", "defaultValue": "python", - "description": "Python command to run pyspark with", + "description": "Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set", "type": "string" }, "PYSPARK_DRIVER_PYTHON": { "envName": "PYSPARK_DRIVER_PYTHON", "propertyName": "PYSPARK_DRIVER_PYTHON", "defaultValue": "python", - "description": "Python command to run pyspark with", + "description": "Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set", "type": "string" }, "zeppelin.pyspark.useIPython": { "envName": null, "propertyName": "zeppelin.pyspark.useIPython", "defaultValue": true, - "description": "whether use IPython when it is available", + "description": "Whether use IPython when it is available", "type": "checkbox" } }, @@ -201,7 +238,8 @@ "editor": { "language": "python", "editOnDblClick": false, - "completionSupport": true + "completionSupport": true, + "completionKey": "TAB" } }, { @@ -210,28 +248,28 @@ "className": "org.apache.zeppelin.spark.SparkRInterpreter", "properties": { "zeppelin.R.knitr": { - "envName": "ZEPPELIN_R_KNITR", + "envName": null, "propertyName": "zeppelin.R.knitr", "defaultValue": true, - "description": "whether use knitr or not", + "description": "Whether use knitr or not", "type": "checkbox" }, "zeppelin.R.cmd": { - "envName": "ZEPPELIN_R_CMD", + "envName": null, "propertyName": "zeppelin.R.cmd", "defaultValue": "R", - "description": "R repl path", + "description": "R binary executable path", "type": "string" }, "zeppelin.R.image.width": { - "envName": "ZEPPELIN_R_IMAGE_WIDTH", + "envName": null, "propertyName": "zeppelin.R.image.width", "defaultValue": "100%", "description": "", "type": "number" }, "zeppelin.R.render.options": { - "envName": "ZEPPELIN_R_RENDER_OPTIONS", + "envName": null, "propertyName": "zeppelin.R.render.options", "defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2", "description": "", @@ -241,7 +279,8 @@ "editor": { "language": "r", "editOnDblClick": false, - "completionSupport": false + "completionSupport": false, + "completionKey": "TAB" } }, { @@ -253,7 +292,21 @@ "editor": { "language": "r", "editOnDblClick": false, - "completionSupport": true + "completionSupport": true, + "completionKey": "TAB" + } + }, + { + "group": "spark", + "name": "shiny", + "className": "org.apache.zeppelin.spark.SparkShinyInterpreter", + "properties": { + }, + "editor": { + "language": "r", + "editOnDblClick": false, + "completionSupport": true, + "completionKey": "TAB" } }, { diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java index 2445cce9c01..7e486661406 100644 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java @@ -54,7 +54,6 @@ public void setUp() throws InterpreterException { properties.setProperty("zeppelin.pyspark.python", "python"); properties.setProperty("zeppelin.dep.localrepo", Files.createTempDir().getAbsolutePath()); properties.setProperty("zeppelin.pyspark.useIPython", "false"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.python.gatewayserver_address", "127.0.0.1"); properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); @@ -109,7 +108,6 @@ public void testFailtoLaunchPythonProcess() throws InterpreterException { properties.setProperty("spark.pyspark.python", "invalid_python"); properties.setProperty("zeppelin.python.useIPython", "false"); properties.setProperty("zeppelin.python.gatewayserver_address", "127.0.0.1"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.maxResult", "3"); interpreter = new LazyOpenInterpreter(new PySparkInterpreter(properties)); diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java index 1feb002350c..b453b13dd09 100644 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java @@ -72,7 +72,6 @@ public void testSparkInterpreter() throws IOException, InterruptedException, Int properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.uiWebUrl", "fake_spark_weburl"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -388,7 +387,6 @@ public void testDisableReplOutput() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.printREPLOutput", "false"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -416,7 +414,6 @@ public void testSchedulePool() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("spark.scheduler.mode", "FAIR"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -446,7 +443,6 @@ public void testDisableSparkUI_1() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("spark.ui.enabled", "false"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -472,7 +468,6 @@ public void testDisableSparkUI_2() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.ui.hidden", "true"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -497,7 +492,6 @@ public void testScopedMode() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java index 65843917112..011812ec95d 100644 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java @@ -54,7 +54,6 @@ public void setUp() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.R.knitr", "true"); properties.setProperty("spark.r.backendConnectionTimeout", "10"); properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java new file mode 100644 index 00000000000..eb0e56c6d19 --- /dev/null +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.spark; + +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.http.exceptions.UnirestException; +import org.apache.commons.io.IOUtils; +import org.apache.zeppelin.interpreter.InterpreterContext; +import org.apache.zeppelin.interpreter.InterpreterException; +import org.apache.zeppelin.interpreter.InterpreterGroup; +import org.apache.zeppelin.interpreter.InterpreterResult; +import org.apache.zeppelin.interpreter.InterpreterResultMessage; +import org.apache.zeppelin.interpreter.LazyOpenInterpreter; +import org.apache.zeppelin.r.ShinyInterpreterTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class SparkShinyInterpreterTest extends ShinyInterpreterTest { + + private SparkInterpreter sparkInterpreter; + + @Before + public void setUp() throws InterpreterException { + Properties properties = new Properties(); + properties.setProperty("master", "local[*]"); + properties.setProperty("spark.app.name", "test"); + + InterpreterContext context = getInterpreterContext(); + InterpreterContext.set(context); + interpreter = new SparkShinyInterpreter(properties); + + InterpreterGroup interpreterGroup = new InterpreterGroup(); + interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(interpreter), "session_1"); + interpreter.setInterpreterGroup(interpreterGroup); + + sparkInterpreter = new SparkInterpreter(properties); + interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkInterpreter), "session_1"); + sparkInterpreter.setInterpreterGroup(interpreterGroup); + + interpreter.open(); + } + + @After + public void tearDown() throws InterpreterException { + if (interpreter != null) { + interpreter.close(); + } + } + + @Test + public void testSparkShinyApp() throws IOException, InterpreterException, InterruptedException, UnirestException { + /****************** Launch Shiny app with default app name *****************************/ + InterpreterContext context = getInterpreterContext(); + context.getLocalProperties().put("type", "ui"); + InterpreterResult result = + interpreter.interpret(IOUtils.toString(getClass().getResource("/spark_ui.R")), context); + assertEquals(InterpreterResult.Code.SUCCESS, result.code()); + + context = getInterpreterContext(); + context.getLocalProperties().put("type", "server"); + result = interpreter.interpret(IOUtils.toString(getClass().getResource("/spark_server.R")), context); + assertEquals(InterpreterResult.Code.SUCCESS, result.code()); + + final InterpreterContext context2 = getInterpreterContext(); + context2.getLocalProperties().put("type", "run"); + Thread thread = new Thread(() -> { + try { + interpreter.interpret("", context2); + } catch (Exception e) { + e.printStackTrace(); + } + }); + thread.start(); + // wait for the shiny app start + Thread.sleep(5 * 1000); + // extract shiny url + List resultMessages = context2.out.toInterpreterResultMessage(); + assertEquals(1, resultMessages.size()); + assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType()); + String resultMessageData = resultMessages.get(0).getData(); + assertTrue(resultMessageData, resultMessageData.contains(" response = Unirest.get(shinyURL).asString(); + if (sparkInterpreter.getSparkVersion().isSpark2()) { + assertEquals(200, response.getStatus()); + assertTrue(response.getBody(), response.getBody().contains("Spark Version")); + } else { + // spark 1.x will fail due to sparkR.version is not available for spark 1.x + assertEquals(500, response.getStatus()); + assertTrue(response.getBody(), + response.getBody().contains("could not find function \"sparkR.version\"")); + } + } +} diff --git a/spark/interpreter/src/test/resources/spark_server.R b/spark/interpreter/src/test/resources/spark_server.R new file mode 100644 index 00000000000..071631dd79f --- /dev/null +++ b/spark/interpreter/src/test/resources/spark_server.R @@ -0,0 +1,23 @@ +# Define server logic to summarize and view selected dataset ---- +server <- function(input, output) { + + # Return the requested dataset ---- + datasetInput <- reactive({ + switch(input$dataset, + "rock" = as.DataFrame(rock), + "pressure" = as.DataFrame(pressure), + "cars" = as.DataFrame(cars)) + }) + + # Generate a summary of the dataset ---- + output$summary <- renderPrint({ + dataset <- datasetInput() + showDF(summary(dataset)) + }) + + # Show the first "n" observations ---- + output$view <- renderTable({ + head(datasetInput(), n = input$obs) + }) + +} \ No newline at end of file diff --git a/spark/interpreter/src/test/resources/spark_ui.R b/spark/interpreter/src/test/resources/spark_ui.R new file mode 100644 index 00000000000..a81ad0c2bcd --- /dev/null +++ b/spark/interpreter/src/test/resources/spark_ui.R @@ -0,0 +1,35 @@ +# Define UI for dataset viewer app ---- +ui <- fluidPage( + +# App title ---- +titlePanel(paste("Spark Version", sparkR.version(), sep=":")), + +# Sidebar layout with a input and output definitions ---- +sidebarLayout( + +# Sidebar panel for inputs ---- +sidebarPanel( + +# Input: Selector for choosing dataset ---- +selectInput(inputId = "dataset", +label = "Choose a dataset:", +choices = c("rock", "pressure", "cars")), + +# Input: Numeric entry for number of obs to view ---- +numericInput(inputId = "obs", +label = "Number of observations to view:", +value = 10) +), + +# Main panel for displaying outputs ---- +mainPanel( + +# Output: Verbatim text for data summary ---- +verbatimTextOutput("summary"), + +# Output: HTML table with requested number of observations ---- +tableOutput("view") + +) +) +) \ No newline at end of file diff --git a/spark/pom.xml b/spark/pom.xml index 32b006f0c2f..876b14e6494 100644 --- a/spark/pom.xml +++ b/spark/pom.xml @@ -198,8 +198,11 @@ spark-2.4 + + true + - 2.4.3 + 2.4.4 2.5.0 0.10.7 @@ -216,9 +219,6 @@ spark-2.2 - - true - 2.2.3 0.10.7 diff --git a/spark/scala-2.11/pom.xml b/spark/scala-2.11/pom.xml index 0fdb1590c2b..3cab22388e0 100644 --- a/spark/scala-2.11/pom.xml +++ b/spark/scala-2.11/pom.xml @@ -32,7 +32,7 @@ Zeppelin: Spark Interpreter Scala_2.11 - 2.4.3 + 2.4.4 2.11.12 2.11 ${spark.scala.version} diff --git a/spark/scala-2.12/pom.xml b/spark/scala-2.12/pom.xml index 086203bdde2..fd31af4e8ac 100644 --- a/spark/scala-2.12/pom.xml +++ b/spark/scala-2.12/pom.xml @@ -33,7 +33,7 @@ Zeppelin: Spark Interpreter Scala_2.12 - 2.4.3 + 2.4.4 2.12.8 2.12 ${spark.scala.version} diff --git a/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala b/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala index 87500114b68..e62fc96900f 100644 --- a/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala +++ b/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala @@ -52,8 +52,6 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, protected lazy val LOGGER: Logger = LoggerFactory.getLogger(getClass) - private val isTest = conf.getBoolean("zeppelin.spark.test", false) - protected var sc: SparkContext = _ protected var sqlContext: SQLContext = _ @@ -197,9 +195,7 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, private def spark1CreateContext(): Unit = { this.sc = SparkContext.getOrCreate(conf) - if (!isTest) { - interpreterOutput.write("Created SparkContext.\n".getBytes()) - } + LOGGER.info("Created SparkContext") getUserFiles().foreach(file => sc.addFile(file)) sc.getClass.getMethod("ui").invoke(sc).asInstanceOf[Option[_]] match { @@ -214,19 +210,13 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, if (hiveEnabled && hiveSiteExisted) { sqlContext = Class.forName("org.apache.spark.sql.hive.HiveContext") .getConstructor(classOf[SparkContext]).newInstance(sc).asInstanceOf[SQLContext] - if (!isTest) { - interpreterOutput.write("Created sql context (with Hive support).\n".getBytes()) - } + LOGGER.info("Created sql context (with Hive support)") } else { - if (hiveEnabled && !hiveSiteExisted && !isTest) { - interpreterOutput.write(("spark.useHiveContext is set as true but no hive-site.xml" + - " is found in classpath, so zeppelin will fallback to SQLContext.\n").getBytes()) - } + LOGGER.warn("spark.useHiveContext is set as true but no hive-site.xml" + + " is found in classpath, so zeppelin will fallback to SQLContext"); sqlContext = Class.forName("org.apache.spark.sql.SQLContext") .getConstructor(classOf[SparkContext]).newInstance(sc).asInstanceOf[SQLContext] - if (!isTest) { - interpreterOutput.write("Created sql context.\n".getBytes()) - } + LOGGER.info("Created sql context (without Hive support)") } bind("sc", "org.apache.spark.SparkContext", sc, List("""@transient""")) @@ -258,28 +248,20 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, if (hiveSiteExisted && hiveClassesPresent) { builder.getClass.getMethod("enableHiveSupport").invoke(builder) sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder) - if (!isTest) { - interpreterOutput.write("Created Spark session (with Hive support).\n".getBytes()) - } + LOGGER.info("Created Spark session (with Hive support)"); } else { - if (!hiveClassesPresent && !isTest) { - interpreterOutput.write( - "Hive support can not be enabled because spark is not built with hive\n".getBytes) + if (!hiveClassesPresent) { + LOGGER.warn("Hive support can not be enabled because spark is not built with hive") } - if (!hiveSiteExisted && !isTest) { - interpreterOutput.write( - "Hive support can not be enabled because no hive-site.xml found\n".getBytes) + if (!hiveSiteExisted) { + LOGGER.warn("Hive support can not be enabled because no hive-site.xml found") } sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder) - if (!isTest) { - interpreterOutput.write("Created Spark session.\n".getBytes()) - } + LOGGER.info("Created Spark session (without Hive support)"); } } else { sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder) - if (!isTest) { - interpreterOutput.write("Created Spark session.\n".getBytes()) - } + LOGGER.info("Created Spark session (without Hive support)"); } sc = sparkSession.getClass.getMethod("sparkContext").invoke(sparkSession) diff --git a/submarine/pom.xml b/submarine/pom.xml index ea0a1626cf3..3d5de0b9c20 100644 --- a/submarine/pom.xml +++ b/submarine/pom.xml @@ -57,6 +57,17 @@ zeppelin-python 0.9.0-SNAPSHOT + + org.apache.zeppelin + zeppelin-jupyter-interpreter + ${project.version} + + + net.sf.py4j + py4j + + + org.apache.zeppelin zeppelin-shell diff --git a/zeppelin-distribution/pom.xml b/zeppelin-distribution/pom.xml index 271067060c1..380e7a2f719 100644 --- a/zeppelin-distribution/pom.xml +++ b/zeppelin-distribution/pom.xml @@ -85,6 +85,12 @@ ${project.version} war + + ${project.groupId} + zeppelin-web-angular + ${project.version} + war + diff --git a/zeppelin-distribution/src/assemble/distribution.xml b/zeppelin-distribution/src/assemble/distribution.xml index 0c5e8b64433..0b18b4ae128 100644 --- a/zeppelin-distribution/src/assemble/distribution.xml +++ b/zeppelin-distribution/src/assemble/distribution.xml @@ -26,7 +26,7 @@ true zeppelin-${project.version} - + ${project.groupId}:zeppelin-web + ${project.groupId}:zeppelin-web-angular false false @@ -42,6 +43,7 @@ /lib ${project.groupId}:zeppelin-web + ${project.groupId}:zeppelin-web-angular false true diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java index 96b484ae24c..aae495105ea 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java @@ -33,7 +33,7 @@ public SparkIntegrationTest24(String sparkVersion) { @Parameterized.Parameters public static List data() { return Arrays.asList(new Object[][]{ - {"2.4.3"} + {"2.4.4"} }); } diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java index 0cb6db80e17..81e476f7f9e 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java @@ -109,8 +109,6 @@ public void setupSparkInterpreter(String sparkHome) throws InterpreterException new InterpreterProperty("zeppelin.pyspark.useIPython", "false")); sparkProperties.put("zeppelin.spark.useNew", new InterpreterProperty("zeppelin.spark.useNew", "true")); - sparkProperties.put("zeppelin.spark.test", - new InterpreterProperty("zeppelin.spark.test", "true")); sparkProperties.put("spark.serializer", new InterpreterProperty("spark.serializer", "org.apache.spark.serializer.KryoSerializer")); sparkProperties.put("zeppelin.spark.scala.color", diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java index 4431f942e65..a55a5043a47 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java @@ -33,7 +33,7 @@ public ZeppelinSparkClusterTest24(String sparkVersion) throws Exception { @Parameterized.Parameters public static List data() { return Arrays.asList(new Object[][]{ - {"2.4.3"} + {"2.4.4"} }); } } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index 2a6e0bbbf2e..a6123ec661b 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -812,6 +812,7 @@ public enum ConfVars { ZEPPELIN_SSL_TRUSTSTORE_TYPE("zeppelin.ssl.truststore.type", null), ZEPPELIN_SSL_TRUSTSTORE_PASSWORD("zeppelin.ssl.truststore.password", null), ZEPPELIN_WAR("zeppelin.war", "zeppelin-web/dist"), + ZEPPELIN_ANGULAR_WAR("zeppelin.angular.war", "zeppelin-web-angular/dist"), ZEPPELIN_WAR_TEMPDIR("zeppelin.war.tempdir", "webapps"), ZEPPELIN_INTERPRETER_JSON("zeppelin.interpreter.setting", "interpreter-setting.json"), diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java index 5ac1c0a8dcd..41768adaf7e 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java @@ -235,6 +235,15 @@ public synchronized void runParagraphs(String noteId, } } + public synchronized void checkpointOutput(String noteId, String paragraphId) { + try { + intpEventServiceClient.checkpointOutput(noteId, paragraphId); + } catch (TException e) { + LOGGER.warn("Fail to checkpointOutput of paragraph: " + + paragraphId + " of note: " + noteId, e); + } + } + public synchronized void onAppOutputAppend( String noteId, String paragraphId, int index, String appId, String output) { AppOutputAppendEvent event = diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java index 7aa2081f3c2..4b053d626b6 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AngularObjectId implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AngularObjectId"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java index 38cff035212..2511ab94b26 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AppOutputAppendEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputAppendEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java index f14b70190c4..8f4c9ca70d4 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AppOutputUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java index 90e6b0d1b6f..550efebd399 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AppStatusUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppStatusUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java index 688daad2d99..ddb5512ab39 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class InterpreterCompletion implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("InterpreterCompletion"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java index 49e5d742b53..c0757fe1d33 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class OutputAppendEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputAppendEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java index 6b9c81c03f7..944241e2c61 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class OutputUpdateAllEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateAllEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java index df163d64c56..cea1774df53 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class OutputUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java index 59e73405e2c..465b8bf31f1 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class ParagraphInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ParagraphInfo"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java index 8cd7b2e1a5e..8744e2b7718 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RegisterInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RegisterInfo"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java index b38b2c4df31..d869dffa324 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteApplicationResult implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteApplicationResult"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java index ddc1d3c353c..ce9dff3eba8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterContext implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterContext"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java index 6fd85d5fae6..2a992086f6f 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java index 8ef10331013..e1eb9e8eab3 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterEventService { public interface Iface { @@ -43,6 +43,8 @@ public interface Iface { public void updateAppStatus(AppStatusUpdateEvent event) throws org.apache.thrift.TException; + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId) throws org.apache.thrift.TException; + public void runParagraphs(RunParagraphsEvent event) throws org.apache.thrift.TException; public void addAngularObject(java.lang.String intpGroupId, java.lang.String json) throws org.apache.thrift.TException; @@ -79,6 +81,8 @@ public interface AsyncIface { public void updateAppStatus(AppStatusUpdateEvent event, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void runParagraphs(RunParagraphsEvent event, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; public void addAngularObject(java.lang.String intpGroupId, java.lang.String json, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; @@ -259,6 +263,27 @@ public void recv_updateAppStatus() throws org.apache.thrift.TException return; } + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId) throws org.apache.thrift.TException + { + send_checkpointOutput(noteId, paragraphId); + recv_checkpointOutput(); + } + + public void send_checkpointOutput(java.lang.String noteId, java.lang.String paragraphId) throws org.apache.thrift.TException + { + checkpointOutput_args args = new checkpointOutput_args(); + args.setNoteId(noteId); + args.setParagraphId(paragraphId); + sendBase("checkpointOutput", args); + } + + public void recv_checkpointOutput() throws org.apache.thrift.TException + { + checkpointOutput_result result = new checkpointOutput_result(); + receiveBase(result, "checkpointOutput"); + return; + } + public void runParagraphs(RunParagraphsEvent event) throws org.apache.thrift.TException { send_runParagraphs(event); @@ -704,6 +729,41 @@ public Void getResult() throws org.apache.thrift.TException { } } + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + checkReady(); + checkpointOutput_call method_call = new checkpointOutput_call(noteId, paragraphId, resultHandler, this, ___protocolFactory, ___transport); + this.___currentMethod = method_call; + ___manager.call(method_call); + } + + public static class checkpointOutput_call extends org.apache.thrift.async.TAsyncMethodCall { + private java.lang.String noteId; + private java.lang.String paragraphId; + public checkpointOutput_call(java.lang.String noteId, java.lang.String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + super(client, protocolFactory, transport, resultHandler, false); + this.noteId = noteId; + this.paragraphId = paragraphId; + } + + public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { + prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("checkpointOutput", org.apache.thrift.protocol.TMessageType.CALL, 0)); + checkpointOutput_args args = new checkpointOutput_args(); + args.setNoteId(noteId); + args.setParagraphId(paragraphId); + args.write(prot); + prot.writeMessageEnd(); + } + + public Void getResult() throws org.apache.thrift.TException { + if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { + throw new java.lang.IllegalStateException("Method call not finished!"); + } + org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); + org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); + return null; + } + } + public void runParagraphs(RunParagraphsEvent event, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); runParagraphs_call method_call = new runParagraphs_call(event, resultHandler, this, ___protocolFactory, ___transport); @@ -1036,6 +1096,7 @@ protected Processor(I iface, java.util.Map extends org.apache.thrift.ProcessFunction { + public checkpointOutput() { + super("checkpointOutput"); + } + + public checkpointOutput_args getEmptyArgsInstance() { + return new checkpointOutput_args(); + } + + protected boolean isOneway() { + return false; + } + + @Override + protected boolean rethrowUnhandledExceptions() { + return false; + } + + public checkpointOutput_result getResult(I iface, checkpointOutput_args args) throws org.apache.thrift.TException { + checkpointOutput_result result = new checkpointOutput_result(); + iface.checkpointOutput(args.noteId, args.paragraphId); + return result; + } + } + public static class runParagraphs extends org.apache.thrift.ProcessFunction { public runParagraphs() { super("runParagraphs"); @@ -1472,6 +1558,7 @@ protected AsyncProcessor(I iface, java.util.Map extends org.apache.thrift.AsyncProcessFunction { + public checkpointOutput() { + super("checkpointOutput"); + } + + public checkpointOutput_args getEmptyArgsInstance() { + return new checkpointOutput_args(); + } + + public org.apache.thrift.async.AsyncMethodCallback getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) { + final org.apache.thrift.AsyncProcessFunction fcall = this; + return new org.apache.thrift.async.AsyncMethodCallback() { + public void onComplete(Void o) { + checkpointOutput_result result = new checkpointOutput_result(); + try { + fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid); + } catch (org.apache.thrift.transport.TTransportException e) { + _LOGGER.error("TTransportException writing to internal frame buffer", e); + fb.close(); + } catch (java.lang.Exception e) { + _LOGGER.error("Exception writing to internal frame buffer", e); + onError(e); + } + } + public void onError(java.lang.Exception e) { + byte msgType = org.apache.thrift.protocol.TMessageType.REPLY; + org.apache.thrift.TSerializable msg; + checkpointOutput_result result = new checkpointOutput_result(); + if (e instanceof org.apache.thrift.transport.TTransportException) { + _LOGGER.error("TTransportException inside handler", e); + fb.close(); + return; + } else if (e instanceof org.apache.thrift.TApplicationException) { + _LOGGER.error("TApplicationException inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = (org.apache.thrift.TApplicationException)e; + } else { + _LOGGER.error("Exception inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage()); + } + try { + fcall.sendResponse(fb,msg,msgType,seqid); + } catch (java.lang.Exception ex) { + _LOGGER.error("Exception writing to internal frame buffer", ex); + fb.close(); + } + } + }; + } + + protected boolean isOneway() { + return false; + } + + public void start(I iface, checkpointOutput_args args, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + iface.checkpointOutput(args.noteId, args.paragraphId,resultHandler); + } + } + public static class runParagraphs extends org.apache.thrift.AsyncProcessFunction { public runParagraphs() { super("runParagraphs"); @@ -6836,6 +6983,732 @@ private static S scheme(org.apache. } } + public static class checkpointOutput_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("checkpointOutput_args"); + + private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)2); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new checkpointOutput_argsStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new checkpointOutput_argsTupleSchemeFactory(); + + public @org.apache.thrift.annotation.Nullable java.lang.String noteId; // required + public @org.apache.thrift.annotation.Nullable java.lang.String paragraphId; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + NOTE_ID((short)1, "noteId"), + PARAGRAPH_ID((short)2, "paragraphId"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // NOTE_ID + return NOTE_ID; + case 2: // PARAGRAPH_ID + return PARAGRAPH_ID; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.PARAGRAPH_ID, new org.apache.thrift.meta_data.FieldMetaData("paragraphId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(checkpointOutput_args.class, metaDataMap); + } + + public checkpointOutput_args() { + } + + public checkpointOutput_args( + java.lang.String noteId, + java.lang.String paragraphId) + { + this(); + this.noteId = noteId; + this.paragraphId = paragraphId; + } + + /** + * Performs a deep copy on other. + */ + public checkpointOutput_args(checkpointOutput_args other) { + if (other.isSetNoteId()) { + this.noteId = other.noteId; + } + if (other.isSetParagraphId()) { + this.paragraphId = other.paragraphId; + } + } + + public checkpointOutput_args deepCopy() { + return new checkpointOutput_args(this); + } + + @Override + public void clear() { + this.noteId = null; + this.paragraphId = null; + } + + @org.apache.thrift.annotation.Nullable + public java.lang.String getNoteId() { + return this.noteId; + } + + public checkpointOutput_args setNoteId(@org.apache.thrift.annotation.Nullable java.lang.String noteId) { + this.noteId = noteId; + return this; + } + + public void unsetNoteId() { + this.noteId = null; + } + + /** Returns true if field noteId is set (has been assigned a value) and false otherwise */ + public boolean isSetNoteId() { + return this.noteId != null; + } + + public void setNoteIdIsSet(boolean value) { + if (!value) { + this.noteId = null; + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.String getParagraphId() { + return this.paragraphId; + } + + public checkpointOutput_args setParagraphId(@org.apache.thrift.annotation.Nullable java.lang.String paragraphId) { + this.paragraphId = paragraphId; + return this; + } + + public void unsetParagraphId() { + this.paragraphId = null; + } + + /** Returns true if field paragraphId is set (has been assigned a value) and false otherwise */ + public boolean isSetParagraphId() { + return this.paragraphId != null; + } + + public void setParagraphIdIsSet(boolean value) { + if (!value) { + this.paragraphId = null; + } + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + case NOTE_ID: + if (value == null) { + unsetNoteId(); + } else { + setNoteId((java.lang.String)value); + } + break; + + case PARAGRAPH_ID: + if (value == null) { + unsetParagraphId(); + } else { + setParagraphId((java.lang.String)value); + } + break; + + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case NOTE_ID: + return getNoteId(); + + case PARAGRAPH_ID: + return getParagraphId(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case NOTE_ID: + return isSetNoteId(); + case PARAGRAPH_ID: + return isSetParagraphId(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof checkpointOutput_args) + return this.equals((checkpointOutput_args)that); + return false; + } + + public boolean equals(checkpointOutput_args that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_noteId = true && this.isSetNoteId(); + boolean that_present_noteId = true && that.isSetNoteId(); + if (this_present_noteId || that_present_noteId) { + if (!(this_present_noteId && that_present_noteId)) + return false; + if (!this.noteId.equals(that.noteId)) + return false; + } + + boolean this_present_paragraphId = true && this.isSetParagraphId(); + boolean that_present_paragraphId = true && that.isSetParagraphId(); + if (this_present_paragraphId || that_present_paragraphId) { + if (!(this_present_paragraphId && that_present_paragraphId)) + return false; + if (!this.paragraphId.equals(that.paragraphId)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetNoteId()) ? 131071 : 524287); + if (isSetNoteId()) + hashCode = hashCode * 8191 + noteId.hashCode(); + + hashCode = hashCode * 8191 + ((isSetParagraphId()) ? 131071 : 524287); + if (isSetParagraphId()) + hashCode = hashCode * 8191 + paragraphId.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(checkpointOutput_args other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetNoteId()).compareTo(other.isSetNoteId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetNoteId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.noteId, other.noteId); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetParagraphId()).compareTo(other.isSetParagraphId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetParagraphId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.paragraphId, other.paragraphId); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("checkpointOutput_args("); + boolean first = true; + + sb.append("noteId:"); + if (this.noteId == null) { + sb.append("null"); + } else { + sb.append(this.noteId); + } + first = false; + if (!first) sb.append(", "); + sb.append("paragraphId:"); + if (this.paragraphId == null) { + sb.append("null"); + } else { + sb.append(this.paragraphId); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class checkpointOutput_argsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_argsStandardScheme getScheme() { + return new checkpointOutput_argsStandardScheme(); + } + } + + private static class checkpointOutput_argsStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, checkpointOutput_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // NOTE_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // PARAGRAPH_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.paragraphId = iprot.readString(); + struct.setParagraphIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, checkpointOutput_args struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.noteId != null) { + oprot.writeFieldBegin(NOTE_ID_FIELD_DESC); + oprot.writeString(struct.noteId); + oprot.writeFieldEnd(); + } + if (struct.paragraphId != null) { + oprot.writeFieldBegin(PARAGRAPH_ID_FIELD_DESC); + oprot.writeString(struct.paragraphId); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class checkpointOutput_argsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_argsTupleScheme getScheme() { + return new checkpointOutput_argsTupleScheme(); + } + } + + private static class checkpointOutput_argsTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetNoteId()) { + optionals.set(0); + } + if (struct.isSetParagraphId()) { + optionals.set(1); + } + oprot.writeBitSet(optionals, 2); + if (struct.isSetNoteId()) { + oprot.writeString(struct.noteId); + } + if (struct.isSetParagraphId()) { + oprot.writeString(struct.paragraphId); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(2); + if (incoming.get(0)) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } + if (incoming.get(1)) { + struct.paragraphId = iprot.readString(); + struct.setParagraphIdIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + + public static class checkpointOutput_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("checkpointOutput_result"); + + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new checkpointOutput_resultStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new checkpointOutput_resultTupleSchemeFactory(); + + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { +; + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(checkpointOutput_result.class, metaDataMap); + } + + public checkpointOutput_result() { + } + + /** + * Performs a deep copy on other. + */ + public checkpointOutput_result(checkpointOutput_result other) { + } + + public checkpointOutput_result deepCopy() { + return new checkpointOutput_result(this); + } + + @Override + public void clear() { + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof checkpointOutput_result) + return this.equals((checkpointOutput_result)that); + return false; + } + + public boolean equals(checkpointOutput_result that) { + if (that == null) + return false; + if (this == that) + return true; + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + return hashCode; + } + + @Override + public int compareTo(checkpointOutput_result other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("checkpointOutput_result("); + boolean first = true; + + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class checkpointOutput_resultStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_resultStandardScheme getScheme() { + return new checkpointOutput_resultStandardScheme(); + } + } + + private static class checkpointOutput_resultStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, checkpointOutput_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, checkpointOutput_result struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class checkpointOutput_resultTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_resultTupleScheme getScheme() { + return new checkpointOutput_resultTupleScheme(); + } + } + + private static class checkpointOutput_resultTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + public static class runParagraphs_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("runParagraphs_args"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java index 47a2bce5562..06be47a1ed1 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public enum RemoteInterpreterEventType implements org.apache.thrift.TEnum { NO_OP(1), ANGULAR_OBJECT_ADD(2), diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java index ea8f808af64..2817903c9a8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterResult implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResult"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java index 877d22d8bdf..e0ec93678d3 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterResultMessage implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResultMessage"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java index 6804d1590f2..68dc727703d 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterService { public interface Iface { diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java index cda3c896789..72cae21620b 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RunParagraphsEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RunParagraphsEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java index fc9ac317862..48861827f27 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class ServiceException extends org.apache.thrift.TException implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ServiceException"); diff --git a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift index 6470a67d09d..339f3e5ba41 100644 --- a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift +++ b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift @@ -107,6 +107,8 @@ service RemoteInterpreterEventService { void updateAppOutput(1: AppOutputUpdateEvent event); void updateAppStatus(1: AppStatusUpdateEvent event); + void checkpointOutput(1: string noteId, 2: string paragraphId); + void runParagraphs(1: RunParagraphsEvent event); void addAngularObject(1: string intpGroupId, 2: string json); diff --git a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java index 54112d47c43..1f4e2005599 100644 --- a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java +++ b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java @@ -104,8 +104,10 @@ public void setInterpreterContext(InterpreterContext context) { * @throws IOException */ private boolean checkForShinyApp(String response) throws IOException { - if (context.getInterpreterClassName() != null && - context.getInterpreterClassName().equals("org.apache.zeppelin.r.ShinyInterpreter")) { + String intpClassName = context.getInterpreterClassName(); + if (intpClassName != null && + (intpClassName.equals("org.apache.zeppelin.r.ShinyInterpreter") || + intpClassName.equals("org.apache.zeppelin.spark.SparkShinyInterpreter"))) { Matcher matcher = ShinyListeningPattern.matcher(response); if (matcher.matches()) { String url = matcher.group(1); @@ -119,6 +121,8 @@ private boolean checkForShinyApp(String response) throws IOException { height + "\" width=\"" + width + "\" frameBorder=\"0\">"); context.out.flush(); context.out.write("\n%text "); + context.getIntpEventClient().checkpointOutput(context.getNoteId(), + context.getParagraphId()); return true; } } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java index f9d8e8b6262..966f5b553aa 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java @@ -97,6 +97,7 @@ /** Main class of Zeppelin. */ public class ZeppelinServer extends ResourceConfig { private static final Logger LOG = LoggerFactory.getLogger(ZeppelinServer.class); + private static final String WEB_APP_CONTEXT_NEXT = "/next"; public static Server jettyWebServer; public static ServiceLocator sharedServiceLocator; @@ -119,9 +120,6 @@ public static void main(String[] args) throws InterruptedException { ContextHandlerCollection contexts = new ContextHandlerCollection(); jettyWebServer.setHandler(contexts); - // Web UI - final WebAppContext webApp = setupWebAppContext(contexts, conf); - sharedServiceLocator = ServiceLocatorFactory.getInstance().create("shared-locator"); ServiceLocatorUtilities.enableImmediateScope(sharedServiceLocator); ServiceLocatorUtilities.addClasses(sharedServiceLocator, @@ -180,25 +178,12 @@ protected void configure() { } }); - webApp.addEventListener( - new ServletContextListener() { - @Override - public void contextInitialized(ServletContextEvent servletContextEvent) { - servletContextEvent - .getServletContext() - .setAttribute(ServletProperties.SERVICE_LOCATOR, sharedServiceLocator); - } - - @Override - public void contextDestroyed(ServletContextEvent servletContextEvent) {} - }); - - // Create `ZeppelinServer` using reflection and setup REST Api - setupRestApiContextHandler(webApp, conf); - - // Notebook server - setupNotebookServer(webApp, conf, sharedServiceLocator); + // Multiple Web UI + final WebAppContext defaultWebApp = setupWebAppContext(contexts, conf, conf.getString(ConfVars.ZEPPELIN_WAR), conf.getServerContextPath()); + final WebAppContext nextWebApp = setupWebAppContext(contexts, conf, conf.getString(ConfVars.ZEPPELIN_ANGULAR_WAR), WEB_APP_CONTEXT_NEXT); + initWebApp(defaultWebApp); + initWebApp(nextWebApp); // Cluster Manager Server setupClusterManagerServer(sharedServiceLocator); @@ -304,14 +289,18 @@ private static Server setupJettyServer(ZeppelinConfiguration conf) { conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_MIN), conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_TIMEOUT)); final Server server = new Server(threadPool); - ServerConnector connector; + initServerConnector(server, conf.getServerPort(), conf.getServerSslPort()); + return server; + } + private static void initServerConnector(Server server, int port, int sslPort) { + ServerConnector connector; HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.addCustomizer(new ForwardedRequestCustomizer()); if (conf.useSsl()) { - LOG.debug("Enabling SSL for Zeppelin Server on port " + conf.getServerSslPort()); + LOG.debug("Enabling SSL for Zeppelin Server on port " + sslPort); httpConfig.setSecureScheme("https"); - httpConfig.setSecurePort(conf.getServerSslPort()); + httpConfig.setSecurePort(sslPort); httpConfig.setOutputBufferSize(32768); httpConfig.setResponseHeaderSize(8192); httpConfig.setSendServerVersion(true); @@ -321,28 +310,20 @@ private static Server setupJettyServer(ZeppelinConfiguration conf) { httpsConfig.addCustomizer(src); connector = - new ServerConnector( - server, - new SslConnectionFactory(getSslContextFactory(conf), HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory(httpsConfig)); + new ServerConnector( + server, + new SslConnectionFactory(getSslContextFactory(conf), HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfig)); } else { connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); + connector.setPort(port); } - configureRequestHeaderSize(conf, connector); // Set some timeout options to make debugging easier. int timeout = 1000 * 30; connector.setIdleTimeout(timeout); connector.setHost(conf.getServerAddress()); - if (conf.useSsl()) { - connector.setPort(conf.getServerSslPort()); - } else { - connector.setPort(conf.getServerPort()); - } - server.addConnector(connector); - - return server; } private static void configureRequestHeaderSize( @@ -437,19 +418,20 @@ private static void setupRestApiContextHandler(WebAppContext webapp, ZeppelinCon } private static WebAppContext setupWebAppContext( - ContextHandlerCollection contexts, ZeppelinConfiguration conf) { + ContextHandlerCollection contexts, ZeppelinConfiguration conf, String warPath, String contextPath) { WebAppContext webApp = new WebAppContext(); - webApp.setContextPath(conf.getServerContextPath()); - File warPath = new File(conf.getString(ConfVars.ZEPPELIN_WAR)); - if (warPath.isDirectory()) { + webApp.setContextPath(contextPath); + LOG.info("warPath is: {}", warPath); + File warFile = new File(warPath); + if (warFile.isDirectory()) { // Development mode, read from FS // webApp.setDescriptor(warPath+"/WEB-INF/web.xml"); - webApp.setResourceBase(warPath.getPath()); + webApp.setResourceBase(warFile.getPath()); webApp.setParentLoaderPriority(true); } else { // use packaged WAR - webApp.setWar(warPath.getAbsolutePath()); - File warTempDirectory = new File(conf.getRelativeDir(ConfVars.ZEPPELIN_WAR_TEMPDIR)); + webApp.setWar(warFile.getAbsolutePath()); + File warTempDirectory = new File(conf.getRelativeDir(ConfVars.ZEPPELIN_WAR_TEMPDIR) + contextPath); warTempDirectory.mkdir(); LOG.info("ZeppelinServer Webapp path: {}", warTempDirectory.getPath()); webApp.setTempDirectory(warTempDirectory); @@ -463,7 +445,27 @@ private static WebAppContext setupWebAppContext( webApp.setInitParameter( "org.eclipse.jetty.servlet.Default.dirAllowed", Boolean.toString(conf.getBoolean(ConfVars.ZEPPELIN_SERVER_DEFAULT_DIR_ALLOWED))); - return webApp; } + + private static void initWebApp(WebAppContext webApp) { + webApp.addEventListener( + new ServletContextListener() { + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + servletContextEvent + .getServletContext() + .setAttribute(ServletProperties.SERVICE_LOCATOR, sharedServiceLocator); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) {} + }); + + // Create `ZeppelinServer` using reflection and setup REST Api + setupRestApiContextHandler(webApp, conf); + + // Notebook server + setupNotebookServer(webApp, conf, sharedServiceLocator); + } } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 831c76e7eb3..291d2c240bb 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -1606,6 +1606,8 @@ public void onOutputUpdated(String noteId, String paragraphId, int index, LOG.warn("Note " + noteId + " note found"); return; } + Paragraph paragraph = note.getParagraph(paragraphId); + paragraph.updateOutputBuffer(index, type, output); if (note.isPersonalizedMode()) { String user = note.getParagraph(paragraphId).getUser(); if (null != user) { @@ -1886,6 +1888,16 @@ public void onOutputUpdateAll(Paragraph paragraph, List + +# Zeppelin WEB + +Zeppelin notebooks front-end built with Angular. + +- Jira issue [ZEPPELIN-4321](https://issues.apache.org/jira/browse/ZEPPELIN-4321) +- Design Document: [Zeppelin Notebook Rework Proposal](https://docs.google.com/document/d/1z_VscS81Xwx_3QaexKB2s0uEMEuWKsPXh9mWFRq0-hY) + +![screenshot](/screenshot.png?raw=true "Screenshot") + +## Setup + +### Prerequisites + +- [Node.js](https://nodejs.org) version 10.9.0 or later or use [creationix/nvm](https://github.com/creationix/nvm). +- NPM package manager (which is installed with Node.js by default). +- [Angular CLI](https://angular.io/cli) version 8.3.0 or later. + +### Install + +Run the `npm install` command to install dependencies in the project directory. + +### Start Zeppelin server + +[Run Zeppelin server](https://zeppelin.apache.org/contribution/contributions.html#run-zeppelin-server-in-development-mode) on `http://localhost:8080`. + +If you are using a custom port instead of the default(http://localhost:8080) or other network address, you can create `.env` file in the project directory and set `SERVER_PROXY`. + +*.env* + +``` +SERVER_PROXY=http://localhost:8080 +``` + +### Development server + +Run `npm start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +### Build + +Run `npm build` to build the project. The build artifacts will be stored in the `dist/` directory. + +### Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Implementation Progress + +### Pages + +| Name | Route | Module | UI | +| --- | ----- | ---------- | -- | +| Home | `/` | HomeModule | Y | +| Login | `/login` | LoginModule | Y | +| Job Manager | `/jobmanager` | JobManagerModule | Y | +| Interpreter Setting | `/interpreter` | InterpreterModule | Y | +| Notebook | `/notebook/{id}` | NotebookModule | Y | +| Notebook Repos | `/notebookRepos` | | | +| Credential | `/credential` | | | +| Helium | `/helium` | | WIP | +| Configuration | `/configuration` | | | + +### Notebook Features + +| Feature | Description | Status | +| ------ | ---- | ---- | +| Files System | Create/ Rename/ Import etc. | Y | +| Toolbar Actions | The top toolbar actions | Y | + +### Paragraph Features + +| Feature | Description | Status | +| ------ | ---- | ---- | +| Grid layout and resizable | | Y | +| Code Editor | | Y | +| Actions | The Corresponding actions of the drop-down menu in the setting button | Y | +| Actions(hot-keys) | Support hot-keys for the actions | WIP | +| Publishable | [publish paragraphs](http://zeppelin.apache.org/docs/0.8.0/usage/other_features/publishing_paragraphs.html) | | +| Stream | | | + +### Result Display + +| Type | Status | +| ------ | ---- | +| Dynamic Form | Y | +| Text | Y | +| Html | Y | +| Table | Y | +| Network | | + +### Table Visualization + +| Type | State | +| ------ | ---- | +| Line Chart | Y | +| Bard Chart | Y | +| Pie Chart | Y | +| Area Chart | Y | +| Scatter Chart | Y | + +### Helium Visualization + +| Type | Description | Status | +| ------ | ---- | ---- | +| Prototype | To verify the implementable prototype | Y | +| Publish Dependencies | Just like [zeppelin-vis](https://github.com/apache/zeppelin/tree/master/zeppelin-web/src/app/visualization) | WIP | +| Example Projects | | Y | +| Development Documents | | WIP | + +## Contributing + +### Dev Mode + +Follow the [Setup](#Setup) steps to starting the frontend service. The app will automatically reload if you change any of the source files. + +### Technologies + +Zeppelin-WEB-Angular is using Angular as the main Framework, before developing we hope highly recommended to have a good knowledge of [Angular](https://angular.io/) and [RxJs](https://github.com/ReactiveX/rxjs). + +In addition: + +- We use [G2](https://github.com/antvis/g2) [(MIT)](https://github.com/antvis/g2/blob/master/LICENSE) visualization +- We use [Lodash](https://lodash.com/) [(MIT)](https://github.com/lodash/lodash/blob/master/LICENSE) to process complex data +- We use [Monaco Editor](https://github.com/microsoft/monaco-editor) [(MIT)](https://github.com/microsoft/monaco-editor/blob/master/LICENSE.md) to make code editor + +### Coding style + +- We follow mainly the [Angular Style Guide](https://angular.io/guide/styleguide) +- We use a 2 spaces indentation +- We use single quotes + +But don't worry, TSLint and prettier will make you remember it for the most part. +Git hooks will automatically check and fix it when commit. + +### Folder Structure + +We follow mainly the [Workspace and project file structure](https://angular.io/guide/styleguide) to organize the folder structure and files. + +#### Src Folder Structure + +`src` folder contains the source code for Zeppelin-WEB-Angular. + +``` +├── app +│ ├── core +│ │ └── message-listener # handle WebSocket message +│ ├── interfaces # interfaces +│ ├── pages +│ │ ├── login # login module +│ │ └── workspace +│ │ ├── home # welcome module +│ │ ├── interpreter # interpreter settings +│ │ ├── job-manager # job manager module +│ │ └── notebook # notebook module +│ │ ├── action-bar # notebook settings +│ │ ├── interpreter-binding # interpreter binding +│ │ ├── permissions # permissions +│ │ └── paragraph # paragraph module +│ │ ├── code-editor # code editor module +│ │ ├── control # paragraph controls +│ │ ├── dynamic-forms # dynamic forms +│ │ └── result # display result +│ ├── sdk # Zeppelin API Frontend SDK +│ ├── share # Share Components +│ ├── services # API Service +│ └── visualization +│ ├── area-chart # Area Chart Component +│ ├── bar-chart # Bar Chart Component +│ ├── line-chart # Line Chart Component +│ ├── pie-chart # Pie Chart Component +│ ├── scatter-chart # Scatter Chart Component +│ └── table # Data Table Component +├── assets # Assets +└── styles + └── theme # Theme Files + ├── dark + └── light +``` + +#### Import Path Rules + +We specify path mapping in the `tsconfig.json` file to get a clear import path. + +So please follow the rules following: + +- Add `public-api.ts` and `index.ts` to the folder where want to export the modules +- `public-api.ts` File only included you wish to export modules +- `index.ts` File only export `./public-api.ts` +- Use relative paths instead of mapped paths when the same level to prevent circular references + +### Good Practices + +The following guide for this project only. Most of the time you only need to follow Angular's guide. + +#### Change Detection Strategy + +Use [OnPush](https://angular.io/api/core/ChangeDetectionStrategy#OnPush) as the change detection strategy for components. + +#### WebSocket Listen and Send + +*Send Message*: Inject the `MessageService` and then use its instance methods. + +```ts + +import { MessageService } from '@zeppelin/services'; + +export class SomeComponent { + + constructor(public messageService: MessageService) { } + + fun() { + // Do something + this.messageService.listNoteJobs(); + } +} +``` + +*Listen to Message* + +Make sure the class extends from `MessageListenersManager` and inject the `MessageService` and ensures that it is public. + +After that, you can use the `@MessageListener` decorator to decorate the corresponding message method. + +```ts +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { MessageService } from '@zeppelin/services'; +import { OP, ListNoteJobs } from '@zeppelin/sdk'; + +export class SomeComponent extends MessageListenersManager { + + constructor(public messageService: MessageService) { } + + @MessageListener(OP.LIST_NOTE_JOBS) + fun(data: ListNoteJobs) { + // Do something + } +} +``` + +#### Theming + +Use we provide the function to wrap component styles to implement theming. You can find the theme variables in the `src/styles/theme/` folder. + +```less +@import "theme-mixin"; + +.themeMixin({ + // component styles +}); +``` + +#### Imports order + +Follow of the following imports order: + +```ts +import * from '@angular/*' // Angular modules +import * from 'rxjs/*' // Rxjs modules +// BLANK LINE +import * from '*' // Other third party modules +// BLANK LINE +import * from '@zeppelin/*' // This project modules +// BLANK LINE +import * from './*' // Same level modules +``` \ No newline at end of file diff --git a/zeppelin-web-angular/WEB-INF/web.xml b/zeppelin-web-angular/WEB-INF/web.xml new file mode 100644 index 00000000000..f40bf861738 --- /dev/null +++ b/zeppelin-web-angular/WEB-INF/web.xml @@ -0,0 +1,41 @@ + + + + + + zeppelin-web-angular + + default + org.glassfish.jersey.servlet.ServletContainer + + jersey.config.server.provider.packages + org.apache.zeppelin.rest + + + 1 + + + + configuration + deployment + + + + + true + true + + + diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json new file mode 100644 index 00000000000..095c3881d31 --- /dev/null +++ b/zeppelin-web-angular/angular.json @@ -0,0 +1,331 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "zeppelin": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "zeppelin", + "schematics": { + "@schematics/angular:component": { + "style": "less", + "skipTests": true, + "changeDetection": "OnPush" + }, + "ng-zorro-antd:component": { + "style": "less", + "skipTests": true, + "changeDetection": "OnPush", + "classnameWithModule": true + }, + "@schematics/angular:class": { + "skipTests": true + }, + "@schematics/angular:directive": { + "skipTests": true + }, + "@schematics/angular:guard": { + "skipTests": true + }, + "@schematics/angular:module": { + "skipTests": true + }, + "@schematics/angular:pipe": { + "skipTests": true + }, + "@schematics/angular:service": { + "skipTests": true + } + }, + "architect": { + "build": { + "builder": "ngx-build-plus:browser", + "options": { + "outputPath": "dist/zeppelin", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets", + { + "glob": "**/*", + "input": "./node_modules/mathjax", + "output": "/" + }, + { + "glob": "**/*", + "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", + "output": "/assets/" + }, + { + "glob": "**/*", + "input": "./WEB-INF", + "output": "/WEB-INF/" + } + ], + "styles": [ + "src/styles/theme/dark/antd-dark.less", + "src/styles/theme/light/antd-light.less", + "src/styles.less", + "./node_modules/highlight.js/styles/github.css", + "./node_modules/monaco-editor/min/vs/editor/editor.main.css", + "./node_modules/github-markdown-css/github-markdown.css" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "src/styles/theme", + "src/styles/theme/dark", + "src/styles/theme/light" + ] + }, + "scripts": [ + "node_modules/mathjax/MathJax.js", + "node_modules/systemjs/dist/s.js", + "node_modules/systemjs/dist/extras/amd.js", + "node_modules/systemjs/dist/extras/named-register.js", + "node_modules/systemjs/dist/extras/use-default.js" + ] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": false + } + } + }, + "serve": { + "builder": "ngx-build-plus:dev-server", + "options": { + "browserTarget": "zeppelin:build" + }, + "configurations": { + "production": { + "browserTarget": "zeppelin:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "zeppelin:build" + } + }, + "test": { + "builder": "ngx-build-plus:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.less" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "zeppelin:serve" + }, + "configurations": { + "production": { + "devServerTarget": "zeppelin:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-helium": { + "projectType": "library", + "root": "projects/zeppelin-helium", + "sourceRoot": "projects/zeppelin-helium/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/zeppelin-helium/tsconfig.lib.json", + "project": "projects/zeppelin-helium/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/zeppelin-helium/src/test.ts", + "tsConfig": "projects/zeppelin-helium/tsconfig.spec.json", + "karmaConfig": "projects/zeppelin-helium/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/zeppelin-helium/tsconfig.lib.json", + "projects/zeppelin-helium/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "helium-vis-example": { + "projectType": "library", + "root": "projects/helium-vis-example", + "sourceRoot": "projects/helium-vis-example/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/helium-vis-example/tsconfig.lib.json", + "project": "projects/helium-vis-example/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/helium-vis-example/src/test.ts", + "tsConfig": "projects/helium-vis-example/tsconfig.spec.json", + "karmaConfig": "projects/helium-vis-example/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/helium-vis-example/tsconfig.lib.json", + "projects/helium-vis-example/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-visualization": { + "projectType": "library", + "root": "projects/zeppelin-visualization", + "sourceRoot": "projects/zeppelin-visualization/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/zeppelin-visualization/tsconfig.lib.json", + "project": "projects/zeppelin-visualization/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/zeppelin-visualization/src/test.ts", + "tsConfig": "projects/zeppelin-visualization/tsconfig.spec.json", + "karmaConfig": "projects/zeppelin-visualization/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/zeppelin-visualization/tsconfig.lib.json", + "projects/zeppelin-visualization/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-sdk": { + "projectType": "library", + "root": "projects/zeppelin-sdk", + "sourceRoot": "projects/zeppelin-sdk/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/zeppelin-sdk/tsconfig.lib.json", + "project": "projects/zeppelin-sdk/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/zeppelin-sdk/src/test.ts", + "tsConfig": "projects/zeppelin-sdk/tsconfig.spec.json", + "karmaConfig": "projects/zeppelin-sdk/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/zeppelin-sdk/tsconfig.lib.json", + "projects/zeppelin-sdk/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "zeppelin" +} \ No newline at end of file diff --git a/zeppelin-web-angular/browserslist b/zeppelin-web-angular/browserslist new file mode 100644 index 00000000000..80848532e47 --- /dev/null +++ b/zeppelin-web-angular/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/zeppelin-web-angular/e2e/protractor.conf.js b/zeppelin-web-angular/e2e/protractor.conf.js new file mode 100644 index 00000000000..1be6b530682 --- /dev/null +++ b/zeppelin-web-angular/e2e/protractor.conf.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/zeppelin-web-angular/e2e/src/app.e2e-spec.ts b/zeppelin-web-angular/e2e/src/app.e2e-spec.ts new file mode 100644 index 00000000000..d788f85250e --- /dev/null +++ b/zeppelin-web-angular/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('zeppelin app is running!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/zeppelin-web-angular/e2e/src/app.po.ts b/zeppelin-web-angular/e2e/src/app.po.ts new file mode 100644 index 00000000000..b8498c26f24 --- /dev/null +++ b/zeppelin-web-angular/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise; + } + + getTitleText() { + return element(by.css('app-root .content span')).getText() as Promise; + } +} diff --git a/zeppelin-web-angular/e2e/tsconfig.json b/zeppelin-web-angular/e2e/tsconfig.json new file mode 100644 index 00000000000..39b800f7896 --- /dev/null +++ b/zeppelin-web-angular/e2e/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/zeppelin-web-angular/karma.conf.js b/zeppelin-web-angular/karma.conf.js new file mode 100644 index 00000000000..67c6820c27b --- /dev/null +++ b/zeppelin-web-angular/karma.conf.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, './coverage/zeppelin'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json new file mode 100644 index 00000000000..8c82716f71c --- /dev/null +++ b/zeppelin-web-angular/package-lock.json @@ -0,0 +1,16043 @@ +{ + "name": "zeppelin", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.14.tgz", + "integrity": "sha512-CPDDNTpM/9XWCFxCRL1/mYB54ivZcmWaVSjUgN2zcHWBc0gW3lrJrmmb+cJ1KSlOI7hoZaMTV1gWoX2QXd4JrA==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/build-angular": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.14.tgz", + "integrity": "sha512-AtrhLDcy5DHi5zWiahEmvbD6THkJkWv27TySTfpZlmMjpRJHNqK7uQiKR1iWSqo4VNpimFle3fwkfjQYHlEKqA==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "@angular-devkit/build-optimizer": "0.803.14", + "@angular-devkit/build-webpack": "0.803.14", + "@angular-devkit/core": "8.3.14", + "@babel/core": "7.5.5", + "@babel/preset-env": "7.5.5", + "@ngtools/webpack": "8.3.14", + "ajv": "6.10.2", + "autoprefixer": "9.6.1", + "browserslist": "4.6.6", + "cacache": "12.0.2", + "caniuse-lite": "1.0.30000989", + "circular-dependency-plugin": "5.2.0", + "clean-css": "4.2.1", + "copy-webpack-plugin": "5.0.4", + "core-js": "3.2.1", + "file-loader": "4.2.0", + "find-cache-dir": "3.0.0", + "glob": "7.1.4", + "istanbul-instrumenter-loader": "3.0.1", + "jest-worker": "24.9.0", + "karma-source-map-support": "1.4.0", + "less": "3.9.0", + "less-loader": "5.0.0", + "license-webpack-plugin": "2.1.2", + "loader-utils": "1.2.3", + "mini-css-extract-plugin": "0.8.0", + "minimatch": "3.0.4", + "open": "6.4.0", + "parse5": "4.0.0", + "postcss": "7.0.17", + "postcss-import": "12.0.1", + "postcss-loader": "3.0.0", + "raw-loader": "3.1.0", + "regenerator-runtime": "0.13.3", + "rxjs": "6.4.0", + "sass": "1.22.9", + "sass-loader": "7.2.0", + "semver": "6.3.0", + "source-map": "0.7.3", + "source-map-loader": "0.2.4", + "source-map-support": "0.5.13", + "speed-measure-webpack-plugin": "1.3.1", + "style-loader": "1.0.0", + "stylus": "0.54.5", + "stylus-loader": "3.0.2", + "terser": "4.3.8", + "terser-webpack-plugin": "1.4.1", + "tree-kill": "1.2.1", + "webpack": "4.39.2", + "webpack-dev-middleware": "3.7.0", + "webpack-dev-server": "3.8.0", + "webpack-merge": "4.2.1", + "webpack-sources": "1.4.3", + "webpack-subresource-integrity": "1.1.0-rc.6", + "worker-plugin": "3.2.0" + }, + "dependencies": { + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + } + } + }, + "@angular-devkit/build-ng-packagr": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-ng-packagr/-/build-ng-packagr-0.803.14.tgz", + "integrity": "sha512-qIYLEOxL8kOmOVjisN0rSMGeN7D2TYc90k73LnXUtT8WL4a+bd6r8PNGrH9hrF8ABZ01oJ4PQi8kuE4Jm7+ptA==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/build-optimizer": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.14.tgz", + "integrity": "sha512-f1RYhO0swLfoLvCj/fUrDWm4vzVSnffcCc4C4PHnqoOGBRQpmIzG7G54Pm8YK677slioToYZQ68s3/zVtsQNWg==", + "dev": true, + "requires": { + "loader-utils": "1.2.3", + "source-map": "0.7.3", + "tslib": "1.10.0", + "typescript": "3.5.3", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.14.tgz", + "integrity": "sha512-hvxAyJzDCaIISATHcu0+rAAj7ZcmX7VREX6J3FUMYDxhdjKqe45Q5J6Oy/Df2ZSV3YxwySZVcIhrBstm+0LC7Q==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "@angular-devkit/core": "8.3.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/core": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.14.tgz", + "integrity": "sha512-+IYLbtCxwIpaieRj0wurEXBzZ/fDSdWbyrCfajzDerzsxqghNcafAXSazHXWwISqtbr/pAOuqUNR+mEk2XBz3Q==", + "dev": true, + "requires": { + "ajv": "6.10.2", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.3", + "rxjs": "6.4.0", + "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.14.tgz", + "integrity": "sha512-5gPmTBN85a2gTxz/FsM5fO9Bxw4KG6uJNLMDAWfPG8vvSQEl7J64ujyqxPz39TernQTEKeuhRC4I5H1aaW9I/Q==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular/animations": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.12.tgz", + "integrity": "sha512-QVtZUw5J9c0RcDaJntIoeWVk/q9dhjDFxh+yw/uPl9Z4upWASdsOpZU2lfjqyU0myfg8dnQyZa1+Ce7n/DaClQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/cdk": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz", + "integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^1.7.1" + } + }, + "@angular/cli": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.14.tgz", + "integrity": "sha512-cOP2UvnnYocx1U1aiNkuLCcBxSktIXkadzrY7UlWJtQiCPGWm3Y87BfrQXub9Nsh79iyV8k8uKZKEax2ayESSg==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "@angular-devkit/core": "8.3.14", + "@angular-devkit/schematics": "8.3.14", + "@schematics/angular": "8.3.14", + "@schematics/update": "0.803.14", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "^4.1.1", + "ini": "1.3.5", + "inquirer": "6.5.1", + "npm-package-arg": "6.1.0", + "npm-pick-manifest": "3.0.2", + "open": "6.4.0", + "pacote": "9.5.5", + "read-package-tree": "5.3.1", + "rimraf": "3.0.0", + "semver": "6.3.0", + "symbol-observable": "1.2.0", + "universal-analytics": "^0.4.20", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "@angular/common": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-8.2.12.tgz", + "integrity": "sha512-BNz1lo+PP+lwIX3sErRGBRnkMzT5yT8CJ5o/M29AanCdcx9dpoJG2WKgpIgw8UBcj9QlP0CkSmzPtUNtcNMthA==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-8.2.12.tgz", + "integrity": "sha512-V5mDWioGmSZ4cJJ2THo8qHYKwj3sUI7dpJ0oab2Al0FQAN8JCimWO6AQKRtjmnr78ZkMy9Xe/KK6ebl40ewL5Q==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler-cli": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-8.2.12.tgz", + "integrity": "sha512-OrNnkJ7OrpbcOtB4TWFBF6D3dtEfUuOQgfc3HBjizZuL8EuX0pU5dv4VTvLTRkmyUT/7fmmWdkEXJL+UQtXqPg==", + "dev": true, + "requires": { + "canonical-path": "1.0.0", + "chokidar": "^2.1.1", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "source-map": "^0.6.1", + "tslib": "^1.9.0", + "yargs": "13.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yargs": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.1.0.tgz", + "integrity": "sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "@angular/core": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-8.2.12.tgz", + "integrity": "sha512-wEFwhHCuuXynXAMeA1G+0KIYY0jqXYs7I8p+GO+ufKoUmzWHFTvtMJ6nvKgy+LmZTByO2gf9oVAAlRodNb8ttQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/forms": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.2.12.tgz", + "integrity": "sha512-y1UObndCGbTYwLSzUWzCiX7th+mb4n712asApooGmfmIQmgTyHbKxYUJ9Ep1pgd0pqLBBnK249MQLH15NDpbyQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/language-service": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-8.2.12.tgz", + "integrity": "sha512-uXGVSC4ugkyBt7pYdI8qaKNV0TIxfjSWb3dWNuhD6b9riPtaa+xJFQrfMu7OX/tVX642aFxca4jkUHBLCyWptA==", + "dev": true + }, + "@angular/platform-browser": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-8.2.12.tgz", + "integrity": "sha512-VBvMjmFJapZ2pFlmxZiHtfPwbHp79RRi5mrdMhETjKMaLaC2tAR/99ijCpx2urDMqb/VDm7YHOtoLEpBFVDulg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.2.12.tgz", + "integrity": "sha512-O4krb+9tj028JOQHPgLk/87lyUlHt8dpNxzuYCT0G6kEmknjpyZBaxhvDPygGjGHXV3LDqlYVH+bh8ygJUhwmw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/router": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-8.2.12.tgz", + "integrity": "sha512-mq1FethFpYosSVzChstMpxZlL+oUFeaA+FrzZQL7zJP/mm61yFkkhoYGVG6pG0NWSzpJE4NY6YvGCvHgN4ZECw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ant-design/colors": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz", + "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", + "requires": { + "tinycolor2": "^1.4.1" + } + }, + "@ant-design/icons-angular": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-angular/-/icons-angular-8.1.1.tgz", + "integrity": "sha512-JMfavPHwahJcGWT13bTCt4IHzrsNgbJzzB+VWYtzjwWszMCVkkOOn+aJbslupHOl72KWDvklN/LjCQPBgu7xLQ==", + "requires": { + "@ant-design/colors": "^3.1.0", + "tslib": "^1.9.0" + } + }, + "@antv/adjust": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz", + "integrity": "sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/attr": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.1.2.tgz", + "integrity": "sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/component": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.3.8.tgz", + "integrity": "sha512-1WN3FzeRyJ1jraS/2og5gnm2ragnwtRMVQMiLolztWaUgC++F/B1CcSrPYfV1WvYrfuwbpX/QQxo3HL9aS+YJA==", + "requires": { + "@antv/attr": "~0.1.2", + "@antv/g": "~3.3.5", + "@antv/util": "~1.3.1", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/coord": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.1.0.tgz", + "integrity": "sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/data-set": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@antv/data-set/-/data-set-0.10.2.tgz", + "integrity": "sha512-FFWG5tiTiFiUrLDRwulraU5XfOdDjkYOlZna+AMT9FJw406D/gfS8eXM9YibscBH28M/+KLAVO8xEwuD1sc3bw==", + "requires": { + "@antv/hierarchy": "~0.4.0", + "@antv/util": "~1.3.1", + "d3-array": "~1.2.0", + "d3-composite-projections": "~1.2.0", + "d3-dsv": "~1.0.5", + "d3-geo": "~1.6.4", + "d3-geo-projection": "~2.1.2", + "d3-hexjson": "~1.0.1", + "d3-hierarchy": "~1.1.5", + "d3-sankey": "~0.7.1", + "d3-voronoi": "~1.1.2", + "dagre": "~0.8.2", + "point-at-length": "~1.0.2", + "regression": "~2.0.0", + "simple-statistics": "~6.1.0", + "topojson-client": "~3.0.0", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/g": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.3.6.tgz", + "integrity": "sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==", + "requires": { + "@antv/gl-matrix": "~2.7.1", + "@antv/util": "~1.3.1", + "d3-ease": "~1.0.3", + "d3-interpolate": "~1.1.5", + "d3-timer": "~1.0.6", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/g2": { + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-3.5.9.tgz", + "integrity": "sha512-AS0Exn9Khhx4Xp8JViv37/wjJbiC9zVY02hIdvUeTx4SaKC0nhE0euPfmthen1cQw7nVlGLYEGoav/qxpLAhiw==", + "requires": { + "@antv/adjust": "~0.1.0", + "@antv/attr": "~0.1.2", + "@antv/component": "~0.3.3", + "@antv/coord": "~0.1.0", + "@antv/g": "~3.3.6", + "@antv/scale": "~0.1.1", + "@antv/util": "~1.3.1", + "venn.js": "~0.2.20", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/gl-matrix": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz", + "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==" + }, + "@antv/hierarchy": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.4.0.tgz", + "integrity": "sha512-ols+m+Z8QA4895SWMTOSjVImOX4tEbWQTwJ0NE+WATc0WLSKs6D9y2yaR+ZWt6P60BMGVIKS6lIfabO3CwGgnQ==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/scale": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.1.3.tgz", + "integrity": "sha512-oknlOg4OUqIh8LygrfQttx+OAnNJm2fQ81si4g8aby1WJJwj/TU1gCr+J3loIpKBtBK4VpP/OzTTqg1Ym67SOQ==", + "requires": { + "@antv/util": "~1.3.1", + "fecha": "~2.3.3" + } + }, + "@antv/util": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz", + "integrity": "sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==", + "requires": { + "@antv/gl-matrix": "^2.7.1" + } + }, + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", + "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helpers": "^7.5.5", + "@babel/parser": "^7.5.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "dev": true, + "requires": { + "@babel/types": "^7.6.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-define-map": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", + "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", + "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", + "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", + "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", + "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", + "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "dev": true, + "requires": { + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.2", + "@babel/types": "^7.6.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", + "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz", + "integrity": "sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz", + "integrity": "sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", + "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz", + "integrity": "sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", + "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", + "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz", + "integrity": "sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", + "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", + "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", + "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", + "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz", + "integrity": "sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==", + "dev": true, + "requires": { + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", + "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", + "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz", + "integrity": "sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz", + "integrity": "sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/preset-env": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.5.5.tgz", + "integrity": "sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.5.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.5.5", + "@babel/plugin-transform-classes": "^7.5.5", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.5.0", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.5.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.5.0", + "@babel/plugin-transform-modules-commonjs": "^7.5.0", + "@babel/plugin-transform-modules-systemjs": "^7.5.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.5.5", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.5.5", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "@babel/traverse": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.3", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@ngtools/webpack": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.14.tgz", + "integrity": "sha512-eIU3W3T4YxiExkS/c09FkqQpnKeIuUFFnxyfdG40zospt28B6V5ZaEVw2z5+2CjxJlDUTUYZlhPiV9Rwadp3jg==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "enhanced-resolve": "4.1.0", + "rxjs": "6.4.0", + "tree-kill": "1.2.1", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, + "@schematics/angular": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.14.tgz", + "integrity": "sha512-1XXBh9+lowvltRlcCjDJa4GEr5Xq+uNJcxULHBaNY7YfQSwZ5KuyhTBWjCdKmMaTOV3pEcIHwyuNh26mpn98Bw==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "@angular-devkit/schematics": "8.3.14" + } + }, + "@schematics/update": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.14.tgz", + "integrity": "sha512-1erj7oaR2vKXo1DLE0s4BbbouBmgeAHEkPHQM7FPtyroZ18kytlT+qjTbsSnlRCwcFsjxmRkbRjXaXDz7ttsYQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "@angular-devkit/schematics": "8.3.14", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "pacote": "9.5.5", + "rxjs": "6.4.0", + "semver": "6.3.0", + "semver-intersect": "1.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "@types/date-fns": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/date-fns/-/date-fns-2.6.0.tgz", + "integrity": "sha1-sGLKRlYgApCb4MY6ZGftFzE2rME=", + "dev": true, + "requires": { + "date-fns": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/highlight.js": { + "version": "9.12.3", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", + "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "dev": true + }, + "@types/jasmine": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.3.16.tgz", + "integrity": "sha512-Nveep4zKGby8uIvG2AEUyYOwZS8uVeHK9TgbuWYSawUDDdIgfhCKz28QzamTo//Jk7Ztt9PO3f+vzlB6a4GV1Q==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz", + "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@types/lodash": { + "version": "4.14.144", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", + "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", + "dev": true + }, + "@types/mathjax": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.35.tgz", + "integrity": "sha512-flo9bVJE2Lzv3X5NQXVhNhv7srqk//Ngr8MT+/jRErkWGYkk8EBm42J5W0XUH6p4nWF1iLGe+atSuIkR5wA2yw==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "8.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz", + "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/parse5": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.2.tgz", + "integrity": "sha512-BOl+6KDs4ItndUWUFchy3aEqGdHhw0BC4Uu+qoDonN/f0rbUnJbm71Ulj8Tt9jLFRaAxPLKvdS1bBLfx1qXR9g==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/selenium-webdriver": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz", + "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz", + "integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz", + "integrity": "sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/webpack": { + "version": "4.39.5", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.39.5.tgz", + "integrity": "sha512-9twG6D97ao13MBLvigwfBJe6rxtb04UY3TcYHBYkW5sXZjUrNhqIRxLYg74VzK/YAE8xlVhOyd+3Whr7E5RrBA==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/webpack-sources": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz", + "integrity": "sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abs-svg-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "integrity": "sha1-32Acjo0roQ1KdtYl4japo5wnI78=" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + }, + "adler-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, + "adm-zip": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", + "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "dev": true, + "requires": { + "type-fest": "^0.5.2" + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "ansi_up": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-4.0.4.tgz", + "integrity": "sha512-vRxC8q6QY918MbehO869biJW4tiunJdjOhi5fpY6NLOliBQlZhOkKgABJKJqH+JZfb/WfjvjN1chLWI6tODerw==" + }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "app-root-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", + "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==", + "dev": true + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", + "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", + "dev": true, + "requires": { + "browserslist": "^4.6.3", + "caniuse-lite": "^1.0.30000980", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.17", + "postcss-value-parser": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boxen": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", + "term-size": "^1.2.0", + "type-fest": "^0.3.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz", + "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000984", + "electron-to-chromium": "^1.3.191", + "node-releases": "^1.1.25" + } + }, + "browserstack": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", + "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.2.tgz", + "integrity": "sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + } + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + }, + "caniuse-lite": { + "version": "1.0.30000989", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", + "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==", + "dev": true + }, + "canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "cfb": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.1.3.tgz", + "integrity": "sha512-joXBW0nMuwV9no7UTMiyVJnQL6XIU3ThXVjFUDHgl9MpILPOomyfaGqC290VELZ48bbQKZXnQ81UT5HouTxHsw==", + "requires": { + "adler-32": "~1.2.0", + "commander": "^2.16.0", + "crc-32": "~1.2.0", + "printj": "~1.1.2" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.2.tgz", + "integrity": "sha512-bw3pm7kZ2Wa6+jQWYP/c7bAZy3i4GwiIiMO2EeRjrE48l8vBqC/WvFhSF0xyM8fQiPEGvwMY/5bqDG7sSEOuhg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-dependency-plugin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", + "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "codelyzer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.0.tgz", + "integrity": "sha512-izfUfhEOOgAizszPlEDxo71DK/C4wprZw0vkY6UWcOSTQvN1JyfXf9DXwaV7WX+/JC+hH0ShXfdtGLA9Rca7LA==", + "dev": true, + "requires": { + "app-root-path": "^2.2.1", + "aria-query": "^3.0.0", + "axobject-query": "^2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "codepage": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", + "integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=", + "requires": { + "commander": "~2.14.1", + "exit-on-epipe": "~1.0.1" + }, + "dependencies": { + "commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", + "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "dev": true, + "requires": { + "mime-db": ">= 1.40.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "configstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "contour_plot": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", + "integrity": "sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc=" + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz", + "integrity": "sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg==", + "dev": true, + "requires": { + "cacache": "^11.3.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "cacache": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + } + } + }, + "core-js": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" + }, + "core-js-compat": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.3.3.tgz", + "integrity": "sha512-GNZkENsx5pMnS7Inwv7ZO/s3B68a9WU5kIjxqrD/tkNR8mtfXJRk8fAKRlbvWZSGPc59/TkiOBDYl5Cb65pTVA==", + "dev": true, + "requires": { + "browserslist": "^4.7.1", + "semver": "^6.3.0" + }, + "dependencies": { + "browserslist": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.2.tgz", + "integrity": "sha512-uZavT/gZXJd2UTi9Ov7/Z340WOSQ3+m1iBVRUknf+okKxonL9P83S3ctiBDtuRmRu8PiCHjqyueqQ9HYlJhxiw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001004", + "electron-to-chromium": "^1.3.295", + "node-releases": "^1.1.38" + } + }, + "caniuse-lite": { + "version": "1.0.30001004", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001004.tgz", + "integrity": "sha512-3nfOR4O8Wa2RWoYfJkMtwRVOsK96TQ+eq57wd0iKaEWl8dwG4hKZ/g0MVBfCvysFvMLi9fQGR/DvozMdkEPl3g==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz", + "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg==" + }, + "d3-composite-projections": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/d3-composite-projections/-/d3-composite-projections-1.2.3.tgz", + "integrity": "sha512-RxNBoRGf3epTnQBUKeEpaXpD8BA/Ud0xRuLwWxyI7dWfuuYgJZMKw6ZsZOwfDNC0ZbMWaU0eBFlL05A2jlcsWg==", + "requires": { + "d3-geo": "^1.11.6", + "d3-path": "^1.0.7" + }, + "dependencies": { + "d3-geo": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.6.tgz", + "integrity": "sha512-z0J8InXR9e9wcgNtmVnPTj0TU8nhYT6lD/ak9may2PdKqXIeHUr8UbFLoCtrPYNsjv6YaLvSDQVl578k6nm7GA==", + "requires": { + "d3-array": "1" + } + } + } + }, + "d3-dispatch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz", + "integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g==" + }, + "d3-dsv": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.10.tgz", + "integrity": "sha512-vqklfpxmtO2ZER3fq/B33R/BIz3A1PV0FaZRuFM8w6jLo7sUX1BZDh73fPlr0s327rzq4H6EN1q9U+eCBCSN8g==", + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.5.tgz", + "integrity": "sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ==" + }, + "d3-geo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.6.4.tgz", + "integrity": "sha1-8g4eRhyxhF9ai+Vatvh2VCp+MZk=", + "requires": { + "d3-array": "1" + } + }, + "d3-geo-projection": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.1.2.tgz", + "integrity": "sha1-ffjh6dBG1jHGUJ9+UxNX1K3CSqM=", + "requires": { + "commander": "2", + "d3-array": "1", + "d3-geo": "^1.1.0" + } + }, + "d3-hexjson": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d3-hexjson/-/d3-hexjson-1.0.1.tgz", + "integrity": "sha512-TeH4T0PSbDazMm3gHgc4ulO0PfrZpz0Uk3y5tCGz+NgC7HnX7KBdem7uAN+j9x3ZshTh7raN3V/bFhaLB2C8DA==", + "requires": { + "d3-array": "1" + } + }, + "d3-hierarchy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz", + "integrity": "sha512-L+GHMSZNwTpiq4rt9GEsNcpLa4M96lXMR8M/nMG9p5hBE0jy6C+3hWtyZMenPQdwla249iJy7Nx0uKt3n+u9+w==" + }, + "d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.8.tgz", + "integrity": "sha512-J6EfUNwcMQ+aM5YPOB8ZbgAZu6wc82f/0WFxrxwV6Ll8wBwLaHLKCqQ5Imub02JriCVVdPjgI+6P3a4EWJCxAg==" + }, + "d3-sankey": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.7.1.tgz", + "integrity": "sha1-0imDImj8aaf+yEgD6WwiVqYUxSE=", + "requires": { + "d3-array": "1", + "d3-collection": "1", + "d3-shape": "^1.2.0" + } + }, + "d3-selection": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.0.tgz", + "integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg==" + }, + "d3-shape": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz", + "integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==", + "requires": { + "d3-path": "1" + } + }, + "d3-timer": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz", + "integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg==" + }, + "d3-transition": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.2.0.tgz", + "integrity": "sha512-VJ7cmX/FPIPJYuaL2r1o1EMHLttvoIuZhhuAlRoOxDzogV8iQS6jYulDm3xEU3TqL80IZIhI551/ebmCMrkvhw==", + "requires": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" + }, + "dagre": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.4.tgz", + "integrity": "sha512-Dj0csFDrWYKdavwROb9FccHfTC4fJbyF/oJdL9LNZJ8WUvl968P6PAKEriGqfbdArVJEmmfA+UyumgWEwcHU6A==", + "requires": { + "graphlib": "^2.1.7", + "lodash": "^4.17.4" + } + }, + "damerau-levenshtein": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz", + "integrity": "sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + }, + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "defer-to-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.2.tgz", + "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-match-patch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz", + "integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.295", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.295.tgz", + "integrity": "sha512-KxlGE9GcZTv7xGwYJGMEABHJq2JuTMNF7jD8NwHk6sBY226mW+Dyp9kZmA2Od9tKHMCS7ltPnqFg+zq3jTWN7Q==", + "dev": true + }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, + "elliptic": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz", + "integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.0.0.tgz", + "integrity": "sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "find-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "fmin": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", + "integrity": "sha1-Wbu0DUP/3ByUzQClaMQflfGXMBc=", + "requires": { + "contour_plot": "^0.0.1", + "json2module": "^0.0.3", + "rollup": "^0.25.8", + "tape": "^4.5.1", + "uglify-js": "^2.6.2" + } + }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, + "follow-redirects": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", + "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "g-status": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", + "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "matcher": "^1.0.0", + "simple-git": "^1.85.0" + } + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", + "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", + "dev": true + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "github-markdown-css": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-3.0.1.tgz", + "integrity": "sha512-9G5CIPsHoyk5ObDsb/H4KTi23J8KE1oDd4KYU51qwqeM+lKWAiO7abpSgCkyWswgmSKBiuE7/4f8xUz7f2qAiQ==" + }, + "glob": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", + "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "graphlib": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.7.tgz", + "integrity": "sha512-TyI9jIy2J4j0qgPmOOrHTCtpPqJGN/aurBwc6ZT+bRii+di1I+Wv3obRhVrmBEXet+qkMaEX67dXrwsd3QQM6w==", + "requires": { + "lodash": "^4.17.5" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, + "handlebars": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.5.tgz", + "integrity": "sha512-0Ce31oWVB7YidkaTq33ZxEbN+UDxMMgThvCe8ptgQViymL5DPis9uLdTA13MiRPhgvqyxIegugrP97iK3JeBHg==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "uglify-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.4.tgz", + "integrity": "sha512-9Yc2i881pF4BPGhjteCXQNaXx1DCwm3dtOyBaG2hitHjLWOczw/ki8vD1bqyT3u6K0Ms/FpCShkmfg+FtlOfYA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "highlight.js": { + "version": "9.15.10", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", + "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "dev": true + }, + "http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz", + "integrity": "sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.9.tgz", + "integrity": "sha512-Yolhupm7le2/MqC1VYLk/cNmYxsSsqKkTyBhzQHhPK1jFnC89mmmNVuGtLNabjDI6Aj8UNIr0KpRNuBkiC4+sg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "ci-info": "^2.0.0", + "cosmiconfig": "^5.2.1", + "execa": "^1.0.0", + "get-stdin": "^7.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "read-pkg": "^5.2.0", + "run-node": "^1.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "injection-js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.2.2.tgz", + "integrity": "sha512-9K4fW2NNPG3JCvORx5G/T6q/PZYIr43RFgxBvtk3OV4omh5iqvpK4cChuBfhgPnRbXSgZRfuROh0XG5KNA8Xlg==", + "dev": true + }, + "inquirer": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.1.tgz", + "integrity": "sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "dev": true + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "dependencies": { + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + } + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-npm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", + "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "requires": { + "symbol-observable": "^1.1.0" + } + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-reference": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39" + } + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.6.tgz", + "integrity": "sha512-x0Eicp6KsShG1k1rMgBAi/1GgY7kFGEBwQpw3PXGEmu+rBcBNhqU8g2DgY9mlepAsLPzrzrbqSgCGANnki4POA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "compare-versions": "^3.4.0", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + } + } + }, + "istanbul-instrumenter-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz", + "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==", + "dev": true, + "requires": { + "convert-source-map": "^1.5.0", + "istanbul-lib-instrument": "^1.7.3", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.0" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", + "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", + "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.1", + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz", + "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json2module": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", + "integrity": "sha1-APtfSpt638PwZHwpyxe80Zeb6bI=", + "requires": { + "rw": "^1.3.2" + } + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jszip": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz", + "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "karma": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz", + "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "braces": "^2.3.2", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.11", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.6.tgz", + "integrity": "sha512-WFh77RI8bMIKdOvI/1/IBmgnM+Q7NOLhnwG91QJrM8lW+CIXCjTzhhUsT/svLvAkLmR10uWY4RyYbHMLkTglvg==", + "dev": true, + "requires": { + "istanbul-api": "^2.1.6", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", + "dev": true, + "requires": { + "jasmine-core": "^3.3" + } + }, + "karma-jasmine-html-reporter": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.4.2.tgz", + "integrity": "sha512-7g0gPj8+9JepCNJR9WjDyQ2RkZ375jpdurYQyAYv8PorUCadepl8vrD6LmMqOGcM17cnrynBawQYZHaumgDjBw==", + "dev": true + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "less": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", + "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz", + "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^4.0.1" + } + }, + "less-plugin-npm-import": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/less-plugin-npm-import/-/less-plugin-npm-import-2.1.0.tgz", + "integrity": "sha1-gj5phskzGKmBccqFiEi2vq1Vvz4=", + "dev": true, + "requires": { + "promise": "~7.0.1", + "resolve": "~1.1.6" + }, + "dependencies": { + "promise": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.0.4.tgz", + "integrity": "sha1-Nj6EpMNsg1a4kP7WLJHOhdAu1Tk=", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "license-webpack-plugin": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.2.tgz", + "integrity": "sha512-7poZHRla+ae0eEButlwMrPpkXyhNVBf2EHePYWT0jyLnI6311/OXJkTI2sOIRungRpQgU2oDMpro5bSFPT5F0A==", + "dev": true, + "requires": { + "@types/webpack-sources": "^0.1.5", + "webpack-sources": "^1.2.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "lint-staged": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.2.1.tgz", + "integrity": "sha512-n0tDGR/rTCgQNwXnUf/eWIpPNddGWxC32ANTNYsj2k02iZb7Cz5ox2tytwBu+2r0zDXMEMKw7Y9OD/qsav561A==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "commander": "^2.14.1", + "cosmiconfig": "^5.2.0", + "debug": "^3.1.0", + "dedent": "^0.7.0", + "del": "^3.0.0", + "execa": "^1.0.0", + "g-status": "^2.0.2", + "is-glob": "^4.0.0", + "is-windows": "^1.0.2", + "listr": "^0.14.2", + "listr-update-renderer": "^0.5.0", + "lodash": "^4.17.11", + "log-symbols": "^2.2.0", + "micromatch": "^3.1.8", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", + "path-is-inside": "^1.0.2", + "pify": "^3.0.0", + "please-upgrade-node": "^3.0.2", + "staged-git-files": "1.1.2", + "string-argv": "^0.0.2", + "stringify-object": "^3.2.2", + "yup": "^0.27.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "dev": true, + "requires": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + } + }, + "loglevel": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", + "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", + "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "make-fetch-happen": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.1.tgz", + "integrity": "sha512-b4dfaMvUDR67zxUq1+GN7Ke9rH5WvGRmoHuMH7l+gmUCR2tCXFP6mpeJ9Dp+jB6z8mShRopSf1vLRBhRs8Cu5w==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.4" + } + }, + "mathjax": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", + "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz", + "integrity": "sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "monaco-editor": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.18.1.tgz", + "integrity": "sha512-fmL+RFZ2Hrezy+X/5ZczQW51LUmvzfcqOurnkCIRFTyjdVjzR7JvENzI6+VKBJzJdPh6EYL4RoWl92b2Hrk9fw==" + }, + "monaco-editor-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-oItymcnlL14Sjd7EF7q+CMhucfwR/2BxsqrXIBrWL6LQplFfAfV+grLEQRmVHeGSBZ/Gk9ptzfueXnWcoEcFuA==", + "dev": true, + "requires": { + "@types/webpack": "^4.4.19" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "ng-packagr": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-5.7.0.tgz", + "integrity": "sha512-/75eqAyk2ef8J0aMLl7XCx1QXmqUUTsQDu+fNCFDIYpkpWBh0C8Rkdd72hMLPv3MMo63pfaNeiMXa0zzpQINyA==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "autoprefixer": "^9.6.0", + "browserslist": "^4.0.0", + "chalk": "^2.3.1", + "chokidar": "^3.0.0", + "clean-css": "^4.1.11", + "commander": "^3.0.0", + "fs-extra": "^8.0.0", + "glob": "^7.1.2", + "injection-js": "^2.2.1", + "less": "^3.8.0", + "less-plugin-npm-import": "^2.1.0", + "node-sass-tilde-importer": "^1.0.0", + "postcss": "^7.0.0", + "postcss-url": "^8.0.0", + "read-pkg-up": "^5.0.0", + "rimraf": "^3.0.0", + "rollup": "^1.12.1", + "rollup-plugin-commonjs": "^10.0.0", + "rollup-plugin-json": "^4.0.0", + "rollup-plugin-node-resolve": "^5.0.0", + "rollup-plugin-sourcemaps": "^0.4.2", + "rxjs": "^6.0.0", + "sass": "^1.17.3", + "stylus": "^0.54.5", + "terser": "^4.1.2", + "update-notifier": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.25.2.tgz", + "integrity": "sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ng-zorro-antd": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/ng-zorro-antd/-/ng-zorro-antd-8.4.1.tgz", + "integrity": "sha512-P/EpGpqRRsx2NmyJyulhH56jNYV2a1e1lf9F2NOp1IIG3J1XKFAxHPCetaGeeeEbXT2voQWshD12iTf2Fb0xAQ==", + "requires": { + "@angular/cdk": "^8.0.0", + "@ant-design/icons-angular": "^8.0.2", + "date-fns": "^1.30.1", + "tslib": "^1.9.0" + } + }, + "ng1-template-updater": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/ng1-template-updater/-/ng1-template-updater-0.0.4.tgz", + "integrity": "sha512-GgmAV7Zbj8ZLQ/IJGjjSi40bXTHFP/k5fhlxcH0V2fWaya5lu6y07Vh4LKvuUqNbkbKl28XW8Z1fhL5pwHxgsA==" + }, + "ngx-build-plus": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-8.1.5.tgz", + "integrity": "sha512-jkMN43wBqCqIBYKnQwf+NiZYgbYY1nNTs/Jg41lt7mc9nxBQobs3Cypty3Hy22m9caFLWQR+3AQIttxmr3o9NA==", + "dev": true, + "requires": { + "@schematics/angular": "8.0.0", + "cross-spawn": "^6.0.5", + "rxjs": "6.4.0", + "webpack-dev-server": "^3.1.14", + "webpack-merge": "^4.2.1" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.0.0.tgz", + "integrity": "sha512-wYf4zzpYj5Y673DG8iteK0GsDDuXBKN/TOXm4lUwmXcz8QHTD+BfR6qA5TBDqlMGpU7CP1/0vgbv2px17CDETQ==", + "dev": true, + "requires": { + "ajv": "6.10.0", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.2", + "rxjs": "6.4.0", + "source-map": "0.7.3" + } + }, + "@angular-devkit/schematics": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.0.0.tgz", + "integrity": "sha512-IXJOs/DkDqNbfG76sNNY5ePZ37rjkMUopmtvhN6/U1hQFwTpGa9N0bCHFphcKraXeS6Jfox5XwFEStc/1xyhfw==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.0.0", + "rxjs": "6.4.0" + } + }, + "@schematics/angular": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.0.0.tgz", + "integrity": "sha512-c/cFpe+u7Xh4xX3/kn9BSRY4YhdO0OsDbRK0pGLDJFFs5JGvwoURtNXn4/4dVlsj3PWyNhxK0Ljl3dyw3NQBHA==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.0.0", + "@angular-devkit/schematics": "8.0.0" + } + }, + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "magic-string": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz", + "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.38.tgz", + "integrity": "sha512-/5NZAaOyTj134Oy5Cp/J8mso8OD/D9CSuL+6TOXXsTKO8yjc5e4up75SRPCganCjwFKMj2jbp5tR0dViVdox7g==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, + "node-sass-tilde-importer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-sass-tilde-importer/-/node-sass-tilde-importer-1.0.2.tgz", + "integrity": "sha512-Swcmr38Y7uB78itQeBm3mThjxBy9/Ah/ykPIaURY/L6Nec9AyRoL/jJ7ECfMR+oZeCTVQNxVMu/aHU+TLRVbdg==", + "dev": true, + "requires": { + "find-parent-dir": "^0.3.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true + }, + "npm-package-arg": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", + "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "npm-packlist": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", + "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "dev": true, + "requires": { + "which": "^1.2.10" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "npm-registry-fetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz", + "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "dev": true, + "requires": { + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nz-tslint-rules": { + "version": "0.800.2", + "resolved": "https://registry.npmjs.org/nz-tslint-rules/-/nz-tslint-rules-0.800.2.tgz", + "integrity": "sha512-iMDMG8XYpOlZ/Shr2qomFEaU9ptRmQNkPT8g+BGeZo7LUBrnSTKlvuak2ZWjEMjpgivZIEo861laow18QDuwcQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + } + }, + "pacote": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.5.tgz", + "integrity": "sha512-jAEP+Nqj4kyMWyNpfTU/Whx1jA7jEc5cCOlurm0/0oL+v8TAp1QSsK83N7bYe+2bEdFzMAtPG5TBebjzzGV0cA==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^2.2.3", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.8", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "npm-pick-manifest": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz", + "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes=" + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "point-at-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/point-at-length/-/point-at-length-1.0.2.tgz", + "integrity": "sha1-kXbY1tfIFi8Stkb3B9ufDqcoEl4=", + "requires": { + "abs-svg-path": "~0.1.1", + "isarray": "~0.0.1", + "parse-svg-path": "~0.1.1" + } + }, + "portfinder": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", + "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + } + } + }, + "postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "postcss-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-8.0.0.tgz", + "integrity": "sha512-E2cbOQ5aii2zNHh8F6fk1cxls7QVFZjLPSrqvmiza8OuXLzIpErij8BDS5Y3STPfJgpIMNCPEr8JlKQWEoozUw==", + "dev": true, + "requires": { + "mime": "^2.3.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^7.0.2", + "xxhashjs": "^0.2.1" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + }, + "postcss-value-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "prettier": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "dev": true + }, + "printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + } + } + }, + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "protractor": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.2.tgz", + "integrity": "sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA==", + "dev": true, + "requires": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "optimist": "~0.6.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.0.6" + }, + "dependencies": { + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "webdriver-manager": { + "version": "12.1.7", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz", + "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + } + } + } + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + } + } + }, + "raw-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz", + "integrity": "sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-package-json": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.0.tgz", + "integrity": "sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-5.0.0.tgz", + "integrity": "sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^5.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", + "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "registry-auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "dev": true, + "requires": { + "rc": "^1.2.8", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "regression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", + "integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "resumer": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", + "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", + "requires": { + "through": "~2.3.4" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", + "integrity": "sha1-v2zoO4dRDRY0Ru6qV37WpvxYNeA=", + "requires": { + "chalk": "^1.1.1", + "minimist": "^1.2.0", + "source-map-support": "^0.3.2" + } + }, + "rollup-plugin-commonjs": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", + "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz", + "integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==", + "dev": true, + "requires": { + "rollup-pluginutils": "^2.5.0" + } + }, + "rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "dev": true, + "requires": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-sourcemaps": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.4.2.tgz", + "integrity": "sha1-YhJaqUCHqt97g+9N+vYptHMTXoc=", + "dev": true, + "requires": { + "rollup-pluginutils": "^2.0.1", + "source-map-resolve": "^0.5.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass": { + "version": "1.22.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.9.tgz", + "integrity": "sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.2.0.tgz", + "integrity": "sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "selfsigned": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "dev": true, + "requires": { + "node-forge": "0.9.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", + "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "simple-git": { + "version": "1.126.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.126.0.tgz", + "integrity": "sha512-47mqHxgZnN8XRa9HbpWprzUv3Ooqz9RY/LSZgvA7jCkW8jcwLahMz7LKugY91KZehfG0sCVPtgXiU72hd6b1Bw==", + "dev": true, + "requires": { + "debug": "^4.0.1" + } + }, + "simple-statistics": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-6.1.1.tgz", + "integrity": "sha512-zGwn0DDRa9Zel4H4n2pjTFIyGoAGpnpjrGIctreCxj5XWrcx9v7Xy7270FkC967WMmcvuc8ZU7m0ZG+hGN7gAA==" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "socks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", + "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-loader": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", + "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==", + "dev": true, + "requires": { + "async": "^2.5.0", + "loader-utils": "^1.1.0" + } + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=", + "requires": { + "source-map": "0.1.32" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", + "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "spdy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "speed-measure-webpack-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz", + "integrity": "sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "ssf": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.2.tgz", + "integrity": "sha512-rDhAPm9WyIsY8eZEKyE8Qsotb3j/wBdvMWBUsOhJdfhKGLfQidRjiBUV0y/MkyCLiXQ38FG6LWW/VYUtqlIDZQ==", + "requires": { + "frac": "~1.1.2" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "staged-git-files": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", + "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", + "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.trim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" + } + }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "style-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz", + "integrity": "sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "stylus": { + "version": "0.54.5", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", + "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", + "dev": true, + "requires": { + "css-parse": "1.7.x", + "debug": "*", + "glob": "7.0.x", + "mkdirp": "0.5.x", + "sax": "0.5.x", + "source-map": "0.1.x" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "synchronous-promise": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.10.tgz", + "integrity": "sha512-6PC+JRGmNjiG3kJ56ZMNWDPL8hjyghF5cMXIFOKg+NiwwEZZIvxTWd0pinWKyD227odg9ygF8xVhhz7gb8Uq7A==", + "dev": true + }, + "systemjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-5.0.0.tgz", + "integrity": "sha512-hnD/IMQhH0UmawiIGlYVnkCPUbbO/WDQjOC+Q4PewHBdsagI1OHH1re1sg1AYFqq7p9ps6b1Bsx4xCeoeIZSCw==" + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "tape": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/tape/-/tape-4.11.0.tgz", + "integrity": "sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA==", + "requires": { + "deep-equal": "~1.0.1", + "defined": "~1.0.0", + "for-each": "~0.3.3", + "function-bind": "~1.1.1", + "glob": "~7.1.4", + "has": "~1.0.3", + "inherits": "~2.0.4", + "minimist": "~1.2.0", + "object-inspect": "~1.6.0", + "resolve": "~1.11.1", + "resumer": "~0.0.0", + "string.prototype.trim": "~1.1.2", + "through": "~2.3.8" + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "terser": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.8.tgz", + "integrity": "sha512-otmIRlRVmLChAWsnSFNO0Bfk6YySuBp6G9qrHiJwlLDd4mxe2ta4sjI7TzIR+W1nBMjilzrMcPOz9pSusgx3hQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", + "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tinycolor2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", + "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "topojson-client": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.1.tgz", + "integrity": "sha512-rfGGzyqefpxOaxvV9OTF9t+1g+WhjGEbAIuCcmKYrQkxr0nttjMMyzZsK+NhLW4cTl2g1bz2jQczPUtEshpbVQ==", + "requires": { + "commander": "2" + } + }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "tsickle": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.37.0.tgz", + "integrity": "sha512-ufUZqLUNqh+kOfr52N/hJ5JbiDO32/CO7ZCteZBX9HA2kiejwEgDaJeJe1GAj2TIu683IgTA/LPKvlns6Liw0w==", + "dev": true, + "requires": { + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, + "tslint": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.15.0.tgz", + "integrity": "sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "universal-analytics": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.20.tgz", + "integrity": "sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==", + "dev": true, + "requires": { + "debug": "^3.0.0", + "request": "^2.88.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "update-notifier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "dev": true, + "requires": { + "boxen": "^3.0.0", + "chalk": "^2.0.1", + "configstore": "^4.0.0", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^3.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + }, + "dependencies": { + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "dev": true, + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "venn.js": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", + "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", + "requires": { + "d3-selection": "^1.0.2", + "d3-transition": "^1.0.1", + "fmin": "0.0.2" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + } + }, + "webpack": { + "version": "4.39.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz", + "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + } + }, + "webpack-core": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", + "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", + "dev": true, + "requires": { + "source-list-map": "~0.1.7", + "source-map": "~0.4.1" + }, + "dependencies": { + "source-list-map": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", + "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz", + "integrity": "sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.2", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz", + "integrity": "sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.6", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.2.1", + "http-proxy-middleware": "^0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.0", + "killable": "^1.0.1", + "loglevel": "^1.6.3", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.21", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.4", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.3.0", + "spdy": "^4.0.1", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.0", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "12.0.5" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", + "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "webpack-subresource-integrity": { + "version": "1.1.0-rc.6", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz", + "integrity": "sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w==", + "dev": true, + "requires": { + "webpack-core": "^0.6.8" + } + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "wolfy87-eventemitter": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz", + "integrity": "sha1-NcGsDdGsDBXjXZgVCPwiCEoToBE=" + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-3.2.0.tgz", + "integrity": "sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xlsx": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz", + "integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==", + "requires": { + "adler-32": "~1.2.0", + "cfb": "^1.1.2", + "codepage": "~1.14.0", + "commander": "~2.17.1", + "crc-32": "~1.2.0", + "exit-on-epipe": "~1.0.1", + "ssf": "~0.10.2" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + } + } + }, + "xml2js": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "yup": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.27.0.tgz", + "integrity": "sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.0.0", + "fn-name": "~2.0.1", + "lodash": "^4.17.11", + "property-expr": "^1.5.0", + "synchronous-promise": "^2.0.6", + "toposort": "^2.0.2" + } + }, + "zone.js": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.9.1.tgz", + "integrity": "sha512-GkPiJL8jifSrKReKaTZ5jkhrMEgXbXYC+IPo1iquBjayRa0q86w3Dipjn8b415jpitMExe9lV8iTsv8tk3DGag==" + } + } +} diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json new file mode 100644 index 00000000000..5459ffd2b35 --- /dev/null +++ b/zeppelin-web-angular/package.json @@ -0,0 +1,101 @@ +{ + "name": "zeppelin", + "version": "0.0.0", + "scripts": { + "postinstall": "npm run build:projects", + "ng": "./node_modules/.bin/ng", + "start": "ng serve --proxy-config proxy.conf.js --extra-webpack-config webpack.partial.js", + "build": "ng build --prod --extra-webpack-config webpack.partial.js --base-href /next/", + "build:projects": "npm run build-project:sdk && npm run build-project:vis && npm run build-project:helium", + "build-helium-vis-example": " ng build --project helium-vis-example", + "build-project:sdk": " ng build --project zeppelin-sdk", + "build-project:vis": " ng build --project zeppelin-visualization", + "build-project:helium": "ng build --project zeppelin-helium", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "~8.2.10", + "@angular/cdk": "~8.2.3", + "@angular/common": "~8.2.10", + "@angular/compiler": "~8.2.10", + "@angular/core": "~8.2.10", + "@angular/forms": "~8.2.10", + "@angular/platform-browser": "~8.2.10", + "@angular/platform-browser-dynamic": "~8.2.10", + "@angular/router": "~8.2.10", + "@antv/data-set": "^0.10.2", + "@antv/g2": "^3.5.4", + "ansi_up": "^4.0.4", + "core-js": "^2.5.4", + "date-fns": "^1.30.1", + "diff-match-patch": "^1.0.4", + "github-markdown-css": "^3.0.1", + "highlight.js": "^9.15.8", + "lodash": "^4.17.11", + "mathjax": "2.7.5", + "monaco-editor": "^0.18.1", + "ng-zorro-antd": "^8.4.0", + "ng1-template-updater": "0.0.4", + "parse5": "^5.1.1", + "rxjs": "~6.5.3", + "systemjs": "^5.0.0", + "tslib": "^1.9.0", + "xlsx": "^0.14.3", + "zone.js": "~0.9.1" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^0.803.9", + "@angular-devkit/build-ng-packagr": "~0.803.6", + "@angular/cli": "~8.3.9", + "@angular/compiler-cli": "~8.2.10", + "@angular/language-service": "~8.2.10", + "@types/date-fns": "^2.6.0", + "@types/highlight.js": "^9.12.3", + "@types/jasmine": "~3.3.8", + "@types/jasminewd2": "~2.0.3", + "@types/lodash": "^4.14.124", + "@types/mathjax": "^0.0.35", + "@types/node": "~8.9.4", + "@types/parse5": "^5.0.2", + "codelyzer": "^5.0.0", + "dotenv": "^8.0.0", + "https-proxy-agent": "^2.2.1", + "husky": "^3.0.9", + "jasmine-core": "~3.4.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.1.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~2.0.1", + "karma-jasmine-html-reporter": "^1.4.0", + "lint-staged": "^8.1.6", + "monaco-editor-webpack-plugin": "^1.7.0", + "ng-packagr": "^5.4.0", + "ngx-build-plus": "^8.1.5", + "nz-tslint-rules": "^0.800.2", + "prettier": "^1.17.0", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tsickle": "^0.37.0", + "tslint": "~5.15.0", + "typescript": "~3.5.3" + }, + "lint-staged": { + "src/**/*.{ts,js,json}": [ + "./node_modules/.bin/prettier --write", + "git add" + ], + "src/**/*.ts": [ + "tslint --project src/tslint.json --fix", + "git add" + ] + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + } +} diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml new file mode 100644 index 00000000000..cae521489e7 --- /dev/null +++ b/zeppelin-web-angular/pom.xml @@ -0,0 +1,174 @@ + + + + + 4.0.0 + + + zeppelin + org.apache.zeppelin + 0.9.0-SNAPSHOT + .. + + + org.apache.zeppelin + zeppelin-web-angular + war + 0.9.0-SNAPSHOT + Zeppelin: web angular Application + + + + 3.1.0 + + + + true + false + ../bin + UTF-8 + + + https://nodejs.org/dist/ + https://registry.npmjs.org/npm/-/ + + + + + + + org.apache.maven.plugins + maven-war-plugin + + dist\zeppelin + dist\zeppelin\WEB-INF\web.xml + + + + + com.github.eirslett + frontend-maven-plugin + ${plugin.frontend.version} + + ${plugin.frontend.nodeDownloadRoot} + ${plugin.frontend.npmDownloadRoot} + + + + + install node + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + + npm install + + npm + + + ${web.e2e.enabled} + install --no-lockfile + + + + + npm build + + npm + + + ${web.e2e.enabled} + run build + + + + + npm test + + npm + + test + + ${web.e2e.disabled} + run test + + + + + npm e2e + + npm + + integration-test + + ${web.e2e.disabled} + run e2e + + + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + + + cobertura + none + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + + + + maven-clean-plugin + + + + node + + + node_modules + + + + + + + maven-resources-plugin + ${plugin.resource.version} + + + + + diff --git a/zeppelin-web-angular/projects/helium-vis-example/README.md b/zeppelin-web-angular/projects/helium-vis-example/README.md new file mode 100644 index 00000000000..e1850116b2e --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/README.md @@ -0,0 +1,36 @@ + + +# HeliumVisExample + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.9. + +## Code scaffolding + +Run `ng generate component component-name --project helium-vis-example` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project helium-vis-example`. +> Note: Don't forget to add `--project helium-vis-example` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build helium-vis-example` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build helium-vis-example`, go to the dist folder `cd dist/helium-vis-example` and run `npm publish`. + +## Running unit tests + +Run `ng test helium-vis-example` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/helium-vis-example/karma.conf.js b/zeppelin-web-angular/projects/helium-vis-example/karma.conf.js new file mode 100644 index 00000000000..ed77432da6e --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/karma.conf.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/helium-vis-example'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/helium-vis-example/ng-package.json b/zeppelin-web-angular/projects/helium-vis-example/ng-package.json new file mode 100644 index 00000000000..2193ef3df33 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/helium-vis-example", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/helium-vis-example/package.json b/zeppelin-web-angular/projects/helium-vis-example/package.json new file mode 100644 index 00000000000..17f7cb02fbc --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/package.json @@ -0,0 +1,8 @@ +{ + "name": "helium-vis-example", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^8.2.9", + "@angular/core": "^8.2.9" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts new file mode 100644 index 00000000000..12234517668 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core'; +import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +@Component({ + selector: 'lib-helium-vis-example', + template: ` +
    {{tableData | json}}
    + `, + styles: [` + pre { + background: #fff7e7; + padding: 10px; + border: 1px solid #ffd278; + color: #fa7e14; + border-radius: 3px; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JsonVisComponent implements OnInit { + tableData: TableData; + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) {} + + ngOnInit() { + } + + render(): void { + this.tableData = this.visualization.transformed; + } + +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts new file mode 100644 index 00000000000..2578f26df39 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { JsonVisComponent } from './json-vis.component'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [CommonModule], + declarations: [JsonVisComponent], + entryComponents: [JsonVisComponent], + exports: [JsonVisComponent] +}) +export class JsonVisModule { } diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts b/zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts new file mode 100644 index 00000000000..9f97db4598f --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts @@ -0,0 +1,64 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ComponentFactoryResolver, ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { + TableTransformation, + Transformation, + Visualization, + VisualizationComponentPortal +} from '@zeppelin/visualization'; + +import { JsonVisComponent } from './json-vis.component'; + +export class JsonVisualization extends Visualization { + tableTransformation = new TableTransformation(this.getConfig()); + componentPortal = new VisualizationComponentPortal( + this, + JsonVisComponent, + this.portalOutlet, + this.viewContainerRef, + this.componentFactoryResolver + ); + constructor(config: GraphConfig, + private portalOutlet: CdkPortalOutlet, + private viewContainerRef: ViewContainerRef, + private componentFactoryResolver?: ComponentFactoryResolver) { + super(config); + } + + destroy(): void { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + } + + getTransformation(): Transformation { + return this.tableTransformation; + } + + refresh(): void {} + + render(data): void { + this.transformed = data; + if (!this.componentRef) { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + this.componentRef.instance.render(); + } +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts b/zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts new file mode 100644 index 00000000000..82ba8d0ce42 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Public API Surface of helium-vis-example + */ + +import { createHeliumPackage, HeliumPackageType } from '@zeppelin/helium'; +import { JsonVisComponent } from './json-vis.component'; +import { JsonVisModule } from './json-vis.module'; +import { JsonVisualization } from './json-visualization'; + +export default createHeliumPackage({ + name: 'helium-vis-example', + id: 'heliumVisExample', + icon: 'appstore', + type: HeliumPackageType.Visualization, + module: JsonVisModule, + component: JsonVisComponent, + visualization: JsonVisualization +}); diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/test.ts b/zeppelin-web-angular/projects/helium-vis-example/src/test.ts new file mode 100644 index 00000000000..9be59f628dd --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/test.ts @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json new file mode 100644 index 00000000000..bd23948e591 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/tslint.json b/zeppelin-web-angular/projects/helium-vis-example/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/README.md b/zeppelin-web-angular/projects/zeppelin-helium/README.md new file mode 100644 index 00000000000..16ea0ea2bd6 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/README.md @@ -0,0 +1,36 @@ + + +# ZeppelinHelium + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.8. + +## Code scaffolding + +Run `ng generate component component-name --project zeppelin-helium` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project zeppelin-helium`. +> Note: Don't forget to add `--project zeppelin-helium` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build zeppelin-helium` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build zeppelin-helium`, go to the dist folder `cd dist/zeppelin-helium` and run `npm publish`. + +## Running unit tests + +Run `ng test zeppelin-helium` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js b/zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js new file mode 100644 index 00000000000..3ddb74a1a49 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/zeppelin-helium'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/ng-package.json b/zeppelin-web-angular/projects/zeppelin-helium/ng-package.json new file mode 100644 index 00000000000..da717624c15 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/zeppelin-helium", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-helium/package.json b/zeppelin-web-angular/projects/zeppelin-helium/package.json new file mode 100644 index 00000000000..cd0b499afa9 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/package.json @@ -0,0 +1,12 @@ +{ + "name": "@zeppelin/helium", + "version": "0.0.0", + "peerDependencies": { + "@angular/common": "~8.2.8", + "@angular/core": "~8.2.8", + "@angular/forms": "~8.2.7", + "@angular/router": "~8.2.7", + "rxjs": "~6.5.3", + "ng-zorro-antd": "^8.3.0" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts new file mode 100644 index 00000000000..677b3d7d1cf --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as common from '@angular/common'; +import * as core from '@angular/core'; +import * as forms from '@angular/forms'; +import * as router from '@angular/router'; +import * as rxjs from 'rxjs'; + +import * as dataSet from '@antv/data-set'; +import * as g2 from '@antv/g2'; +import * as sdk from '@zeppelin/sdk'; +import * as visualization from '@zeppelin/visualization'; +import * as lodash from 'lodash'; + +import * as ngZorro from 'ng-zorro-antd'; +import * as tslib from 'tslib'; +import * as zeppelinHelium from './public-api'; + +export const COMMON_DEPS = { + '@angular/core': core, + '@angular/common': common, + '@angular/forms': forms, + '@angular/router': router, + '@antv/data-set': dataSet, + '@antv/g2': g2, + '@zeppelin/sdk': sdk, + '@zeppelin/visualization': visualization, + '@zeppelin/helium': zeppelinHelium, + 'lodash': lodash, + 'ng-zorro-antd': ngZorro, + rxjs, + tslib +}; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/index.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts new file mode 100644 index 00000000000..4b9b89fd7db --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts @@ -0,0 +1,18 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Public API Surface of zeppelin-helium + */ + +export * from './zeppelin-helium.service'; +export * from './zeppelin-helium.module'; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/test.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/test.ts new file mode 100644 index 00000000000..9be59f628dd --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/test.ts @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts new file mode 100644 index 00000000000..e24ac800a78 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts @@ -0,0 +1,16 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; + +@NgModule({}) +export class ZeppelinHeliumModule { } diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts new file mode 100644 index 00000000000..10f8997dbf7 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts @@ -0,0 +1,96 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable, Type } from '@angular/core'; +import { Visualization } from '@zeppelin/visualization'; +import { COMMON_DEPS } from './common-deps'; +import { ZeppelinHeliumModule } from './zeppelin-helium.module'; + +// tslint:disable-next-line:no-any +const SystemJs = (window as any).System; + +// tslint:disable-next-line:no-any +export class ZeppelinHeliumPackage { + constructor( + public name: string, + public id: string, + // tslint:disable-next-line:no-any + public module: Type, + // tslint:disable-next-line:no-any + public component: Type, + // tslint:disable-next-line:no-any + public visualization?: any, + public icon = 'build' + ) { + } +} + +export enum HeliumPackageType { + Visualization +} + +// tslint:disable-next-line:no-any +export function createHeliumPackage(config: { + name: string; + id: string; + icon?: string; + type: HeliumPackageType; + // tslint:disable-next-line:no-any + module: Type; + // tslint:disable-next-line:no-any + component: Type; + // tslint:disable-next-line:no-any + visualization?: any +}) { + return new ZeppelinHeliumPackage( + config.name, + config.id, + config.module, + config.component, + config.visualization, + config.icon + ); +} + +@Injectable({ + providedIn: ZeppelinHeliumModule +}) +export class ZeppelinHeliumService { + + depsDefined = false; + + constructor() { } + + defineDeps() { + if (this.depsDefined) { + return; + } + Object.keys(COMMON_DEPS).forEach(externalKey => + // tslint:disable-next-line:no-any + (window as any).define(externalKey, [], () => COMMON_DEPS[ externalKey ]) + ); + this.depsDefined = true; + } + + loadPackage(name: string): Promise { + this.defineDeps(); + return SystemJs.import(`./assets/helium-packages/${name}.umd.js`) + .then(() => SystemJs.import(name)) + .then(plugin => { + if (plugin instanceof ZeppelinHeliumPackage) { + return Promise.resolve(plugin); + } else { + throw new TypeError('This module is not a valid helium package'); + } + }); + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json new file mode 100644 index 00000000000..45b781973db --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "flatModuleId": "@zeppelin/helium" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/tslint.json b/zeppelin-web-angular/projects/zeppelin-helium/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/README.md b/zeppelin-web-angular/projects/zeppelin-sdk/README.md new file mode 100644 index 00000000000..91a87204e35 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/README.md @@ -0,0 +1,36 @@ + + +# ZeppelinSdk + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.9. + +## Code scaffolding + +Run `ng generate component component-name --project zeppelin-sdk` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project zeppelin-sdk`. +> Note: Don't forget to add `--project zeppelin-sdk` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build zeppelin-sdk` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build zeppelin-sdk`, go to the dist folder `cd dist/zeppelin-sdk` and run `npm publish`. + +## Running unit tests + +Run `ng test zeppelin-sdk` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js b/zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js new file mode 100644 index 00000000000..bf69ea2ebb1 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/zeppelin-sdk'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json b/zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json new file mode 100644 index 00000000000..41dc5a032d3 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/zeppelin-sdk", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/package.json b/zeppelin-web-angular/projects/zeppelin-sdk/package.json new file mode 100644 index 00000000000..9be3b66d006 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/package.json @@ -0,0 +1,8 @@ +{ + "name": "@zeppelin/sdk", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^8.2.9", + "@angular/core": "^8.2.9" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts new file mode 100644 index 00000000000..0a5ad6dadd5 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts @@ -0,0 +1,129 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type EditorMode = + | 'ace/mode/scala' + | 'ace/mode/python' + | 'ace/mode/r' + | 'ace/mode/sql' + | 'ace/mode/markdown' + | 'ace/mode/sh'; + +export type EditorCompletionKey = 'TAB' | string; +export type EditorLanguage = 'scala' | 'python' | 'r' | 'sql' | 'markdown' | 'sh' | string; + +export interface Ticket { + principal: string; + ticket: string; + redirectURL?: string; + roles: string; +} + +export interface ConfigurationsInfo { + configurations: { + 'zeppelin.war.tempdir': string; + 'zeppelin.notebook.azure.user': string; + 'zeppelin.helium.npm.installer.url': string; + 'zeppelin.notebook.git.remote.username': string; + 'zeppelin.interpreter.remoterunner': string; + 'zeppelin.notebook.s3.user': string; + 'zeppelin.server.port': string; + 'zeppelin.plugins.dir': string; + 'zeppelin.notebook.new_format.delete_old': string; + 'zeppelin.ssl.truststore.type': string; + 'zeppelin.ssl.keystore.path': string; + 'zeppelin.notebook.s3.bucket': string; + 'zeppelin.notebook.git.remote.access-token': string; + 'zeppelin.recovery.dir': string; + 'zeppelin.notebook.s3.timeout': string; + 'zeppelin.notebook.cron.enable': string; + 'zeppelin.server.addr': string; + 'zeppelin.username.force.lowercase': string; + 'zeppelin.ssl.keystore.type': string; + 'zeppelin.ssl.truststore.path': string; + 'zeppelin.notebook.dir': string; + 'zeppelin.interpreter.lifecyclemanager.class': string; + 'zeppelin.notebook.gcs.dir': string; + 'zeppelin.notebook.s3.sse': string; + 'zeppelin.websocket.max.text.message.size': string; + 'zeppelin.notebook.git.remote.origin': string; + 'zeppelin.server.authorization.header.clear': string; + isRevisionSupported: string; + 'zeppelin.interpreter.dep.mvnRepo': string; + 'zeppelin.ssl': string; + 'zeppelin.notebook.autoInterpreterBinding': string; + 'zeppelin.config.storage.class': string; + 'zeppelin.helium.node.installer.url': string; + 'zeppelin.cluster.heartbeat.interval': string; + 'zeppelin.notebook.storage': string; + 'zeppelin.notebook.new_format.convert': string; + 'zeppelin.interpreter.dir': string; + 'zeppelin.anonymous.allowed': string; + 'zeppelin.credentials.persist': string; + 'zeppelin.notebook.mongo.uri': string; + 'zeppelin.config.fs.dir': string; + 'zeppelin.server.allowed.origins': string; + 'zeppelin.notebook.mongo.database': string; + 'zeppelin.encoding': string; + 'zeppelin.server.jetty.request.header.size': string; + 'zeppelin.search.temp.path': string; + 'zeppelin.cluster.heartbeat.timeout': string; + 'zeppelin.notebook.s3.endpoint': string; + 'zeppelin.notebook.homescreen.hide': string; + 'zeppelin.scheduler.threadpool.size': string; + 'zeppelin.notebook.azure.share': string; + 'zeppelin.helium.yarnpkg.installer.url': string; + 'zeppelin.server.strict.transport': string; + 'zeppelin.interpreter.setting': string; + 'zeppelin.server.xxss.protection': string; + 'zeppelin.server.rpc.portRange': string; + 'zeppelin.war': string; + 'zeppelin.interpreter.output.limit': string; + 'zeppelin.dep.localrepo': string; + 'zeppelin.interpreter.max.poolsize': string; + 'zeppelin.server.ssl.port': string; + 'zeppelin.notebook.mongo.collection': string; + 'zeppelin.notebook.public': string; + 'zeppelin.helium.registry': string; + 'zeppelin.server.kerberos.principal': string; + 'zeppelin.server.default.dir.allowed': string; + 'zeppelin.ssl.client.auth': string; + 'zeppelin.server.context.path': string; + 'zeppelin.recovery.storage.class': string; + 'zeppelin.notebook.default.owner.username': string; + 'zeppelin.home': string; + 'zeppelin.interpreter.lifecyclemanager.timeout.threshold': string; + 'zeppelin.cluster.addr': string; + 'zeppelin.notebook.git.remote.url': string; + 'zeppelin.notebook.mongo.autoimport': string; + 'zeppelin.notebook.one.way.sync': string; + 'zeppelin.notebook.homescreen': string; + 'zeppelin.interpreter.connect.timeout': string; + 'zeppelin.server.xframe.options': string; + 'zeppelin.interpreter.lifecyclemanager.timeout.checkinterval': string; + 'zeppelin.server.kerberos.keytab': string; + 'zeppelin.interpreter.rpc.portRange': string; + 'zeppelin.interpreter.group.default': string; + 'zeppelin.conf.dir': string; + 'zeppelin.interpreter.localRepo': string; + 'zeppelin.notebook.collaborative.mode.enable': string; + 'zeppelin.search.use.disk': string; + }; +} + +export interface ErrorInfo { + info?: string; +} + +export interface AuthInfo { + info?: string; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts new file mode 100644 index 00000000000..ddf934e2433 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts @@ -0,0 +1,164 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AuthInfo, ConfigurationsInfo, ErrorInfo } from './message-common.interface'; +import { + CheckpointNote, + CloneNote, + CollaborativeModeStatus, + DeleteNote, + EditorSettingReceived, + EditorSettingSend, + FolderRename, + GetInterpreterBindings, + GetNode, + ListRevision, + ListRevisionHistory, + MoveFolderToTrash, + MoveNoteToTrash, + NewNote, + Note, + NotesInfo, + NoteRename, + NoteRevision, + NoteRevisionForCompare, + NoteRunningStatus, + NoteUpdate, + NoteUpdated, + ParagraphAdded, + ParagraphMoved, + RemoveFolder, + RemoveNoteForms, + RestoreFolder, + RestoreNote, + SaveNoteFormsReceived, + SaveNoteFormsSend, + SetNoteRevision, + SetNoteRevisionStatus, + UpdateParagraph, + UpdatePersonalizedMode +} from './message-notebook.interface'; +import { + AngularObjectClientBind, + AngularObjectClientUnbind, + AngularObjectRemove, + AngularObjectUpdate, + AngularObjectUpdated, + CancelParagraph, + CommitParagraph, + Completion, + CompletionReceived, + CopyParagraph, + InsertParagraph, + MoveParagraph, + ParagraphClearAllOutput, + ParagraphClearOutput, + ParagraphRemove, + ParagraphRemoved, + ParasInfo, + PatchParagraphReceived, + PatchParagraphSend, + Progress, + RunAllParagraphs, + RunParagraph +} from './message-paragraph.interface'; + +import { ListNoteJobs, ListUpdateNoteJobs } from './message-job.interface'; + +import { InterpreterBindings, InterpreterSetting } from './message-interpreter.interface'; +import { OP } from './message-operator.interface'; + +export type MixMessageDataTypeMap = MessageSendDataTypeMap & MessageReceiveDataTypeMap; + +export interface MessageReceiveDataTypeMap { + [OP.COMPLETION_LIST]: CompletionReceived; + [OP.NOTES_INFO]: NotesInfo; + [OP.CONFIGURATIONS_INFO]: ConfigurationsInfo; + [OP.NOTE]: Note; + [OP.NOTE_REVISION]: NoteRevision; + [OP.ERROR_INFO]: ErrorInfo; + [OP.LIST_NOTE_JOBS]: ListNoteJobs; + [OP.LIST_UPDATE_NOTE_JOBS]: ListUpdateNoteJobs; + [OP.INTERPRETER_SETTINGS]: InterpreterSetting; + [OP.LIST_REVISION_HISTORY]: ListRevision; + [OP.INTERPRETER_BINDINGS]: InterpreterBindings; + [OP.COLLABORATIVE_MODE_STATUS]: CollaborativeModeStatus; + [OP.SET_NOTE_REVISION]: SetNoteRevisionStatus; + [OP.PARAGRAPH_ADDED]: ParagraphAdded; + [OP.NOTE_RUNNING_STATUS]: NoteRunningStatus; + [OP.NEW_NOTE]: NoteRevision; + [OP.SAVE_NOTE_FORMS]: SaveNoteFormsSend; + [OP.PARAGRAPH]: UpdateParagraph; + [OP.PATCH_PARAGRAPH]: PatchParagraphSend; + [OP.PARAGRAPH_REMOVED]: ParagraphRemoved; + [OP.EDITOR_SETTING]: EditorSettingReceived; + [OP.PROGRESS]: Progress; + [OP.PARAGRAPH_MOVED]: ParagraphMoved; + [OP.AUTH_INFO]: AuthInfo; + [OP.NOTE_UPDATED]: NoteUpdated; + [OP.ANGULAR_OBJECT_UPDATE]: AngularObjectUpdate; + [OP.ANGULAR_OBJECT_REMOVE]: AngularObjectRemove; + [OP.PARAS_INFO]: ParasInfo; +} + +export interface MessageSendDataTypeMap { + [OP.PING]: undefined; + [OP.LIST_CONFIGURATIONS]: undefined; + [OP.LIST_NOTES]: undefined; + [OP.GET_HOME_NOTE]: undefined; + [OP.RESTORE_ALL]: undefined; + [OP.EMPTY_TRASH]: undefined; + [OP.RELOAD_NOTES_FROM_REPO]: undefined; + [OP.GET_NOTE]: GetNode; + [OP.NEW_NOTE]: NewNote; + [OP.MOVE_NOTE_TO_TRASH]: MoveNoteToTrash; + [OP.MOVE_FOLDER_TO_TRASH]: MoveFolderToTrash; + [OP.RESTORE_NOTE]: RestoreNote; + [OP.RESTORE_FOLDER]: RestoreFolder; + [OP.REMOVE_FOLDER]: RemoveFolder; + [OP.DEL_NOTE]: DeleteNote; + [OP.CLONE_NOTE]: CloneNote; + [OP.NOTE_UPDATE]: NoteUpdate; + [OP.UPDATE_PERSONALIZED_MODE]: UpdatePersonalizedMode; + [OP.NOTE_RENAME]: NoteRename; + [OP.FOLDER_RENAME]: FolderRename; + [OP.MOVE_PARAGRAPH]: MoveParagraph; + [OP.INSERT_PARAGRAPH]: InsertParagraph; + [OP.COPY_PARAGRAPH]: CopyParagraph; + [OP.ANGULAR_OBJECT_UPDATED]: AngularObjectUpdated; + [OP.ANGULAR_OBJECT_CLIENT_BIND]: AngularObjectClientBind; + [OP.ANGULAR_OBJECT_CLIENT_UNBIND]: AngularObjectClientUnbind; + [OP.CANCEL_PARAGRAPH]: CancelParagraph; + [OP.PARAGRAPH_EXECUTED_BY_SPELL]: {}; // TODO(hsuanxyz) + [OP.RUN_PARAGRAPH]: RunParagraph; + [OP.RUN_ALL_PARAGRAPHS]: RunAllParagraphs; + [OP.PARAGRAPH_REMOVE]: ParagraphRemove; + [OP.PARAGRAPH_CLEAR_OUTPUT]: ParagraphClearOutput; + [OP.PARAGRAPH_CLEAR_ALL_OUTPUT]: ParagraphClearAllOutput; + [OP.COMPLETION]: Completion; + [OP.COMMIT_PARAGRAPH]: CommitParagraph; + [OP.PATCH_PARAGRAPH]: PatchParagraphReceived; + [OP.IMPORT_NOTE]: {}; // TODO(hsuanxyz) + [OP.CHECKPOINT_NOTE]: CheckpointNote; + [OP.SET_NOTE_REVISION]: SetNoteRevision; + [OP.LIST_REVISION_HISTORY]: ListRevisionHistory; + [OP.NOTE_REVISION]: NoteRevision; + [OP.NOTE_REVISION_FOR_COMPARE]: NoteRevisionForCompare; + [OP.EDITOR_SETTING]: EditorSettingSend; + [OP.LIST_NOTE_JOBS]: undefined; + [OP.UNSUBSCRIBE_UPDATE_NOTE_JOBS]: undefined; + [OP.LIST_UPDATE_NOTE_JOBS]: undefined; + [OP.GET_INTERPRETER_BINDINGS]: GetInterpreterBindings; + [OP.GET_INTERPRETER_SETTINGS]: undefined; + [OP.SAVE_NOTE_FORMS]: SaveNoteFormsReceived; + [OP.REMOVE_NOTE_FORMS]: RemoveNoteForms; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts new file mode 100644 index 00000000000..c59e459410e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface InterpreterSetting { + interpreterSettings: InterpreterItem[]; +} + +export interface InterpreterItem { + id: string; + name: string; + group: string; + properties: Properties; + status: string; + interpreterGroup: InterpreterGroupItem[]; + dependencies: string[]; + option: Option; +} + +export interface InterpreterBindings { + interpreterBindings: InterpreterBindingItem[]; +} + +export interface InterpreterBindingItem { + id: string; + name: string; + selected: boolean; + interpreters: InterpreterGroupItem[]; +} + +interface Properties { + [name: string]: { + name: string; + value: boolean; + type: string; + }; +} + +interface InterpreterGroupItem { + name: string; + class: string; + defaultInterpreter: boolean; + editor?: Editor; +} + +interface Editor { + language?: string; + editOnDblClick?: boolean; + completionKey?: string; + completionSupport?: boolean; +} + +interface Option { + remote: boolean; + port: number; + isExistingProcess: boolean; + setPermission: boolean; + owners: string[]; + isUserImpersonate: boolean; + perNote?: string; + perUser?: string; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts new file mode 100644 index 00000000000..c59122b3a38 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts @@ -0,0 +1,48 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ListNoteJobs { + noteJobs: NoteJobs; +} + +export interface ListUpdateNoteJobs { + noteRunningJobs: NoteJobs; +} + +export interface NoteJobs { + lastResponseUnixTime: number; + jobs: JobsItem[]; +} +export interface JobsItem { + noteId: string; + noteName: string; + noteType: string; + interpreter: string; + isRunningJob: boolean; + isRemoved: boolean; + unixTimeLastRun: number; + paragraphs: JobItemParagraphItem[]; +} +export interface JobItemParagraphItem { + id: string; + name: string; + status: JobStatus; +} + +export enum JobStatus { + READY = 'READY', + FINISHED = 'FINISHED', + ABORT = 'ABORT', + ERROR = 'ERROR', + PENDING = 'PENDING', + RUNNING = 'RUNNING' +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts new file mode 100644 index 00000000000..649a312561a --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts @@ -0,0 +1,210 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ParagraphItem } from './message-paragraph.interface'; + +interface ID { + id: string; +} + +interface Name { + name: string; +} + +export type GetNode = ID; +export type MoveNoteToTrash = ID; +export type MoveFolderToTrash = ID; +export type RestoreNote = ID; +export type RestoreFolder = ID; +export type DeleteNote = ID; +export type RemoveFolder = ID; +export type CloneNote = ID & Name; +export type FolderRename = ID & Name; +export type PersonalizedMode = 'true' | 'false'; + +export interface NoteRename extends Name, ID { + relative: boolean; +} + +export interface SendNote { + id: string; + noteParams: NoteParams; +} + +export interface NoteUpdated { + config: NoteConfig; + info: NoteInfo; + name: string; +} + +export interface Note { + note?: { + paragraphs: ParagraphItem[]; + name: string; + id: string; + defaultInterpreterGroup: string; + noteParams: NoteParams; + noteForms: NoteForms; + angularObjects: NoteAngularObjects; + config: NoteConfig; + info: NoteInfo; + }; +} + +export interface NoteAngularObjects { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface NoteInfo { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface NoteParams { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface NoteForms { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface RemoveNoteForms { + noteId: string; + formName: string; +} + +export interface SaveNoteFormsReceived { + noteId: string; + noteParams: NoteParams; +} + +export interface GetInterpreterBindings { + noteId: string; +} + +export interface EditorSettingSend { + paragraphId: string; + magic: string; +} + +export interface EditorSettingReceived { + paragraphId: string; + editor: { + completionSupport: boolean; + editOnDblClick: boolean; + language: string; + }; +} + +export interface NoteRevisionForCompare { + noteId: string; + revisionId: string; + position: string; +} + +export interface CollaborativeModeStatus { + status: boolean; + users: string[]; +} + +export interface ParagraphMoved { + index: number; + id: string; +} + +export interface UpdateParagraph { + paragraph: ParagraphItem; +} + +export interface SaveNoteFormsSend { + formsData: { + forms: NoteForms; + params: NoteParams; + }; +} + +export interface NoteRunningStatus { + status: boolean; +} + +export interface ParagraphAdded { + index: number; + paragraph: ParagraphItem; +} + +export interface SetNoteRevisionStatus { + status: boolean; +} + +export interface ListRevision { + revisionList: RevisionListItem[]; +} + +export interface RevisionListItem { + id: string; + message: string; + time?: number; +} + +export interface NoteRevision { + note?: Note['note']; + noteId: string; + revisionId: string; +} + +export interface ListRevisionHistory { + noteId: string; +} + +export interface SetNoteRevision { + noteId: string; + revisionId: string; +} + +export interface CheckpointNote { + noteId: string; + commitMessage: string; +} + +export interface NoteUpdate extends Name, ID { + config: NoteConfig; +} + +export interface NewNote extends Name { + defaultInterpreterGroup: string; +} + +export interface NotesInfo { + notes: NotesInfoItem[]; +} + +export interface NotesInfoItem extends ID { + path: string; +} + +export interface NoteConfig { + cron?: string; + releaseresource: boolean; + noteFormTitle?: string; + cronExecutingRoles?: string; + cronExecutingUser?: string; + isZeppelinNotebookCronEnable: boolean; + looknfeel: 'report' | 'default' | 'simple'; + personalizedMode: PersonalizedMode; +} + +export interface UpdatePersonalizedMode extends ID { + personalized: PersonalizedMode; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts new file mode 100644 index 00000000000..d3ce82b6029 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts @@ -0,0 +1,482 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// tslint:disable:no-redundant-jsdoc +/** + * Representation of event type. + */ +export enum OP { + /** + * [c-s] + * load note for home screen + */ + GET_HOME_NOTE = 'GET_HOME_NOTE', + + /** + * [c-s] + * client load note + * @param id note id + */ + GET_NOTE = 'GET_NOTE', + + /** + * [s-c] + * note info + * @param note serialized SendNote object + */ + NOTE = 'NOTE', + + /** + * [s-c] + * paragraph info + * @param paragraph serialized paragraph object + */ + PARAGRAPH = 'PARAGRAPH', + + /** + * [s-c] + * progress update + * @param id paragraph id + * @param progress percentage progress + */ + PROGRESS = 'PROGRESS', + + /** + * [c-s] + * create new notebook + */ + NEW_NOTE = 'NEW_NOTE', + + /** + * [c-s] + * delete notebook + * @param id note id + */ + DEL_NOTE = 'DEL_NOTE', + REMOVE_FOLDER = 'REMOVE_FOLDER', + MOVE_NOTE_TO_TRASH = 'MOVE_NOTE_TO_TRASH', + MOVE_FOLDER_TO_TRASH = 'MOVE_FOLDER_TO_TRASH', + RESTORE_FOLDER = 'RESTORE_FOLDER', + RESTORE_NOTE = 'RESTORE_NOTE', + RESTORE_ALL = 'RESTORE_ALL', + EMPTY_TRASH = 'EMPTY_TRASH', + + /** + * [c-s] + * clone new notebook + * @param id id of note to clone + * @param name name for the cloned note + */ + CLONE_NOTE = 'CLONE_NOTE', + + /** + * [c-s] + * import notebook + * @param object notebook + */ + IMPORT_NOTE = 'IMPORT_NOTE', + NOTE_UPDATE = 'NOTE_UPDATE', + NOTE_RENAME = 'NOTE_RENAME', + + /** + * [c-s] + * update personalized mode (boolean) + * @param note id and boolean personalized mode value + */ + UPDATE_PERSONALIZED_MODE = 'UPDATE_PERSONALIZED_MODE', + FOLDER_RENAME = 'FOLDER_RENAME', + + /** + * [c-s] + * run paragraph + * @param id paragraph id + * @param paragraph paragraph content.ie. script + * @param config paragraph config + * @param params paragraph params + */ + RUN_PARAGRAPH = 'RUN_PARAGRAPH', + + /** + * [c-s] + * commit paragraph + * @param id paragraph id + * @param title paragraph title + * @param paragraph paragraph content.ie. script + * @param config paragraph config + * @param params paragraph params + */ + COMMIT_PARAGRAPH = 'COMMIT_PARAGRAPH', + + /** + * [c-s] + * cancel paragraph run + * @param id paragraph id + */ + CANCEL_PARAGRAPH = 'CANCEL_PARAGRAPH', + + /** + * [c-s] + * move paragraph order + * @param id paragraph id + * @param index index the paragraph want to go + */ + MOVE_PARAGRAPH = 'MOVE_PARAGRAPH', + + /** + * [c-s] + * create new paragraph below current paragraph + * @param target index + */ + INSERT_PARAGRAPH = 'INSERT_PARAGRAPH', + + /** + * [c-s] + * create new para below current para as a copy of current para + * @param target index + * @param title paragraph title + * @param paragraph paragraph content.ie. script + * @param config paragraph config + * @param params paragraph params + */ + COPY_PARAGRAPH = 'COPY_PARAGRAPH', + + /** + * [c-s] + * ask paragraph editor setting + * @param magic magic keyword written in paragraph + * ex) spark.spark or spark + */ + EDITOR_SETTING = 'EDITOR_SETTING', + + /** + * [c-s] + * ask completion candidates + * @param id + * @param buf current code + * @param cursor cursor position in code + */ + COMPLETION = 'COMPLETION', + + /** + * [s-c] + * send back completion candidates list + * @param id + * @param completions list of string + */ + COMPLETION_LIST = 'COMPLETION_LIST', + + /** + * [c-s] + * ask list of note + */ + LIST_NOTES = 'LIST_NOTES', + + /** + * [c-s] + * reload notes from repo + */ + RELOAD_NOTES_FROM_REPO = 'RELOAD_NOTES_FROM_REPO', + + /** + * [s-c] + * list of note infos + * @param notes serialized List object + */ + NOTES_INFO = 'NOTES_INFO', + PARAGRAPH_REMOVE = 'PARAGRAPH_REMOVE', + + /** + * [c-s] + * clear output of paragraph + */ + PARAGRAPH_CLEAR_OUTPUT = 'PARAGRAPH_CLEAR_OUTPUT', + + /** [c-s] + * clear output of all paragraphs + */ + PARAGRAPH_CLEAR_ALL_OUTPUT = 'PARAGRAPH_CLEAR_ALL_OUTPUT', + + /** + * [s-c] + * ppend output + */ + PARAGRAPH_APPEND_OUTPUT = 'PARAGRAPH_APPEND_OUTPUT', + + /** + * [s-c] + * update (replace) output + */ + PARAGRAPH_UPDATE_OUTPUT = 'PARAGRAPH_UPDATE_OUTPUT', + PING = 'PING', + AUTH_INFO = 'AUTH_INFO', + + /** + * [s-c] + * add/update angular object + */ + ANGULAR_OBJECT_UPDATE = 'ANGULAR_OBJECT_UPDATE', + + /** [s-c] + * add angular object del + */ + ANGULAR_OBJECT_REMOVE = 'ANGULAR_OBJECT_REMOVE', + + /** + * [c-s] + * angular object value updated + */ + ANGULAR_OBJECT_UPDATED = 'ANGULAR_OBJECT_UPDATED', + + /** + * [c-s] + * angular object updated from AngularJS z object + */ + ANGULAR_OBJECT_CLIENT_BIND = 'ANGULAR_OBJECT_CLIENT_BIND', + + /** + * [c-s] + * angular object unbind from AngularJS z object + */ + ANGULAR_OBJECT_CLIENT_UNBIND = 'ANGULAR_OBJECT_CLIENT_UNBIND', + + /** + * [c-s] + * ask all key/value pairs of configurations + */ + LIST_CONFIGURATIONS = 'LIST_CONFIGURATIONS', + + /** + * [s-c] + * all key/value pairs of configurations + * @param settings serialized Map object + */ + CONFIGURATIONS_INFO = 'CONFIGURATIONS_INFO', + + /** + * [c-s] + * checkpoint note to storage repository + * @param noteId + * @param checkpointName + */ + CHECKPOINT_NOTE = 'CHECKPOINT_NOTE', + + /** + * [c-s] + * list revision history of the notebook + * @param noteId + */ + LIST_REVISION_HISTORY = 'LIST_REVISION_HISTORY', + + /** + * [c-s] + * get certain revision of note + * @param noteId + * @param revisionId + */ + NOTE_REVISION = 'NOTE_REVISION', + + /** + * [c-s] + * set current notebook head to this revision + * @param noteId + * @param revisionId + */ + SET_NOTE_REVISION = 'SET_NOTE_REVISION', + + /** + * [c-s] + * get certain revision of note for compare + * @param noteId + * @param revisionId + * @param position + */ + NOTE_REVISION_FOR_COMPARE = 'NOTE_REVISION_FOR_COMPARE', + + /** + * [s-c] + * append output + */ + APP_APPEND_OUTPUT = 'APP_APPEND_OUTPUT', + + /** + * [s-c] + * update (replace) output + */ + APP_UPDATE_OUTPUT = 'APP_UPDATE_OUTPUT', + + /** + * [s-c] + * on app load + */ + APP_LOAD = 'APP_LOAD', + + /** + * [s-c] + * on app status change + */ + APP_STATUS_CHANGE = 'APP_STATUS_CHANGE', + + /** + * [s-c] + * get note job management information + */ + LIST_NOTE_JOBS = 'LIST_NOTE_JOBS', + + /** + * [c-s] + * get job management information for until unixtime + */ + LIST_UPDATE_NOTE_JOBS = 'LIST_UPDATE_NOTE_JOBS', + + /** + * [c-s] + * unsubscribe job information for job management + * @param unixTime + */ + UNSUBSCRIBE_UPDATE_NOTE_JOBS = 'UNSUBSCRIBE_UPDATE_NOTE_JOBS', + + /** + * [c-s] + * get interpreter bindings + */ + GET_INTERPRETER_BINDINGS = 'GET_INTERPRETER_BINDINGS', + + /** + * [s-c] + * interpreter bindings + */ + INTERPRETER_BINDINGS = 'INTERPRETER_BINDINGS', + + /** + * [c-s] + * get interpreter settings + */ + GET_INTERPRETER_SETTINGS = 'GET_INTERPRETER_SETTINGS', + + /** + * [s-c] + * interpreter settings + */ + INTERPRETER_SETTINGS = 'INTERPRETER_SETTINGS', + + /** + * [s-c] + * error information to be sent + */ + ERROR_INFO = 'ERROR_INFO', + + /** + * [s-c] + * error information to be sent + */ + SESSION_LOGOUT = 'SESSION_LOGOUT', + + /** + * [s-c] + * Change websocket to watcher mode. + */ + WATCHER = 'WATCHER', + + /** + * [s-c] + * paragraph is added + */ + PARAGRAPH_ADDED = 'PARAGRAPH_ADDED', + + /** + * [s-c] + * paragraph deleted + */ + PARAGRAPH_REMOVED = 'PARAGRAPH_REMOVED', + + /** + * [s-c] + * paragraph moved + */ + PARAGRAPH_MOVED = 'PARAGRAPH_MOVED', + + /** + * [s-c] + * paragraph updated(name, config) + */ + NOTE_UPDATED = 'NOTE_UPDATED', + + /** + * [c-s] + * run all paragraphs + */ + RUN_ALL_PARAGRAPHS = 'RUN_ALL_PARAGRAPHS', + + /** + * [c-s] + * paragraph was executed by spell + */ + PARAGRAPH_EXECUTED_BY_SPELL = 'PARAGRAPH_EXECUTED_BY_SPELL', + + /** + * [s-c] + * run paragraph using spell + */ + RUN_PARAGRAPH_USING_SPELL = 'RUN_PARAGRAPH_USING_SPELL', + + /** + * [s-c] + * paragraph runtime infos + */ + PARAS_INFO = 'PARAS_INFO', + + /** + * save note forms + */ + SAVE_NOTE_FORMS = 'SAVE_NOTE_FORMS', + + /** + * remove note forms + */ + REMOVE_NOTE_FORMS = 'REMOVE_NOTE_FORMS', + + /** + * [s-c] + * start to download an interpreter + */ + INTERPRETER_INSTALL_STARTED = 'INTERPRETER_INSTALL_STARTED', + + /** + * [s-c] + * Status of an interpreter installation + */ + INTERPRETER_INSTALL_RESULT = 'INTERPRETER_INSTALL_RESULT', + + /** + * [s-c] + * collaborative mode status + */ + COLLABORATIVE_MODE_STATUS = 'COLLABORATIVE_MODE_STATUS', + + /** + * [c-s][s-c] + * patch editor text + */ + PATCH_PARAGRAPH = 'PATCH_PARAGRAPH', + + /** + * [s-c] + * sequential run status will be change + */ + NOTE_RUNNING_STATUS = 'NOTE_RUNNING_STATUS', + + /** + * [s-c] + * Notice + */ + NOTICE = 'NOTICE' +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts new file mode 100644 index 00000000000..2e04b225adb --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts @@ -0,0 +1,468 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EditorCompletionKey, EditorLanguage, EditorMode } from './message-common.interface'; + +export enum DynamicFormsType { + TextBox = 'TextBox', + Password = 'Password', + Select = 'Select', + CheckBox = 'CheckBox' +} + +export interface DynamicFormsItem { + defaultValue: string | string[]; + hidden: boolean; + name: string; + displayName?: string; + type: DynamicFormsType; + argument?: string; + options?: Array<{ value: string; displayName?: string }>; +} + +export interface DynamicForms { + [key: string]: DynamicFormsItem; +} + +export interface DynamicFormParams { + [key: string]: string | string[]; +} + +export interface ParagraphEditorSetting { + language?: EditorLanguage; + editOnDblClick?: boolean; + isOutputHidden?: boolean; + completionKey?: EditorCompletionKey; + completionSupport?: boolean; + params?: DynamicFormParams; + forms?: DynamicForms; +} + +// TODO(hsuanxyz) +export interface ParagraphParams { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface ParagraphConfigResults { + [index: string]: ParagraphConfigResult; +} + +export interface ParagraphConfigResult { + graph: GraphConfig; +} + +export interface ParagraphConfig { + editorSetting?: ParagraphEditorSetting; + colWidth?: number; + editorMode?: EditorMode; + fontSize?: number; + results?: ParagraphConfigResults; + enabled?: boolean; + tableHide?: boolean; + lineNumbers?: boolean; + editorHide?: boolean; + title?: boolean; + runOnSelectionChange?: boolean; + isZeppelinNotebookCronEnable?: boolean; +} + +export interface ParagraphResults { + code?: string; + msg?: ParagraphIResultsMsgItem[]; + + [index: number]: {}; +} + +export enum DatasetType { + NETWORK = 'NETWORK', + TABLE = 'TABLE', + HTML = 'HTML', + TEXT = 'TEXT', + ANGULAR = 'ANGULAR', + IMG = 'IMG' +} + +export class ParagraphIResultsMsgItem { + type: DatasetType = DatasetType.TEXT; + data = ''; +} + +export interface ParasInfo { + id: string; + infos: RuntimeInfos; +} + +export interface RuntimeInfos { + jobUrl: RuntimeInfosJobUrl; +} + +interface RuntimeInfosJobUrl { + propertyName: string; + label: string; + tooltip: string; + group: string; + values: RuntimeInfosValuesItem[]; + interpreterSettingId: string; +} + +interface RuntimeInfosValuesItem { + jobUrl: string; +} + +export interface ParagraphItem { + text: string; + user: string; + dateUpdated: string; + config: ParagraphConfig; + settings: ParagraphEditorSetting; + results?: ParagraphResults; + // tslint:disable-next-line no-any + apps: any[]; + progressUpdateIntervalMs: number; + jobName: string; + id: string; + dateCreated: string; + dateStarted?: string; + dateFinished?: string; + errorMessage?: string; + runtimeInfos?: RuntimeInfos; + status: string; + title?: string; + focus?: boolean; + // tslint:disable-next-line no-any TODO(hsuanxyz) + aborted: any; + // tslint:disable-next-line no-any TODO(hsuanxyz) + lineNumbers: any; + // tslint:disable-next-line no-any TODO(hsuanxyz) + fontSize: any; +} + +export interface SendParagraph { + id: string; + title?: string; + paragraph: string; + config: ParagraphConfig; + params: ParagraphParams; +} + +export interface CopyParagraph { + index: number; + title?: string; + paragraph: string; + config: ParagraphConfig; + params: ParagraphParams; +} + +export interface RunParagraph extends SendParagraph { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface CommitParagraph extends SendParagraph { + noteId: string; +} + +export interface RunAllParagraphs { + noteId: string; + paragraphs: string; +} + +export interface InsertParagraph { + index: number; +} + +export interface MoveParagraph { + id: string; + index: number; +} + +export interface AngularObjectUpdated { + noteId: string; + paragraphId: string; + name: string; + value: string; + interpreterGroupId: string; +} + +export interface AngularObjectRemove { + noteId: string; + paragraphId: string; + name: string; +} + +export interface AngularObjectUpdate { + noteId: string; + paragraphId: string; + interpreterGroupId: string; + angularObject: { + name: string; + // tslint:disable-next-line:no-any + object: any; + noteId: string; + paragraphId: string; + }; +} + +export interface AngularObjectClientBind { + noteId: string; + name: string; + value: string; + paragraphId: string; +} + +export interface AngularObjectClientUnbind { + noteId: string; + name: string; + paragraphId: string; +} + +export interface CancelParagraph { + id: string; +} + +export interface ParagraphRemove { + id: string; +} + +export interface ParagraphClearOutput { + id: string; +} + +export interface ParagraphClearAllOutput { + id: string; +} + +export interface Completion { + id: string; + buf: string; + cursor: number; +} + +export interface CompletionItem { + meta: string; + value: string; + name: string; +} + +export interface CompletionReceived { + completions: CompletionItem[]; + id: string; +} + +export interface PatchParagraphReceived { + id: string; + noteId: string; + patch: string; +} + +export interface PatchParagraphSend { + paragraphId: string; + patch: string; +} + +export interface ParagraphRemoved { + id: string; +} + +export type VisualizationMode = + | 'table' + | 'lineChart' + | 'stackedAreaChart' + | 'multiBarChart' + | 'scatterChart' + | 'pieChart' + | string; + +export class GraphConfig { + mode: VisualizationMode = 'table'; + height = 300; + optionOpen = false; + setting: GraphConfigSetting = {}; + keys: GraphConfigKeysItem[] = []; + groups: GraphConfigGroupsItem[] = []; + values: GraphConfigValuesItem[] = []; + commonSetting: GraphConfigCommonSetting; +} + +export interface Progress { + id: string; + progress: number; +} + +interface GraphConfigSetting { + table?: VisualizationTable; + lineChart?: VisualizationLineChart; + stackedAreaChart?: VisualizationStackedAreaChart; + multiBarChart?: VisualizationMultiBarChart; + scatterChart?: VisualizationScatterChart; +} + +interface VisualizationTable { + tableGridState: TableGridState; + tableColumnTypeState: TableColumnTypeState; + updated: boolean; + initialized: boolean; + tableOptionSpecHash: string; + tableOptionValue: TableOptionValue; +} + +interface TableGridState { + columns: ColumnsItem[]; + scrollFocus: ScrollFocus; + // tslint:disable-next-line + selection: any[]; + grouping: Grouping; + treeView: TreeView; + pagination: Pagination; +} + +interface ColumnsItem { + name: string; + visible: boolean; + width: string; + sort: Sort; + filters: FiltersItem[]; + pinned: string; +} + +interface Sort { + // tslint:disable-next-line + [key: string]: any; +} + +interface FiltersItem { + // tslint:disable-next-line + [key: string]: any; +} + +interface ScrollFocus { + // tslint:disable-next-line + [key: string]: any; +} + +interface Grouping { + // tslint:disable-next-line + grouping: any[]; + // tslint:disable-next-line + aggregations: any[]; + rowExpandedStates: RowExpandedStates; +} + +interface RowExpandedStates { + // tslint:disable-next-line + [key: string]: any; +} + +interface TreeView { + // tslint:disable-next-line + [key: string]: any; +} + +interface Pagination { + paginationCurrentPage: number; + paginationPageSize: number; +} + +interface TableColumnTypeState { + updated: boolean; + names: Names; +} + +interface Names { + index: string; + value: string; + random: string; + count: string; +} + +interface TableOptionValue { + useFilter: boolean; + showPagination: boolean; + showAggregationFooter: boolean; +} + +export type XLabelStatus = 'default' | 'rotate' | 'hide'; + +export class XAxisSetting { + rotate = { degree: '-45' }; + xLabelStatus: XLabelStatus = 'default'; +} + +export class VisualizationLineChart extends XAxisSetting { + forceY = false; + lineWithFocus = false; + isDateFormat = false; + dateFormat = ''; +} + +export class VisualizationStackedAreaChart extends XAxisSetting { + style: 'stream' | 'expand' | 'stack' = 'stack'; +} + +export class VisualizationMultiBarChart extends XAxisSetting { + stacked = false; +} + +export class VisualizationScatterChart { + xAxis?: XAxis; + yAxis?: YAxis; + group?: Group; + size?: Size; +} + +interface XAxis { + name: string; + index: number; + aggr: string; +} + +interface YAxis { + name: string; + index: number; + aggr: string; +} + +interface Group { + name: string; + index: number; + aggr: string; +} + +interface Size { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigKeysItem { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigGroupsItem { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigValuesItem { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigCommonSetting { + // tslint:disable-next-line + [key: string]: any; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts new file mode 100644 index 00000000000..4160fa7f035 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './message-common.interface'; +export * from './message-data-type-map.interface'; +export * from './message-notebook.interface'; +export * from './message-operator.interface'; +export * from './message-paragraph.interface'; +export * from './websocket-message.interface'; +export * from './message-job.interface'; +export * from './message-interpreter.interface'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts new file mode 100644 index 00000000000..bdc71e1f428 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MixMessageDataTypeMap } from './message-data-type-map.interface'; + +export interface WebSocketMessage { + op: K; + data?: MixMessageDataTypeMap[K]; + ticket?: string; // default 'anonymous' + principal?: string; // default 'anonymous' + roles?: string; // default '[]' +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts new file mode 100644 index 00000000000..4505e365726 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts @@ -0,0 +1,506 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { interval, Observable, Subject, Subscription } from 'rxjs'; +import { delay, filter, map, mergeMap, retryWhen, take } from 'rxjs/operators'; +import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; + +import { Ticket } from './interfaces/message-common.interface'; +import { + MessageReceiveDataTypeMap, + MessageSendDataTypeMap, + MixMessageDataTypeMap +} from './interfaces/message-data-type-map.interface'; +import { NoteConfig, PersonalizedMode, SendNote } from './interfaces/message-notebook.interface'; +import { OP } from './interfaces/message-operator.interface'; +import { ParagraphConfig, ParagraphParams, SendParagraph } from './interfaces/message-paragraph.interface'; +import { WebSocketMessage } from './interfaces/websocket-message.interface'; + +export type ArgumentsType = T extends (...args: infer U) => void ? U : never; + +export type SendArgumentsType = MessageSendDataTypeMap[K] extends undefined + ? ArgumentsType<(op: K) => void> + : ArgumentsType<(op: K, data: MessageSendDataTypeMap[K]) => void>; + +export type ReceiveArgumentsType< + K extends keyof MessageReceiveDataTypeMap +> = MessageReceiveDataTypeMap[K] extends undefined ? () => void : (data?: MessageReceiveDataTypeMap[K]) => void; + +export class Message { + public connectedStatus = false; + public connectedStatus$ = new Subject(); + private ws: WebSocketSubject>; + private open$ = new Subject(); + private close$ = new Subject(); + private sent$ = new Subject>(); + private received$ = new Subject>(); + private pingIntervalSubscription = new Subscription(); + private wsUrl: string; + private ticket: Ticket; + + constructor() { + this.open$.subscribe(() => { + this.connectedStatus = true; + this.connectedStatus$.next(this.connectedStatus); + this.pingIntervalSubscription.unsubscribe(); + this.pingIntervalSubscription = interval(1000 * 10).subscribe(() => this.ping()); + }); + this.close$.subscribe(() => { + this.connectedStatus = false; + this.connectedStatus$.next(this.connectedStatus); + this.pingIntervalSubscription.unsubscribe(); + }); + } + + bootstrap(ticket: Ticket, wsUrl: string) { + this.setTicket(ticket); + this.setWsUrl(wsUrl); + this.connect(); + } + + getWsInstance(): WebSocketSubject> { + return this.ws; + } + + setWsUrl(wsUrl: string): void { + this.wsUrl = wsUrl; + } + + setTicket(ticket: Ticket): void { + this.ticket = ticket; + } + + interceptReceived( + data: WebSocketMessage + ): WebSocketMessage { + return data; + } + + connect() { + this.ws = webSocket({ + url: this.wsUrl, + openObserver: this.open$, + closeObserver: this.close$ + }); + + this.ws + .pipe( + // reconnect + retryWhen(errors => + errors.pipe( + mergeMap(() => + this.close$.pipe( + take(1), + delay(4000) + ) + ) + ) + ) + ) + .subscribe((e: WebSocketMessage) => { + console.log('Receive:', e); + this.received$.next(this.interceptReceived(e)); + }); + } + + ping() { + this.send(OP.PING); + } + + close() { + this.close$.next(); + } + + opened(): Observable { + return this.open$.asObservable(); + } + + closed(): Observable { + return this.close$.asObservable(); + } + + sent(): Observable> { + return this.sent$.asObservable(); + } + + received(): Observable> { + return this.received$.asObservable(); + } + + send(...args: SendArgumentsType): void { + const [op, data] = args; + const message: WebSocketMessage = { + op, + data: data as MixMessageDataTypeMap[K], + ...this.ticket + }; + console.log('Send:', message); + + this.ws.next(message); + this.sent$.next(message); + } + + receive(op: K): Observable[K]> { + return this.received$.pipe( + filter(message => message.op === op), + map(message => message.data) + ) as Observable[K]>; + } + + destroy(): void { + this.ws.complete(); + this.ws = null; + } + + getHomeNote(): void { + this.send(OP.GET_HOME_NOTE); + } + + newNote(noteName: string, defaultInterpreterGroup: string): void { + this.send(OP.NEW_NOTE, { + name: noteName, + defaultInterpreterGroup + }); + } + + moveNoteToTrash(noteId: string): void { + this.send(OP.MOVE_NOTE_TO_TRASH, { + id: noteId + }); + } + + restoreNote(noteId: string): void { + this.send(OP.RESTORE_NOTE, { + id: noteId + }); + } + + deleteNote(noteId): void { + this.send(OP.DEL_NOTE, { + id: noteId + }); + } + + restoreFolder(folderPath: string): void { + this.send(OP.RESTORE_FOLDER, { + id: folderPath + }); + } + + removeFolder(folderPath: string): void { + this.send(OP.REMOVE_FOLDER, { + id: folderPath + }); + } + + moveFolderToTrash(folderPath: string): void { + this.send(OP.MOVE_FOLDER_TO_TRASH, { + id: folderPath + }); + } + + restoreAll(): void { + this.send(OP.RESTORE_ALL); + } + + emptyTrash(): void { + this.send(OP.EMPTY_TRASH); + } + + cloneNote(noteIdToClone, newNoteName): void { + this.send(OP.CLONE_NOTE, { id: noteIdToClone, name: newNoteName }); + } + + /** + * get nodes list + */ + listNodes(): void { + this.send(OP.LIST_NOTES); + } + + reloadAllNotesFromRepo(): void { + this.send(OP.RELOAD_NOTES_FROM_REPO); + } + + getNote(noteId: string): void { + this.send(OP.GET_NOTE, { id: noteId }); + } + + updateNote(noteId: string, noteName: string, noteConfig: NoteConfig): void { + this.send(OP.NOTE_UPDATE, { id: noteId, name: noteName, config: noteConfig }); + } + + updatePersonalizedMode(noteId: string, modeValue: PersonalizedMode): void { + this.send(OP.UPDATE_PERSONALIZED_MODE, { id: noteId, personalized: modeValue }); + } + + noteRename(noteId: string, noteName: string, relative: boolean): void { + this.send(OP.NOTE_RENAME, { id: noteId, name: noteName, relative: relative }); + } + + folderRename(folderId: string, folderPath: string): void { + this.send(OP.FOLDER_RENAME, { id: folderId, name: folderPath }); + } + + moveParagraph(paragraphId: string, newIndex: number): void { + this.send(OP.MOVE_PARAGRAPH, { id: paragraphId, index: newIndex }); + } + + insertParagraph(newIndex: number): void { + this.send(OP.INSERT_PARAGRAPH, { index: newIndex }); + } + + copyParagraph( + newIndex: number, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + this.send(OP.COPY_PARAGRAPH, { + index: newIndex, + title: paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + }); + } + + angularObjectUpdate( + noteId: string, + paragraphId: string, + name: string, + value: string, + interpreterGroupId: string + ): void { + this.send(OP.ANGULAR_OBJECT_UPDATED, { + noteId: noteId, + paragraphId: paragraphId, + name: name, + value: value, + interpreterGroupId: interpreterGroupId + }); + } + + // tslint:disable-next-line:no-any + angularObjectClientBind(noteId: string, name: string, value: any, paragraphId: string): void { + this.send(OP.ANGULAR_OBJECT_CLIENT_BIND, { + noteId: noteId, + name: name, + value: value, + paragraphId: paragraphId + }); + } + + angularObjectClientUnbind(noteId: string, name: string, paragraphId: string): void { + this.send(OP.ANGULAR_OBJECT_CLIENT_UNBIND, { + noteId: noteId, + name: name, + paragraphId: paragraphId + }); + } + + cancelParagraph(paragraphId): void { + this.send(OP.CANCEL_PARAGRAPH, { id: paragraphId }); + } + + paragraphExecutedBySpell( + paragraphId, + paragraphTitle, + paragraphText, + paragraphResultsMsg, + paragraphStatus, + paragraphErrorMessage, + paragraphConfig, + paragraphParams, + paragraphDateStarted, + paragraphDateFinished + ): void { + this.send(OP.PARAGRAPH_EXECUTED_BY_SPELL, { + id: paragraphId, + title: paragraphTitle, + paragraph: paragraphText, + results: { + code: paragraphStatus, + msg: paragraphResultsMsg.map(dataWithType => { + const serializedData = dataWithType.data; + return { type: dataWithType.type, serializedData }; + }) + }, + status: paragraphStatus, + errorMessage: paragraphErrorMessage, + config: paragraphConfig, + params: paragraphParams, + dateStarted: paragraphDateStarted, + dateFinished: paragraphDateFinished + }); + } + + runParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + this.send(OP.RUN_PARAGRAPH, { + id: paragraphId, + title: paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + }); + } + + runAllParagraphs(noteId: string, paragraphs: SendParagraph[]): void { + this.send(OP.RUN_ALL_PARAGRAPHS, { + noteId: noteId, + paragraphs: JSON.stringify(paragraphs) + }); + } + + paragraphRemove(paragraphId: string): void { + this.send(OP.PARAGRAPH_REMOVE, { id: paragraphId }); + } + + paragraphClearOutput(paragraphId: string): void { + this.send(OP.PARAGRAPH_CLEAR_OUTPUT, { id: paragraphId }); + } + + paragraphClearAllOutput(noteId: string): void { + this.send(OP.PARAGRAPH_CLEAR_ALL_OUTPUT, { id: noteId }); + } + + completion(paragraphId: string, buf: string, cursor: number): void { + this.send(OP.COMPLETION, { + id: paragraphId, + buf: buf, + cursor: cursor + }); + } + + commitParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphConfig, + noteId: string + ): void { + return this.send(OP.COMMIT_PARAGRAPH, { + id: paragraphId, + noteId: noteId, + title: paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + }); + } + + patchParagraph(paragraphId: string, noteId: string, patch: string): void { + // javascript add "," if change contains several patches + // but java library requires patch list without "," + const normalPatch = patch.replace(/,@@/g, '@@'); + return this.send(OP.PATCH_PARAGRAPH, { + id: paragraphId, + noteId: noteId, + patch: normalPatch + }); + } + + importNote(note: SendNote): void { + this.send(OP.IMPORT_NOTE, { + note: note + }); + } + + checkpointNote(noteId: string, commitMessage: string): void { + this.send(OP.CHECKPOINT_NOTE, { + noteId: noteId, + commitMessage: commitMessage + }); + } + + setNoteRevision(noteId: string, revisionId: string): void { + this.send(OP.SET_NOTE_REVISION, { + noteId: noteId, + revisionId: revisionId + }); + } + + listRevisionHistory(noteId: string): void { + this.send(OP.LIST_REVISION_HISTORY, { + noteId: noteId + }); + } + + noteRevision(noteId: string, revisionId: string): void { + this.send(OP.NOTE_REVISION, { + noteId: noteId, + revisionId: revisionId + }); + } + + noteRevisionForCompare(noteId: string, revisionId: string, position: string): void { + this.send(OP.NOTE_REVISION_FOR_COMPARE, { + noteId: noteId, + revisionId: revisionId, + position: position + }); + } + + editorSetting(paragraphId: string, replName: string): void { + this.send(OP.EDITOR_SETTING, { + paragraphId: paragraphId, + magic: replName + }); + } + + listNoteJobs(): void { + this.send(OP.LIST_NOTE_JOBS); + } + + unsubscribeUpdateNoteJobs(): void { + this.send(OP.UNSUBSCRIBE_UPDATE_NOTE_JOBS); + } + + getInterpreterBindings(noteId: string): void { + this.send(OP.GET_INTERPRETER_BINDINGS, { noteId: noteId }); + } + + saveInterpreterBindings(noteId, selectedSettingIds): void { + // this.send(OP.SAVE_INTERPRETER_BINDINGS, + // {noteId: noteId, selectedSettingIds: selectedSettingIds}); + } + + listConfigurations(): void { + this.send(OP.LIST_CONFIGURATIONS); + } + + getInterpreterSettings(): void { + this.send(OP.GET_INTERPRETER_SETTINGS); + } + + saveNoteForms(note: SendNote): void { + this.send(OP.SAVE_NOTE_FORMS, { + noteId: note.id, + noteParams: note.noteParams + }); + } + + removeNoteForms(note, formName): void { + this.send(OP.REMOVE_NOTE_FORMS, { + noteId: note.id, + formName: formName + }); + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts new file mode 100644 index 00000000000..c5417873004 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './message'; +// https://github.com/ng-packagr/ng-packagr/issues/1093 +export * from './interfaces/public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json new file mode 100644 index 00000000000..784751866f8 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "flatModuleId": "@zeppelin/sdk" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tslint.json b/zeppelin-web-angular/projects/zeppelin-sdk/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/README.md b/zeppelin-web-angular/projects/zeppelin-visualization/README.md new file mode 100644 index 00000000000..aa8e560c926 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/README.md @@ -0,0 +1,36 @@ + + +# ZeppelinVisualization + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.8. + +## Code scaffolding + +Run `ng generate component component-name --project zeppelin-visualization` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project zeppelin-visualization`. +> Note: Don't forget to add `--project zeppelin-visualization` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build zeppelin-visualization` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build zeppelin-visualization`, go to the dist folder `cd dist/zeppelin-visualization` and run `npm publish`. + +## Running unit tests + +Run `ng test zeppelin-visualization` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js b/zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js new file mode 100644 index 00000000000..e04c06a8f52 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/zeppelin-visualization'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json b/zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json new file mode 100644 index 00000000000..78b3ecf185e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/zeppelin-visualization", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/package.json b/zeppelin-web-angular/projects/zeppelin-visualization/package.json new file mode 100644 index 00000000000..1d4232be543 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/package.json @@ -0,0 +1,8 @@ +{ + "name": "@zeppelin/visualization", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^8.2.8", + "@angular/core": "^8.2.8" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts new file mode 100644 index 00000000000..98d4632fcab --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ParagraphIResultsMsgItem } from '@zeppelin/sdk'; + +export abstract class DataSet { + abstract loadParagraphResult(paragraphResult: ParagraphIResultsMsgItem): void; +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts new file mode 100644 index 00000000000..d663788be0e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts @@ -0,0 +1,57 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GraphConfig } from '@zeppelin/sdk'; + +import { G2VisualizationComponentBase } from './g2-visualization-component-base'; +import { PivotTransformation } from './pivot-transformation'; +import { Transformation } from './transformation'; +import { Visualization } from './visualization'; +import { VisualizationComponentPortal } from './visualization-component-portal'; + +export abstract class G2VisualizationBase extends Visualization { + pivot = new PivotTransformation(this.getConfig()); + abstract componentPortal: VisualizationComponentPortal; + + constructor(config: GraphConfig) { + super(config); + } + + destroy(): void { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + } + + getTransformation(): Transformation { + return this.pivot; + } + + refresh(): void { + if (this.componentRef) { + this.componentRef.instance.refresh(); + } + } + + render(data): void { + this.transformed = data; + if (this.componentRef) { + this.componentRef.instance.refreshSetting(); + this.componentRef.instance.render(); + } else { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts new file mode 100644 index 00000000000..8e52dcdc9de --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts @@ -0,0 +1,93 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ElementRef, OnDestroy } from '@angular/core'; + +import * as G2 from '@antv/g2'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { Visualization } from './visualization'; + +export abstract class G2VisualizationComponentBase implements OnDestroy { + abstract container: ElementRef; + chart: G2.Chart; + config: GraphConfig; + + constructor(public visualization: Visualization) {} + + abstract renderBefore(chart: G2.Chart): void; + + abstract refreshSetting(): void; + abstract setScale(): void; + + render() { + this.config = this.visualization.getConfig(); + this.refreshSetting(); + this.initChart(); + this.chart.source(this.visualization.transformed); + this.renderBefore(this.chart); + this.chart.render(); + this.renderAfter(); + } + + renderAfter(): void {} + + getKey(): string { + let key = ''; + if (this.config.keys && this.config.keys[0]) { + key = this.config.keys[0].name; + } + return key; + } + + refresh(): void { + this.config = this.visualization.getConfig(); + this.chart.changeHeight(this.config.height || 400); + setTimeout(() => { + this.setScale(); + this.chart.forceFit(); + }); + } + + initChart() { + if (this.chart) { + this.chart.clear(); + } else { + if (this.container && this.container.nativeElement) { + this.chart = new G2.Chart({ + forceFit: true, + container: this.container.nativeElement, + height: this.config.height || 400, + padding: { + top: 80, + left: 50, + right: 50, + bottom: 50 + } + }); + this.chart.legend({ + position: 'top-right' + // tslint:disable-next-line + } as any); + } else { + throw new Error(`Can't find the container, Please make sure on correct assignment.`); + } + } + } + + ngOnDestroy(): void { + if (this.chart) { + this.chart.destroy(); + this.chart = null; + } + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts new file mode 100644 index 00000000000..963cc48f9fa --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts @@ -0,0 +1,230 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DataSet } from '@antv/data-set'; +import { get } from 'lodash'; + +import { TableData } from './table-data'; +import { Transformation } from './transformation'; + +export class PivotTransformation extends Transformation { + constructor(config) { + super(config); + } + + removeUnknown(array: Array<{ name: string }>, tableData: TableData): void { + for (let i = 0; i < array.length; i++) { + // remove non existing column + let found = false; + for (let j = 0; j < tableData.columns.length; j++) { + const a = array[i]; + const b = tableData.columns[j]; + if (a.name === b) { + found = true; + break; + } + } + if (!found) { + array.splice(i, 1); + i--; + } + } + } + + setDefaultConfig(tableData: TableData) { + const config = this.getConfig(); + config.keys = config.keys || []; + config.groups = config.groups || []; + config.values = config.values || []; + this.removeUnknown(config.keys, tableData); + this.removeUnknown(config.values, tableData); + this.removeUnknown(config.groups, tableData); + if (config.keys.length === 0 && config.groups.length === 0 && config.values.length === 0) { + if (config.keys.length === 0 && tableData.columns[0]) { + config.keys = [ + { + name: tableData.columns[0], + index: 0, + aggr: 'sum' + } + ]; + } + + if (config.values.length === 0 && tableData.columns[1]) { + config.values = [ + { + name: tableData.columns[1], + index: 1, + aggr: 'sum' + } + ]; + } + } + } + + // tslint:disable-next-line:no-any + transform(tableData: TableData): any { + const config = this.getConfig(); + this.setDefaultConfig(tableData); + const ds = new DataSet(); + let dv = ds.createView().source(tableData.rows); + + let firstKey = ''; + if (config.keys && config.keys[0]) { + firstKey = config.keys[0].name; + } + let keys = []; + let groups = []; + let values = []; + let aggregates = []; + + // set values from config + if (config.mode !== 'scatterChart') { + keys = config.keys.map(e => e.name); + groups = config.groups.map(e => e.name); + values = config.values.map(v => `${v.name}(${v.aggr})`); + aggregates = config.values.map(v => (v.aggr === 'avg' ? 'mean' : v.aggr)); + } else { + const xAxis = get(config.setting, 'scatterChart.xAxis.name', tableData.columns[0]); + const yAxis = get(config.setting, 'scatterChart.yAxis.name', tableData.columns[1]); + const group = get(config.setting, 'scatterChart.group.name'); + keys = xAxis ? [xAxis] : []; + values = yAxis ? [yAxis] : []; + groups = group ? [group] : []; + } + + // try coercion to number type + dv.transform({ + type: 'map', + callback: row => { + Object.keys(row).forEach(k => { + if (config.keys.map(e => e.name).indexOf(k) === -1) { + const numberValue = Number.parseFloat(row[k]); + row[k] = Number.isFinite(numberValue) ? numberValue : row[k]; + } + }); + return row; + } + }); + + // not applicable with type scatter chart + if (config.mode !== 'scatterChart') { + + // aggregate values + dv.transform({ + type: 'aggregate', + fields: config.values.map(v => v.name), + operations: aggregates, + as: values, + groupBy: [...keys, ...groups] + }); + + // fill the rows to keep the charts is continuity + dv.transform({ + type: 'fill-rows', + groupBy: [...keys, ...groups], + fillBy: 'group' + }); + + /** + * fill the field to keep the charts is continuity + * + * before + * ``` + * [ + * { x: 0, y: 1 }, + * { x: 0, y: 2 }, + * { x: 0, y: 3 }, + * { x: 0 } + * ] + * ``` + * after + * ``` + * [ + * { x: 0, y: 1 }, + * { x: 0, y: 2 }, + * { x: 0, y: 3 }, + * { x: 0, y: 0 } + * // ^^^^^ filled this + * ] + * ``` + */ + config.values + .map(v => `${v.name}(${v.aggr})`) + .forEach(field => { + dv.transform({ + field, + type: 'impute', + groupBy: keys, + method: 'value', + value: config.mode === 'stackedAreaChart' ? 0 : null + }); + }); + } + + dv.transform({ + type: 'fold', + fields: values, + key: '__key__', + value: '__value__' + }); + + dv.transform({ + type: 'partition', + groupBy: groups + }); + + const groupsData = []; + Object.keys(dv.rows).forEach(groupKey => { + const groupName = groupKey.replace(/^_/, ''); + dv.rows[groupKey].forEach(row => { + const getKey = () => { + if (config.mode !== 'pieChart') { + return groupName ? `${row.__key__}.${groupName}` : row.__key__ + } else { + const keyName = keys.map(k => row[k]).join('.'); + return groupName ? `${keyName}.${groupName}` : keyName; + } + }; + groupsData.push({ + ...row, + __key__: getKey() + }); + }); + }); + + groupsData.sort( + (a, b) => + dv.origin.findIndex(o => o[firstKey] === a[firstKey]) - dv.origin.findIndex(o => o[firstKey] === b[firstKey]) + ); + + console.log(groupsData); + dv = ds + .createView({ + state: { + filterData: null + } + }) + .source(groupsData); + + if (config.mode === 'stackedAreaChart' || config.mode === 'pieChart') { + dv.transform({ + type: 'percent', + field: '__value__', + dimension: '__key__', + groupBy: keys, + as: '__percent__' + }); + } + return dv; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts new file mode 100644 index 00000000000..c28b0e2a649 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Public API Surface of zeppelin-visualization + */ + +export * from './data-set'; +export * from './transformation'; +export * from './visualization-component-portal'; +export * from './visualization'; +export * from './table-data'; +export * from './table-transformation'; +export * from './pivot-transformation'; +export * from './g2-visualization-base'; +export * from './g2-visualization-component-base'; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts new file mode 100644 index 00000000000..f0bd5ad4227 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DataSet as AntvDataSet } from '@antv/data-set'; + +import { DatasetType, ParagraphIResultsMsgItem } from '@zeppelin/sdk'; +import { DataSet } from './data-set'; + +export class TableData extends DataSet { + columns: string[] = []; + // tslint:disable-next-line + rows: any[] = []; + + loadParagraphResult({ data, type }: ParagraphIResultsMsgItem): void { + if (type !== DatasetType.TABLE) { + console.error('Can not load paragraph result'); + return; + } + const ds = new AntvDataSet(); + const dv = ds.createView().source(data, { + type: 'tsv' + }); + this.columns = dv.origin && dv.origin.columns ? dv.origin.columns : []; + this.rows = dv.rows || []; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts new file mode 100644 index 00000000000..19111ecad88 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TableData } from './table-data'; +import { Transformation } from './transformation'; + +// tslint:disable-next-line:no-any +export class TableTransformation extends Transformation { + constructor(config) { + super(config); + } + + // tslint:disable-next-line:no-any + transform(tableData: TableData): any { + return tableData; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts new file mode 100644 index 00000000000..522ac021326 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GraphConfig } from '@zeppelin/sdk'; + +import { DataSet } from './data-set'; + +export interface Setting { + // tslint:disable-next-line:no-any + template: any; + // tslint:disable-next-line:no-any + scope: any; +} + +export abstract class Transformation { + dataset: DataSet; + constructor(private config: GraphConfig) {} + + // tslint:disable-next-line:no-any + abstract transform(tableData): any; + + setConfig(config) { + this.config = config; + } + + setTableData(dataset: DataSet) { + this.dataset = dataset; + } + + getTableData(): DataSet { + return this.dataset; + } + + getConfig() { + return this.config; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts new file mode 100644 index 00000000000..a9418d98307 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet, ComponentPortal, ComponentType, PortalInjector } from '@angular/cdk/portal'; +import { ComponentFactoryResolver, InjectionToken, ViewContainerRef } from '@angular/core'; + +import { Visualization } from './visualization'; + +export const VISUALIZATION = new InjectionToken('Visualization'); + +export class VisualizationComponentPortal { + constructor( + private visualization: T, + private component: ComponentType, + private portalOutlet: CdkPortalOutlet, + private viewContainerRef: ViewContainerRef, + private componentFactoryResolver?: ComponentFactoryResolver + ) {} + + createInjector() { + const userInjector = this.viewContainerRef && this.viewContainerRef.injector; + // tslint:disable-next-line + const injectionTokens = new WeakMap([[VISUALIZATION, this.visualization]]); + return new PortalInjector(userInjector, injectionTokens); + } + + getComponentPortal() { + const injector = this.createInjector(); + return new ComponentPortal(this.component, null, injector, this.componentFactoryResolver); + } + + attachComponentPortal() { + const componentRef = this.portalOutlet.attachComponentPortal(this.getComponentPortal()); + componentRef.changeDetectorRef.markForCheck(); + return componentRef; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts new file mode 100644 index 00000000000..bb483e58766 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentRef } from '@angular/core'; +import { Subject } from 'rxjs'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { Transformation } from './transformation'; + +// tslint:disable-next-line +export abstract class Visualization { + // tslint:disable-next-line + transformed: any; + componentRef: ComponentRef; + configChange$ = new Subject(); + constructor(private config: GraphConfig) {} + + abstract getTransformation(): Transformation; + abstract render(tableData): void; + abstract refresh(): void; + abstract destroy(): void; + + configChanged() { + return this.configChange$.asObservable(); + } + + setConfig(config: GraphConfig) { + this.config = config; + this.refresh(); + } + + getConfig() { + return this.config; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json new file mode 100644 index 00000000000..15689086f6e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "flatModuleId": "@zeppelin/visualization" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tslint.json b/zeppelin-web-angular/projects/zeppelin-visualization/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/proxy.conf.js b/zeppelin-web-angular/proxy.conf.js new file mode 100644 index 00000000000..c3d571ce3e5 --- /dev/null +++ b/zeppelin-web-angular/proxy.conf.js @@ -0,0 +1,59 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const dotenv = require('dotenv'); +const HttpsProxyAgent = require('https-proxy-agent'); +dotenv.config(); + +const proxyConfig = [ + { + context: ['/'], + target: 'http://localhost:8080', + secure: false, + changeOrigin: true + }, + { + context: '/ws', + target: 'ws://localhost:8080', + secure: false, + ws:true, + changeOrigin: true + } +]; + +function httpUrlToWSUrl(url) { + return url.replace(/(http)(s)?\:\/\//, "ws$2://"); +} + +function setupForCorporateProxy(proxyConfig) { + const proxyServer = process.env.SERVER_PROXY; + const httpProxy = process.env.HTTP_PROXY; + if (proxyServer) { + let agent = null; + if (httpProxy) { + agent = new HttpsProxyAgent(httpProxy); + } + proxyConfig.forEach(function(entry) { + if (entry.context === '/ws') { + entry.target = httpUrlToWSUrl(proxyServer) + } else { + entry.target = proxyServer; + } + if (agent) { + entry.agent = agent; + } + }); + } + return proxyConfig; +} + +module.exports = setupForCorporateProxy(proxyConfig); diff --git a/zeppelin-web-angular/screenshot.png b/zeppelin-web-angular/screenshot.png new file mode 100644 index 00000000000..4c157c5fdef Binary files /dev/null and b/zeppelin-web-angular/screenshot.png differ diff --git a/zeppelin-web-angular/src/.editorconfig b/zeppelin-web-angular/src/.editorconfig new file mode 100644 index 00000000000..8b14efe23aa --- /dev/null +++ b/zeppelin-web-angular/src/.editorconfig @@ -0,0 +1,12 @@ +# Editor configuration, see https://editorconfig.org + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/zeppelin-web-angular/src/.gitignore b/zeppelin-web-angular/src/.gitignore new file mode 100644 index 00000000000..85158b7a442 --- /dev/null +++ b/zeppelin-web-angular/src/.gitignore @@ -0,0 +1,43 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/zeppelin-web-angular/src/app/app-http.interceptor.ts b/zeppelin-web-angular/src/app/app-http.interceptor.ts new file mode 100644 index 00000000000..520eea89418 --- /dev/null +++ b/zeppelin-web-angular/src/app/app-http.interceptor.ts @@ -0,0 +1,53 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { throwError, Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { isNil } from 'lodash'; + +import { environment } from '@zeppelin/environment'; +import { TicketService } from '@zeppelin/services'; + +@Injectable() +export class AppHttpInterceptor implements HttpInterceptor { + constructor(private ticketService: TicketService) {} + + // tslint:disable-next-line:no-any + intercept(httpRequest: HttpRequest, next: HttpHandler): Observable> { + let httpRequestUpdated = httpRequest.clone({ withCredentials: true }); + if (environment.production) { + httpRequestUpdated = httpRequest.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); + } + return next.handle(httpRequestUpdated).pipe( + map(event => { + if (event instanceof HttpResponse) { + return event.clone({ body: event.body.body }); + } else { + return event; + } + }), + catchError(event => { + const redirect = event.headers.get('Location'); + if (event.status === 401 && !isNil(redirect)) { + // Handle page redirect + window.location.href = redirect; + } else if (event.status === 405 && !event.url.contains('logout')) { + this.ticketService.logout().subscribe(); + } + return throwError(event); + }) + ); + } +} diff --git a/zeppelin-web-angular/src/app/app-message.interceptor.ts b/zeppelin-web-angular/src/app/app-message.interceptor.ts new file mode 100644 index 00000000000..02fdf962c6c --- /dev/null +++ b/zeppelin-web-angular/src/app/app-message.interceptor.ts @@ -0,0 +1,69 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +import { NzModalService } from 'ng-zorro-antd/modal'; +import { NzNotificationService } from 'ng-zorro-antd/notification'; + +import { MessageInterceptor } from '@zeppelin/interfaces'; +import { MessageReceiveDataTypeMap, OP, WebSocketMessage } from '@zeppelin/sdk'; +import { TicketService } from '@zeppelin/services'; + +@Injectable() +export class AppMessageInterceptor implements MessageInterceptor { + constructor( + private router: Router, + private nzNotificationService: NzNotificationService, + private ticketService: TicketService, + private nzModalService: NzModalService + ) {} + + received(data: WebSocketMessage): WebSocketMessage { + if (data.op === OP.NEW_NOTE) { + const rData = data.data as MessageReceiveDataTypeMap[OP.NEW_NOTE]; + this.router.navigate(['/notebook', rData.note.id]).then(); + } else if (data.op === OP.AUTH_INFO) { + const rData = data.data as MessageReceiveDataTypeMap[OP.AUTH_INFO]; + if (this.ticketService.ticket.roles === '[]') { + this.nzModalService.confirm({ + nzClosable: false, + nzMaskClosable: false, + nzTitle: 'Insufficient privileges', + nzContent: rData.info + }); + } else { + this.nzModalService.create({ + nzClosable: false, + nzMaskClosable: false, + nzTitle: 'Insufficient privileges', + nzContent: rData.info, + nzOkText: 'Login', + nzOnOk: () => { + this.router.navigate(['/login']).then(); + }, + nzOnCancel: () => { + this.router.navigate(['/']).then(); + } + }); + } + } else if (data.op === OP.ERROR_INFO) { + // tslint:disable-next-line:no-any + const rData = (data.data as any) as MessageReceiveDataTypeMap[OP.ERROR_INFO]; + if (rData.info) { + this.nzNotificationService.warning('ERROR', rData.info); + } + } + return data; + } +} diff --git a/zeppelin-web-angular/src/app/app-routing.module.ts b/zeppelin-web-angular/src/app/app-routing.module.ts new file mode 100644 index 00000000000..4a580cf9c8f --- /dev/null +++ b/zeppelin-web-angular/src/app/app-routing.module.ts @@ -0,0 +1,36 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + { + path: '', + loadChildren: () => import('./pages/workspace/workspace.module').then(m => m.WorkspaceModule) + }, + { + path: 'login', + loadChildren: () => import('./pages/login/login.module').then(m => m.LoginModule) + } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(routes, { + useHash: true, + preloadingStrategy: PreloadAllModules + }) + ], + exports: [RouterModule] +}) +export class AppRoutingModule {} diff --git a/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts b/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts new file mode 100644 index 00000000000..bde0d988f2f --- /dev/null +++ b/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts @@ -0,0 +1,41 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Compiler, + CompilerFactory, + CompilerOptions, + COMPILER_OPTIONS, + StaticProvider, + ViewEncapsulation +} from '@angular/core'; +import { JitCompilerFactory } from '@angular/platform-browser-dynamic'; + +const compilerOptions: CompilerOptions = { + useJit: true, + defaultEncapsulation: ViewEncapsulation.None +}; + +export function createCompiler(compilerFactory: CompilerFactory) { + return compilerFactory.createCompiler([compilerOptions]); +} + +export const RUNTIME_COMPILER_PROVIDERS: StaticProvider[] = [ + { provide: COMPILER_OPTIONS, useValue: compilerOptions, multi: true }, + { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] }, + { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] } +]; + +// TODO(hsuanxyz) +// buildOptimizer false +// import 'core-js/es7/reflect'; +// https://github.com/angular/angular/issues/27584#issuecomment-446462051 diff --git a/zeppelin-web-angular/src/app/app.component.html b/zeppelin-web-angular/src/app/app.component.html new file mode 100644 index 00000000000..d101c77150d --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.html @@ -0,0 +1,15 @@ + + + +Getting Ticket Data ... +Logging out ... diff --git a/zeppelin-web-angular/src/app/app.component.less b/zeppelin-web-angular/src/app/app.component.less new file mode 100644 index 00000000000..f9587c7330a --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.less @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .content { + background: @layout-body-background; + min-height: 100vh; + display: block; + position: relative; + + &.blur { + filter: blur(6px); + } + } +}); diff --git a/zeppelin-web-angular/src/app/app.component.spec.ts b/zeppelin-web-angular/src/app/app.component.spec.ts new file mode 100644 index 00000000000..3dfbc76cc22 --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.spec.ts @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + declarations: [AppComponent] + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); +}); diff --git a/zeppelin-web-angular/src/app/app.component.ts b/zeppelin-web-angular/src/app/app.component.ts new file mode 100644 index 00000000000..dc9fcb3afbb --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.ts @@ -0,0 +1,39 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { NavigationEnd, NavigationStart, Router } from '@angular/router'; +import { filter, map } from 'rxjs/operators'; + +import { TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.less'] +}) +export class AppComponent { + logout$ = this.ticketService.logout$; + loading$ = this.router.events.pipe( + filter(data => data instanceof NavigationEnd || data instanceof NavigationStart), + map(data => { + if (data instanceof NavigationStart) { + // load ticket when redirect to workspace + return data.url === '/'; + } else if (data instanceof NavigationEnd) { + return false; + } + }) + ); + + constructor(private router: Router, private ticketService: TicketService) {} +} diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts new file mode 100644 index 00000000000..5f651027048 --- /dev/null +++ b/zeppelin-web-angular/src/app/app.module.ts @@ -0,0 +1,90 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { registerLocaleData } from '@angular/common'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import en from '@angular/common/locales/en'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { Router, RouterModule } from '@angular/router'; + +import { ZeppelinHeliumModule } from '@zeppelin/helium'; +import { en_US, NZ_I18N } from 'ng-zorro-antd/i18n'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { NzNotificationService } from 'ng-zorro-antd/notification'; + +import { MESSAGE_INTERCEPTOR, TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { loadMonacoBefore } from '@zeppelin/languages'; +import { TicketService } from '@zeppelin/services'; +import { ShareModule } from '@zeppelin/share'; + +import { NZ_CODE_EDITOR_CONFIG } from '@zeppelin/share/code-editor'; +import { AppHttpInterceptor } from './app-http.interceptor'; +import { AppMessageInterceptor } from './app-message.interceptor'; +import { AppRoutingModule } from './app-routing.module'; +import { RUNTIME_COMPILER_PROVIDERS } from './app-runtime-compiler.providers'; +import { AppComponent } from './app.component'; + +export const loadMonaco = () => { + loadMonacoBefore(); +}; + +registerLocaleData(en); + +@NgModule({ + declarations: [AppComponent], + imports: [ + BrowserModule, + FormsModule, + HttpClientModule, + BrowserAnimationsModule, + ShareModule, + AppRoutingModule, + RouterModule, + ZeppelinHeliumModule + ], + providers: [ + ...RUNTIME_COMPILER_PROVIDERS, + { + provide: NZ_I18N, + useValue: en_US + }, + { + provide: HTTP_INTERCEPTORS, + useClass: AppHttpInterceptor, + multi: true, + deps: [TicketService] + }, + { + provide: NZ_CODE_EDITOR_CONFIG, + useValue: { + defaultEditorOption: { + scrollBeyondLastLine: false + }, + onLoad: loadMonaco + } + }, + { + provide: MESSAGE_INTERCEPTOR, + useClass: AppMessageInterceptor, + deps: [Router, NzNotificationService, TicketService, NzModalService] + }, + { + provide: TRASH_FOLDER_ID_TOKEN, + useValue: '~Trash' + } + ], + bootstrap: [AppComponent] +}) +export class AppModule {} diff --git a/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts b/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts new file mode 100644 index 00000000000..fb1e6208e78 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts @@ -0,0 +1,65 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function copyTextToClipboard(text: string): void { + const textArea: HTMLTextAreaElement = document.createElement('textarea'); + + // + // *** This styling is an extra step which is likely not required. *** + // + // Why is it here? To ensure: + // 1. the element is able to have focus and selection. + // 2. if element was to flash render it has minimal visual impact. + // 3. less flakyness with selection and copying which **might** occur if + // the textarea element is not visible. + // + // The likelihood is the element won't even render, not even a flash, + // so some of these are just precautions. However in IE the element + // is visible whilst the popup box asking the user for permission for + // the web page to copy to the clipboard. + // + + // Place in top-left corner of screen regardless of scroll position. + textArea.style.position = 'fixed'; + textArea.style.top = '0'; + textArea.style.left = '0'; + + // Ensure it has a small width and height. Setting to 1px / 1em + // doesn't work as this gives a negative w/h on some browsers. + textArea.style.width = '2em'; + textArea.style.height = '2em'; + + // We don't need padding, reducing the size if it does flash render. + textArea.style.padding = '0'; + + // Clean up any borders. + textArea.style.border = 'none'; + textArea.style.outline = 'none'; + textArea.style.boxShadow = 'none'; + + // Avoid flash of white box if rendered for any reason. + textArea.style.background = 'transparent'; + + textArea.value = text; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + } catch (err) { + window.prompt('Copy to clipboard: Ctrl+C, Enter', text); + } + + document.body.removeChild(textArea); +} diff --git a/zeppelin-web-angular/src/app/core/copy-text/index.ts b/zeppelin-web-angular/src/app/core/copy-text/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/copy-text/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/copy-text/public-api.ts b/zeppelin-web-angular/src/app/core/copy-text/public-api.ts new file mode 100644 index 00000000000..aa47aad6726 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/copy-text/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './copy-text-to-clipboard'; diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts new file mode 100644 index 00000000000..7f394c0c4c9 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +export class DestroyHookComponent implements OnDestroy { + readonly destroy$ = new Subject(); + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/index.ts b/zeppelin-web-angular/src/app/core/destroy-hook/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/destroy-hook/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts b/zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts new file mode 100644 index 00000000000..c4b93aa16d8 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './destroy-hook.component'; diff --git a/zeppelin-web-angular/src/app/core/index.ts b/zeppelin-web-angular/src/app/core/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/message-listener/index.ts b/zeppelin-web-angular/src/app/core/message-listener/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/message-listener/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts new file mode 100644 index 00000000000..5c29be8aaa0 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts @@ -0,0 +1,59 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OnDestroy } from '@angular/core'; +import { Subscriber } from 'rxjs'; + +import { MessageReceiveDataTypeMap, ReceiveArgumentsType } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services'; + +export class MessageListenersManager implements OnDestroy { + __zeppelinMessageListeners__: Array<() => void>; + __zeppelinMessageListeners$__ = new Subscriber(); + constructor(public messageService: MessageService) { + if (this.__zeppelinMessageListeners__) { + this.__zeppelinMessageListeners__.forEach(fn => fn.apply(this)); + } + } + + ngOnDestroy(): void { + this.__zeppelinMessageListeners$__.unsubscribe(); + this.__zeppelinMessageListeners$__ = null; + } +} + +export function MessageListener(op: K) { + return function( + target: MessageListenersManager, + propertyKey: string, + descriptor: TypedPropertyDescriptor> + ) { + const oldValue = descriptor.value as ReceiveArgumentsType; + + const fn = function() { + // tslint:disable:no-invalid-this + this.__zeppelinMessageListeners$__.add( + this.messageService.receive(op).subscribe(data => { + oldValue.apply(this, [data]); + }) + ); + }; + + if (!target.__zeppelinMessageListeners__) { + target.__zeppelinMessageListeners__ = [fn]; + } else { + target.__zeppelinMessageListeners__.push(fn); + } + + return descriptor; + }; +} diff --git a/zeppelin-web-angular/src/app/core/message-listener/public-api.ts b/zeppelin-web-angular/src/app/core/message-listener/public-api.ts new file mode 100644 index 00000000000..61a92db9183 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/message-listener/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './message-listener'; diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/index.ts b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts new file mode 100644 index 00000000000..f8f9a1be7b2 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts @@ -0,0 +1,315 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectorRef, QueryList } from '@angular/core'; + +import { + AngularObjectRemove, + AngularObjectUpdate, + GraphConfig, + MessageReceiveDataTypeMap, + OP, + ParagraphConfig, + ParagraphEditorSetting, + ParagraphItem, + ParagraphIResultsMsgItem +} from '@zeppelin/sdk'; + +import { MessageService } from '@zeppelin/services/message.service'; +import { NgZService } from '@zeppelin/services/ng-z.service'; +import { NoteStatusService, ParagraphStatus } from '@zeppelin/services/note-status.service'; + +import DiffMatchPatch from 'diff-match-patch'; +import { isEmpty, isEqual } from 'lodash'; + +import { NotebookParagraphResultComponent } from '@zeppelin/pages/workspace/share/result/result.component'; +import { MessageListener, MessageListenersManager } from '../message-listener/message-listener'; + +export abstract class ParagraphBase extends MessageListenersManager { + paragraph: ParagraphItem; + dirtyText: string; + originalText: string; + isEntireNoteRunning = false; + revisionView = false; + diffMatchPatch = new DiffMatchPatch(); + isParagraphRunning = false; + results = []; + configs = {}; + progress = 0; + colWidthOption = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + editorSetting: ParagraphEditorSetting = {}; + + notebookParagraphResultComponents: QueryList; + + constructor( + public messageService: MessageService, + protected noteStatusService: NoteStatusService, + protected ngZService: NgZService, + protected cdr: ChangeDetectorRef + ) { + super(messageService); + } + + abstract changeColWidth(needCommit: boolean, updateResult?: boolean): void; + + @MessageListener(OP.PROGRESS) + onProgress(data: MessageReceiveDataTypeMap[OP.PROGRESS]) { + if (data.id === this.paragraph.id) { + this.progress = data.progress; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.NOTE_RUNNING_STATUS) + noteRunningStatusChange(data: MessageReceiveDataTypeMap[OP.NOTE_RUNNING_STATUS]) { + this.isEntireNoteRunning = data.status; + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAS_INFO) + updateParaInfos(data: MessageReceiveDataTypeMap[OP.PARAS_INFO]) { + if (this.paragraph.id === data.id) { + this.paragraph.runtimeInfos = data.infos; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.EDITOR_SETTING) + getEditorSetting(data: MessageReceiveDataTypeMap[OP.EDITOR_SETTING]) { + if (this.paragraph.id === data.paragraphId) { + this.paragraph.config.editorSetting = { ...this.paragraph.config.editorSetting, ...data.editor }; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.PARAGRAPH) + paragraphData(data: MessageReceiveDataTypeMap[OP.PARAGRAPH]) { + const oldPara = this.paragraph; + const newPara = data.paragraph; + if (this.isUpdateRequired(oldPara, newPara)) { + this.updateParagraph(oldPara, newPara, () => { + if (newPara.results && newPara.results.msg) { + // tslint:disable-next-line:no-for-in-array + for (const i in newPara.results.msg) { + if (newPara.results.msg[i]) { + const newResult = newPara.results.msg ? newPara.results.msg[i] : new ParagraphIResultsMsgItem(); + const oldResult = + oldPara.results && oldPara.results.msg ? oldPara.results.msg[i] : new ParagraphIResultsMsgItem(); + const newConfig = newPara.config.results ? newPara.config.results[i] : { graph: new GraphConfig() }; + const oldConfig = oldPara.config.results ? oldPara.config.results[i] : { graph: new GraphConfig() }; + if (!isEqual(newResult, oldResult) || !isEqual(newConfig, oldConfig)) { + const resultComponent = this.notebookParagraphResultComponents.toArray()[i]; + if (resultComponent) { + resultComponent.updateResult(newConfig, newResult); + } + } + } + } + } + this.cdr.markForCheck(); + }); + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.PATCH_PARAGRAPH) + patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) { + if (data.paragraphId === this.paragraph.id) { + let patch = data.patch; + patch = this.diffMatchPatch.patch_fromText(patch); + if (!this.paragraph.text) { + this.paragraph.text = ''; + } + this.paragraph.text = this.diffMatchPatch.patch_apply(patch, this.paragraph.text)[0]; + this.originalText = this.paragraph.text; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.ANGULAR_OBJECT_UPDATE) + angularObjectUpdate(data: AngularObjectUpdate) { + if (data.paragraphId === this.paragraph.id) { + const { name, object } = data.angularObject; + this.ngZService.setContextValue(name, object, data.paragraphId, false); + } + } + + @MessageListener(OP.ANGULAR_OBJECT_REMOVE) + angularObjectRemove(data: AngularObjectRemove) { + if (data.paragraphId === this.paragraph.id) { + this.ngZService.unsetContextValue(data.name, data.paragraphId, false); + } + } + + updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) { + // 1. can't update on revision view + if (!this.revisionView) { + // 2. get status, refreshed + const statusChanged = newPara.status !== oldPara.status; + const resultRefreshed = + newPara.dateFinished !== oldPara.dateFinished || + isEmpty(newPara.results) !== isEmpty(oldPara.results) || + newPara.status === ParagraphStatus.ERROR || + (newPara.status === ParagraphStatus.FINISHED && statusChanged); + + // 3. update texts managed by paragraph + this.updateAllScopeTexts(oldPara, newPara); + // 4. execute callback to update result + updateCallback(); + + // 5. update remaining paragraph objects + this.updateParagraphObjectWhenUpdated(newPara); + + // 6. handle scroll down by key properly if new paragraph is added + if (statusChanged || resultRefreshed) { + // when last paragraph runs, zeppelin automatically appends new paragraph. + // this broadcast will focus to the newly inserted paragraph + // TODO(hsuanxyz) + } + this.cdr.markForCheck(); + } + } + + isUpdateRequired(oldPara: ParagraphItem, newPara: ParagraphItem): boolean { + return ( + newPara.id === oldPara.id && + (newPara.dateCreated !== oldPara.dateCreated || + newPara.text !== oldPara.text || + newPara.dateFinished !== oldPara.dateFinished || + newPara.dateStarted !== oldPara.dateStarted || + newPara.dateUpdated !== oldPara.dateUpdated || + newPara.status !== oldPara.status || + newPara.jobName !== oldPara.jobName || + newPara.title !== oldPara.title || + isEmpty(newPara.results) !== isEmpty(oldPara.results) || + newPara.errorMessage !== oldPara.errorMessage || + !isEqual(newPara.settings, oldPara.settings) || + !isEqual(newPara.config, oldPara.config) || + !isEqual(newPara.runtimeInfos, oldPara.runtimeInfos)) + ); + } + + updateAllScopeTexts(oldPara: ParagraphItem, newPara: ParagraphItem) { + if (oldPara.text !== newPara.text) { + if (this.dirtyText) { + // check if editor has local update + if (this.dirtyText === newPara.text) { + // when local update is the same from remote, clear local update + this.paragraph.text = newPara.text; + this.dirtyText = undefined; + this.originalText = newPara.text; + } else { + // if there're local update, keep it. + this.paragraph.text = newPara.text; + } + } else { + this.paragraph.text = newPara.text; + this.originalText = newPara.text; + } + } + this.cdr.markForCheck(); + } + + updateParagraphObjectWhenUpdated(newPara: ParagraphItem) { + if (this.paragraph.config.colWidth !== newPara.config.colWidth) { + this.changeColWidth(false); + } + this.paragraph.aborted = newPara.aborted; + this.paragraph.user = newPara.user; + this.paragraph.dateUpdated = newPara.dateUpdated; + this.paragraph.dateCreated = newPara.dateCreated; + this.paragraph.dateFinished = newPara.dateFinished; + this.paragraph.dateStarted = newPara.dateStarted; + this.paragraph.errorMessage = newPara.errorMessage; + this.paragraph.jobName = newPara.jobName; + this.paragraph.title = newPara.title; + this.paragraph.lineNumbers = newPara.lineNumbers; + this.paragraph.status = newPara.status; + this.paragraph.fontSize = newPara.fontSize; + if (newPara.status !== ParagraphStatus.RUNNING) { + this.paragraph.results = newPara.results; + } + this.paragraph.settings = newPara.settings; + this.paragraph.runtimeInfos = newPara.runtimeInfos; + this.isParagraphRunning = this.noteStatusService.isParagraphRunning(newPara); + this.paragraph.config = newPara.config; + this.initializeDefault(this.paragraph.config); + this.setResults(); + this.cdr.markForCheck(); + } + + setResults() { + if (this.paragraph.results) { + this.results = this.paragraph.results.msg; + this.configs = this.paragraph.config.results; + } + if (!this.paragraph.config) { + this.paragraph.config = {}; + } + } + + initializeDefault(config: ParagraphConfig) { + const forms = this.paragraph.settings.forms; + + if (!config.colWidth) { + config.colWidth = 12; + } + + if (!config.fontSize) { + config.fontSize = 9; + } + + if (config.enabled === undefined) { + config.enabled = true; + } + + for (const idx in forms) { + if (forms[idx]) { + if (forms[idx].options) { + if (config.runOnSelectionChange === undefined) { + config.runOnSelectionChange = true; + } + } + } + } + + if (!config.results) { + config.results = {}; + } + + if (!config.editorSetting) { + config.editorSetting = {}; + } else if (config.editorSetting.editOnDblClick) { + this.editorSetting.isOutputHidden = config.editorSetting.editOnDblClick; + } + } + + runParagraphUsingSpell(paragraphText: string, magic: string, propagated: boolean) { + // TODO(hsuanxyz) + } + + runParagraphUsingBackendInterpreter(paragraphText: string) { + this.messageService.runParagraph( + this.paragraph.id, + this.paragraph.title, + paragraphText, + this.paragraph.config, + this.paragraph.settings.params + ); + } + + cancelParagraph() { + if (!this.isEntireNoteRunning) { + this.messageService.cancelParagraph(this.paragraph.id); + } + } +} diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts new file mode 100644 index 00000000000..a6ba53216ed --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts @@ -0,0 +1,14 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './paragraph-base'; +export * from './published'; diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/published.ts b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts new file mode 100644 index 00000000000..0f415779679 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const publishedSymbol = Symbol('published'); + +export interface Published { + readonly [publishedSymbol]: true; +} diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/public-api.ts new file mode 100644 index 00000000000..3f334c803b8 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/public-api.ts @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './message-listener'; +export * from './destroy-hook'; +export * from './copy-text'; +export * from './paragraph-base'; +export * from './runtime-dynamic-module'; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts new file mode 100644 index 00000000000..42c2d11e210 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts @@ -0,0 +1,148 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; + +import { NzAffixModule } from 'ng-zorro-antd/affix'; +import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzAnchorModule } from 'ng-zorro-antd/anchor'; +import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; +import { NzAvatarModule } from 'ng-zorro-antd/avatar'; +import { NzBackTopModule } from 'ng-zorro-antd/back-top'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCalendarModule } from 'ng-zorro-antd/calendar'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzCarouselModule } from 'ng-zorro-antd/carousel'; +import { NzCascaderModule } from 'ng-zorro-antd/cascader'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzCollapseModule } from 'ng-zorro-antd/collapse'; +import { NzCommentModule } from 'ng-zorro-antd/comment'; +import { NzNoAnimationModule, NzTransButtonModule, NzWaveModule } from 'ng-zorro-antd/core'; +import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; +import { NzDescriptionsModule } from 'ng-zorro-antd/descriptions'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDrawerModule } from 'ng-zorro-antd/drawer'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzEmptyModule } from 'ng-zorro-antd/empty'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzI18nModule } from 'ng-zorro-antd/i18n'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzInputNumberModule } from 'ng-zorro-antd/input-number'; +import { NzLayoutModule } from 'ng-zorro-antd/layout'; +import { NzListModule } from 'ng-zorro-antd/list'; +import { NzMentionModule } from 'ng-zorro-antd/mention'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzNotificationModule } from 'ng-zorro-antd/notification'; +import { NzPageHeaderModule } from 'ng-zorro-antd/page-header'; +import { NzPaginationModule } from 'ng-zorro-antd/pagination'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzPopoverModule } from 'ng-zorro-antd/popover'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzRateModule } from 'ng-zorro-antd/rate'; +import { NzResultModule } from 'ng-zorro-antd/result'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; +import { NzSliderModule } from 'ng-zorro-antd/slider'; +import { NzSpinModule } from 'ng-zorro-antd/spin'; +import { NzStatisticModule } from 'ng-zorro-antd/statistic'; +import { NzStepsModule } from 'ng-zorro-antd/steps'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzTabsModule } from 'ng-zorro-antd/tabs'; +import { NzTagModule } from 'ng-zorro-antd/tag'; +import { NzTimePickerModule } from 'ng-zorro-antd/time-picker'; +import { NzTimelineModule } from 'ng-zorro-antd/timeline'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTransferModule } from 'ng-zorro-antd/transfer'; +import { NzTreeModule } from 'ng-zorro-antd/tree'; +import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select'; +import { NzTypographyModule } from 'ng-zorro-antd/typography'; +import { NzUploadModule } from 'ng-zorro-antd/upload'; + +@NgModule({ + exports: [ + NzAffixModule, + NzAlertModule, + NzAnchorModule, + NzAutocompleteModule, + NzAvatarModule, + NzBackTopModule, + NzBadgeModule, + NzButtonModule, + NzBreadCrumbModule, + NzCalendarModule, + NzCardModule, + NzCarouselModule, + NzCascaderModule, + NzCheckboxModule, + NzCollapseModule, + NzCommentModule, + NzDatePickerModule, + NzDescriptionsModule, + NzDividerModule, + NzDrawerModule, + NzDropDownModule, + NzEmptyModule, + NzFormModule, + NzGridModule, + NzI18nModule, + NzIconModule, + NzInputModule, + NzInputNumberModule, + NzLayoutModule, + NzListModule, + NzMentionModule, + NzMenuModule, + NzMessageModule, + NzModalModule, + NzNoAnimationModule, + NzNotificationModule, + NzPageHeaderModule, + NzPaginationModule, + NzPopconfirmModule, + NzPopoverModule, + NzProgressModule, + NzRadioModule, + NzRateModule, + NzResultModule, + NzSelectModule, + NzSkeletonModule, + NzSliderModule, + NzSpinModule, + NzStatisticModule, + NzStepsModule, + NzSwitchModule, + NzTableModule, + NzTabsModule, + NzTagModule, + NzTimePickerModule, + NzTimelineModule, + NzToolTipModule, + NzTransButtonModule, + NzTransferModule, + NzTreeModule, + NzTreeSelectModule, + NzTypographyModule, + NzUploadModule, + NzWaveModule + ] +}) +export class NzModule { + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts new file mode 100644 index 00000000000..a8a0702b5a0 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './runtime-dynamic-module.module'; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts new file mode 100644 index 00000000000..27d08f94a81 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { NzModule } from './ng-zorro-antd-module'; + +@NgModule({ + declarations: [], + exports: [CommonModule, FormsModule, NzModule] +}) +export class RuntimeDynamicModuleModule {} diff --git a/zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts b/zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts new file mode 100644 index 00000000000..940a29249fc --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts @@ -0,0 +1,27 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Compiler, CompilerFactory, COMPILER_OPTIONS, NgModule } from '@angular/core'; +import { JitCompilerFactory } from '@angular/platform-browser-dynamic'; + +export function createCompiler(compilerFactory: CompilerFactory) { + return compilerFactory.createCompiler(); +} + +@NgModule({ + providers: [ + { provide: COMPILER_OPTIONS, useValue: {}, multi: true }, + { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] }, + { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] } + ] +}) +export class HeliumManagerModule {} diff --git a/zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts b/zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts new file mode 100644 index 00000000000..1a1a03c55c3 --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts @@ -0,0 +1,75 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Compiler, Injectable, Injector, NgModuleFactory, OnDestroy, Type } from '@angular/core'; +import { ZeppelinHeliumPackage, ZeppelinHeliumService } from '@zeppelin/helium'; +import { of, BehaviorSubject } from 'rxjs'; +import { HeliumManagerModule } from './helium-manager.module'; + +export interface CompiledPackage { + // tslint:disable-next-line:no-any + moduleFactory: NgModuleFactory; + // tslint:disable-next-line:no-any + component: Type; + injector?: Injector; + name: string; + _raw: ZeppelinHeliumPackage; +} + +@Injectable({ + providedIn: HeliumManagerModule +}) +export class HeliumManagerService implements OnDestroy { + private packages$ = new BehaviorSubject([]); + + constructor(private zeppelinHeliumService: ZeppelinHeliumService, private compiler: Compiler) {} + + initPackages() { + this.getEnabledPackages().subscribe(packages => { + packages.forEach(name => { + this.zeppelinHeliumService.loadPackage(name).then(heliumPackage => { + const loaded = this.packages$.value; + if (!loaded.find(p => p.name === heliumPackage.name)) { + this.compilePackage(heliumPackage); + } + }); + }); + }); + } + + getEnabledPackages() { + // return of(['helium-vis-example']); + return of([]); + } + + packagesLoadChange() { + return this.packages$.asObservable(); + } + + compilePackage(pack: ZeppelinHeliumPackage) { + this.compiler.compileModuleAsync(pack.module).then(moduleFactory => { + this.packages$.next([ + ...this.packages$.value, + { + moduleFactory, + name: pack.name, + component: pack.component, + _raw: pack + } + ]); + }); + } + + ngOnDestroy(): void { + this.packages$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/helium-manager/index.ts b/zeppelin-web-angular/src/app/helium-manager/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/helium-manager/public-api.ts b/zeppelin-web-angular/src/app/helium-manager/public-api.ts new file mode 100644 index 00000000000..8ba1a21026a --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/public-api.ts @@ -0,0 +1,14 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './helium-manager.service'; +export * from './helium-manager.module'; diff --git a/zeppelin-web-angular/src/app/interfaces/credential.ts b/zeppelin-web-angular/src/app/interfaces/credential.ts new file mode 100644 index 00000000000..533b1206819 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/credential.ts @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Credential { + userCredentials: { + [key: string]: CredentialItem; + }; +} + +export interface CredentialItem { + username: string; + password: string; +} + +export interface CredentialForm { + entity: string; + password: string; + username: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/index.ts b/zeppelin-web-angular/src/app/interfaces/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/interfaces/interpreter.ts b/zeppelin-web-angular/src/app/interfaces/interpreter.ts new file mode 100644 index 00000000000..2e1d661d678 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/interpreter.ts @@ -0,0 +1,104 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type InterpreterPropertyTypes = 'textarea' | 'string' | 'number' | 'url' | 'password' | 'checkbox'; + +export interface Interpreter { + id: string; + name: string; + group: string; + properties: Properties; + status: string; + errorReason?: string; + interpreterGroup: InterpreterGroupItem[]; + dependencies: DependenciesItem[]; + option: Option; +} + +export interface InterpreterMap { + [key: string]: Interpreter; +} + +export interface CreateInterpreterRepositoryForm { + id: string; + url: string; + snapshot: boolean; + username: string; + password: string; + proxyProtocol: string; + proxyHost: string; + proxyPort: string; + proxyLogin: string; + proxyPassword: string; +} + +export interface InterpreterRepository { + id: string; + type: string; + url: string; + releasePolicy: ReleasePolicy; + snapshotPolicy: SnapshotPolicy; + // tslint:disable-next-line + mirroredRepositories: any[]; + repositoryManager: boolean; +} +interface ReleasePolicy { + enabled: boolean; + updatePolicy: string; + checksumPolicy: string; +} +interface SnapshotPolicy { + enabled: boolean; + updatePolicy: string; + checksumPolicy: string; +} + +interface Properties { + [key: string]: { + name: string; + value: boolean; + type: string; + defaultValue?: string; + description?: string; + }; +} + +interface InterpreterGroupItem { + name: string; + class: string; + defaultInterpreter: boolean; + editor: Editor; +} +interface Editor { + language: string; + editOnDblClick: boolean; + completionKey?: string; + completionSupport?: boolean; +} + +interface DependenciesItem { + groupArtifactVersion: string; + local: boolean; + exclusions: string[]; +} + +interface Option { + remote: boolean; + port: number; + isExistingProcess: boolean; + setPermission: boolean; + // tslint:disable-next-line:no-any + owners: any[]; + isUserImpersonate: boolean; + perNote?: string; + perUser?: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/message-interceptor.ts b/zeppelin-web-angular/src/app/interfaces/message-interceptor.ts new file mode 100644 index 00000000000..85618dfa44a --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/message-interceptor.ts @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InjectionToken } from '@angular/core'; +import { MessageReceiveDataTypeMap, WebSocketMessage } from '@zeppelin/sdk'; + +export interface MessageInterceptor { + received(data: WebSocketMessage): WebSocketMessage; +} + +export const MESSAGE_INTERCEPTOR = new InjectionToken('MESSAGE_INTERCEPTOR'); diff --git a/zeppelin-web-angular/src/app/interfaces/node-list.ts b/zeppelin-web-angular/src/app/interfaces/node-list.ts new file mode 100644 index 00000000000..55331a9e740 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/node-list.ts @@ -0,0 +1,42 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface NodeList { + root: RootNode; + flatList: FlatListNodeItem[]; + flatFolderMap: FlatFolderNodeMap; +} + +export interface RootNode { + children: NodeItem[]; +} + +export interface NodeItem { + id: string; + title: string; + isLeaf?: boolean; + expanded?: boolean; + children?: NodeItem[]; + isTrash: boolean; + nodeType?: string; + path?: string; +} + +interface FlatListNodeItem { + id: string; + path: string; + isTrash: boolean; +} + +interface FlatFolderNodeMap { + [title: string]: NodeItem; +} diff --git a/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts b/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts new file mode 100644 index 00000000000..de037783ca7 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface NotebookRepo { + name: string; + className: string; + settings: NotebookRepoSettingsItem[]; +} + +export interface NotebookRepoPutData { + name: string; + settings: { + [key: string]: string; + }; +} + +export interface NotebookRepoSettingsItem { + type: string; + // tslint:disable-next-line:no-any + value: any[]; + selected: string; + name: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/notebook-search.ts b/zeppelin-web-angular/src/app/interfaces/notebook-search.ts new file mode 100644 index 00000000000..267ee943a59 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/notebook-search.ts @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface NotebookSearchResultItem { + id: string; + name: string; + snippet: string; + text: string; + header: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts new file mode 100644 index 00000000000..e762a5c3667 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './ticket'; +export * from './trash-folder-id'; +export * from './interpreter'; +export * from './message-interceptor'; +export * from './security'; +export * from './credential'; +export * from './notebook-repo'; +export * from './notebook-search'; diff --git a/zeppelin-web-angular/src/app/interfaces/security.ts b/zeppelin-web-angular/src/app/interfaces/security.ts new file mode 100644 index 00000000000..ff7db2a97d2 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/security.ts @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface SecurityUserList { + roles: string[]; + users: string[]; +} + +export interface Permissions { + readers: string[]; + owners: string[]; + writers: string[]; + runners: string[]; +} diff --git a/zeppelin-web-angular/src/app/interfaces/ticket.ts b/zeppelin-web-angular/src/app/interfaces/ticket.ts new file mode 100644 index 00000000000..0f4883e0d2b --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/ticket.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class ITicket { + principal = ''; + ticket = ''; + redirectURL = ''; + roles = ''; +} + +export class IZeppelinVersion { + 'git-commit-id': string; + 'git-timestamp': string; + 'version': string; +} + +export class ITicketWrapped extends ITicket { + init = false; + screenUsername = ''; +} diff --git a/zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts b/zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts new file mode 100644 index 00000000000..035b92a1789 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InjectionToken } from '@angular/core'; + +export const TRASH_FOLDER_ID_TOKEN = new InjectionToken('TRASH_FOLDER_ID'); diff --git a/zeppelin-web-angular/src/app/languages/index.ts b/zeppelin-web-angular/src/app/languages/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/languages/load.ts b/zeppelin-web-angular/src/app/languages/load.ts new file mode 100644 index 00000000000..64c617acd6e --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/load.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { editor, languages } from 'monaco-editor'; +import { conf as ScalaConf, language as ScalaLanguage } from './scala'; + +export const loadMonacoBefore = () => { + editor.defineTheme('zeppelin-theme', { + base: 'vs', + inherit: true, + rules: [], + colors: { + 'editor.lineHighlightBackground': '#0000FF10' + } + }); + editor.setTheme('zeppelin-theme'); + languages.register({ id: 'scala' }); + languages.setMonarchTokensProvider('scala', ScalaLanguage); + languages.setLanguageConfiguration('scala', ScalaConf); +}; diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts b/zeppelin-web-angular/src/app/languages/public-api.ts new file mode 100644 index 00000000000..973c93158ba --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/public-api.ts @@ -0,0 +1,14 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './scala'; +export * from './load'; diff --git a/zeppelin-web-angular/src/app/languages/scala.ts b/zeppelin-web-angular/src/app/languages/scala.ts new file mode 100644 index 00000000000..581049129e0 --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/scala.ts @@ -0,0 +1,236 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; +import ILanguage = monaco.languages.IMonarchLanguage; + +export const conf: IRichLanguageConfiguration = { + // the default separators except `@$` + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'] + }, + brackets: [['{', '}'], ['[', ']'], ['(', ')']], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" } + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '<', close: '>' } + ] +}; + +export const language = { + defaultToken: '', + tokenPostfix: '.scala', + + keywords: [ + // From https://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html + 'abstract', + 'case', + 'catch', + 'class', + 'def', + 'do', + 'else', + 'extends', + 'false', + 'final', + 'finally', + 'for', + 'forSome', + 'if', + 'implicit', + 'import', + 'lazy', + 'macro', + 'match', + 'new', + 'null', + 'object', + 'override', + 'package', + 'private', + 'protected', + 'return', + 'sealed', + 'super', + 'this', + 'throw', + 'trait', + 'try', + 'true', + 'type', + 'val', + 'var', + 'while', + 'with', + 'yield' + ], + + operators: [ + '_', + ':', + '=', + '=>', + '<-', + '<:', + '<%', + '>:', + '#', + '@', + + // Copied from java.ts, to be validated + '=', + '>', + '<', + '!', + '~', + '?', + ':', + '==', + '<=', + '>=', + '!=', + '&&', + '||', + '++', + '--', + '+', + '-', + '*', + '/', + '&', + '|', + '^', + '%', + '<<', + '>>', + '>>>', + '+=', + '-=', + '*=', + '/=', + '&=', + '|=', + '^=', + '%=', + '<<=', + '>>=', + '>>>=' + ], + + // we include these common regular expressions + symbols: /[=>](?!@symbols)/, '@brackets'], + [ + /@symbols/, + { + cases: { + '@operators': 'delimiter', + '@default': '' + } + } + ], + + // @ annotations. + [/@\s*[a-zA-Z_\$][\w\$]*/, 'annotation'], + + // numbers + [/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/, 'number.float'], + [/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/, 'number.float'], + [/0[xX](@hexdigits)[Ll]?/, 'number.hex'], + [/0(@octaldigits)[Ll]?/, 'number.octal'], + [/0[bB](@binarydigits)[Ll]?/, 'number.binary'], + [/(@digits)[fFdD]/, 'number.float'], + [/(@digits)[lL]?/, 'number'], + + // delimiter: after number because of .\d floats + [/[;,.]/, 'delimiter'], + + // strings + [/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string + [/"/, 'string', '@string'], + + // characters + [/'[^\\']'/, 'string'], + [/(')(@escapes)(')/, ['string', 'string.escape', 'string']], + [/'/, 'string.invalid'] + ], + + whitespace: [ + [/[ \t\r\n]+/, ''], + [/\/\*\*(?!\/)/, 'comment.doc', '@scaladoc'], + [/\/\*/, 'comment', '@comment'], + [/\/\/.*$/, 'comment'] + ], + + comment: [ + [/[^\/*]+/, 'comment'], + // [/\/\*/, 'comment', '@push' ], // nested comment not allowed :-( + // [/\/\*/, 'comment.invalid' ], // this breaks block comments in the shape of /* //*/ + [/\*\//, 'comment', '@pop'], + [/[\/*]/, 'comment'] + ], + // Identical copy of comment above, except for the addition of .doc + scaladoc: [ + [/[^\/*]+/, 'comment.doc'], + // [/\/\*/, 'comment.doc', '@push' ], // nested comment not allowed :-( + [/\/\*/, 'comment.doc.invalid'], + [/\*\//, 'comment.doc', '@pop'], + [/[\/*]/, 'comment.doc'] + ], + + string: [ + [/[^\\"]+/, 'string'], + [/@escapes/, 'string.escape'], + [/\\./, 'string.escape.invalid'], + [/"/, 'string', '@pop'] + ] + } +} as ILanguage; diff --git a/zeppelin-web-angular/src/app/pages/login/login-routing.module.ts b/zeppelin-web-angular/src/app/pages/login/login-routing.module.ts new file mode 100644 index 00000000000..06dd0304db8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login-routing.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { LoginComponent } from './login.component'; + +const routes: Routes = [ + { + path: '', + component: LoginComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class LoginRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.html b/zeppelin-web-angular/src/app/pages/login/login.component.html new file mode 100644 index 00000000000..faa16b67189 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.component.html @@ -0,0 +1,46 @@ + + +
    +
    +
    +
    + + User Name + + + + + + + + Password + + + + + + + + + + + +
    +
    + +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.less b/zeppelin-web-angular/src/app/pages/login/login.component.less new file mode 100644 index 00000000000..7aac210300d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.component.less @@ -0,0 +1,69 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .content { + height: 100vh; + width: 100vw; + + &:after { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url("../../../assets/images/bg.jpg"); + background-size: cover; + filter: blur(4px); + background-repeat: no-repeat; + background-position: center; + } + + .inner { + width: 800px; + height: 300px; + position: absolute; + z-index: 1; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + box-shadow: @box-shadow-base; + + .form { + width: 500px; + position: absolute; + left: 0; + height: 100%; + background: @component-background; + padding: 36px; + } + + .sidebar { + width: 300px; + position: absolute; + right: 0; + height: 100%; + background: @primary-color; + padding: 24px 36px; + color: @text-color-dark; + + h1 { + color: @heading-color-dark; + } + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.ts b/zeppelin-web-angular/src/app/pages/login/login.component.ts new file mode 100644 index 00000000000..937724974b6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.component.ts @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LoginComponent implements OnInit { + userName: string; + password: string; + loading = false; + + login() { + this.loading = true; + this.ticketService.login(this.userName, this.password).subscribe( + () => { + this.loading = false; + this.cdr.markForCheck(); + this.router.navigate(['/']).then(); + }, + () => { + this.loading = false; + this.cdr.markForCheck(); + } + ); + } + + constructor(private ticketService: TicketService, private cdr: ChangeDetectorRef, private router: Router) {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/login/login.module.ts b/zeppelin-web-angular/src/app/pages/login/login.module.ts new file mode 100644 index 00000000000..7a040a69364 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; + +import { LoginRoutingModule } from './login-routing.module'; +import { LoginComponent } from './login.component'; + +@NgModule({ + declarations: [LoginComponent], + imports: [CommonModule, LoginRoutingModule, FormsModule, NzFormModule, NzInputModule, NzButtonModule, NzIconModule] +}) +export class LoginModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts new file mode 100644 index 00000000000..6d499a0c7bc --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts @@ -0,0 +1,27 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ConfigurationComponent } from './configuration.component'; + +const routes: Routes = [ + { + path: '', + component: ConfigurationComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ConfigurationRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html new file mode 100644 index 00000000000..6708f345203 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html @@ -0,0 +1,37 @@ + + + + + Shows current configurations for Zeppelin Server. +
    + Note: For security reasons, some key/value pairs including passwords would not be shown. +
    +
    + + + + Name + Value + + + + + {{data[0]}} + {{data[1]}} + + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less new file mode 100644 index 00000000000..b3c4ee24e55 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less @@ -0,0 +1,22 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .content { + padding: @card-padding-base / 2; + nz-table { + background: @card-background; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts new file mode 100644 index 00000000000..fb3b1205743 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts @@ -0,0 +1,36 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { ConfigurationService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-configuration', + templateUrl: './configuration.component.html', + styleUrls: ['./configuration.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ConfigurationComponent implements OnInit { + configEntries: Array<[string, string]> = []; + + constructor(private configurationService: ConfigurationService, private cdr: ChangeDetectorRef) {} + + ngOnInit() { + this.getAllConfig(); + } + + getAllConfig(): void { + this.configurationService.getAll().subscribe(data => { + this.configEntries = [...Object.entries(data)]; + this.cdr.markForCheck(); + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts new file mode 100644 index 00000000000..954017082ec --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ShareModule } from '@zeppelin/share'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { ConfigurationRoutingModule } from './configuration-routing.module'; +import { ConfigurationComponent } from './configuration.component'; + +@NgModule({ + declarations: [ConfigurationComponent], + imports: [CommonModule, ShareModule, NzTableModule, ConfigurationRoutingModule] +}) +export class ConfigurationModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts new file mode 100644 index 00000000000..5624c7e28ba --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CredentialComponent } from './credential.component'; + +const routes: Routes = [ + { + path: '', + component: CredentialComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class CredentialRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html new file mode 100644 index 00000000000..51b0c84c208 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html @@ -0,0 +1,134 @@ + + + + + Manage your credentials. You can add new credential information. + + + + + + + +
    + +

    Add new credential

    +
    +
    +
    + + Entity + + + + + {{ option }} + + + + + + Username + + + + + + Password + + + + +
    +
    + + + + + + +
    +
    +
    +
    +
    +
    + + + + Entity + Username + Password + Actions + + + + + + {{entity}} + + + + + + + + + + + + {{control.get('username')?.value}} + ********** + + + + + + + + + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less new file mode 100644 index 00000000000..87649caf0a5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less @@ -0,0 +1,39 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + ::ng-deep { + .ant-form-inline .ant-form-item-with-help { + margin-bottom: 0; + } + + .credential-actions, .new-actions { + text-align: right; + button+button { + margin-left: 8px; + } + } + + .actions-head { + text-align: right; + } + } + + .content { + padding: @card-padding-base / 2; + nz-table { + background: @card-background; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts new file mode 100644 index 00000000000..b28a6a63dfa --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts @@ -0,0 +1,202 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { collapseMotion } from 'ng-zorro-antd/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; + +import { finalize } from 'rxjs/operators'; + +import { CredentialForm } from '@zeppelin/interfaces'; +import { CredentialService, InterpreterService, TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-credential', + templateUrl: './credential.component.html', + styleUrls: ['./credential.component.less'], + animations: [collapseMotion], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CredentialComponent implements OnInit { + addForm: FormGroup; + showAdd = false; + adding = false; + interpreterNames: string[] = []; + interpreterFilteredNames: string[] = []; + editFlags: Map = new Map(); + credentialFormArray: FormArray = this.fb.array([]); + docsLink: string; + + get credentialControls(): FormGroup[] { + return this.credentialFormArray.controls as FormGroup[]; + } + + constructor( + private cdr: ChangeDetectorRef, + private fb: FormBuilder, + private nzMessageService: NzMessageService, + private interpreterService: InterpreterService, + private credentialService: CredentialService, + private ticketService: TicketService + ) { + this.setDocsLink(); + } + + setDocsLink() { + const version = this.ticketService.version; + this.docsLink = `https://zeppelin.apache.org/docs/${version}/setup/security/datasource_authorization.html`; + } + + onEntityInput(event: Event) { + const input = event.target as HTMLInputElement; + if (input && input.value) { + this.interpreterFilteredNames = this.interpreterNames + .filter(e => e.indexOf(input.value.trim()) !== -1) + .slice(0, 10); + } else { + this.interpreterFilteredNames = this.interpreterNames.slice(0, 10); + } + } + + getEntityFromForm(form: FormGroup): string { + return form.get('entity') && form.get('entity').value; + } + + isEditing(form: FormGroup): boolean { + const entity = this.getEntityFromForm(form); + return entity && this.editFlags.has(entity); + } + + setEditable(form: FormGroup) { + const entity = this.getEntityFromForm(form); + if (entity) { + this.editFlags.set(entity, form.getRawValue()); + } + this.cdr.markForCheck(); + } + + unsetEditable(form: FormGroup, reset = true) { + const entity = this.getEntityFromForm(form); + if (reset && entity && this.editFlags.has(entity)) { + form.reset(this.editFlags.get(entity)); + } + this.editFlags.delete(entity); + this.cdr.markForCheck(); + } + + submitForm(): void { + for (const i in this.addForm.controls) { + this.addForm.controls[i].markAsDirty(); + this.addForm.controls[i].updateValueAndValidity(); + } + if (this.addForm.valid) { + const data = this.addForm.getRawValue() as CredentialForm; + this.addCredential(data); + } + } + + saveCredential(form: FormGroup) { + for (const i in form.controls) { + form.controls[i].markAsDirty(); + form.controls[i].updateValueAndValidity(); + } + if (form.valid) { + this.credentialService.updateCredential(form.getRawValue()).subscribe(() => { + this.nzMessageService.success('Successfully saved credentials.'); + this.unsetEditable(form, false); + }); + } + } + + removeCredential(form: FormGroup) { + const entity = this.getEntityFromForm(form); + if (entity) { + this.credentialService.removeCredential(entity).subscribe(() => { + this.getCredentials(); + }); + } + } + + triggerAdd(): void { + this.showAdd = !this.showAdd; + this.cdr.markForCheck(); + } + + cancelAdd() { + this.showAdd = false; + this.resetAddForm(); + this.cdr.markForCheck(); + } + + getCredentials() { + this.credentialService.getCredentials().subscribe(data => { + const controls = [...Object.entries(data.userCredentials)].map(e => { + const entity = e[0]; + const { username, password } = e[1]; + return this.fb.group({ + entity: [entity, [Validators.required]], + username: [username, [Validators.required]], + password: [password, [Validators.required]] + }); + }); + this.credentialFormArray = this.fb.array(controls); + this.cdr.markForCheck(); + }); + } + + getInterpreterNames() { + this.interpreterService.getInterpretersSetting().subscribe(data => { + this.interpreterNames = data.map(e => `${e.group}.${e.name}`); + this.interpreterFilteredNames = this.interpreterNames.slice(0, 10); + this.cdr.markForCheck(); + }); + } + + addCredential(data: CredentialForm) { + this.adding = true; + this.cdr.markForCheck(); + this.credentialService + .addCredential(data) + .pipe( + finalize(() => { + this.adding = false; + this.cdr.markForCheck(); + }) + ) + .subscribe(() => { + this.nzMessageService.success('Successfully saved credentials.'); + this.getCredentials(); + this.resetAddForm(); + this.cdr.markForCheck(); + }); + } + + resetAddForm() { + this.addForm.reset({ + entity: null, + username: null, + password: null + }); + this.cdr.markForCheck(); + } + + ngOnInit(): void { + this.getCredentials(); + this.getInterpreterNames(); + this.addForm = this.fb.group({ + entity: [null, [Validators.required]], + username: [null, [Validators.required]], + password: [null, [Validators.required]] + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts new file mode 100644 index 00000000000..39756edb9f4 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts @@ -0,0 +1,54 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ShareModule } from '@zeppelin/share'; +import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { CredentialRoutingModule } from './credential-routing.module'; +import { CredentialComponent } from './credential.component'; + +@NgModule({ + declarations: [CredentialComponent], + imports: [ + CommonModule, + CredentialRoutingModule, + FormsModule, + ShareModule, + ReactiveFormsModule, + NzFormModule, + NzAutocompleteModule, + NzButtonModule, + NzCardModule, + NzIconModule, + NzDividerModule, + NzInputModule, + NzMessageModule, + NzTableModule, + NzPopconfirmModule, + NzGridModule, + NzToolTipModule + ] +}) +export class CredentialModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts new file mode 100644 index 00000000000..23a345f025a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { HomeComponent } from './home.component'; + +const routes: Routes = [ + { + path: '', + component: HomeComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class HomeRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html new file mode 100644 index 00000000000..5a26044c970 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html @@ -0,0 +1,41 @@ + + +
    +
    +

    + Welcome to Zeppelin! +

    + Zeppelin is web-based notebook that enables interactive data analytics.
    + You can make beautiful data-driven, interactive, collaborative document with SQL, code and even more!
    +
    +
    +
    +

    Notebook

    + +
    +
    +

    Help

    + Get started with Zeppelin + documentation
    + +

    Community

    + Please feel free to help us to improve Zeppelin,
    + Any contribution are welcome!

    + Mailing list
    + Issues + tracking
    + Github +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.less b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.less new file mode 100644 index 00000000000..3f79862ddc6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.less @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .content { + margin: 12px; + border: 1px solid @border-color-base; + padding: 24px; + background-color: @component-background; + position: relative; + background-image: url(../../../../assets/images/zeppelin_svg_logo_bg.svg); + background-repeat: no-repeat; + background-position: right bottom; + } + .welcome { + margin-bottom: 12px; + } + .more-info { + h3 { + margin-top: 0.5em; + } + } + .refresh-note { + margin-left: 6px + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts new file mode 100644 index 00000000000..ecc40995d68 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts @@ -0,0 +1,48 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { OP } from '@zeppelin/sdk'; +import { MessageService, TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class HomeComponent extends MessageListenersManager implements OnInit { + loading = false; + + reloadNoteList() { + this.messageService.reloadAllNotesFromRepo(); + this.loading = true; + } + + @MessageListener(OP.NOTES_INFO) + getNotes() { + this.loading = false; + this.cdr.markForCheck(); + } + + constructor( + public ticketService: TicketService, + public messageService: MessageService, + private cdr: ChangeDetectorRef + ) { + super(messageService); + } + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts new file mode 100644 index 00000000000..49a29734486 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; + +import { ShareModule } from '@zeppelin/share'; + +import { HomeRoutingModule } from './home-routing.module'; +import { HomeComponent } from './home.component'; + +@NgModule({ + declarations: [HomeComponent], + imports: [CommonModule, HomeRoutingModule, NzGridModule, NzIconModule, NzToolTipModule, ShareModule] +}) +export class HomeModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html new file mode 100644 index 00000000000..57a0b6339d7 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html @@ -0,0 +1,158 @@ + + +
    + + + ID + + + + + + + + URL + + + + + + + + + + + + + + + + + Snapshot + + + + + + + + Username + + + + + + + + Password + + + + + + + + + Protocol + + + + + + + + + + + Host + + + + + + + + Port + + + + + + + + Login + + + + + + + + Password + + + + + +
    + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less new file mode 100644 index 00000000000..f348ef32466 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + nz-form-item { + margin-bottom: 5px; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts new file mode 100644 index 00000000000..90e02a7f3ed --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; + +import { NzModalRef } from 'ng-zorro-antd/modal'; + +import { DestroyHookComponent } from '@zeppelin/core'; +import { CreateInterpreterRepositoryForm } from '@zeppelin/interfaces'; +import { InterpreterService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-interpreter-create-repository-modal', + templateUrl: './create-repository-modal.component.html', + styleUrls: ['./create-repository-modal.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InterpreterCreateRepositoryModalComponent extends DestroyHookComponent implements OnInit { + validateForm: FormGroup; + submitting = false; + urlProtocol = 'http://'; + + handleCancel() { + this.nzModalRef.close(); + } + + handleSubmit() { + const data = this.validateForm.getRawValue() as CreateInterpreterRepositoryForm; + // set url protocol + data.url = `${this.urlProtocol}${data.url}`; + // reset proxy port + const proxyPort = Number.parseInt(data.proxyPort, 10); + data.proxyPort = Number.isNaN(proxyPort) ? null : `${proxyPort}`; + this.interpreterService + .addRepository(data) + .pipe(takeUntil(this.destroy$)) + .subscribe(() => { + this.nzModalRef.close('Done'); + }); + } + + constructor( + private formBuilder: FormBuilder, + private nzModalRef: NzModalRef, + private interpreterService: InterpreterService + ) { + super(); + } + + ngOnInit() { + this.validateForm = this.formBuilder.group({ + id: ['', [Validators.required]], + url: ['', [Validators.required]], + snapshot: [false, [Validators.required]], + username: '', + password: '', + proxyProtocol: 'HTTP', + proxyHost: '', + proxyPort: [ + null, + [Validators.pattern('^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$')] + ], + proxyLogin: '', + proxyPassword: '' + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts new file mode 100644 index 00000000000..c9c995825cb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { InterpreterComponent } from './interpreter.component'; + +const routes: Routes = [ + { + path: '', + component: InterpreterComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class InterpreterRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html new file mode 100644 index 00000000000..144a57d2fca --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html @@ -0,0 +1,66 @@ + + + + + + + + + + +
    + +

    Repositories

    +

    Available repository lists. These repositories are used to resolve external dependencies of interpreter.

    + + {{repo.id}} + + + + +
    +
    +
    + + + Create + + + + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less new file mode 100644 index 00000000000..8d5f88d6044 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less @@ -0,0 +1,51 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .search-input { + width: 256px; + } + + @media (max-width:959px){ + .search-input { + width: 100%; + } + } + + nz-tag.repo-item { + border-color: transparent; + background: @primary-6; + color: @text-color-inverse; + ::ng-deep i.anticon-close { + color: @text-color-inverse; + &:hover { + color: @icon-color-hover; + } + } + } + + .editable-tag { + background: @white; + border-style: dashed; + } + + .content { + padding: @card-padding-base / 2; + + .create-interpreter { + text-align: center; + margin-bottom: 10px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts new file mode 100644 index 00000000000..0507cd8313c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts @@ -0,0 +1,188 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; + +import { collapseMotion } from 'ng-zorro-antd/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { Interpreter, InterpreterPropertyTypes, InterpreterRepository } from '@zeppelin/interfaces'; +import { InterpreterService } from '@zeppelin/services'; + +import { InterpreterCreateRepositoryModalComponent } from './create-repository-modal/create-repository-modal.component'; + +@Component({ + selector: 'zeppelin-interpreter', + templateUrl: './interpreter.component.html', + styleUrls: ['./interpreter.component.less'], + animations: [collapseMotion], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InterpreterComponent implements OnInit, OnDestroy { + searchInterpreter = ''; + search$ = new Subject(); + showRepository = false; + showCreateSetting = false; + propertyTypes: InterpreterPropertyTypes[] = []; + interpreterSettings: Interpreter[] = []; + repositories: InterpreterRepository[] = []; + availableInterpreters: Interpreter[] = []; + filteredInterpreterSettings: Interpreter[] = []; + + onSearchChange(value: string) { + this.search$.next(value); + } + + filterInterpreters(value: string) { + this.filteredInterpreterSettings = this.interpreterSettings.filter(e => e.name.search(value) !== -1); + this.cdr.markForCheck(); + } + + triggerRepository(): void { + this.showRepository = !this.showRepository; + this.cdr.markForCheck(); + } + + removeRepository(repo: InterpreterRepository): void { + this.nzModalService.confirm({ + nzTitle: repo.id, + nzContent: 'Do you want to delete this repository?', + nzOnOk: () => { + this.interpreterService.removeRepository(repo.id).subscribe(() => { + this.repositories = this.repositories.filter(e => e.id !== repo.id); + this.cdr.markForCheck(); + }); + } + }); + } + + addInterpreterSetting(data: Interpreter): void { + this.interpreterService.addInterpreterSetting(data).subscribe(res => { + this.interpreterSettings.push(res); + this.showCreateSetting = false; + this.filterInterpreters(this.searchInterpreter); + this.cdr.markForCheck(); + }); + } + + updateInterpreter(data: Interpreter): void { + this.interpreterService.updateInterpreter(data).subscribe(res => { + const current = this.interpreterSettings.find(e => e.name === res.name); + if (current) { + current.status = res.status; + current.errorReason = res.errorReason; + current.option = res.option; + current.properties = res.properties; + current.dependencies = res.dependencies; + } + this.filterInterpreters(this.searchInterpreter); + this.cdr.markForCheck(); + }); + } + + removeInterpreterSetting(settingId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Remove Interpreter', + nzContent: 'Do you want to delete this interpreter setting?', + nzOnOk: () => { + this.interpreterService.removeInterpreterSetting(settingId).subscribe(() => { + const index = this.interpreterSettings.findIndex(e => e.name === settingId); + this.interpreterSettings.splice(index, 1); + this.filterInterpreters(this.searchInterpreter); + this.cdr.markForCheck(); + }); + } + }); + } + + restartInterpreterSetting(settingId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Restart Interpreter', + nzContent: 'Do you want to restart this interpreter?', + nzOnOk: () => { + this.interpreterService.restartInterpreterSetting(settingId).subscribe(() => { + this.nzMessageService.info('Interpreter stopped. Will be lazily started on next run.'); + }); + } + }); + } + + createRepository(): void { + const modalRef = this.nzModalService.create({ + nzTitle: 'Add New Repository', + nzContent: InterpreterCreateRepositoryModalComponent, + nzFooter: null, + nzWidth: '600px' + }); + modalRef.afterClose.subscribe(data => { + if (data === 'Done') { + this.getRepositories(); + } + }); + } + + getPropertyTypes(): void { + this.interpreterService.getAvailableInterpreterPropertyTypes().subscribe(data => { + this.propertyTypes = data; + this.cdr.markForCheck(); + }); + } + + getInterpreterSettings(): void { + this.interpreterService.getInterpretersSetting().subscribe(data => { + this.interpreterSettings = data; + this.filteredInterpreterSettings = data; + this.cdr.markForCheck(); + }); + } + + getAvailableInterpreters(): void { + this.interpreterService.getAvailableInterpreters().subscribe(data => { + this.availableInterpreters = Object.keys(data) + .sort() + .map(key => data[key]); + this.cdr.markForCheck(); + }); + } + + getRepositories(): void { + this.interpreterService.getRepositories().subscribe(data => { + this.repositories = data; + this.cdr.markForCheck(); + }); + } + + constructor( + private interpreterService: InterpreterService, + private cdr: ChangeDetectorRef, + private nzModalService: NzModalService, + private nzMessageService: NzMessageService + ) {} + + ngOnInit() { + this.getPropertyTypes(); + this.getInterpreterSettings(); + this.getAvailableInterpreters(); + this.getRepositories(); + + this.search$.pipe(debounceTime(150)).subscribe(value => this.filterInterpreters(value)); + } + + ngOnDestroy(): void { + this.search$.next(); + this.search$.complete(); + this.search$ = null; + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts new file mode 100644 index 00000000000..6ed202f1774 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts @@ -0,0 +1,71 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzTagModule } from 'ng-zorro-antd/tag'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; + +import { ShareModule } from '@zeppelin/share'; + +import { InterpreterCreateRepositoryModalComponent } from './create-repository-modal/create-repository-modal.component'; +import { InterpreterRoutingModule } from './interpreter-routing.module'; +import { InterpreterComponent } from './interpreter.component'; +import { InterpreterItemComponent } from './item/item.component'; + +@NgModule({ + declarations: [InterpreterComponent, InterpreterCreateRepositoryModalComponent, InterpreterItemComponent], + entryComponents: [InterpreterCreateRepositoryModalComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + InterpreterRoutingModule, + ShareModule, + NzFormModule, + NzSelectModule, + NzSwitchModule, + NzToolTipModule, + NzCheckboxModule, + NzRadioModule, + NzBadgeModule, + NzButtonModule, + NzModalModule, + NzInputModule, + NzDividerModule, + NzTagModule, + NzCardModule, + NzDropDownModule, + NzIconModule, + NzTableModule, + NzMessageModule, + NzAlertModule + ] +}) +export class InterpreterModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html new file mode 100644 index 00000000000..2e4e374520b --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html @@ -0,0 +1,447 @@ + + + + +
    +

    + {{ interpreter.name }} + + , %{{ interpreter.name }}.{{ item.name }} + %{{ interpreter.name }} + + + + + + +

    +
    +
    + + + + + +
    + + + +
    +
    + + +

    Create new interpreter

    +
    + + Interpreter Name + + + + {{ formGroup.get('name')?.errors?.message }} + + + + + Interpreter group + + + + + + +
    +
    +

    Option

    +

    + + + + The interpreter will be instantiated + + {{ interpreterRunningOption }} + + + + +

    + + in + + + {{ optionFormGroup.get('perUser').value }} + + + + {{ optionFormGroup.get('perNote').value }} + + + + + + + + {{ optionFormGroup.get('perUser').value }} + + + + {{ optionFormGroup.get('perNote').value }} + + + + + + + process + + and Per Note in + + {{ optionFormGroup.get('perNote').value }} + + + + + + process + + . + + + + + + +

    +
    + + + + + + + + + + + + + + + Host + + + + + + Port + + + + + + + + + + + + + + + Owners + + + + + + Enter comma separated users and groups in the fields. Empty field (*) implies anyone can run this + interpreter. + + + + +
    + + +

    Properties

    +
    + + + + Name + Value + Description + Action + + + + + {{ control.get('key').value }} + + + + + + + + + + + + ****** + + {{control.get('value').value}} + + {{ control.get('value').value }} + + + + {{ control.get('description').value }} + + + + + + + + + +
    + + + + + + + + + + + +
    + + N/A + + + + + + +
    +
    +
    + + +

    Dependencies

    +
    + + + + Artifact + Exclude + Action + + + + + + + + + + + + + + + + + {{ control.get('groupArtifactVersion').value }} + {{ control.get('exclusions').value }} + + + + + + + + + + + + + + + +
    +
    + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less new file mode 100644 index 00000000000..746967dc88f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less @@ -0,0 +1,105 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + display: block; + margin-bottom: @card-padding-base; + position: relative; + + ::ng-deep .interpreter-item { + &.edit { + //background: @orange-1; + } + .ant-card-body { + margin-top: -@card-padding-base; + } + } + + .error-alter { + margin-top: @card-padding-base; + } + + .interpreter-status { + margin-left: 5px; + } + + .card-title { + display: inline-block; + h3 { + color: @primary-color; + margin-bottom: 0; + font-size: 1.4em; + .interpreter-group-item { + font-size: 60%; + font-weight: 400; + color: @text-color-secondary; + } + } + } + + h3.form-title { + margin: @card-padding-base 0; + } + + nz-form-item { + margin-bottom: 5px; + } + + form td textarea.ant-input { + margin-bottom: 0; + resize: none; + } + + .interpreter-form, .option-form { + input, nz-select { + width: 256px; + } + @media (max-width:959px){ + input, nz-select { + width: 100%; + } + } + } + + .edit-properties-value { + display: flex; + align-items: center; + + .value-input { + flex: 1; + } + + .type-selector { + width: 150px; + margin-left: 5px; + } + } + + .extra-wrap { + button + button { + margin-bottom: 0; + margin-left: 8px; + } + } + + .item-footer { + padding: 24px 0px 12px 0px; + text-align: right; + button + button { + margin-bottom: 0; + margin-left: 8px; + } + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts new file mode 100644 index 00000000000..fb9fb0097d1 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts @@ -0,0 +1,405 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { AbstractControl, FormArray, FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; +import { DestroyHookComponent } from '@zeppelin/core'; +import { Interpreter } from '@zeppelin/interfaces'; +import { InterpreterService, SecurityService, TicketService } from '@zeppelin/services'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; +import { InterpreterComponent } from '../interpreter.component'; + +@Component({ + selector: 'zeppelin-interpreter-item', + templateUrl: './item.component.html', + styleUrls: ['./item.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InterpreterItemComponent extends DestroyHookComponent implements OnInit, OnDestroy { + @Input() mode: 'create' | 'view' | 'edit' = 'view'; + @Input() interpreter: Interpreter; + + formGroup: FormGroup; + optionFormGroup: FormGroup; + editingPropertiesFormGroup: FormGroup; + editingDependenceFormGroup: FormGroup; + propertiesFormArray: FormArray; + dependenciesFormArray: FormArray; + userList$: Observable; + userSearchChange$ = new BehaviorSubject(''); + runningOptionMap = { + sharedModeName: 'shared', + globallyModeName: 'Globally', + perNoteModeName: 'Per Note', + perUserModeName: 'Per User' + }; + + sessionOptionMap = { + isolated: 'isolated', + scoped: 'scoped', + shared: 'shared' + }; + + interpreterRunningOption = 'Globally'; + + switchToEditMode(): void { + this.setupEditableForm(); + this.formGroup.enable(); + this.mode = 'edit'; + this.cdr.markForCheck(); + } + + handleRestart() { + this.parent.restartInterpreterSetting(this.interpreter.name); + } + + handleRemove() { + this.parent.removeInterpreterSetting(this.interpreter.name); + } + + handleSave() { + const formData = this.formGroup.getRawValue(); + const properties = {}; + + formData.properties + .sort(e => e.key) + .forEach(e => { + const { key, value, type } = e; + properties[key] = { + value, + type, + name: key + }; + }); + formData.properties = properties; + + formData.dependencies.forEach(e => { + e.exclusions = e.exclusions.split(',').filter(s => s !== ''); + }); + + if (this.mode === 'create') { + this.parent.addInterpreterSetting(formData); + } else { + this.parent.updateInterpreter(formData); + this.mode = 'view'; + } + } + + handleCancel() { + if (this.mode === 'create') { + this.parent.showCreateSetting = false; + } else { + this.mode = 'view'; + this.buildForm(); + this.formGroup.disable(); + } + } + + interpretersTrackFn(_: number, item: Interpreter) { + return item.name; + } + + onUserSearch(value: string): void { + this.userSearchChange$.next(value); + } + + removeProperty(index: number): void { + this.propertiesFormArray.removeAt(index); + this.cdr.markForCheck(); + } + + removeDependence(index: number): void { + this.dependenciesFormArray.removeAt(index); + this.cdr.markForCheck(); + } + + onTypeChange(type: string) { + let valueSet: string | boolean | number; + switch (type) { + case 'number': + valueSet = 0; + break; + case 'checkbox': + valueSet = false; + break; + default: + valueSet = ''; + } + this.editingPropertiesFormGroup.get('value').setValue(valueSet); + } + + addDependence(): void { + this.editingDependenceFormGroup.updateValueAndValidity(); + if (this.editingDependenceFormGroup.valid) { + const data = this.editingDependenceFormGroup.getRawValue(); + const current = this.dependenciesFormArray.controls.find( + control => control.get('groupArtifactVersion').value === data.groupArtifactVersion + ); + if (current) { + current.get('exclusions').setValue(data.exclusions); + } else { + this.dependenciesFormArray.push( + this.formBuilder.group({ + groupArtifactVersion: [data.groupArtifactVersion, [Validators.required]], + exclusions: data.exclusions + }) + ); + } + this.editingDependenceFormGroup.reset({ + exclusions: '', + groupArtifactVersion: '' + }); + } + } + + addProperties(): void { + this.editingPropertiesFormGroup.updateValueAndValidity(); + if (this.editingPropertiesFormGroup.valid) { + const data = this.editingPropertiesFormGroup.getRawValue(); + + const current = this.propertiesFormArray.controls.find(control => control.get('key').value === data.key); + if (current) { + current.get('value').setValue(data.value); + current.get('type').setValue(data.type); + } else { + this.propertiesFormArray.push( + this.formBuilder.group({ + key: [data.key, [Validators.required]], + value: data.value || '', + description: null, + type: data.type + }) + ); + } + this.editingPropertiesFormGroup.reset({ + key: '', + value: '', + description: null, + type: 'string' + }); + } + } + + setInterpreterRunningOption(perNote: string, perUser: string) { + const { sharedModeName, globallyModeName, perNoteModeName, perUserModeName } = this.runningOptionMap; + + this.optionFormGroup.get('perNote').setValue(perNote); + this.optionFormGroup.get('perUser').setValue(perUser); + + // Globally == shared_perNote + shared_perUser + if (perNote === sharedModeName && perUser === sharedModeName) { + this.interpreterRunningOption = globallyModeName; + return; + } + + const ticket = this.ticketService.originTicket; + + if (ticket.ticket === 'anonymous' && ticket.roles === '[]') { + if (perNote !== undefined && typeof perNote === 'string' && perNote !== '') { + this.interpreterRunningOption = perNoteModeName; + return; + } + } else if (ticket.ticket !== 'anonymous') { + if (perNote !== undefined && typeof perNote === 'string' && perNote !== '') { + if (perUser !== undefined && typeof perUser === 'string' && perUser !== '') { + this.interpreterRunningOption = perUserModeName; + return; + } + this.interpreterRunningOption = perNoteModeName; + return; + } + } + + this.optionFormGroup.get('perNote').setValue(sharedModeName); + this.optionFormGroup.get('perUser').setValue(sharedModeName); + this.interpreterRunningOption = globallyModeName; + } + + setPerNoteOrUserOption(type: 'perNote' | 'perUser', value: string) { + this.optionFormGroup.get(type).setValue(value); + switch (value) { + case this.sessionOptionMap.isolated: + this.optionFormGroup.get('session').setValue(false); + this.optionFormGroup.get('process').setValue(true); + break; + case this.sessionOptionMap.scoped: + this.optionFormGroup.get('session').setValue(true); + this.optionFormGroup.get('process').setValue(false); + break; + case this.sessionOptionMap.shared: + this.optionFormGroup.get('session').setValue(false); + this.optionFormGroup.get('process').setValue(false); + break; + } + } + + nameValidator(control: AbstractControl): ValidationErrors | null { + if (this.mode !== 'create') { + return null; + } + const name = (control.value as string).trim(); + const exist = this.parent.interpreterSettings.find(e => e.name === name); + if (exist) { + return { exist: true, message: `Name '${name}' already exists` }; + } else { + return null; + } + } + + buildForm(): void { + let name = ''; + let group = ''; + this.optionFormGroup = this.formBuilder.group({ + isExistingProcess: false, + isUserImpersonate: false, + owners: [[]], + perNote: '', + perUser: '', + port: [ + null, + [Validators.pattern('^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$')] + ], + host: '', + remote: true, + setPermission: false, + session: false, + process: false + }); + + this.propertiesFormArray = this.formBuilder.array([]); + this.dependenciesFormArray = this.formBuilder.array([]); + + if (this.mode === 'view' && this.interpreter) { + name = this.interpreter.name; + group = this.interpreter.group; + + // set option fields + this.optionFormGroup.reset({ + ...this.interpreter.option, + port: this.interpreter.option.port === -1 ? null : this.interpreter.option.port + }); + + // set dependencies fields + this.interpreter.dependencies.forEach(e => { + this.dependenciesFormArray.push( + this.formBuilder.group({ + exclusions: [e.exclusions.join(',')], + groupArtifactVersion: [e.groupArtifactVersion, [Validators.required]] + }) + ); + }); + + // set properties fields + Object.keys(this.interpreter.properties).forEach(key => { + const item = this.interpreter.properties[key]; + this.propertiesFormArray.push( + this.formBuilder.group({ + key: key, + value: item.value, + description: null, + type: item.type + }) + ); + }); + } + + this.formGroup = this.formBuilder.group({ + name: [name, [Validators.required, c => this.nameValidator(c)]], + group: [group, [Validators.required]], + option: this.optionFormGroup, + properties: this.propertiesFormArray, + dependencies: this.dependenciesFormArray + }); + } + + setupEditableForm(): void { + this.userList$ = this.userSearchChange$.pipe( + debounceTime(500), + filter(value => !!value), + switchMap(value => this.securityService.searchUsers(value)), + map(data => data.users), + tap(() => { + this.cdr.markForCheck(); + }) + ); + + this.editingPropertiesFormGroup = this.formBuilder.group({ + key: ['', [Validators.required]], + value: '', + description: null, + type: 'string' + }); + + this.editingDependenceFormGroup = this.formBuilder.group({ + groupArtifactVersion: ['', [Validators.required]], + exclusions: [''] + }); + + if (this.mode === 'create') { + this.formGroup + .get('group') + .valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe(value => { + // remove all controls + while (this.propertiesFormArray.length) { + this.propertiesFormArray.removeAt(0); + } + + const interpreters = this.parent.availableInterpreters.filter(e => e.group === value); + interpreters.forEach(interpreter => { + Object.keys(interpreter.properties).forEach(key => { + this.propertiesFormArray.push( + this.formBuilder.group({ + key: [key, [Validators.required]], + value: interpreter.properties[key].defaultValue, + description: interpreter.properties[key].description, + type: interpreter.properties[key].type + }) + ); + }); + }); + this.cdr.markForCheck(); + }); + } + } + + constructor( + public parent: InterpreterComponent, + public ticketService: TicketService, + private securityService: SecurityService, + private interpreterService: InterpreterService, + private formBuilder: FormBuilder, + private cdr: ChangeDetectorRef + ) { + super(); + } + + ngOnInit() { + this.buildForm(); + const option = this.optionFormGroup.getRawValue(); + this.setInterpreterRunningOption(option.perNote, option.perUser); + + if (this.mode !== 'view') { + this.setupEditableForm(); + this.formGroup.enable(); + } else { + this.formGroup.disable(); + } + } + + ngOnDestroy(): void { + this.userSearchChange$.complete(); + this.userSearchChange$ = null; + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts new file mode 100644 index 00000000000..5d12c451d5c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { JobManagerComponent } from './job-manager.component'; + +const routes: Routes = [ + { + path: '', + component: JobManagerComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class JobManagerRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html new file mode 100644 index 00000000000..a5eba0e5f04 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html @@ -0,0 +1,75 @@ + + + +
    + + + + + + + + + + + + Interpreter + + + + + + + + + Sort + + + + + + + + Total + + {{ filteredJobs.length }} + + + + + + + + +
    +
    +
    + + + + + + + + + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less new file mode 100644 index 00000000000..0bdc612836a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less @@ -0,0 +1,50 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .header-form { + .interpreter-select { + min-width: 100px; + } + .sort-select { + min-width: 155px; + } + } + + .content { + padding: @card-padding-base / 2; + + ::ng-deep .ant-skeleton-paragraph { + margin-bottom: 0; + } + + nz-empty { + margin-top: 76px; + } + } + + @media (max-width: 1230px) { + .status-legend { + display: none; + } + } + .status-legend { + float: right; + margin-right: 0; + zeppelin-job-manager-job-status { + margin-left: 10px; + display: inline-block; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts new file mode 100644 index 00000000000..fef84410ca2 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts @@ -0,0 +1,138 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; + +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { JobsItem, JobStatus, ListNoteJobs, ListUpdateNoteJobs, OP } from '@zeppelin/sdk'; +import { JobManagerService, MessageService } from '@zeppelin/services'; + +enum JobDateSortKeys { + RECENTLY_UPDATED = 'Recently Update', + OLDEST_UPDATED = 'Oldest Updated' +} + +interface FilterForm { + noteName: string; + interpreter: string; + sortBy: string; +} + +@Component({ + selector: 'zeppelin-job-manager', + templateUrl: './job-manager.component.html', + styleUrls: ['./job-manager.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JobManagerComponent extends MessageListenersManager implements OnInit, OnDestroy { + form: FormGroup; + jobStatusKeys = Object.keys(JobStatus).map(k => JobStatus[k]); + sortKeys = Object.keys(JobDateSortKeys).map(k => JobDateSortKeys[k]); + interpreters: string[] = []; + filteredJobs: JobsItem[] = []; + filterString: string = ''; + jobs: JobsItem[] = []; + loading = true; + + @MessageListener(OP.LIST_NOTE_JOBS) + setJobs(data: ListNoteJobs) { + this.jobs = data.noteJobs.jobs.filter(j => typeof j.interpreter !== 'undefined'); + const interpreters = this.jobs.map(job => job.interpreter); + this.interpreters = Array.from(new Set(interpreters)); + this.loading = false; + this.filterJobs(); + } + + @MessageListener(OP.LIST_UPDATE_NOTE_JOBS) + updateJobs(data: ListUpdateNoteJobs) { + data.noteRunningJobs.jobs.forEach(updateJob => { + const currentJobIndex = this.jobs.findIndex(job => job.noteId === updateJob.noteId); + if (currentJobIndex === -1) { + this.jobs.push(updateJob); + } else { + if (updateJob.isRemoved) { + this.jobs.splice(currentJobIndex, 1); + } else { + this.jobs[currentJobIndex] = updateJob; + } + } + }); + this.filterJobs(); + } + + filterJobs() { + const filterData = this.form.getRawValue() as FilterForm; + this.filterString = filterData.noteName; + const isSortByAsc = filterData.sortBy === JobDateSortKeys.OLDEST_UPDATED; + this.filteredJobs = this.jobs + .filter(job => { + const escapedString = filterData.noteName.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$&'); + const noteNameReg = new RegExp(escapedString, 'gi'); + return ( + (filterData.interpreter === '*' || job.interpreter === filterData.interpreter) && + job.noteName.match(noteNameReg) + ); + }) + .sort((x, y) => (isSortByAsc ? x.unixTimeLastRun - y.unixTimeLastRun : y.unixTimeLastRun - x.unixTimeLastRun)); + this.cdr.markForCheck(); + } + + onStart(noteId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Job Dialog', + nzContent: 'Run all paragraphs?', + nzOnOk: () => { + this.jobManagerService.startJob(noteId).subscribe(); + } + }); + } + + onStop(noteId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Job Dialog', + nzContent: 'Stop all paragraphs?', + nzOnOk: () => { + this.jobManagerService.stopJob(noteId).subscribe(); + } + }); + } + + constructor( + public messageService: MessageService, + private jobManagerService: JobManagerService, + private fb: FormBuilder, + private cdr: ChangeDetectorRef, + private nzModalService: NzModalService + ) { + super(messageService); + } + + ngOnInit() { + this.form = this.fb.group({ + noteName: [''], + interpreter: ['*'], + sortBy: [JobDateSortKeys.RECENTLY_UPDATED] + }); + + this.form.valueChanges.subscribe(() => this.filterJobs()); + + this.messageService.listNoteJobs(); + } + + ngOnDestroy(): void { + this.messageService.unsubscribeUpdateNoteJobs(); + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts new file mode 100644 index 00000000000..c8b1b18bf28 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; +import { IconDefinition } from '@ant-design/icons-angular'; +import { ClockCircleOutline, FileOutline, FileUnknownOutline, SearchOutline } from '@ant-design/icons-angular/icons'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzHighlightModule } from 'ng-zorro-antd/core'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzEmptyModule } from 'ng-zorro-antd/empty'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule, NZ_ICONS } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; + +import { ShareModule } from '@zeppelin/share'; + +import { JobManagerRoutingModule } from './job-manager-routing.module'; +import { JobManagerComponent } from './job-manager.component'; +import { JobManagerJobStatusComponent } from './job-status/job-status.component'; +import { JobManagerJobComponent } from './job/job.component'; + +const icons: IconDefinition[] = [SearchOutline, FileOutline, FileUnknownOutline, ClockCircleOutline]; + +@NgModule({ + declarations: [JobManagerComponent, JobManagerJobComponent, JobManagerJobStatusComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + NzHighlightModule, + ShareModule, + NzIconModule, + NzInputModule, + NzBadgeModule, + NzGridModule, + NzModalModule, + RouterModule, + NzSelectModule, + NzInputModule, + NzFormModule, + JobManagerRoutingModule, + NzDividerModule, + NzCardModule, + NzToolTipModule, + NzProgressModule, + NzSkeletonModule, + NzEmptyModule + ], + providers: [{ provide: NZ_ICONS, useValue: icons }] +}) +export class JobManagerModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html new file mode 100644 index 00000000000..2bd375de558 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html @@ -0,0 +1,17 @@ + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less new file mode 100644 index 00000000000..0f2d8c0d122 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + display: inline-block; + nz-badge.ready { + ::ng-deep .ant-badge-status-success { + background: fade(@success-color, 20%); + border: 1px solid @success-color; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts new file mode 100644 index 00000000000..18828cd9827 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +import { JobStatus } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-job-manager-job-status', + templateUrl: './job-status.component.html', + styleUrls: ['./job-status.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JobManagerJobStatusComponent { + @Input() status: JobStatus; + @Input() showText = false; + jobStatus = JobStatus; + statusMap = { + [JobStatus.READY]: 'success', + [JobStatus.FINISHED]: 'success', + [JobStatus.ABORT]: 'warning', + [JobStatus.ERROR]: 'error', + [JobStatus.PENDING]: 'default', + [JobStatus.RUNNING]: 'processing' + }; + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html new file mode 100644 index 00000000000..4d76c7694aa --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html @@ -0,0 +1,58 @@ + + + +
    + + + - + + {{note.interpreter || 'interpreter is not set'}} + + + {{relativeTime}} + {{note.isRunningJob ? 'RUNNING' : 'READY'}} + {{progress | percent: '1.0-0'}} + + +
    + +
    + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less new file mode 100644 index 00000000000..bf958132e1c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + display: block; + margin-bottom: 10px; + position: relative; + + ::ng-deep .job-item .ant-card-body { + padding: @card-padding-base / 2; + } + + .job-title { + margin-bottom: 10px; + } + + .note-icon { + margin-right: 5px; + } + + .right-tools { + display: inline-block; + float: right; + color: @text-color-secondary; + & > * { + margin-left: 5px; + } + .job-control-btn { + cursor: pointer; + color: @processing-color; + &.running { + color: @error-color; + } + } + } + + .interpreter { + color: @text-color; + &.unset { + color: @text-color-secondary; + } + } + + zeppelin-job-manager-job-status { + ::ng-deep .ant-badge-status-text { + margin-left: 0; + } + margin: 0 4px; + } + + .footer-progress { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + margin-bottom: -5px; + padding: 0 1px; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts new file mode 100644 index 00000000000..e2990c24922 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts @@ -0,0 +1,83 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; + +import * as distanceInWords from 'date-fns/distance_in_words'; + +import { JobsItem, JobStatus } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-job-manager-job', + templateUrl: './job.component.html', + styleUrls: ['./job.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JobManagerJobComponent implements OnInit, OnChanges { + @Input() note: JobsItem; + @Input() highlight: string | null = null; + @Output() readonly start = new EventEmitter(); + @Output() readonly stop = new EventEmitter(); + + icon = 'file'; + relativeTime = ''; + progress = 0; + + setIcon(): void { + const noteType = this.note.noteType; + if (noteType === 'normal') { + this.icon = 'file'; + } else if (noteType === 'cron') { + this.icon = 'close-circle'; + } else { + this.icon = 'file-unknown'; + } + } + + setRelativeTime(): void { + this.relativeTime = distanceInWords(new Date(), new Date(this.note.unixTimeLastRun)); + } + + setProgress(): void { + const runningCount = this.note.paragraphs.filter( + paragraph => [JobStatus.FINISHED, JobStatus.RUNNING].indexOf(paragraph.status) !== -1 + ).length; + this.progress = runningCount / this.note.paragraphs.length; + } + + onStartClick(): void { + this.start.emit(this.note.noteId); + } + + onStopClick(): void { + this.stop.emit(this.note.noteId); + } + + constructor() {} + + ngOnInit() {} + + ngOnChanges(changes: SimpleChanges): void { + this.setIcon(); + this.setRelativeTime(); + this.setProgress(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html new file mode 100644 index 00000000000..3f4875a5bca --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html @@ -0,0 +1,79 @@ + + + + +
    + +
    +
    + + +
    +
    +

    Setting

    +
    + + + + Name + Value + + + + + {{setting.name}} + + {{setting.selected}} + + + + + + + + + + + + + + +
    + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less new file mode 100644 index 00000000000..7e242390dcf --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + + display: block; + margin-bottom: @card-padding-base; + position: relative; + + ::ng-deep .repo-item { + &.edit { + //background: @orange-1; + } + } + + .extra-wrap { + button { + transition: none; + } + button + button { + margin-bottom: 0; + margin-left: 8px; + } + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts new file mode 100644 index 00000000000..f66247c9599 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges +} from '@angular/core'; +import { FormArray, FormBuilder, Validators } from '@angular/forms'; +import { NotebookRepo } from '@zeppelin/interfaces'; + +@Component({ + selector: 'zeppelin-notebook-repo-item', + templateUrl: './item.component.html', + styleUrls: ['./item.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookRepoItemComponent implements OnChanges { + @Input() repo: NotebookRepo; + @Output() readonly repoChange = new EventEmitter(); + + settingFormArray: FormArray; + editMode = false; + + constructor(private cdr: ChangeDetectorRef, private fb: FormBuilder) {} + + triggerEditMode() { + this.editMode = !this.editMode; + this.cdr.markForCheck(); + } + + save() { + this.settingFormArray.controls.forEach(control => { + control.markAsDirty(); + control.updateValueAndValidity(); + }); + + if (this.settingFormArray.valid) { + const values = this.settingFormArray.getRawValue() as string[]; + values.forEach((value, i) => (this.repo.settings[i].selected = value)); + this.repoChange.emit(this.repo); + this.editMode = false; + this.cdr.markForCheck(); + } + } + + cancel() { + this.buildForm(); + this.editMode = false; + this.cdr.markForCheck(); + } + + buildForm() { + const controls = this.repo.settings.map(setting => { + return this.fb.control(setting.selected, [Validators.required]); + }); + this.settingFormArray = this.fb.array(controls); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.repo) { + this.buildForm(); + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts new file mode 100644 index 00000000000..e7e7ca19ad2 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { NotebookReposComponent } from './notebook-repos.component'; + +const routes: Routes = [ + { + path: '', + component: NotebookReposComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class NotebookReposRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html new file mode 100644 index 00000000000..d47ad877782 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html @@ -0,0 +1,21 @@ + + + +
    + + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less new file mode 100644 index 00000000000..5a3f8f0b1ff --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + + .content { + padding: @card-padding-base / 2; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts new file mode 100644 index 00000000000..1faffeeeab0 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts @@ -0,0 +1,51 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { NotebookRepo } from '@zeppelin/interfaces'; +import { NotebookRepoService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-repos', + templateUrl: './notebook-repos.component.html', + styleUrls: ['./notebook-repos.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookReposComponent implements OnInit { + repositories: NotebookRepo[] = []; + + constructor(private notebookRepoService: NotebookRepoService, private cdr: ChangeDetectorRef) {} + + ngOnInit() { + this.getRepos(); + } + + getRepos() { + this.notebookRepoService.getRepos().subscribe(data => { + this.repositories = data.sort((a, b) => a.name.charCodeAt(0) - b.name.charCodeAt(0)); + this.cdr.markForCheck(); + }); + } + + updateRepoSetting(repo: NotebookRepo) { + const data = { + name: repo.className, + settings: {} + }; + repo.settings.forEach(({ name, selected }) => { + data.settings[name] = selected; + }); + + this.notebookRepoService.updateRepo(data).subscribe(() => { + this.getRepos(); + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts new file mode 100644 index 00000000000..9f30074443e --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ShareModule } from '@zeppelin/share'; + +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzTableModule } from 'ng-zorro-antd/table'; + +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NotebookRepoItemComponent } from './item/item.component'; +import { NotebookReposRoutingModule } from './notebook-repos-routing.module'; +import { NotebookReposComponent } from './notebook-repos.component'; + +@NgModule({ + declarations: [NotebookReposComponent, NotebookRepoItemComponent], + imports: [ + CommonModule, + ShareModule, + FormsModule, + ReactiveFormsModule, + NotebookReposRoutingModule, + NzCardModule, + NzButtonModule, + NzInputModule, + NzTableModule, + NzIconModule, + NzFormModule, + NzSelectModule + ] +}) +export class NotebookReposModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts new file mode 100644 index 00000000000..91277928ca4 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { NotebookSearchComponent } from './notebook-search.component'; + +const routes: Routes = [ + { + path: '', + component: NotebookSearchComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class NotebookSearchRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html new file mode 100644 index 00000000000..e1db6d90f26 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html @@ -0,0 +1,17 @@ + +
    + + +
    + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less new file mode 100644 index 00000000000..108b1a4ac92 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .main { + padding: @card-padding-base / 2; + } + + zeppelin-notebook-search-result-item { + margin-bottom: 16px; + display: block; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts new file mode 100644 index 00000000000..2036d23b828 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts @@ -0,0 +1,58 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { NotebookSearchResultItem } from '@zeppelin/interfaces'; +import { NotebookSearchService } from '@zeppelin/services/notebook-search.service'; +import { Subject } from 'rxjs'; +import { filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; + +@Component({ + selector: 'zeppelin-notebook-search', + templateUrl: './notebook-search.component.html', + styleUrls: ['./notebook-search.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookSearchComponent implements OnInit, OnDestroy { + private destroy$ = new Subject(); + private searchAction$ = this.router.params.pipe( + takeUntil(this.destroy$), + map(params => params.queryStr), + filter(queryStr => typeof queryStr === 'string' && !!queryStr.trim()), + tap(() => (this.searching = true)), + switchMap(queryStr => this.notebookSearchService.search(queryStr)) + ); + + results: NotebookSearchResultItem[] = []; + searching = false; + + constructor( + private cdr: ChangeDetectorRef, + private router: ActivatedRoute, + private notebookSearchService: NotebookSearchService + ) {} + + ngOnInit() { + this.searchAction$.subscribe(results => { + this.results = results; + this.searching = false; + this.cdr.markForCheck(); + }); + } + + ngOnDestroy(): void { + this.notebookSearchService.clear(); + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.module.ts new file mode 100644 index 00000000000..69dafa8688f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.module.ts @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzCardModule } from 'ng-zorro-antd/card'; + +import { ShareModule } from '@zeppelin/share'; + +import { NotebookSearchRoutingModule } from './notebook-search-routing.module'; +import { NotebookSearchComponent } from './notebook-search.component'; +import { NotebookSearchResultItemComponent } from './result-item/result-item.component'; + +@NgModule({ + declarations: [NotebookSearchComponent, NotebookSearchResultItemComponent], + imports: [CommonModule, NotebookSearchRoutingModule, ShareModule, NzCardModule, FormsModule] +}) +export class NotebookSearchModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html new file mode 100644 index 00000000000..14d6ee6bacc --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html @@ -0,0 +1,22 @@ + + + + + {{displayName}} + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less new file mode 100644 index 00000000000..cb24d4e47b3 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +::ng-deep { + .monaco-editor { + .mark { + background: #fdf733; + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts new file mode 100644 index 00000000000..67eabe6406e --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts @@ -0,0 +1,173 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + NgZone, + OnChanges, + OnDestroy, + SimpleChanges +} from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { NotebookSearchResultItem } from '@zeppelin/interfaces'; +import { getKeywordPositions, KeywordPosition } from '@zeppelin/utility/get-keyword-positions'; +import { editor, Range } from 'monaco-editor'; +import IEditor = editor.IEditor; +import IStandaloneCodeEditor = editor.IStandaloneCodeEditor; + +@Component({ + selector: 'zeppelin-notebook-search-result-item', + templateUrl: './result-item.component.html', + styleUrls: ['./result-item.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookSearchResultItemComponent implements OnChanges, OnDestroy { + @Input() result: NotebookSearchResultItem; + queryParams = {}; + displayName = ''; + routerLink = []; + mergedStr: string; + keywords: string[] = []; + highlightPositions: KeywordPosition[] = []; + editor: IStandaloneCodeEditor; + height = 0; + decorations: string[] = []; + editorOption = { + readOnly: true, + fontSize: 12, + renderLineHighlight: 'none', + minimap: { enabled: false }, + lineNumbers: 'off', + glyphMargin: false, + scrollBeyondLastLine: false, + contextmenu: false + }; + + constructor(private ngZone: NgZone, private cdr: ChangeDetectorRef, private router: ActivatedRoute) {} + + setDisplayNameAndRouterLink(): void { + const term = this.router.snapshot.params.queryStr; + const listOfId = this.result.id.split('/'); + const [noteId, hasParagraph, paragraph] = listOfId; + if (!hasParagraph) { + this.routerLink = ['/', 'notebook', this.result.id]; + this.queryParams = {}; + } else { + this.routerLink = ['/', 'notebook', noteId]; + this.queryParams = { + paragraph, + term + }; + } + this.displayName = this.result.name ? this.result.name : `Note ${noteId}`; + } + + setHighlightKeyword(): void { + let mergedStr = this.result.header ? `${this.result.header}\n\n${this.result.snippet}` : this.result.snippet; + + const regexp = /(.+?)<\/B>/g; + const matches = []; + let match = regexp.exec(mergedStr); + + while (match !== null) { + if (match[1]) { + matches.push(match[1].toLocaleLowerCase()); + } + match = regexp.exec(mergedStr); + } + + mergedStr = mergedStr.replace(regexp, '$1'); + this.mergedStr = mergedStr; + const keywords = [...new Set(matches)]; + this.highlightPositions = getKeywordPositions(keywords, mergedStr); + } + + applyHighlight() { + if (this.editor) { + this.decorations = this.editor.deltaDecorations( + this.decorations, + this.highlightPositions.map(highlight => { + const line = highlight.line + 1; + const character = highlight.character + 1; + return { + range: new Range(line, character, line, character + highlight.length), + options: { + className: 'mark', + stickiness: 1 + } + }; + }) + ); + this.cdr.markForCheck(); + } + } + + setLanguage() { + const editorModes = { + scala: /^%(\w*\.)?(spark|flink)/, + python: /^%(\w*\.)?(pyspark|python)/, + html: /^%(\w*\.)?(angular|ng)/, + r: /^%(\w*\.)?(r|sparkr|knitr)/, + sql: /^%(\w*\.)?\wql/, + yaml: /^%(\w*\.)?\wconf/, + markdown: /^%md/, + shell: /^%sh/ + }; + let mode = 'text'; + const model = this.editor.getModel(); + const keys = Object.keys(editorModes); + for (let i = 0; i < keys.length; i++) { + if (editorModes[keys[i]].test(this.result.snippet)) { + mode = keys[i]; + break; + } + } + editor.setModelLanguage(model, mode); + } + + autoAdjustEditorHeight() { + this.ngZone.run(() => { + setTimeout(() => { + if (this.editor) { + this.height = + this.editor.getTopForLineNumber(Number.MAX_SAFE_INTEGER) + this.editor.getConfiguration().lineHeight * 2; + this.editor.layout(); + this.cdr.markForCheck(); + } + }); + }); + } + + initializedEditor(editorInstance: IEditor) { + this.editor = editorInstance as IStandaloneCodeEditor; + this.editor.setValue(this.mergedStr); + this.setLanguage(); + this.autoAdjustEditorHeight(); + this.applyHighlight(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.result) { + this.setDisplayNameAndRouterLink(); + this.setHighlightKeyword(); + this.autoAdjustEditorHeight(); + this.applyHighlight(); + } + } + + ngOnDestroy(): void { + this.editor.dispose(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html new file mode 100644 index 00000000000..1da21e63a63 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html @@ -0,0 +1,239 @@ + + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
    • + {{r.message}} + + {{(r.time * 1000 | date: 'MMMM dd yyyy, h:mm:ss a') || 'Current'}} +
    • +
    +
    +
    + + + + + + + + + + + + + +
    + Run note with cron scheduler. + Either choose from preset or write your own + + cron expression + + . +
    + - Preset + {{cr.name}} +
    +
    + - Preset + +

    + {{note.info.cron}} +

    +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + +
      +
    • {{lf}}
    • +
    +
    +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less new file mode 100644 index 00000000000..5161d77070a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less @@ -0,0 +1,105 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.scheduler { + width: 300px; + + .cron-preset { + margin-right: 6px; + + &.selected { + font-weight: bold; + } + } + + > div { + line-height: 24px; + + span { + margin-right: 6px; + } + + input { + display: inline-block; + width: 160px; + } + } +} + +.themeMixin({ + nz-dropdown-button { + height: 24px; + line-height: 22px; + margin-left: -1px; + } + .bar { + height: 50px; + background: @component-background; + box-shadow: -2px 4px 2px 0 rgba(0, 0, 0, 0.06); + padding: 0 15px; + position: absolute; + width: 100%; + top: 0; + line-height: 50px; + + &.simple { + box-shadow: none; + + .control { + display: none; + } + + .setting { + display: none; + } + + &:hover { + .control { + display: block; + } + + .setting { + display: block; + } + } + } + + .title { + float: left; + width: auto; + max-width: 40%; + } + + .control { + float: left; + + nz-button-group { + margin-right: 24px; + + &:last-child { + margin-right: 0; + } + } + } + + .setting { + float: right; + + button { + box-shadow: none; + border: none; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts new file mode 100644 index 00000000000..9ec5dedb631 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts @@ -0,0 +1,293 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Inject, + Input, + OnInit, + Output +} from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { Note, OP, RevisionListItem } from '@zeppelin/sdk'; +import { MessageService, NoteActionService, NoteStatusService, SaveAsService, TicketService } from '@zeppelin/services'; + +import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; + +@Component({ + selector: 'zeppelin-notebook-action-bar', + templateUrl: './action-bar.component.html', + styleUrls: ['./action-bar.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookActionBarComponent extends MessageListenersManager implements OnInit { + @Input() note: Note['note']; + @Input() isOwner = true; + @Input() looknfeel: string; + @Input() noteRevisions: RevisionListItem[] = []; + @Input() currentRevision: string; + @Input() collaborativeMode = false; + @Input() collaborativeModeUsers = []; + @Input() revisionView = false; + @Input() activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + @Output() readonly activatedExtensionChange = new EventEmitter< + 'interpreter' | 'permissions' | 'revisions' | 'hide' + >(); + @Output() readonly editorHideChange = new EventEmitter(); + @Output() readonly tableHideChange = new EventEmitter(); + lfOption: Array<'report' | 'default' | 'simple'> = ['default', 'simple', 'report']; + isNoteParagraphRunning = false; + principal = this.ticketService.ticket.principal; + editorHide = false; + commitVisible = false; + tableHide = false; + isRevisionSupported = JSON.parse(this.ticketService.configuration.isRevisionSupported); + cronOption = [ + { name: 'None', value: undefined }, + { name: '1m', value: '0 0/1 * * * ?' }, + { name: '5m', value: '0 0/5 * * * ?' }, + { name: '1h', value: '0 0 0/1 * * ?' }, + { name: '3h', value: '0 0 0/3 * * ?' }, + { name: '6h', value: '0 0 0/6 * * ?' }, + { name: '12h', value: '0 0 0/12 * * ?' }, + { name: '1d', value: '0 0 0 * * ?' } + ]; + updateNoteName(name: string) { + const trimmedNewName = name.trim(); + if (trimmedNewName.length > 0 && this.note.name !== trimmedNewName) { + this.note.name = trimmedNewName; + this.messageService.noteRename(this.note.id, this.note.name, true); + } + } + + visitRevision(revision: RevisionListItem) { + if (revision.id) { + if (revision.id === 'Head') { + this.router.navigate(['/notebook', this.activatedRoute.snapshot.params.noteId]).then(); + } else { + this.router.navigate(['/notebook', this.activatedRoute.snapshot.params.noteId, 'revision', revision.id]).then(); + } + } else { + this.nzMessageService.warning('There is a problem with this Revision'); + } + } + + checkpointNote(value: string, e: MouseEvent) { + e.preventDefault(); + this.commitVisible = false; + this.messageService.checkpointNote(this.note.id, value); + } + + setNoteRevision() { + const { revisionId } = this.activatedRoute.snapshot.params; + if (revisionId) { + this.nzModalService.confirm({ + nzTitle: 'Set revision', + nzContent: 'Set notebook head to current revision?', + nzOnOk: () => { + this.messageService.setNoteRevision(this.note.id, revisionId); + } + }); + } + } + + toggleExtension(extension: 'interpreter' | 'permissions' | 'revisions' | 'hide') { + if (this.activatedExtension === extension) { + this.activatedExtension = 'hide'; + } else { + this.activatedExtension = extension; + } + this.activatedExtensionChange.emit(this.activatedExtension); + } + + @MessageListener(OP.PARAGRAPH) + paragraphUpdate() { + this.updateIsNoteParagraphRunning(); + this.cdr.markForCheck(); + } + + runAllParagraphs() { + this.messageService.runAllParagraphs( + this.note.id, + this.note.paragraphs.map(p => { + return { + id: p.id, + title: p.title, + paragraph: p.text, + config: p.config, + params: p.settings.params + }; + }) + ); + } + + clearAllParagraphOutput() { + this.messageService.paragraphClearAllOutput(this.note.id); + } + + setCronScheduler(cronExpr: string) { + if (cronExpr) { + if (!this.note.config.cronExecutingUser) { + this.note.config.cronExecutingUser = this.ticketService.ticket.principal; + } + if (!this.note.config.cronExecutingRoles) { + this.note.config.cronExecutingRoles = this.ticketService.ticket.roles; + } + } else { + this.note.config.cronExecutingUser = ''; + this.note.config.cronExecutingRoles = ''; + } + this.note.config.cron = cronExpr; + this.setConfig(); + } + + setReleaseResource(releaseresource: boolean) { + this.note.config.releaseresource = releaseresource; + this.setConfig(); + } + + setConfig() { + // TODO(hsuanxyz) + } + + cloneNote() { + this.nzModalService.create({ + nzTitle: 'Clone Note', + nzContent: NoteCreateComponent, + nzComponentParams: { + cloneNote: this.note + }, + nzFooter: null + }); + } + + exportNote() { + const sizeLimit = +this.ticketService.configuration['zeppelin.websocket.max.text.message.size']; + const jsonContent = JSON.stringify(this.note); + if (jsonContent.length > sizeLimit) { + this.nzModalService.confirm({ + nzTitle: `Note size exceeds importable limit (${sizeLimit})`, + nzContent: 'Do you still want to export this note?', + nzOnOk: () => { + this.saveAsService.saveAs(jsonContent, this.note.name, 'zpln'); + } + }); + } else { + this.saveAsService.saveAs(jsonContent, this.note.name, 'zpln'); + } + } + + toggleAllEditor() { + this.editorHide = !this.editorHide; + this.editorHideChange.emit(this.editorHide); + } + + toggleAllTable() { + this.tableHide = !this.tableHide; + this.tableHideChange.emit(this.tableHide); + } + + searchCode() { + // TODO(hsuanxyz) + } + + deleteNote() { + this.messageService.deleteNote(this.note.id); + } + + moveNoteToTrash() { + this.messageService.moveNoteToTrash(this.note.id); + } + + get isTrash() { + return this.noteStatusService.isTrash(this.note); + } + + get viewOnly(): boolean { + return this.noteStatusService.viewOnly(this.note); + } + + updateIsNoteParagraphRunning() { + this.isNoteParagraphRunning = this.noteStatusService.isNoteParagraphRunning(this.note); + } + + showShortCut() { + // TODO(hsuanxyz) + } + + togglePermissions() { + this.toggleExtension('permissions'); + } + + setLookAndFeel(lf: 'report' | 'default' | 'simple') { + this.note.config.looknfeel = lf; + if (!this.activatedRoute.snapshot.params.revisionId) { + this.messageService.updateNote(this.note.id, this.note.name, this.note.config); + } + } + + toggleNotePersonalizedMode() { + const modeText = this.note.config.personalizedMode === 'true' ? 'collaborate' : 'personalize'; + if (this.isOwner) { + this.nzModalService.confirm({ + nzTitle: 'Setting the result display', + nzContent: `Do you want to ${modeText} your analysis?`, + nzOnOk: () => { + if (this.note.config.personalizedMode === undefined || this.note.config.personalizedMode === 'true') { + this.note.config.personalizedMode = 'false'; + } else { + this.note.config.personalizedMode = 'true'; + } + this.messageService.updatePersonalizedMode(this.note.id, this.note.config.personalizedMode); + } + }); + } + } + + get getCronOptionNameFromValue() { + if (!this.note.config.cron) { + return ''; + } else if (this.cronOption.find(cron => cron.value === this.note.config.cron)) { + return this.cronOption.find(cron => cron.value === this.note.config.cron).name; + } else { + return this.note.config.cron; + } + } + + constructor( + public messageService: MessageService, + private nzModalService: NzModalService, + private ticketService: TicketService, + private nzMessageService: NzMessageService, + private router: Router, + private cdr: ChangeDetectorRef, + private noteActionService: NoteActionService, + private noteStatusService: NoteStatusService, + @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, + private activatedRoute: ActivatedRoute, + private saveAsService: SaveAsService + ) { + super(messageService); + } + + ngOnInit(): void { + this.updateIsNoteParagraphRunning(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html new file mode 100644 index 00000000000..76d6475a7c5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html @@ -0,0 +1,17 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less new file mode 100644 index 00000000000..c51b70e61a6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less @@ -0,0 +1,50 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .add-paragraph { + height: 32px; + text-align: center; + margin: -12px 0; + color: @primary-color; + font-weight: 500; + position: relative;; + + .inner { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 10; + display: none; + line-height: 30px; + background: @blue-1; + border: 1px solid @border-color-split; + box-shadow: @btn-shadow; + padding: 0 12px; + + &.disabled { + cursor: default; + color: @disabled-color; + } + } + + &:hover { + .inner { + display: block; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts new file mode 100644 index 00000000000..bb77a832979 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts @@ -0,0 +1,34 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; + +@Component({ + selector: 'zeppelin-notebook-add-paragraph', + templateUrl: './add-paragraph.component.html', + styleUrls: ['./add-paragraph.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookAddParagraphComponent implements OnInit { + @Output() readonly addParagraph = new EventEmitter(); + @Input() disabled = false; + + clickAdd() { + if (!this.disabled) { + this.addParagraph.emit(); + } + } + + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html new file mode 100644 index 00000000000..263390cbce6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html @@ -0,0 +1,55 @@ + + +
    +
    +

    Settings

    +
    + +
    +

    Interpreter binding

    +

    + Bind interpreter for this note. + Click to Bind/Unbind interpreter. + Drag and drop to reorder interpreters.
    + The first interpreter on the list becomes default. To create/remove interpreters, go to + Interpreter + menu. +

    +
    +
    +
    +
    + + + +
    + +
    +
    +
    +
    + + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less new file mode 100644 index 00000000000..fcaea0a913f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .interpreter-binding { + .interpreter-list { + background: @layout-body-background; + padding: 12px; + } + + .submit-interpreter { + margin-top: 12px; + + button { + margin-right: 12px; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts new file mode 100644 index 00000000000..34a9990e829 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts @@ -0,0 +1,81 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; + +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { InterpreterBindingItem } from '@zeppelin/sdk'; +import { InterpreterService, MessageService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-interpreter-binding', + templateUrl: './interpreter-binding.component.html', + styleUrls: ['./interpreter-binding.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookInterpreterBindingComponent { + private restarting = false; + @Input() noteId: string; + @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Input() activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + @Output() readonly activatedExtensionChange = new EventEmitter< + 'interpreter' | 'permissions' | 'revisions' | 'hide' + >(); + + restartInterpreter(interpreter: InterpreterBindingItem) { + this.nzModalService.create({ + nzTitle: 'Restart interpreter', + nzContent: `Do you want to restart ${interpreter.name} interpreter?`, + nzOkLoading: this.restarting, + nzOnOk: () => + new Promise(resolve => { + this.restarting = true; + this.interpreterService.restartInterpreter(interpreter.id, this.noteId).subscribe( + data => { + this.restarting = false; + this.cdr.markForCheck(); + resolve(); + }, + () => { + this.restarting = false; + resolve(); + } + ); + }) + }); + } + + drop(event: CdkDragDrop) { + moveItemInArray(this.interpreterBindings, event.previousIndex, event.currentIndex); + } + + saveSetting() { + const selectedSettingIds = this.interpreterBindings.filter(item => item.selected).map(item => item.id); + this.messageService.saveInterpreterBindings(this.noteId, selectedSettingIds); + this.messageService.getInterpreterBindings(this.noteId); + this.closeSetting(); + } + + closeSetting() { + this.activatedExtension = 'hide'; + this.activatedExtensionChange.emit('hide'); + } + + constructor( + private nzModalService: NzModalService, + private interpreterService: InterpreterService, + private cdr: ChangeDetectorRef, + private messageService: MessageService + ) {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html new file mode 100644 index 00000000000..2ca58518f71 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html @@ -0,0 +1,25 @@ + +
    + + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less new file mode 100644 index 00000000000..896b6f8dabf --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less @@ -0,0 +1,27 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import "theme-mixin"; + +:host { + display: block; + padding: 0 4px; +} + +.themeMixin({ + .forms-wrap { + background: @component-background; + border: 1px solid @border-color-split; + box-shadow: @card-shadow; + padding: 12px; + position: relative; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts new file mode 100644 index 00000000000..9eb0b721403 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { DynamicForms, DynamicFormParams } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-note-form-block', + templateUrl: './note-form-block.component.html', + styleUrls: ['./note-form-block.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteFormBlockComponent implements OnInit { + @Input() noteTitle: string; + @Input() formDefs: DynamicForms; + @Input() paramDefs: DynamicFormParams; + @Output() readonly noteTitleChange = new EventEmitter(); + @Output() readonly noteFormChange = new EventEmitter(); + @Output() readonly noteFormNameRemove = new EventEmitter(); + constructor() {} + + ngOnInit() {} + + onFormRemove({ name }) { + this.noteFormNameRemove.emit(name); + } + + onFormChange() { + this.noteFormChange.emit(this.paramDefs); + } + + setTitle(title: string) { + this.noteTitleChange.emit(title); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts new file mode 100644 index 00000000000..321b788e74f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { NotebookComponent } from './notebook.component'; + +const routes: Routes = [ + { + path: ':noteId', + component: NotebookComponent + }, + { + path: ':noteId/revision/:revisionId', + component: NotebookComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class NotebookRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html new file mode 100644 index 00000000000..b204c867388 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -0,0 +1,67 @@ + + +
    + +
    + + + +
    +
    + + +
    + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less new file mode 100644 index 00000000000..582bbb74910 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less @@ -0,0 +1,36 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + + +.themeMixin({ + .notebook-container { + background: @layout-body-background; + display: block; + position: relative; + padding-top: 50px; + min-height: calc(~"100vh - 50px"); + + &.simple { + background: @component-background; + } + } + .extension-area { + padding: 24px; + background: @component-background; + box-shadow: -2px 4px 2px 0 rgba(0, 0, 0, 0.06); + } + .paragraph-area { + margin: 6px 0 0 0; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts new file mode 100644 index 00000000000..9a0ecc9a26e --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -0,0 +1,401 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + QueryList, + ViewChildren +} from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { isNil } from 'lodash'; +import { Subject } from 'rxjs'; +import { distinctUntilKeyChanged, map, startWith, takeUntil } from 'rxjs/operators'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { Permissions } from '@zeppelin/interfaces'; +import { + DynamicFormParams, + InterpreterBindingItem, + MessageReceiveDataTypeMap, + Note, + OP, + RevisionListItem +} from '@zeppelin/sdk'; +import { + MessageService, + NgZService, + NoteStatusService, + NoteVarShareService, + SecurityService, + TicketService +} from '@zeppelin/services'; + +import { scrollIntoViewIfNeeded } from '@zeppelin/utility/element'; +import { NotebookParagraphComponent } from './paragraph/paragraph.component'; + +@Component({ + selector: 'zeppelin-notebook', + templateUrl: './notebook.component.html', + styleUrls: ['./notebook.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookComponent extends MessageListenersManager implements OnInit, OnDestroy { + @ViewChildren(NotebookParagraphComponent) listOfNotebookParagraphComponent: QueryList; + private destroy$ = new Subject(); + note: Note['note']; + permissions: Permissions; + selectId: string | null = null; + scrolledId: string | null = null; + isOwner = true; + noteRevisions: RevisionListItem[] = []; + currentRevision: string; + collaborativeMode = false; + revisionView = false; + collaborativeModeUsers = []; + isNoteDirty = false; + isShowNoteForms = false; + saveTimer = null; + interpreterBindings: InterpreterBindingItem[] = []; + activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + + @MessageListener(OP.NOTE) + getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) { + const note = data.note; + if (isNil(note)) { + this.router.navigate(['/']).then(); + } else { + this.removeParagraphFromNgZ(); + this.note = note; + const { paragraphId } = this.activatedRoute.snapshot.params; + if (paragraphId) { + this.note = this.cleanParagraphExcept(paragraphId); + this.initializeLookAndFeel(); + } else { + this.initializeLookAndFeel(); + this.getInterpreterBindings(); + this.getPermissions(); + this.note.config.personalizedMode = + this.note.config.personalizedMode === undefined ? 'false' : this.note.config.personalizedMode; + } + if (this.note.noteForms && this.note.noteParams) { + this.saveNoteForms({ + formsData: { + forms: this.note.noteForms, + params: this.note.noteParams + } + }); + } + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.INTERPRETER_BINDINGS) + loadInterpreterBindings(data: MessageReceiveDataTypeMap[OP.INTERPRETER_BINDINGS]) { + this.interpreterBindings = data.interpreterBindings; + if (!this.interpreterBindings.some(item => item.selected)) { + this.activatedExtension = 'interpreter'; + } + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAGRAPH_REMOVED) + removeParagraph(data: MessageReceiveDataTypeMap[OP.PARAGRAPH_REMOVED]) { + const { paragraphId } = this.activatedRoute.snapshot.params; + if (paragraphId || this.revisionView) { + return; + } + this.note.paragraphs = this.note.paragraphs.filter(p => p.id !== data.id); + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAGRAPH_ADDED) + addParagraph(data: MessageReceiveDataTypeMap[OP.PARAGRAPH_ADDED]) { + const { paragraphId } = this.activatedRoute.snapshot.params; + if (paragraphId || this.revisionView) { + return; + } + this.note.paragraphs.splice(data.index, 0, data.paragraph).map(p => { + return { + ...p, + focus: p.id === data.paragraph.id + }; + }); + this.note.paragraphs = [...this.note.paragraphs]; + this.cdr.markForCheck(); + // TODO(hsuanxyz) focus on paragraph + } + + @MessageListener(OP.SAVE_NOTE_FORMS) + saveNoteForms(data: MessageReceiveDataTypeMap[OP.SAVE_NOTE_FORMS]) { + this.note.noteForms = data.formsData.forms; + this.note.noteParams = data.formsData.params; + this.setNoteFormsStatus(); + } + + @MessageListener(OP.NOTE_REVISION) + getNoteRevision(data: MessageReceiveDataTypeMap[OP.NOTE_REVISION]) { + const note = data.note; + if (isNil(note)) { + this.router.navigate(['/']).then(); + } else { + this.note = data.note; + this.initializeLookAndFeel(); + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.SET_NOTE_REVISION) + setNoteRevision() { + const { noteId } = this.activatedRoute.snapshot.params; + this.router.navigate(['/notebook', noteId]).then(); + } + + @MessageListener(OP.PARAGRAPH_MOVED) + moveParagraph(data: MessageReceiveDataTypeMap[OP.PARAGRAPH_MOVED]) { + if (!this.revisionView) { + const movedPara = this.note.paragraphs.find(p => p.id === data.id); + if (movedPara) { + const listOfRestPara = this.note.paragraphs.filter(p => p.id !== data.id); + this.note.paragraphs = [...listOfRestPara.slice(0, data.index), movedPara, ...listOfRestPara.slice(data.index)]; + const paragraphComponent = this.listOfNotebookParagraphComponent.find(e => e.paragraph.id === data.id); + this.cdr.markForCheck(); + if (paragraphComponent) { + // Call when next tick + setTimeout(() => { + scrollIntoViewIfNeeded(paragraphComponent.getElement()); + }); + } + } + } + } + + @MessageListener(OP.COLLABORATIVE_MODE_STATUS) + getCollaborativeModeStatus(data: MessageReceiveDataTypeMap[OP.COLLABORATIVE_MODE_STATUS]) { + this.collaborativeMode = Boolean(data.status); + this.collaborativeModeUsers = data.users; + this.cdr.markForCheck(); + } + + @MessageListener(OP.PATCH_PARAGRAPH) + patchParagraph() { + this.collaborativeMode = true; + this.cdr.markForCheck(); + } + + @MessageListener(OP.NOTE_UPDATED) + noteUpdated(data: MessageReceiveDataTypeMap[OP.NOTE_UPDATED]) { + if (data.name !== this.note.name) { + this.note.name = data.name; + } + this.note.config = data.config; + this.note.info = data.info; + this.initializeLookAndFeel(); + this.cdr.markForCheck(); + } + + @MessageListener(OP.LIST_REVISION_HISTORY) + listRevisionHistory(data: MessageReceiveDataTypeMap[OP.LIST_REVISION_HISTORY]) { + this.noteRevisions = data.revisionList; + if (this.noteRevisions) { + if (this.noteRevisions.length === 0 || this.noteRevisions[0].id !== 'Head') { + this.noteRevisions.splice(0, 0, { id: 'Head', message: 'Head' }); + } + const { revisionId } = this.activatedRoute.snapshot.params; + if (revisionId) { + this.currentRevision = this.noteRevisions.find(r => r.id === revisionId).message; + } else { + this.currentRevision = 'Head'; + } + } + this.cdr.markForCheck(); + } + + saveParagraph(id: string) { + this.listOfNotebookParagraphComponent + .toArray() + .find(p => p.paragraph.id === id) + .saveParagraph(); + } + + killSaveTimer() { + if (this.saveTimer) { + clearTimeout(this.saveTimer); + this.saveTimer = null; + } + } + + startSaveTimer() { + this.killSaveTimer(); + this.isNoteDirty = true; + this.saveTimer = setTimeout(() => { + this.saveNote(); + }, 10000); + } + + onParagraphSelect(id: string) { + this.selectId = id; + } + + onParagraphScrolled(id: string) { + this.scrolledId = id; + } + + onSelectAtIndex(index: number) { + const scopeIndex = Math.min(this.note.paragraphs.length, Math.max(0, index)); + if (this.note.paragraphs[scopeIndex]) { + this.selectId = this.note.paragraphs[scopeIndex].id; + } + } + + saveNote() { + if (this.note && this.note.paragraphs && this.listOfNotebookParagraphComponent) { + this.listOfNotebookParagraphComponent.toArray().forEach(p => { + p.saveParagraph(); + }); + this.isNoteDirty = null; + this.cdr.markForCheck(); + } + } + + getInterpreterBindings() { + this.messageService.getInterpreterBindings(this.note.id); + } + + getPermissions() { + this.securityService.getPermissions(this.note.id).subscribe(data => { + this.permissions = data; + this.isOwner = !( + this.permissions.owners.length && this.permissions.owners.indexOf(this.ticketService.ticket.principal) < 0 + ); + this.cdr.markForCheck(); + }); + } + + get viewOnly(): boolean { + return this.noteStatusService.viewOnly(this.note); + } + + initializeLookAndFeel() { + this.note.config.looknfeel = this.note.config.looknfeel || 'default'; + if (this.note.paragraphs && this.note.paragraphs[0]) { + this.note.paragraphs[0].focus = true; + } + } + + cleanParagraphExcept(paragraphId) { + const targetParagraph = this.note.paragraphs.find(p => p.id === paragraphId); + const config = targetParagraph.config || {}; + config.editorHide = true; + config.tableHide = false; + const paragraphs = [{ ...targetParagraph, config }]; + return { ...this.note, paragraphs }; + } + + setAllParagraphTableHide(tableHide: boolean) { + this.listOfNotebookParagraphComponent.forEach(p => p.setTableHide(tableHide)); + } + + setAllParagraphEditorHide(editorHide: boolean) { + this.listOfNotebookParagraphComponent.forEach(p => p.setEditorHide(editorHide)); + } + + onNoteFormChange(noteParams: DynamicFormParams) { + this.messageService.saveNoteForms({ + noteParams, + id: this.note.id + }); + } + + onFormNameRemove(formName: string) { + this.messageService.removeNoteForms(this.note, formName); + } + + onNoteTitleChange(noteFormTitle: string) { + this.messageService.updateNote(this.note.id, this.note.name, { + ...this.note.config, + noteFormTitle + }); + } + + setNoteFormsStatus() { + this.isShowNoteForms = this.note && this.note.noteForms && Object.keys(this.note.noteForms).length !== 0; + this.cdr.markForCheck(); + } + + constructor( + private activatedRoute: ActivatedRoute, + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private noteStatusService: NoteStatusService, + private noteVarShareService: NoteVarShareService, + private ticketService: TicketService, + private securityService: SecurityService, + private router: Router, + protected ngZService: NgZService + ) { + super(messageService); + } + + ngOnInit() { + this.activatedRoute.queryParamMap + .pipe( + startWith(this.activatedRoute.snapshot.queryParamMap), + takeUntil(this.destroy$), + map(data => data.get('paragraph')) + ) + .subscribe(id => { + this.onParagraphSelect(id); + this.onParagraphScrolled(id); + }); + this.activatedRoute.params + .pipe( + takeUntil(this.destroy$), + distinctUntilKeyChanged('noteId') + ) + .subscribe(() => { + this.noteVarShareService.clear(); + }); + this.activatedRoute.params.pipe(takeUntil(this.destroy$)).subscribe(param => { + const { noteId, revisionId } = param; + if (revisionId) { + this.messageService.noteRevision(noteId, revisionId); + } else { + this.messageService.getNote(noteId); + } + this.revisionView = !!revisionId; + this.cdr.markForCheck(); + this.messageService.listRevisionHistory(noteId); + // TODO(hsuanxyz) scroll to current paragraph + }); + this.revisionView = !!this.activatedRoute.snapshot.params.revisionId; + } + + removeParagraphFromNgZ(): void { + if (this.note && Array.isArray(this.note.paragraphs)) { + this.note.paragraphs.forEach(p => { + this.ngZService.removeParagraph(p.id); + }); + } + } + + ngOnDestroy(): void { + super.ngOnDestroy(); + this.killSaveTimer(); + this.saveNote(); + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts new file mode 100644 index 00000000000..49a6230e22c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -0,0 +1,100 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { PortalModule } from '@angular/cdk/portal'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'; +import { NzNoAnimationModule } from 'ng-zorro-antd/core'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzPopoverModule } from 'ng-zorro-antd/popover'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; + +import { ShareModule } from '@zeppelin/share'; + +import { NotebookAddParagraphComponent } from './add-paragraph/add-paragraph.component'; +import { NotebookInterpreterBindingComponent } from './interpreter-binding/interpreter-binding.component'; +import { NotebookParagraphCodeEditorComponent } from './paragraph/code-editor/code-editor.component'; +import { NotebookParagraphControlComponent } from './paragraph/control/control.component'; +import { NotebookParagraphFooterComponent } from './paragraph/footer/footer.component'; +import { NotebookParagraphComponent } from './paragraph/paragraph.component'; +import { NotebookParagraphProgressComponent } from './paragraph/progress/progress.component'; +import { NotebookPermissionsComponent } from './permissions/permissions.component'; +import { NotebookRevisionsComparatorComponent } from './revisions-comparator/revisions-comparator.component'; + +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { WorkspaceShareModule } from '../../workspace/share/share.module'; +import { NotebookActionBarComponent } from './action-bar/action-bar.component'; +import { NoteFormBlockComponent } from './note-form-block/note-form-block.component'; +import { NotebookRoutingModule } from './notebook-routing.module'; +import { NotebookComponent } from './notebook.component'; +import { NotebookShareModule } from './share/share.module'; + +@NgModule({ + declarations: [ + NotebookComponent, + NotebookActionBarComponent, + NotebookInterpreterBindingComponent, + NotebookPermissionsComponent, + NotebookRevisionsComparatorComponent, + NotebookParagraphComponent, + NotebookAddParagraphComponent, + NotebookParagraphCodeEditorComponent, + NotebookParagraphProgressComponent, + NotebookParagraphFooterComponent, + NotebookParagraphControlComponent, + NoteFormBlockComponent + ], + imports: [ + CommonModule, + PortalModule, + WorkspaceShareModule, + NotebookRoutingModule, + ShareModule, + NotebookShareModule, + NzButtonModule, + NzIconModule, + NzDropDownModule, + NzNoAnimationModule, + NzToolTipModule, + NzPopconfirmModule, + NzFormModule, + NzPopoverModule, + NzInputModule, + FormsModule, + ReactiveFormsModule, + NzDividerModule, + NzProgressModule, + NzSwitchModule, + NzSelectModule, + NzGridModule, + NzRadioModule, + DragDropModule, + NzCodeEditorModule, + NzCheckboxModule + ] +}) +export class NotebookModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html new file mode 100644 index 00000000000..d543e670d49 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html @@ -0,0 +1,17 @@ + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less new file mode 100644 index 00000000000..8f61bd5b93f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +:host { + display: block; +} + +.themeMixin({ + + zeppelin-code-editor { + display: block; + border-left: 4px solid @border-color-split; + overflow: hidden; + + &.dirty { + border-left-color: @warning-color; + } + + &.focused:not(.dirty) { + border-left-color: @primary-color; + } + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts new file mode 100644 index 00000000000..99cc97d14b6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -0,0 +1,232 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + NgZone, + OnChanges, + OnDestroy, + Output, + SimpleChanges +} from '@angular/core'; + +import { editor as MonacoEditor, IDisposable } from 'monaco-editor'; +import IStandaloneCodeEditor = MonacoEditor.IStandaloneCodeEditor; +import IEditor = monaco.editor.IEditor; + +import { InterpreterBindingItem } from '@zeppelin/sdk'; +import { CompletionService, MessageService } from '@zeppelin/services'; + +import { pt2px } from '@zeppelin/utility/css-unit-conversion'; +import { NotebookParagraphControlComponent } from '../control/control.component'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-code-editor', + templateUrl: './code-editor.component.html', + styleUrls: ['./code-editor.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestroy, AfterViewInit { + // TODO(hsuanxyz): + // 1. cursor position + @Input() readOnly = false; + @Input() language = 'text'; + @Input() paragraphControl: NotebookParagraphControlComponent; + @Input() lineNumbers = false; + @Input() focus = false; + @Input() collaborativeMode = false; + @Input() text: string; + @Input() fontSize: number; + @Input() dirty = false; + @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Input() pid: string; + @Output() readonly textChanged = new EventEmitter(); + @Output() readonly editorBlur = new EventEmitter(); + @Output() readonly editorFocus = new EventEmitter(); + private editor: IStandaloneCodeEditor; + private monacoDisposables: IDisposable[] = []; + height = 0; + interpreterName: string; + + autoAdjustEditorHeight() { + if (this.editor) { + this.ngZone.run(() => { + this.height = + this.editor.getTopForLineNumber(Number.MAX_SAFE_INTEGER) + this.editor.getConfiguration().lineHeight * 2; + this.editor.layout(); + this.cdr.markForCheck(); + }); + } + } + + initEditorListener() { + const editor = this.editor; + this.monacoDisposables.push( + editor.onDidFocusEditorText(() => { + this.editorFocus.emit(); + }), + editor.onDidBlurEditorText(() => { + this.editorBlur.emit(); + }), + + editor.onDidChangeModelContent(() => { + this.ngZone.run(() => { + this.text = editor.getModel().getValue(); + this.textChanged.emit(this.text); + this.setParagraphMode(true); + this.autoAdjustEditorHeight(); + setTimeout(() => { + this.autoAdjustEditorHeight(); + }); + }); + }) + ); + } + + setEditorValue() { + if (this.editor && this.editor.getModel() && this.editor.getModel().getValue() !== this.text) { + this.editor.getModel().setValue(this.text || ''); + } + } + + initializedEditor(editor: IEditor) { + this.editor = editor as IStandaloneCodeEditor; + this.editor.addCommand( + monaco.KeyCode.Escape, + () => { + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + }, + '!suggestWidgetVisible' + ); + + this.updateEditorOptions(); + this.setParagraphMode(); + this.initEditorListener(); + this.initEditorFocus(); + this.initCompletionService(); + this.setEditorValue(); + setTimeout(() => { + this.autoAdjustEditorHeight(); + }); + } + + initCompletionService(): void { + this.completionService.registerAsCompletionReceiver(this.editor.getModel(), this.paragraphControl.pid); + } + + initEditorFocus() { + if (this.focus && this.editor) { + this.editor.focus(); + } + } + + updateEditorOptions() { + if (this.editor) { + this.editor.updateOptions({ + readOnly: this.readOnly, + fontSize: pt2px(this.fontSize), + renderLineHighlight: this.focus ? 'all' : 'none', + minimap: { enabled: false }, + lineNumbers: this.lineNumbers ? 'on' : 'off', + glyphMargin: false, + folding: false, + scrollBeyondLastLine: false, + contextmenu: false, + matchBrackets: false + }); + } + } + + getInterpreterName(paragraphText: string) { + const match = /^\s*%(.+?)(\s|\()/g.exec(paragraphText); + if (match) { + return match[1].trim(); + // get default interpreter name if paragraph text doesn't start with '%' + // TODO(hsuanxyz): dig into the cause what makes interpreterBindings to have no element + } else if (this.interpreterBindings && this.interpreterBindings.length !== 0) { + return this.interpreterBindings[0].name; + } + return ''; + } + + setParagraphMode(changed = false) { + if (this.editor && !changed) { + const model = this.editor.getModel(); + if (this.language) { + // TODO(hsuanxyz): config convertMap + const convertMap = { + sh: 'shell' + }; + monaco.editor.setModelLanguage(model, convertMap[this.language] || this.language); + } + } else { + const interpreterName = this.getInterpreterName(this.text); + if (this.interpreterName !== interpreterName) { + this.interpreterName = interpreterName; + this.getEditorSetting(interpreterName); + } + } + } + + getEditorSetting(interpreterName: string) { + this.messageService.editorSetting(this.pid, interpreterName); + } + + layout() { + if (this.editor) { + setTimeout(() => { + this.editor.layout(); + }); + } + } + + constructor( + private cdr: ChangeDetectorRef, + private ngZone: NgZone, + private messageService: MessageService, + private completionService: CompletionService + ) {} + + ngOnChanges(changes: SimpleChanges): void { + const { text, interpreterBindings, language, readOnly, focus, lineNumbers, fontSize } = changes; + if (readOnly || focus || lineNumbers || fontSize) { + this.updateEditorOptions(); + } + if (focus) { + this.initEditorFocus(); + } + if (text) { + this.setEditorValue(); + } + + if (interpreterBindings || language) { + this.setParagraphMode(); + } + if (text || fontSize) { + this.autoAdjustEditorHeight(); + } + } + + ngOnDestroy(): void { + this.completionService.unregister(this.editor.getModel()); + this.monacoDisposables.forEach(d => d.dispose()); + } + + ngAfterViewInit(): void {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html new file mode 100644 index 00000000000..5ec5f52fccf --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html @@ -0,0 +1,85 @@ + + + +
    {{status}}
    +
    {{progress}}%
    + + + + + + + + + + + + + + + +
      +
    • + {{ pid }} +
    • +
    • +
    • + Run on selection change + +
    • +
    • + Width + + + +
    • +
    • + Font size + + + +
    • + +
    • + + {{menu.label}} + {{menu.shortCut}} +
    • +
      +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less new file mode 100644 index 00000000000..700a6b666e8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less @@ -0,0 +1,73 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +:host { + display: flex; +} + +.list-item { + display: flex; + justify-content: space-between; +} + +.setting-menu { + width: 270px; + + li { + font-size: 12px; + + i { + margin-right: 6px; + } + } +} + +.short-cut { + opacity: 0.7; +} + +.paragraph-id { + text-align: center; +} + +.themeMixin({ + .job-link { + margin-right: 12px; + + a { + color: @link-color; + } + } + .status { + color: @text-color-secondary; + margin-right: 12px; + } + .progress { + color: @text-color-secondary; + margin-right: 12px; + } + + a { + margin-left: 8px; + color: @text-color-secondary; + + .run-para { + color: @primary-color; + } + + .cancel-para { + color: @warning-color; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts new file mode 100644 index 00000000000..846a46de1b9 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -0,0 +1,279 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output +} from '@angular/core'; +import { copyTextToClipboard } from '@zeppelin/core'; + +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { ActivatedRoute } from '@angular/router'; +import { RuntimeInfos } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-control', + exportAs: 'paragraphControl', + templateUrl: './control.component.html', + styleUrls: ['./control.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphControlComponent implements OnInit, OnChanges { + @Input() status: string; + @Input() progress = 0; + @Input() revisionView = false; + @Input() enabled = true; + @Input() pid: string; + @Input() tableHide = false; + @Input() editorHide = false; + @Input() colWidth: number; + @Input() fontSize: number; + @Input() runOnSelectionChange = true; + @Input() isEntireNoteRunning = true; + @Input() runtimeInfos: RuntimeInfos; + @Input() colWidthOption = []; + @Input() first = false; + @Input() last = false; + @Input() title = false; + @Input() lineNumbers = false; + @Input() paragraphLength: number; + @Output() readonly colWidthChange = new EventEmitter(); + @Output() readonly titleChange = new EventEmitter(); + @Output() readonly enabledChange = new EventEmitter(); + @Output() readonly fontSizeChange = new EventEmitter(); + @Output() readonly tableHideChange = new EventEmitter(); + @Output() readonly runParagraph = new EventEmitter(); + @Output() readonly lineNumbersChange = new EventEmitter(); + @Output() readonly cancelParagraph = new EventEmitter(); + @Output() readonly editorHideChange = new EventEmitter(); + @Output() readonly runOnSelectionChangeChange = new EventEmitter(); + @Output() readonly moveUp = new EventEmitter(); + @Output() readonly moveDown = new EventEmitter(); + @Output() readonly insertNew = new EventEmitter(); + @Output() readonly runAllAbove = new EventEmitter(); + @Output() readonly runAllBelowAndCurrent = new EventEmitter(); + @Output() readonly cloneParagraph = new EventEmitter(); + @Output() readonly removeParagraph = new EventEmitter(); + @Output() readonly openSingleParagraph = new EventEmitter(); + fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + dropdownVisible = false; + isMac = navigator.appVersion.indexOf('Mac') !== -1; + listOfMenu: Array<{ + label: string; + show: boolean; + disabled: boolean; + icon: string; + shortCut: string; + trigger(): void; + }> = []; + + updateListOfMenu() { + this.listOfMenu = [ + { + label: 'Run', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'play-circle', + trigger: () => this.trigger(this.runParagraph), + shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + }, + { + label: 'Run all above', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'up-square', + trigger: () => this.trigger(this.runAllAbove), + shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + }, + { + label: 'Run all below', + show: !this.last, + disabled: this.isEntireNoteRunning, + icon: 'down-square', + trigger: () => this.trigger(this.runAllBelowAndCurrent), + shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + }, + { + label: 'Link this paragraph', + show: true, + disabled: false, + icon: 'export', + trigger: () => { + this.openSingleParagraph.emit(this.pid); + }, + shortCut: this.isMac ? '⌥+⌘+T' : 'Alt+Ctrl+T' + }, + { + label: 'Clear output', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'fire', + trigger: () => this.clearParagraphOutput(), + shortCut: this.isMac ? '⌥+⌘+L' : 'Alt+Ctrl+L' + }, + { + label: 'Remove', + show: this.paragraphLength > 1, + disabled: this.isEntireNoteRunning, + icon: 'delete', + trigger: () => this.onRemoveParagraph(), + shortCut: this.isMac ? '⇧+Del (Command)' : 'Shift+Del (Command)' + }, + { + label: 'Move up', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'up', + trigger: () => this.trigger(this.moveUp), + shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+K (Command)` + }, + { + label: 'Move down', + show: !this.last, + disabled: this.isEntireNoteRunning, + icon: 'down', + trigger: () => this.trigger(this.moveDown), + shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+J (Command)` + }, + { + label: 'Insert new', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'plus', + trigger: () => this.trigger(this.insertNew), + shortCut: `B (Command)` + }, + { + label: 'Clone paragraph', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'copy', + trigger: () => this.trigger(this.cloneParagraph), + shortCut: `C (Command)` + }, + { + label: this.title ? 'Hide Title' : 'Show Title', + show: true, + disabled: false, + icon: 'font-colors', + trigger: () => this.toggleTitle(), + shortCut: `T (Command)` + }, + { + label: this.lineNumbers ? 'Hide line numbers' : 'Show line numbers', + show: true, + disabled: false, + icon: 'ordered-list', + trigger: () => this.toggleLineNumbers(), + shortCut: `L (Command)` + }, + { + label: this.enabled ? 'Disable run' : 'Enable run', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'api', + trigger: () => this.toggleEnabled(), + shortCut: `R (Command)` + } + ]; + } + + toggleEditor() { + this.editorHide = !this.editorHide; + this.editorHideChange.emit(this.editorHide); + } + + toggleOutput() { + this.tableHide = !this.tableHide; + this.tableHideChange.emit(this.tableHide); + } + + toggleRunOnSelectionChange() { + this.runOnSelectionChange = !this.runOnSelectionChange; + this.runOnSelectionChangeChange.emit(this.runOnSelectionChange); + } + + toggleTitle() { + this.title = !this.title; + this.titleChange.emit(this.title); + } + + toggleLineNumbers() { + this.lineNumbers = !this.lineNumbers; + this.lineNumbersChange.emit(this.lineNumbers); + } + + toggleEnabled() { + if (!this.isEntireNoteRunning) { + this.enabled = !this.enabled; + this.enabledChange.emit(this.enabled); + } + } + + changeColWidth(colWidth: number) { + this.colWidth = +colWidth; + this.colWidthChange.emit(this.colWidth); + this.dropdownVisible = false; + } + + changeFontSize(fontSize: number) { + this.fontSize = +fontSize; + this.fontSizeChange.emit(this.fontSize); + } + + copyClipboard(id: string) { + copyTextToClipboard(id); + this.nzMessageService.info('Paragraph id copied'); + } + + clearParagraphOutput() { + if (!this.isEntireNoteRunning) { + this.messageService.paragraphClearOutput(this.pid); + } + } + + onRemoveParagraph() { + this.removeParagraph.emit(); + } + + trigger(event: EventEmitter) { + if (!this.isEntireNoteRunning) { + this.dropdownVisible = false; + event.emit(); + } + } + + constructor( + private cdr: ChangeDetectorRef, + private nzMessageService: NzMessageService, + private activatedRoute: ActivatedRoute, + private messageService: MessageService + ) {} + + ngOnInit() { + this.updateListOfMenu(); + } + + ngOnChanges(): void { + this.updateListOfMenu(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html new file mode 100644 index 00000000000..677356b1d5d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html @@ -0,0 +1,16 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less new file mode 100644 index 00000000000..767a5491765 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .footer { + color: @text-color-secondary; + font-size: 12px; + margin-top: 12px; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts new file mode 100644 index 00000000000..1be51ca9c31 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts @@ -0,0 +1,74 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; + +import * as distanceInWordsStrict from 'date-fns/distance_in_words_strict'; +import * as distanceInWordsToNow from 'date-fns/distance_in_words_to_now'; +import * as format from 'date-fns/format'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphFooterComponent implements OnChanges { + @Input() dateStarted: string; + @Input() dateFinished: string; + @Input() dateUpdated: string; + @Input() showExecutionTime = false; + @Input() showElapsedTime = false; + @Input() user: string; + executionTime: string; + elapsedTime: string; + + isResultOutdated() { + return this.dateUpdated !== undefined && Date.parse(this.dateUpdated) > Date.parse(this.dateStarted); + } + + getExecutionTime() { + const end = this.dateFinished; + const start = this.dateStarted; + const timeMs = Date.parse(end) - Date.parse(start); + if (isNaN(timeMs) || timeMs < 0) { + if (this.isResultOutdated()) { + return 'outdated'; + } + return ''; + } + + const durationFormat = distanceInWordsStrict(start, end); + const endFormat = format(this.dateFinished, 'MMMM DD YYYY, h:mm:ss A'); + + const user = this.user === undefined || this.user === null ? 'anonymous' : this.user; + let desc = `Took ${durationFormat}. Last updated by ${user} at ${endFormat}.`; + + if (this.isResultOutdated()) { + desc += ' (outdated)'; + } + + return desc; + } + + getElapsedTime() { + // TODO(hsuanxyz) dateStarted undefined after start + return `Started ${distanceInWordsToNow(this.dateStarted || new Date())} ago.`; + } + + constructor() {} + + ngOnChanges() { + this.executionTime = this.getExecutionTime(); + this.elapsedTime = this.getElapsedTime(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html new file mode 100644 index 00000000000..e2866272e97 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -0,0 +1,105 @@ + + +
    + +
    + + + + + + + + + + + +
    + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less new file mode 100644 index 00000000000..60cc5ac3b19 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less @@ -0,0 +1,77 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +:host { + display: block; + padding: 0 4px; +} + +.themeMixin({ + + .paragraph { + background: @component-background; + border: 1px solid @border-color-split; + box-shadow: @card-shadow; + padding: 32px 12px 12px 12px; + position: relative; + + &.focused { + box-shadow: 0 0 5px rgba(0, 0, 0, 0.46); + } + + zeppelin-notebook-paragraph-code-editor + zeppelin-notebook-paragraph-dynamic-forms { + margin-top: 24px; + } + + zeppelin-notebook-paragraph-progress + zeppelin-notebook-paragraph-dynamic-forms { + margin-top: 24px; + } + + &.simple { + box-shadow: none; + border-color: transparent; + + zeppelin-notebook-paragraph-control, zeppelin-notebook-paragraph-footer { + visibility: hidden; + } + + &:hover { + border: 1px solid @border-color-split; + box-shadow: @card-shadow; + + zeppelin-notebook-paragraph-control, zeppelin-notebook-paragraph-footer { + visibility: visible; + } + } + } + + &.report { + &:hover { + box-shadow: none; + border-color: transparent; + + zeppelin-notebook-paragraph-control, zeppelin-notebook-paragraph-footer { + visibility: hidden; + } + } + } + + zeppelin-notebook-paragraph-control { + position: absolute; + right: 12px; + top: 8px; + z-index: 10; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts new file mode 100644 index 00000000000..3afdea13f6d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -0,0 +1,647 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + QueryList, + SimpleChanges, + ViewChild, + ViewChildren +} from '@angular/core'; +import { merge, Observable, Subject } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; + +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { ParagraphBase } from '@zeppelin/core'; +import { InterpreterBindingItem, Note, ParagraphConfigResult, ParagraphItem } from '@zeppelin/sdk'; +import { + HeliumService, + MessageService, + NgZService, + NoteStatusService, + NoteVarShareService, + ParagraphActions, + ShortcutsMap, + ShortcutService +} from '@zeppelin/services'; +import { SpellResult } from '@zeppelin/spell/spell-result'; + +import { NgTemplateAdapterService } from '@zeppelin/services/ng-template-adapter.service'; +import { NzResizeEvent } from 'ng-zorro-antd/resizable'; +import { NotebookParagraphResultComponent } from '../../share/result/result.component'; +import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component'; + +type Mode = 'edit' | 'command'; + +@Component({ + selector: 'zeppelin-notebook-paragraph', + templateUrl: './paragraph.component.html', + styleUrls: ['./paragraph.component.less'], + host: { + tabindex: '-1', + '(focusin)': 'onFocus()' + }, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphComponent extends ParagraphBase implements OnInit, OnChanges, OnDestroy, AfterViewInit { + @ViewChild(NotebookParagraphCodeEditorComponent, { static: false }) + notebookParagraphCodeEditorComponent: NotebookParagraphCodeEditorComponent; + @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList< + NotebookParagraphResultComponent + >; + @Input() paragraph: ParagraphItem; + @Input() note: Note['note']; + @Input() looknfeel: string; + @Input() revisionView: boolean; + @Input() select: boolean = false; + @Input() scrolled: boolean = false; + @Input() index: number = -1; + @Input() viewOnly: boolean; + @Input() last: boolean; + @Input() collaborativeMode = false; + @Input() first: boolean; + @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Output() readonly saveNoteTimer = new EventEmitter(); + @Output() readonly triggerSaveParagraph = new EventEmitter(); + @Output() readonly selected = new EventEmitter(); + @Output() readonly selectAtIndex = new EventEmitter(); + + private destroy$ = new Subject(); + private mode: Mode = 'command'; + waitConfirmFromEdit = false; + + switchMode(mode: Mode): void { + if (mode === this.mode) { + return; + } + this.mode = mode; + if (mode === 'edit') { + this.focusEditor(); + } else { + this.blurEditor(); + } + } + + textChanged(text: string) { + this.dirtyText = text; + this.paragraph.text = text; + if (this.dirtyText !== this.originalText) { + if (this.collaborativeMode) { + this.sendPatch(); + } else { + this.startSaveTimer(); + } + } + } + + sendPatch() { + this.originalText = this.originalText ? this.originalText : ''; + const patch = this.diffMatchPatch.patch_make(this.originalText, this.dirtyText).toString(); + this.originalText = this.dirtyText; + this.messageService.patchParagraph(this.paragraph.id, this.note.id, patch); + } + + startSaveTimer() { + this.saveNoteTimer.emit(); + } + + onFocus() { + this.selected.emit(this.paragraph.id); + } + + focusEditor() { + this.paragraph.focus = true; + this.saveParagraph(); + this.cdr.markForCheck(); + } + + blurEditor() { + this.paragraph.focus = false; + (this.host.nativeElement as HTMLElement).focus(); + this.saveParagraph(); + this.cdr.markForCheck(); + } + + onEditorFocus() { + this.switchMode('edit'); + } + + onEditorBlur() { + // Ignore events triggered by open the confirm box in edit mode + if (!this.waitConfirmFromEdit) { + this.switchMode('command'); + } + } + + saveParagraph() { + const dirtyText = this.paragraph.text; + if (dirtyText === undefined || dirtyText === this.originalText) { + return; + } + this.commitParagraph(); + this.originalText = dirtyText; + this.dirtyText = undefined; + this.cdr.markForCheck(); + } + + removeParagraph() { + if (!this.isEntireNoteRunning) { + if (this.note.paragraphs.length === 1) { + this.nzModalService.warning({ + nzTitle: `Warning`, + nzContent: `All the paragraphs can't be deleted` + }); + } else { + this.nzModalService.confirm({ + nzTitle: 'Delete Paragraph', + nzContent: 'Do you want to delete this paragraph?', + nzOnOk: () => { + this.messageService.paragraphRemove(this.paragraph.id); + this.cdr.markForCheck(); + // TODO(hsuanxyz) moveFocusToNextParagraph + } + }); + } + } + } + + runAllAbove() { + const index = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id); + const toRunParagraphs = this.note.paragraphs.filter((p, i) => i < index); + + const paragraphs = toRunParagraphs.map(p => { + return { + id: p.id, + title: p.title, + paragraph: p.text, + config: p.config, + params: p.settings.params + }; + }); + this.nzModalService.confirm({ + nzTitle: 'Run all above?', + nzContent: 'Are you sure to run all above paragraphs?', + nzOnOk: () => { + this.messageService.runAllParagraphs(this.note.id, paragraphs); + } + }); + // TODO(hsuanxyz): save cursor + } + + doubleClickParagraph() { + if (this.paragraph.config.editorSetting.editOnDblClick && this.revisionView !== true) { + this.paragraph.config.editorHide = false; + this.paragraph.config.tableHide = true; + // TODO(hsuanxyz): focus editor + } + } + + runAllBelowAndCurrent() { + const index = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id); + const toRunParagraphs = this.note.paragraphs.filter((p, i) => i >= index); + + const paragraphs = toRunParagraphs.map(p => { + return { + id: p.id, + title: p.title, + paragraph: p.text, + config: p.config, + params: p.settings.params + }; + }); + this.nzModalService + .confirm({ + nzTitle: 'Run current and all below?', + nzContent: 'Are you sure to run current and all below?', + nzOnOk: () => { + this.messageService.runAllParagraphs(this.note.id, paragraphs); + } + }) + .afterClose.pipe(takeUntil(this.destroy$)) + .subscribe(() => { + this.waitConfirmFromEdit = false; + }); + // TODO(hsuanxyz): save cursor + } + + cloneParagraph(position: string = 'below', newText?: string) { + let newIndex = -1; + for (let i = 0; i < this.note.paragraphs.length; i++) { + if (this.note.paragraphs[i].id === this.paragraph.id) { + // determine position of where to add new paragraph; default is below + if (position === 'above') { + newIndex = i; + } else { + newIndex = i + 1; + } + break; + } + } + + if (newIndex < 0 || newIndex > this.note.paragraphs.length) { + return; + } + + const config = this.paragraph.config; + config.editorHide = false; + + this.messageService.copyParagraph( + newIndex, + this.paragraph.title, + newText || this.paragraph.text, + config, + this.paragraph.settings.params + ); + } + + runParagraphAfter(text: string) { + this.originalText = text; + this.dirtyText = undefined; + + if (this.paragraph.config.editorSetting.editOnDblClick) { + this.paragraph.config.editorHide = true; + this.paragraph.config.tableHide = false; + this.commitParagraph(); + } else if (this.editorSetting.isOutputHidden && !this.paragraph.config.editorSetting.editOnDblClick) { + // %md/%angular repl make output to be hidden by default after running + // so should open output if repl changed from %md/%angular to another + this.paragraph.config.editorHide = false; + this.paragraph.config.tableHide = false; + this.commitParagraph(); + } + this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick; + } + + runParagraph(paragraphText?: string, propagated: boolean = false) { + const text = paragraphText || this.paragraph.text; + if (text && !this.isParagraphRunning) { + const magic = SpellResult.extractMagic(text); + + if (this.heliumService.getSpellByMagic(magic)) { + this.runParagraphUsingSpell(text, magic, propagated); + this.runParagraphAfter(text); + } else { + const check = this.ngTemplateAdapterService.preCheck(text); + if (!check) { + this.runParagraphUsingBackendInterpreter(text); + this.runParagraphAfter(text); + } else { + this.waitConfirmFromEdit = true; + this.nzModalService + .confirm({ + nzTitle: 'Do you want to migrate the Angular.js template?', + nzContent: + 'The Angular.js template has been deprecated, please upgrade to Angular template.' + + ' (more info)', + nzOnOk: () => { + this.switchMode('command'); + this.ngTemplateAdapterService + .openMigrationDialog(check) + .pipe(takeUntil(this.destroy$)) + .subscribe(newText => { + this.cloneParagraph('below', newText); + }); + } + }) + .afterClose.pipe(takeUntil(this.destroy$)) + .subscribe(() => (this.waitConfirmFromEdit = false)); + } + } + } + } + + insertParagraph(position: string) { + if (this.revisionView === true) { + return; + } + let newIndex = -1; + for (let i = 0; i < this.note.paragraphs.length; i++) { + if (this.note.paragraphs[i].id === this.paragraph.id) { + // determine position of where to add new paragraph; default is below + if (position === 'above') { + newIndex = i; + } else { + newIndex = i + 1; + } + break; + } + } + + if (newIndex < 0 || newIndex > this.note.paragraphs.length) { + return; + } + this.messageService.insertParagraph(newIndex); + this.cdr.markForCheck(); + } + + setTitle(title: string) { + this.paragraph.title = title; + this.commitParagraph(); + } + + commitParagraph() { + const { + id, + title, + text, + config, + settings: { params } + } = this.paragraph; + this.messageService.commitParagraph(id, title, text, config, params, this.note.id); + this.cdr.markForCheck(); + } + + moveUpParagraph() { + const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1; + if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { + return; + } + // save dirtyText of moving paragraphs. + const prevParagraph = this.note.paragraphs[newIndex]; + // TODO(hsuanxyz): save pre paragraph? + this.saveParagraph(); + this.triggerSaveParagraph.emit(prevParagraph.id); + this.messageService.moveParagraph(this.paragraph.id, newIndex); + } + + moveDownParagraph() { + const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) + 1; + if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { + return; + } + // save dirtyText of moving paragraphs. + const nextParagraph = this.note.paragraphs[newIndex]; + // TODO(hsuanxyz): save pre paragraph? + this.saveParagraph(); + this.triggerSaveParagraph.emit(nextParagraph.id); + this.messageService.moveParagraph(this.paragraph.id, newIndex); + } + + changeColWidth(needCommit: boolean, updateResult = true) { + if (needCommit) { + this.commitParagraph(); + } + if (this.notebookParagraphCodeEditorComponent) { + this.notebookParagraphCodeEditorComponent.layout(); + } + + if (updateResult) { + this.notebookParagraphResultComponents.forEach(comp => { + comp.setGraphConfig(); + }); + } + } + + onSizeChange(resize: NzResizeEvent) { + this.paragraph.config.colWidth = resize.col; + this.changeColWidth(true, false); + this.cdr.markForCheck(); + } + + onConfigChange(configResult: ParagraphConfigResult, index: number) { + this.paragraph.config.results[index] = configResult; + this.commitParagraph(); + } + + setEditorHide(editorHide: boolean) { + this.paragraph.config.editorHide = editorHide; + this.cdr.markForCheck(); + } + + setTableHide(tableHide: boolean) { + this.paragraph.config.tableHide = tableHide; + this.cdr.markForCheck(); + } + + openSingleParagraph(paragraphId: string): void { + const noteId = this.note.id; + const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${paragraphId}`; + window.open(redirectToUrl); + } + + trackByIndexFn(index: number) { + return index; + } + + constructor( + noteStatusService: NoteStatusService, + cdr: ChangeDetectorRef, + ngZService: NgZService, + private heliumService: HeliumService, + public messageService: MessageService, + private nzModalService: NzModalService, + private noteVarShareService: NoteVarShareService, + private shortcutService: ShortcutService, + private host: ElementRef, + private ngTemplateAdapterService: NgTemplateAdapterService + ) { + super(messageService, noteStatusService, ngZService, cdr); + } + + ngOnInit() { + const shortcutService = this.shortcutService.forkByElement(this.host.nativeElement); + const observables: Array< + Observable<{ + action: ParagraphActions; + event: KeyboardEvent; + }> + > = []; + Object.entries(ShortcutsMap).forEach(([action, keys]) => { + const keysArr: string[] = Array.isArray(keys) ? keys : [keys]; + keysArr.forEach(key => { + observables.push( + shortcutService + .bindShortcut({ + keybindings: key + }) + .pipe( + takeUntil(this.destroy$), + map(({ event }) => { + return { + event, + action: action as ParagraphActions + }; + }) + ) + ); + }); + }); + + merge<{ + action: ParagraphActions; + event: KeyboardEvent; + }>(...observables) + .pipe(takeUntil(this.destroy$)) + .subscribe(({ action, event }) => { + if (this.mode === 'command') { + switch (action) { + case ParagraphActions.InsertAbove: + this.insertParagraph('above'); + break; + case ParagraphActions.InsertBelow: + this.insertParagraph('below'); + break; + case ParagraphActions.SwitchEditorShow: + this.setEditorHide(!this.paragraph.config.editorHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchOutputShow: + this.setTableHide(!this.paragraph.config.tableHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchTitleShow: + this.paragraph.config.title = !this.paragraph.config.title; + this.commitParagraph(); + break; + case ParagraphActions.SwitchLineNumber: + this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers; + this.commitParagraph(); + break; + case ParagraphActions.MoveToUp: + event.preventDefault(); + this.moveUpParagraph(); + break; + case ParagraphActions.MoveToDown: + event.preventDefault(); + this.moveDownParagraph(); + break; + case ParagraphActions.SwitchEnable: + this.paragraph.config.enabled = !this.paragraph.config.enabled; + this.commitParagraph(); + break; + case ParagraphActions.ReduceWidth: + this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.IncreaseWidth: + this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.Delete: + this.removeParagraph(); + break; + case ParagraphActions.SelectAbove: + event.preventDefault(); + this.selectAtIndex.emit(this.index - 1); + break; + case ParagraphActions.SelectBelow: + event.preventDefault(); + this.selectAtIndex.emit(this.index + 1); + break; + default: + break; + } + } + switch (action) { + case ParagraphActions.Link: + this.openSingleParagraph(this.paragraph.id); + break; + case ParagraphActions.EditMode: + if (this.mode === 'command') { + event.preventDefault(); + } + if (!this.paragraph.config.editorHide) { + this.switchMode('edit'); + } + break; + case ParagraphActions.Run: + event.preventDefault(); + this.runParagraph(); + break; + case ParagraphActions.RunBelow: + this.waitConfirmFromEdit = true; + this.runAllBelowAndCurrent(); + break; + case ParagraphActions.Cancel: + event.preventDefault(); + this.cancelParagraph(); + break; + default: + break; + } + }); + this.setResults(); + this.originalText = this.paragraph.text; + this.isEntireNoteRunning = this.noteStatusService.isEntireNoteRunning(this.note); + this.isParagraphRunning = this.noteStatusService.isParagraphRunning(this.paragraph); + this.noteVarShareService.set(this.paragraph.id + '_paragraphScope', this); + this.initializeDefault(this.paragraph.config); + this.ngZService + .runParagraphAction() + .pipe(takeUntil(this.destroy$)) + .subscribe(id => { + if (id === this.paragraph.id) { + this.runParagraph(); + } + }); + this.ngZService + .contextChanged() + .pipe(takeUntil(this.destroy$)) + .subscribe(change => { + if (change.paragraphId === this.paragraph.id && change.emit) { + if (change.set) { + this.messageService.angularObjectClientBind(this.note.id, change.key, change.value, change.paragraphId); + } else { + this.messageService.angularObjectClientUnbind(this.note.id, change.key, change.paragraphId); + } + } + }); + } + + scrollIfNeeded(): void { + if (this.scrolled && this.host.nativeElement) { + setTimeout(() => { + this.host.nativeElement.scrollIntoView(); + }); + } + } + ngOnChanges(changes: SimpleChanges): void { + const { index, select, scrolled } = changes; + if ( + (index && index.currentValue !== index.previousValue && this.select) || + (select && select.currentValue === true && select.previousValue !== true) + ) { + setTimeout(() => { + if (this.mode === 'command' && this.host.nativeElement) { + (this.host.nativeElement as HTMLElement).focus(); + } + }); + } + if (scrolled) { + this.scrollIfNeeded(); + } + } + + getElement(): HTMLElement { + return this.host && this.host.nativeElement; + } + ngAfterViewInit(): void { + this.scrollIfNeeded(); + } + + ngOnDestroy(): void { + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html new file mode 100644 index 00000000000..07c886a22d0 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html @@ -0,0 +1,16 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts new file mode 100644 index 00000000000..ce205a0ad59 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-progress', + templateUrl: './progress.component.html', + styleUrls: ['./progress.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphProgressComponent implements OnChanges { + @Input() progress = 0; + displayProgress = 0; + + ngOnChanges(): void { + if (this.progress > 0 && this.progress < 100) { + this.displayProgress = this.progress; + } else { + this.displayProgress = 100; + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html new file mode 100644 index 00000000000..c3e699d4aef --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html @@ -0,0 +1,88 @@ + + +
    +
    +

    Note Permissions (Only note owners can change)

    +
    + +
    +

    + Enter comma separated users and groups in the fields.
    + Empty field (*) implies anyone can do the operation. +

    +
    +
    +
    + + Owners + + + + + + + + + + Owners can change permissions,read, run and write the note. + + + + Writers + + + + + + + + + + Writers can read, run and write the note. + + + + Runners + + + + + + + + + + Runners can read and run the note. + + + + Readers + + + + + + + + + + Readers can only read the note. + + +
    +
    + + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less new file mode 100644 index 00000000000..146cd37f4af --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .permissions-form { + background: @layout-body-background; + padding: 12px; + margin-bottom: 12px; + } + nz-form-item { + margin-bottom: 12px; + + &:last-child { + margin-bottom: 0; + } + } + .submit-permissions { + button { + margin-right: 12px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts new file mode 100644 index 00000000000..6ceaaeb5951 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts @@ -0,0 +1,136 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output +} from '@angular/core'; + +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { Permissions } from '@zeppelin/interfaces'; +import { SecurityService, TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-permissions', + templateUrl: './permissions.component.html', + styleUrls: ['./permissions.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookPermissionsComponent implements OnInit, OnChanges { + @Input() permissions: Permissions; + @Input() noteId: string; + @Input() activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + @Output() readonly activatedExtensionChange = new EventEmitter< + 'interpreter' | 'permissions' | 'revisions' | 'hide' + >(); + permissionsBack: Permissions; + listOfUserAndRole = []; + + savePermissions() { + const principal = this.ticketService.ticket.principal; + const isAnonymous = principal === 'anonymous'; + if (isAnonymous || this.ticketService.ticket.principal.trim().length === 0) { + this.blockAnonUsers(); + } + if (this.isOwnerEmpty()) { + this.nzModalService.create({ + nzTitle: 'Setting Owners Permissions', + nzContent: `Please fill the [Owners] field. If not, it will set as current user. Current user : [ ${this.ticketService.ticket.principal.trim()} ]`, + nzOnOk: () => { + this.permissions.owners = [this.ticketService.ticket.principal]; + this.setPermissions(); + }, + nzOnCancel: () => { + this.resetPermissions(); + } + }); + } else { + this.setPermissions(); + } + } + + closePermissions() { + this.activatedExtension = 'hide'; + this.activatedExtensionChange.emit('hide'); + } + + blockAnonUsers() { + this.nzModalService.create({ + nzTitle: 'No permission', + nzContent: 'Only authenticated user can set the permission.', + nzOkText: 'Read Doc', + nzOnOk: () => { + const url = `https://zeppelin.apache.org/docs/${this.ticketService.version}/security/notebook_authorization.html`; + window.open(url); + } + }); + } + + setPermissions() { + this.securityService.setPermissions(this.noteId, this.permissions).subscribe(() => { + this.nzMessageService.success('Permissions Saved Successfully'); + this.closePermissions(); + }); + } + + resetPermissions() { + this.permissions = { ...this.permissionsBack }; + } + + isOwnerEmpty() { + return !this.permissions.owners.some(o => o.trim().length > 0); + } + + searchUser(search: string) { + this.securityService.searchUsers(search).subscribe(data => { + const results = []; + if (data.users.length) { + results.push({ + text: 'Users :', + children: data.users + }); + } + if (data.roles.length) { + results.push({ + text: 'Roles :', + children: data.roles + }); + } + this.listOfUserAndRole = results; + this.cdr.markForCheck(); + }); + } + + constructor( + private securityService: SecurityService, + private cdr: ChangeDetectorRef, + private nzMessageService: NzMessageService, + private ticketService: TicketService, + private nzModalService: NzModalService + ) {} + + ngOnInit() { + this.permissionsBack = { ...this.permissions }; + } + + ngOnChanges(): void { + this.permissionsBack = { ...this.permissions }; + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html new file mode 100644 index 00000000000..6f0e1be83f1 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html @@ -0,0 +1,20 @@ + + +
    +
    +

    Revisions comparator

    +
    + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts new file mode 100644 index 00000000000..1876b3cbbdb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'zeppelin-notebook-revisions-comparator', + templateUrl: './revisions-comparator.component.html', + styleUrls: ['./revisions-comparator.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookRevisionsComparatorComponent implements OnInit { + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html new file mode 100644 index 00000000000..aa7b5e777b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html @@ -0,0 +1,23 @@ + + +
    + +

    {{value || defaultTitle}}

    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less new file mode 100644 index 00000000000..6efdd89a7aa --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less @@ -0,0 +1,56 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .elastic { + margin-right: 24px; + overflow: hidden; + max-width: 100%; + + &.min { + margin-bottom: 6px; + margin-right: 0; + p, input { + font-size: 16px; + padding: 0 1px; + } + + input { + height: 24px; + margin: 0; + padding: 0; + } + } + + p, input { + font-size: 28px; + width: 100%; + font-weight: 700; + } + + p { + margin: 0 1px; + padding: 0 11px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + input { + height: 36px; + margin: 7px 0; + padding: 0 10px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts new file mode 100644 index 00000000000..2057a875cf1 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts @@ -0,0 +1,89 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + Output, + Renderer2, + SimpleChanges, + ViewChild +} from '@angular/core'; + +@Component({ + selector: 'zeppelin-elastic-input', + templateUrl: './elastic-input.component.html', + styleUrls: ['./elastic-input.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ElasticInputComponent implements OnChanges { + @Input() value: string; + @Input() readonly = false; + @Input() min = false; + @Input() defaultTitle = 'Untitled'; + @Output() readonly valueUpdate = new EventEmitter(); + @ViewChild('inputElement', { read: ElementRef, static: false }) inputElement: ElementRef; + @ViewChild('pElement', { read: ElementRef, static: false }) pElement: ElementRef; + @ViewChild('elasticElement', { read: ElementRef, static: true }) elasticElement: ElementRef; + showEditor = false; + editValue: string; + + cancelEdit() { + this.editValue = this.value; + this.showEditor = false; + } + + updateValue(value: string) { + const trimmedNewName = value.trim(); + if (typeof value === 'string') { + this.editValue = trimmedNewName; + } + } + + setEditorState(showEditor: boolean) { + if (!this.readonly) { + this.showEditor = showEditor; + if (!this.showEditor) { + this.valueUpdate.emit(this.editValue); + } else { + const width = this.pElement.nativeElement.getBoundingClientRect().width; + this.renderer.setStyle(this.elasticElement.nativeElement, 'width', `${width}px`); + setTimeout(() => { + this.inputElement.nativeElement.focus(); + this.renderer.setStyle(this.inputElement.nativeElement, 'width', `${width}px`); + }); + } + } + } + + updateInputWidth() { + const width = this.inputElement.nativeElement.scrollWidth; + if (width > this.inputElement.nativeElement.getBoundingClientRect().width) { + this.renderer.removeStyle(this.elasticElement.nativeElement, 'width'); + this.renderer.setStyle(this.inputElement.nativeElement, 'width', `${width}px`); + } + } + + constructor(private renderer: Renderer2) {} + + ngOnChanges(changes: SimpleChanges) { + if (changes.value) { + this.showEditor = false; + this.editValue = this.value; + this.renderer.removeStyle(this.elasticElement.nativeElement, 'width'); + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts new file mode 100644 index 00000000000..b8ae9a7d06b --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzInputModule } from 'ng-zorro-antd/input'; + +import { ElasticInputComponent } from './elastic-input/elastic-input.component'; + +@NgModule({ + declarations: [ElasticInputComponent], + exports: [ElasticInputComponent], + imports: [CommonModule, NzInputModule, FormsModule] +}) +export class NotebookShareModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html new file mode 100644 index 00000000000..4423ddafd7d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html @@ -0,0 +1,26 @@ + + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less new file mode 100644 index 00000000000..2fe3799b5f3 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less @@ -0,0 +1,11 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts new file mode 100644 index 00000000000..2b4e17c1599 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts @@ -0,0 +1,99 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MessageListener, ParagraphBase } from '@zeppelin/core'; +import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published'; +import { NotebookParagraphResultComponent } from '@zeppelin/pages/workspace/share/result/result.component'; +import { MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk'; +import { HeliumService, MessageService, NgZService, NoteStatusService } from '@zeppelin/services'; +import { SpellResult } from '@zeppelin/spell/spell-result'; +import { isNil } from 'lodash'; + +@Component({ + selector: 'zeppelin-publish-paragraph', + templateUrl: './paragraph.component.html', + styleUrls: ['./paragraph.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PublishedParagraphComponent extends ParagraphBase implements Published, OnInit { + readonly [publishedSymbol] = true; + + noteId: string; + paragraphId: string; + + @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList< + NotebookParagraphResultComponent + >; + + constructor( + public messageService: MessageService, + noteStatusService: NoteStatusService, + ngZService: NgZService, + cdr: ChangeDetectorRef, + private activatedRoute: ActivatedRoute, + private heliumService: HeliumService + ) { + super(messageService, noteStatusService, ngZService, cdr); + this.activatedRoute.params.subscribe(params => { + this.noteId = params.noteId; + this.paragraphId = params.paragraphId; + this.messageService.getNote(this.noteId); + }); + } + + ngOnInit() {} + + @MessageListener(OP.NOTE) + getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) { + const note = data.note; + if (!isNil(note)) { + this.paragraph = (note as Note['note']).paragraphs.find(p => p.id === this.paragraphId); + if (this.paragraph) { + this.setResults(); + this.originalText = this.paragraph.text; + this.initializeDefault(this.paragraph.config); + } + } + this.cdr.markForCheck(); + } + + trackByIndexFn(index: number) { + return index; + } + + setResults() { + if (this.paragraph.results) { + this.results = this.paragraph.results.msg; + this.configs = this.paragraph.config.results; + } + if (!this.paragraph.config) { + this.paragraph.config = {}; + } + } + + changeColWidth(needCommit: boolean, updateResult?: boolean): void { + // noop + } + + runParagraph(): void { + const text = this.paragraph.text; + if (text && !this.isParagraphRunning) { + const magic = SpellResult.extractMagic(this.paragraph.text); + if (this.heliumService.getSpellByMagic(magic)) { + this.runParagraphUsingSpell(text, magic, false); + } else { + this.runParagraphUsingBackendInterpreter(text); + } + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts new file mode 100644 index 00000000000..eaf001fde06 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { PublishedParagraphComponent } from './paragraph/paragraph.component'; + +const routes: Routes = [ + { + path: ':paragraphId', + component: PublishedParagraphComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class PublishedRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts new file mode 100644 index 00000000000..f6474d94896 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { WorkspaceShareModule } from '../../workspace/share/share.module'; +import { PublishedParagraphComponent } from './paragraph/paragraph.component'; +import { PublishedRoutingModule } from './published-ruoting.module'; + +@NgModule({ + declarations: [PublishedParagraphComponent], + imports: [CommonModule, WorkspaceShareModule, PublishedRoutingModule] +}) +export class PublishedModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html new file mode 100644 index 00000000000..330b3e82220 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html @@ -0,0 +1,63 @@ + + +
    +
    +
    + +
    + + + + + + + + + + + +
    +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less new file mode 100644 index 00000000000..a9a4b889420 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +:host { + display: block; +} + +.themeMixin({ + .control-wrap { + display: flex; + } + .form-item { + margin-bottom: 24px; + .item-label { + font-weight: 700; + } + nz-select { + width: 100%; + } + ::ng-deep .ant-checkbox-wrapper { + margin-left: 0; + line-height: 32px; + } + &:hover { + .remove-button { + color: @text-color-danger; + } + } + .remove-button { + margin: 0 4px; + transition: color ease-in-out .3s; + color: @text-color-secondary; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts new file mode 100644 index 00000000000..b6eb9f9bb73 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts @@ -0,0 +1,126 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; +import { Subject } from 'rxjs'; +import { debounceTime, takeUntil } from 'rxjs/operators'; + +import { NzCheckBoxOptionInterface } from 'ng-zorro-antd/checkbox'; + +import { DynamicForms, DynamicFormsItem, DynamicFormsType, DynamicFormParams } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-dynamic-forms', + templateUrl: './dynamic-forms.component.html', + styleUrls: ['./dynamic-forms.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphDynamicFormsComponent implements OnInit, OnChanges, OnDestroy { + private destroy$ = new Subject(); + + @Input() formDefs: DynamicForms; + @Input() paramDefs: DynamicFormParams; + @Input() runOnChange = false; + @Input() disable = false; + @Input() removable = false; + @Output() readonly formChange = new EventEmitter(); + @Output() readonly formRemove = new EventEmitter(); + + formChange$ = new Subject(); + forms: DynamicFormsItem[] = []; + formType = DynamicFormsType; + checkboxGroups: { + [key: string]: NzCheckBoxOptionInterface[]; + } = {}; + + @HostListener('keydown.enter') + onEnter() { + if (!this.runOnChange) { + this.formChange.emit(); + } + } + + trackByNameFn(_index, form: DynamicFormsItem) { + return form.name; + } + + setForms() { + this.forms = Object.values(this.formDefs); + this.checkboxGroups = {}; + this.forms.forEach(e => { + if (!this.paramDefs[e.name]) { + this.paramDefs[e.name] = e.defaultValue; + } + if (e.type === DynamicFormsType.CheckBox) { + this.checkboxGroups[e.name] = e.options.map(opt => { + let checked = false; + if (this.paramDefs[e.name] && Array.isArray(this.paramDefs[e.name])) { + const param = this.paramDefs[e.name] as string[]; + checked = param.indexOf(opt.value) !== -1; + } + return { + checked, + label: opt.displayName || opt.value, + value: opt.value + }; + }); + } + }); + } + + checkboxChange(value: NzCheckBoxOptionInterface[], name) { + this.paramDefs[name] = value.filter(e => e.checked).map(e => e.value); + this.onFormChange(); + } + + onFormChange() { + if (this.runOnChange) { + this.formChange$.next(); + } + } + + remove(item: DynamicFormsItem) { + this.formRemove.emit(item); + } + + constructor() {} + + ngOnInit() { + this.setForms(); + this.formChange$ + .pipe( + debounceTime(800), + takeUntil(this.destroy$) + ) + .subscribe(() => this.formChange.emit()); + } + + ngOnChanges(changes: SimpleChanges): void { + this.setForms(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/index.ts b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts new file mode 100644 index 00000000000..e865360a6bb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './share.module'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html new file mode 100644 index 00000000000..cb8369f273e --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html @@ -0,0 +1,75 @@ + + +
    +
    + + + +
    + + + + + + +
      +
    • CSV
    • +
    • TSV
    • +
    +
    + + + Setting + + +
    +
    + + + + + +
    +
    +
    img
    +
    +
    {{frontEndError}}
    +
    + +
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less new file mode 100644 index 00000000000..37f0dcb16a8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less @@ -0,0 +1,114 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + display: block; + + .nz-resizable-preview { + left: -12px; + padding-right: 10px; + border: none; + &::before { + content: ' '; + display: block; + border: 1px dashed #d1d1d1; + width: 100%; + height: 100%; + } + } + + ::ng-deep { + + .visualization-selector .ant-radio-button-wrapper { + padding: 0 10px; + } + + .inner-html, .text-plain { + + overflow: auto; + + ol, ul, dl { + padding-left: 20px; + } + + img { + max-width: 100%; + height: auto; + width: auto; + } + + table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: @text-color; + table-layout: fixed; + } + thead { + color: @table-header-color; + border-bottom: 2px @border-style-base fade(@black, 65%); + vertical-align: bottom; + } + tr, th, td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; + } + th { + font-weight: bold; + } + tbody tr:nth-child(odd) { + background: darken(@table-header-bg, 3%); + } + tbody tr:hover { + background: @table-row-hover-bg; + } + } + } + + .text-plain { + font-size: 12px; + color: @text-color; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + } + .setting-bar { + display: flex; + margin: 10px 0; + + .export-dropdown { + margin: 0 20px; + + .export-dropdown-icon-btn { + width: 32px; + height: 32px; + padding: 0; + font-size: 16px; + } + } + + .setting-trigger { + line-height: 32px; + + i { + font-size: 12px; + } + } + + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts new file mode 100644 index 00000000000..c8b75b903a6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts @@ -0,0 +1,373 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Injector, + Input, + OnDestroy, + OnInit, + Output, + ViewChild, + ViewContainerRef +} from '@angular/core'; +import { DomSanitizer, SafeHtml, SafeUrl } from '@angular/platform-browser'; +import { Subject, Subscription } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { default as AnsiUp } from 'ansi_up'; +import * as hljs from 'highlight.js'; +import { NzResizeEvent } from 'ng-zorro-antd/resizable'; +import { utils, writeFile, WorkSheet, WritingOptions } from 'xlsx'; + +import { + DatasetType, + GraphConfig, + ParagraphConfigResult, + ParagraphIResultsMsgItem, + VisualizationLineChart, + VisualizationMode, + VisualizationMultiBarChart, + VisualizationScatterChart, + VisualizationStackedAreaChart +} from '@zeppelin/sdk'; + +import { ZeppelinHeliumService } from '@zeppelin/helium'; +import { TableData, Visualization } from '@zeppelin/visualization'; + +import { HeliumManagerService } from '@zeppelin/helium-manager'; +import { DynamicTemplate, NgZService, RuntimeCompilerService } from '@zeppelin/services'; +import { AreaChartVisualization } from '@zeppelin/visualizations/area-chart/area-chart-visualization'; +import { BarChartVisualization } from '@zeppelin/visualizations/bar-chart/bar-chart-visualization'; +import { LineChartVisualization } from '@zeppelin/visualizations/line-chart/line-chart-visualization'; +import { PieChartVisualization } from '@zeppelin/visualizations/pie-chart/pie-chart-visualization'; +import { ScatterChartVisualization } from '@zeppelin/visualizations/scatter-chart/scatter-chart-visualization'; +import { TableVisualization } from '@zeppelin/visualizations/table/table-visualization'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-result', + templateUrl: './result.component.html', + styleUrls: ['./result.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, OnDestroy { + @Input() result: ParagraphIResultsMsgItem; + @Input() config: ParagraphConfigResult; + @Input() id: string; + @Input() published = false; + @Input() currentCol = 12; + @Output() readonly configChange = new EventEmitter(); + @Output() readonly sizeChange = new EventEmitter(); + @ViewChild(CdkPortalOutlet, { static: false }) portalOutlet: CdkPortalOutlet; + + private destroy$ = new Subject(); + datasetType = DatasetType; + angularComponent: DynamicTemplate; + innerHTML: string | SafeHtml = ''; + plainText: string | SafeHtml = ''; + imgData: string | SafeUrl = ''; + tableData = new TableData(); + frontEndError: string; + // tslint:disable-next-line:no-any + visualizations: any[] = [ + { + id: 'table', + name: 'Table', + icon: 'table', + Class: TableVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'multiBarChart', + name: 'Bar Chart', + icon: 'bar-chart', + Class: BarChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'pieChart', + name: 'Pie Chart', + icon: 'pie-chart', + Class: PieChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'lineChart', + name: 'Line Chart', + icon: 'line-chart', + Class: LineChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'stackedAreaChart', + name: 'Area Chart', + icon: 'area-chart', + Class: AreaChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'scatterChart', + name: 'Scatter Chart', + icon: 'dot-chart', + Class: ScatterChartVisualization, + changeSubscription: null, + instance: undefined + } + ]; + + constructor( + private viewContainerRef: ViewContainerRef, + private cdr: ChangeDetectorRef, + private runtimeCompilerService: RuntimeCompilerService, + private sanitizer: DomSanitizer, + private injector: Injector, + private ngZService: NgZService, + private zeppelinHeliumService: ZeppelinHeliumService, + private heliumManagerService: HeliumManagerService + ) { + this.heliumManagerService + .packagesLoadChange() + .pipe(takeUntil(this.destroy$)) + .subscribe(packages => { + packages.forEach(pack => { + this.visualizations.push({ + id: pack._raw.id, + name: pack.name, + icon: pack._raw.icon, + Class: pack._raw.visualization, + componentFactoryResolver: pack.moduleFactory.create(this.injector).componentFactoryResolver, + changeSubscription: null, + instance: undefined + }); + }); + this.cdr.markForCheck(); + }); + } + + ngOnInit() { + this.ngZService + .contextChanged() + .pipe(takeUntil(this.destroy$)) + .subscribe(change => { + if (change.paragraphId === this.id) { + this.cdr.markForCheck(); + } + }); + } + + exportFile(type: 'csv' | 'tsv'): void { + if (this.tableData && this.tableData.rows) { + const wb = utils.book_new(); + let ws: WorkSheet; + ws = utils.json_to_sheet(this.tableData.rows); + utils.book_append_sheet(wb, ws, 'Sheet1'); + writeFile(wb, `export.${type}`, { + bookType: 'csv', + FS: type === 'tsv' ? '\t' : ',' + } as WritingOptions); + } + } + + switchMode(mode: VisualizationMode) { + this.config.graph.mode = mode; + this.renderGraph(); + this.configChange.emit(this.config); + } + + switchSetting() { + this.config.graph.optionOpen = !this.config.graph.optionOpen; + this.renderGraph(); + this.configChange.emit(this.config); + } + + updateResult(config: ParagraphConfigResult, result: ParagraphIResultsMsgItem) { + this.config = config; + this.result = result; + this.renderDefaultDisplay(); + } + + renderDefaultDisplay() { + this.frontEndError = ''; + switch (this.result.type) { + case DatasetType.TABLE: + this.renderGraph(); + break; + case DatasetType.TEXT: + this.renderText(); + break; + case DatasetType.HTML: + this.renderHTML(); + break; + case DatasetType.IMG: + this.renderImg(); + break; + case DatasetType.ANGULAR: + this.renderAngular(); + break; + } + this.cdr.markForCheck(); + if (this.published) { + this.cdr.detectChanges(); + } + } + + renderHTML(): void { + const div = document.createElement('div'); + div.innerHTML = this.result.data; + const codeEle: HTMLElement = div.querySelector('pre code'); + if (codeEle) { + hljs.highlightBlock(codeEle); + } + this.innerHTML = this.sanitizer.bypassSecurityTrustHtml(div.innerHTML); + } + + renderAngular(): void { + this.runtimeCompilerService + .createAndCompileTemplate(this.id, this.result.data) + .then(data => { + this.angularComponent = data; + this.cdr.markForCheck(); + }) + .catch(error => { + this.angularComponent = null; + this.frontEndError = error.message; + this.cdr.markForCheck(); + }); + } + + renderText(): void { + const ansiUp = new AnsiUp(); + this.plainText = this.sanitizer.bypassSecurityTrustHtml(ansiUp.ansi_to_html(this.result.data)); + } + + renderImg(): void { + this.imgData = this.sanitizer.bypassSecurityTrustUrl(`data:image/png;base64,${this.result.data}`); + } + + setGraphConfig() { + if (!this.config || !this.config.graph) { + return; + } + const visualizationItem = this.visualizations.find(v => v.id === this.config.graph.mode); + if (!visualizationItem || !visualizationItem.instance) { + return; + } + visualizationItem.instance.setConfig(this.config.graph); + } + + renderGraph() { + this.setDefaultConfig(); + let instance: Visualization; + const visualizationItem = this.visualizations.find(v => v.id === this.config.graph.mode); + if (!visualizationItem) { + return; + } + this.destroyVisualizations(this.config.graph.mode); + if (!visualizationItem.instance) { + // tslint:disable-next-line:no-any + instance = new visualizationItem.Class( + this.config.graph, + this.portalOutlet, + this.viewContainerRef, + visualizationItem.componentFactoryResolver + ); + visualizationItem.instance = instance; + visualizationItem.changeSubscription = instance.configChanged().subscribe(config => { + this.config.graph = config; + this.renderGraph(); + this.configChange.emit({ + graph: config + }); + }); + } else { + instance = visualizationItem.instance; + instance.setConfig(this.config.graph); + } + this.tableData.loadParagraphResult(this.result); + const transformation = instance.getTransformation(); + transformation.setConfig(this.config.graph); + transformation.setTableData(this.tableData); + const transformed = transformation.transform(this.tableData); + instance.render(transformed); + } + + destroyVisualizations(omit?: string) { + this.visualizations.forEach(v => { + if (v.id !== omit && v.instance) { + if (v.changeSubscription instanceof Subscription) { + v.changeSubscription.unsubscribe(); + v.changeSubscription = null; + } + if (typeof v.instance.destroy === 'function') { + v.instance.destroy(); + } + v.instance = undefined; + } + }); + } + + setDefaultConfig() { + if (!this.config || !this.config.graph) { + this.config = { graph: new GraphConfig() }; + } + if (!this.config.graph.setting) { + this.config.graph.setting = {}; + } + if (!this.config.graph.setting[this.config.graph.mode]) { + switch (this.config.graph.mode) { + case 'multiBarChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationMultiBarChart(); + break; + case 'stackedAreaChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationStackedAreaChart(); + break; + case 'lineChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationLineChart(); + break; + case 'scatterChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationScatterChart(); + break; + default: + break; + } + } + } + + onResize($event: NzResizeEvent) { + const { width, height, col } = $event; + if (this.result.type === DatasetType.TABLE) { + this.config.graph.height = height; + this.setGraphConfig(); + } + this.sizeChange.emit({ width, height, col }); + } + + ngAfterViewInit(): void { + this.renderDefaultDisplay(); + } + + ngOnDestroy(): void { + this.destroyVisualizations(); + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts new file mode 100644 index 00000000000..dfc2c4c5bae --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts @@ -0,0 +1,58 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PortalModule } from '@angular/cdk/portal'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzResizableModule } from 'ng-zorro-antd/resizable'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; + +import { ShareModule } from '@zeppelin/share'; +import { VisualizationModule } from '@zeppelin/visualizations/visualization.module'; + +import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component'; +import { NotebookParagraphResultComponent } from './result/result.component'; + +@NgModule({ + exports: [NotebookParagraphResultComponent, NotebookParagraphDynamicFormsComponent], + declarations: [NotebookParagraphResultComponent, NotebookParagraphDynamicFormsComponent], + imports: [ + CommonModule, + ShareModule, + PortalModule, + VisualizationModule, + FormsModule, + NzButtonModule, + NzDropDownModule, + NzRadioModule, + NzResizableModule, + NzToolTipModule, + NzIconModule, + NzCheckboxModule, + NzSelectModule, + NzSwitchModule, + NzGridModule, + NzInputModule + ] +}) +export class WorkspaceShareModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts new file mode 100644 index 00000000000..d4faf206d8b --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts @@ -0,0 +1,75 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { WorkspaceComponent } from './workspace.component'; +import { WorkspaceGuard } from './workspace.guard'; + +const routes: Routes = [ + { + path: '', + component: WorkspaceComponent, + canActivate: [WorkspaceGuard], + children: [ + { + path: '', + loadChildren: () => import('@zeppelin/pages/workspace/home/home.module').then(m => m.HomeModule) + }, + { + path: 'notebook', + loadChildren: () => import('@zeppelin/pages/workspace/notebook/notebook.module').then(m => m.NotebookModule) + }, + { + path: 'notebook/:noteId/paragraph', + loadChildren: () => import('@zeppelin/pages/workspace/published/published.module').then(m => m.PublishedModule) + }, + { + path: 'search/:queryStr', + loadChildren: () => + import('@zeppelin/pages/workspace/notebook-search/notebook-search.module').then(m => m.NotebookSearchModule) + }, + { + path: 'jobmanager', + loadChildren: () => + import('@zeppelin/pages/workspace/job-manager/job-manager.module').then(m => m.JobManagerModule) + }, + { + path: 'interpreter', + loadChildren: () => + import('@zeppelin/pages/workspace/interpreter/interpreter.module').then(m => m.InterpreterModule) + }, + { + path: 'configuration', + loadChildren: () => + import('@zeppelin/pages/workspace/configuration/configuration.module').then(m => m.ConfigurationModule) + }, + { + path: 'credential', + loadChildren: () => + import('@zeppelin/pages/workspace/credential/credential.module').then(m => m.CredentialModule) + }, + { + path: 'notebook-repos', + loadChildren: () => + import('@zeppelin/pages/workspace/notebook-repos/notebook-repos.module').then(m => m.NotebookReposModule) + } + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class WorkspaceRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html new file mode 100644 index 00000000000..a955afa0056 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html @@ -0,0 +1,16 @@ + + +
    + + +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less new file mode 100644 index 00000000000..dfe293f383c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less @@ -0,0 +1,22 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .content { + background: @layout-body-background; + min-height: 100vh; + display: block; + position: relative; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts new file mode 100644 index 00000000000..19175cb1be3 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts @@ -0,0 +1,80 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { publishedSymbol } from '@zeppelin/core/paragraph-base/published'; +import { HeliumManagerService } from '@zeppelin/helium-manager'; +import { MessageService } from '@zeppelin/services'; +import { setTheme } from '@zeppelin/visualizations/g2.config'; +import { NzMessageService } from 'ng-zorro-antd/message'; + +@Component({ + selector: 'zeppelin-workspace', + templateUrl: './workspace.component.html', + styleUrls: ['./workspace.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class WorkspaceComponent implements OnInit, OnDestroy { + private destroy$ = new Subject(); + private messageId = null; + publishMode = false; + + constructor( + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private nzMessageService: NzMessageService, + private heliumManagerService: HeliumManagerService + ) {} + + onActivate(component) { + this.publishMode = component && component[publishedSymbol]; + this.cdr.markForCheck(); + } + + /** + * Close the old connection manually when the network is offline + * and connect a new, the {@link MessageService} will auto-retry + */ + @HostListener('window:offline') + onOffline() { + this.messageService.close(); + this.messageService.connect(); + } + + setUpWebsocketReconnectMessage() { + this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => { + if (!data) { + if (this.messageId === null) { + this.messageId = this.nzMessageService.loading('Connecting WebSocket ...', { nzDuration: 0 }).messageId; + } + } else { + this.nzMessageService.remove(this.messageId); + this.messageId = null; + } + this.cdr.markForCheck(); + }); + } + + ngOnInit() { + setTheme(); + this.setUpWebsocketReconnectMessage(); + this.heliumManagerService.initPackages(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts new file mode 100644 index 00000000000..b491d750cc4 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts @@ -0,0 +1,36 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { of, Observable } from 'rxjs'; +import { catchError, mapTo, tap } from 'rxjs/operators'; + +import { MessageService, TicketService } from '@zeppelin/services'; + +@Injectable({ + providedIn: 'root' +}) +export class WorkspaceGuard implements CanActivate { + constructor(private ticketService: TicketService, private router: Router, private messageService: MessageService) {} + + canActivate( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable | Promise | boolean | UrlTree { + return this.ticketService.getTicket().pipe( + mapTo(true), + tap(() => this.messageService.bootstrap()), + catchError(() => of(this.router.createUrlTree(['/login']))) + ); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts new file mode 100644 index 00000000000..3be5f544986 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts @@ -0,0 +1,40 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { HeliumManagerModule } from '@zeppelin/helium-manager'; +import { ShareModule } from '@zeppelin/share'; + +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { WorkspaceComponent } from './workspace.component'; + +import { WorkspaceRoutingModule } from './workspace-routing.module'; + +@NgModule({ + declarations: [WorkspaceComponent], + imports: [ + CommonModule, + WorkspaceRoutingModule, + FormsModule, + HttpClientModule, + ShareModule, + RouterModule, + HeliumManagerModule, + NzMessageModule + ] +}) +export class WorkspaceModule {} diff --git a/zeppelin-web-angular/src/app/services/array-ordering.service.ts b/zeppelin-web-angular/src/app/services/array-ordering.service.ts new file mode 100644 index 00000000000..766f729fd90 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/array-ordering.service.ts @@ -0,0 +1,62 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Inject, Injectable } from '@angular/core'; +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; + +@Injectable({ + providedIn: 'root' +}) +export class ArrayOrderingService { + noteListOrdering(note) { + if (note.id === this.TRASH_FOLDER_ID) { + return '\uFFFF'; + } + return this.getNoteName(note); + } + + getNoteName(note) { + if (note.name === undefined || note.name.trim() === '') { + return 'Note ' + note.id; + } else { + return note.name; + } + } + + noteComparator = (v1, v2) => { + const note1 = v1.value || v1; + const note2 = v2.value || v2; + + if (note1.id === this.TRASH_FOLDER_ID) { + return 1; + } + + if (note2.id === this.TRASH_FOLDER_ID) { + return -1; + } + + if (note1.children === undefined && note2.children !== undefined) { + return 1; + } + + if (note1.children !== undefined && note2.children === undefined) { + return -1; + } + + const noteName1 = this.getNoteName(note1); + const noteName2 = this.getNoteName(note2); + + return noteName1.localeCompare(noteName2); + }; + + constructor(@Inject(TRASH_FOLDER_ID_TOKEN) private TRASH_FOLDER_ID: string) {} +} diff --git a/zeppelin-web-angular/src/app/services/base-rest.ts b/zeppelin-web-angular/src/app/services/base-rest.ts new file mode 100644 index 00000000000..7f0ba1b0a19 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/base-rest.ts @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BaseUrlService } from './base-url.service'; + +/** + * @private + */ +export class BaseRest { + constructor(public baseUrlService: BaseUrlService) {} + + /** + * ```ts + * this.restUrl`/user/${username}` + * this.restUrl(['/user/'], username) + * this.restUrl(`/user/${username}`) + * ``` + * @param str` + * @param values + */ + restUrl(str: TemplateStringsArray | string, ...values): string { + let output = this.baseUrlService.getRestApiBase(); + + if (typeof str === 'string') { + return `${output}${str}`; + } + + let index; + for (index = 0; index < values.length; index++) { + output += str[index] + values[index]; + } + + output += str[index]; + return output; + } +} diff --git a/zeppelin-web-angular/src/app/services/base-url.service.ts b/zeppelin-web-angular/src/app/services/base-url.service.ts new file mode 100644 index 00000000000..c6c6a3d83f7 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/base-url.service.ts @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class BaseUrlService { + getPort() { + let port = Number(location.port); + if (!port) { + port = 80; + if (location.protocol === 'https:') { + port = 443; + } + } + return port; + } + + getWebsocketUrl() { + const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; + return `${wsProtocol}//${location.hostname}:${this.getPort()}${this.skipTrailingSlash(location.pathname)}/ws`; + } + + getBase() { + return `${location.protocol}//${location.hostname}:${this.getPort()}${location.pathname}`; + } + + getRestApiBase() { + return this.skipTrailingSlash(this.getBase()) + '/api'; + } + + skipTrailingSlash(path) { + return path.replace(/\/$/, ''); + } +} diff --git a/zeppelin-web-angular/src/app/services/completion.service.ts b/zeppelin-web-angular/src/app/services/completion.service.ts new file mode 100644 index 00000000000..9f772ecb95e --- /dev/null +++ b/zeppelin-web-angular/src/app/services/completion.service.ts @@ -0,0 +1,97 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter, map, take } from 'rxjs/operators'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { CompletionReceived, OP } from '@zeppelin/sdk'; + +import { MessageService } from './message.service'; + +@Injectable({ + providedIn: 'root' +}) +export class CompletionService extends MessageListenersManager { + private completionLanguages = ['python', 'scala']; + private completionItem$ = new Subject(); + private receivers = new WeakMap(); + private bound = false; + + constructor(messageService: MessageService) { + super(messageService); + } + + @MessageListener(OP.COMPLETION_LIST) + onCompletion(data?: CompletionReceived): void { + console.log('on receive!', data.id); + this.completionItem$.next(data); + } + + registerAsCompletionReceiver(model: monaco.editor.ITextModel, pid: string): void { + if (this.receivers.has(model)) { + return; + } + + if (!this.bound) { + this.bindMonacoCompletion(); + this.bound = true; + } + + this.receivers.set(model, pid); + } + + unregister(model: monaco.editor.ITextModel): void { + this.receivers.delete(model); + } + + private bindMonacoCompletion(): void { + // tslint:disable-next-line:no-this-assignment + const that = this; + + this.completionLanguages.forEach(l => { + monaco.languages.registerCompletionItemProvider(l, { + provideCompletionItems(model: monaco.editor.ITextModel, position: monaco.Position) { + const id = that.getIdForModel(model); + + if (!id) { + return { suggestions: null }; + } + + that.messageService.completion(id, model.getValue(), model.getOffsetAt(position)); + + return that.completionItem$ + .pipe( + filter(d => d.id === id), + take(1), + map(d => { + return { + suggestions: d.completions.map(i => ({ + kind: monaco.languages.CompletionItemKind.Keyword, + label: i.name, + insertText: i.name, + range: undefined + })) + }; + }) + ) + .toPromise(); + } + }); + }); + } + + private getIdForModel(model?: monaco.editor.ITextModel): string | null { + return this.receivers.get(model); + } +} diff --git a/zeppelin-web-angular/src/app/services/configuration.service.ts b/zeppelin-web-angular/src/app/services/configuration.service.ts new file mode 100644 index 00000000000..b8c392f0ff4 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/configuration.service.ts @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ConfigurationService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getAll() { + return this.http.get<{ [key: string]: string }>(this.restUrl`/configurations/all`); + } +} diff --git a/zeppelin-web-angular/src/app/services/credential.service.ts b/zeppelin-web-angular/src/app/services/credential.service.ts new file mode 100644 index 00000000000..0e08f7b2d96 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/credential.service.ts @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { Credential, CredentialForm } from '@zeppelin/interfaces'; +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class CredentialService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getCredentials() { + return this.http.get(this.restUrl`/credential`); + } + + addCredential(data: CredentialForm) { + return this.http.put(this.restUrl`/credential`, data); + } + + updateCredential(data: CredentialForm) { + return this.http.put(this.restUrl`/credential`, data); + } + + removeCredential(entity: string) { + return this.http.delete(this.restUrl`/credential/${entity}`); + } +} diff --git a/zeppelin-web-angular/src/app/services/helium.service.ts b/zeppelin-web-angular/src/app/services/helium.service.ts new file mode 100644 index 00000000000..327c6987f88 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/helium.service.ts @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class HeliumService { + getSpellByMagic(magic: string): string { + return null; + } + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/services/index.ts b/zeppelin-web-angular/src/app/services/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/services/interpreter.service.ts b/zeppelin-web-angular/src/app/services/interpreter.service.ts new file mode 100644 index 00000000000..82f93bbfae4 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/interpreter.service.ts @@ -0,0 +1,84 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { + CreateInterpreterRepositoryForm, + Interpreter, + InterpreterMap, + InterpreterPropertyTypes, + InterpreterRepository +} from '@zeppelin/interfaces'; +import { InterpreterItem } from '@zeppelin/sdk'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class InterpreterService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getRepositories() { + return this.http.get(this.restUrl`/interpreter/repository`); + } + + addRepository(repo: CreateInterpreterRepositoryForm) { + return this.http.post(this.restUrl`/interpreter/repository`, repo); + } + + removeRepository(repoId: string) { + return this.http.delete(this.restUrl`/interpreter/repository/${repoId}`); + } + + getInterpretersSetting() { + return this.http.get(this.restUrl`/interpreter/setting`); + } + + getAvailableInterpreters() { + return this.http.get(this.restUrl`/interpreter`); + } + + getAvailableInterpreterPropertyTypes() { + return this.http.get(this.restUrl`/interpreter/property/types`); + } + + addInterpreterSetting(interpreter: Interpreter) { + return this.http.post(this.restUrl`/interpreter/setting`, interpreter); + } + + updateInterpreter(interpreter: Interpreter) { + const { option, properties, dependencies } = interpreter; + return this.http.put(this.restUrl`/interpreter/setting/${interpreter.name}`, { + option, + properties, + dependencies + }); + } + + restartInterpreter(interpreterId: string, noteId: string) { + return this.http.put(this.restUrl`/interpreter/setting/restart/${interpreterId}`, { noteId }); + } + + removeInterpreterSetting(settingId: string) { + return this.http.delete(this.restUrl`/interpreter/setting/${settingId}`); + } + + restartInterpreterSetting(settingId: string) { + return this.http.put(this.restUrl`/interpreter/setting/restart/${settingId}`, null); + } +} diff --git a/zeppelin-web-angular/src/app/services/job-manager.service.ts b/zeppelin-web-angular/src/app/services/job-manager.service.ts new file mode 100644 index 00000000000..b61523219c2 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/job-manager.service.ts @@ -0,0 +1,34 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class JobManagerService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + startJob(noteId: string) { + return this.http.post(this.restUrl`/notebook/job/${noteId}`, {}); + } + + stopJob(noteId: string) { + return this.http.delete(this.restUrl`/notebook/job/${noteId}`, {}); + } +} diff --git a/zeppelin-web-angular/src/app/services/message.service.ts b/zeppelin-web-angular/src/app/services/message.service.ts new file mode 100644 index 00000000000..fd47803749f --- /dev/null +++ b/zeppelin-web-angular/src/app/services/message.service.ts @@ -0,0 +1,331 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Inject, Injectable, OnDestroy, Optional } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { MessageInterceptor, MESSAGE_INTERCEPTOR } from '@zeppelin/interfaces'; +import { + Message, + MessageReceiveDataTypeMap, + MessageSendDataTypeMap, + NoteConfig, + ParagraphConfig, + ParagraphParams, + PersonalizedMode, + SendArgumentsType, + SendNote, + SendParagraph, + WebSocketMessage +} from '@zeppelin/sdk'; + +import { BaseUrlService } from './base-url.service'; +import { TicketService } from './ticket.service'; + +@Injectable({ + providedIn: 'root' +}) +export class MessageService extends Message implements OnDestroy { + constructor( + private baseUrlService: BaseUrlService, + private ticketService: TicketService, + @Optional() @Inject(MESSAGE_INTERCEPTOR) private messageInterceptor: MessageInterceptor + ) { + super(); + } + + interceptReceived( + data: WebSocketMessage + ): WebSocketMessage { + return this.messageInterceptor ? this.messageInterceptor.received(data) : super.interceptReceived(data); + } + + bootstrap(): void { + super.bootstrap(this.ticketService.originTicket, this.baseUrlService.getWebsocketUrl()); + } + + ping() { + super.ping(); + } + + closed(): Observable { + return super.closed(); + } + + sent(): Observable> { + return super.sent(); + } + + received(): Observable> { + return super.received(); + } + + send(...args: SendArgumentsType): void { + super.send(...args); + } + + receive(op: K): Observable[K]> { + return super.receive(op); + } + + opened(): Observable { + return super.opened(); + } + + ngOnDestroy(): void { + super.destroy(); + } + + getHomeNote(): void { + super.getHomeNote(); + } + + newNote(noteName: string, defaultInterpreterGroup: string): void { + super.newNote(noteName, defaultInterpreterGroup); + } + + moveNoteToTrash(noteId: string): void { + super.moveNoteToTrash(noteId); + } + + restoreNote(noteId: string): void { + super.restoreNote(noteId); + } + + deleteNote(noteId): void { + super.deleteNote(noteId); + } + + restoreFolder(folderPath: string): void { + super.restoreFolder(folderPath); + } + + removeFolder(folderPath: string): void { + super.removeFolder(folderPath); + } + + moveFolderToTrash(folderPath: string): void { + super.moveFolderToTrash(folderPath); + } + + restoreAll(): void { + super.restoreAll(); + } + + emptyTrash(): void { + super.emptyTrash(); + } + + cloneNote(noteIdToClone, newNoteName): void { + super.cloneNote(noteIdToClone, newNoteName); + } + + listNodes(): void { + super.listNodes(); + } + + reloadAllNotesFromRepo(): void { + super.reloadAllNotesFromRepo(); + } + + getNote(noteId: string): void { + super.getNote(noteId); + } + + updateNote(noteId: string, noteName: string, noteConfig: NoteConfig): void { + super.updateNote(noteId, noteName, noteConfig); + } + + updatePersonalizedMode(noteId: string, modeValue: PersonalizedMode): void { + super.updatePersonalizedMode(noteId, modeValue); + } + + noteRename(noteId: string, noteName: string, relative?: boolean): void { + super.noteRename(noteId, noteName, relative); + } + + folderRename(folderId: string, folderPath: string): void { + super.folderRename(folderId, folderPath); + } + + moveParagraph(paragraphId: string, newIndex: number): void { + super.moveParagraph(paragraphId, newIndex); + } + + insertParagraph(newIndex: number): void { + super.insertParagraph(newIndex); + } + + copyParagraph( + newIndex: number, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + super.copyParagraph(newIndex, paragraphTitle, paragraphData, paragraphConfig, paragraphParams); + } + + angularObjectUpdate( + noteId: string, + paragraphId: string, + name: string, + value: string, + interpreterGroupId: string + ): void { + super.angularObjectUpdate(noteId, paragraphId, name, value, interpreterGroupId); + } + + // tslint:disable-next-line:no-any + angularObjectClientBind(noteId: string, name: string, value: any, paragraphId: string): void { + super.angularObjectClientBind(noteId, name, value, paragraphId); + } + + angularObjectClientUnbind(noteId: string, name: string, paragraphId: string): void { + super.angularObjectClientUnbind(noteId, name, paragraphId); + } + + cancelParagraph(paragraphId): void { + super.cancelParagraph(paragraphId); + } + + paragraphExecutedBySpell( + paragraphId, + paragraphTitle, + paragraphText, + paragraphResultsMsg, + paragraphStatus, + paragraphErrorMessage, + paragraphConfig, + paragraphParams, + paragraphDateStarted, + paragraphDateFinished + ): void { + super.paragraphExecutedBySpell( + paragraphId, + paragraphTitle, + paragraphText, + paragraphResultsMsg, + paragraphStatus, + paragraphErrorMessage, + paragraphConfig, + paragraphParams, + paragraphDateStarted, + paragraphDateFinished + ); + } + + runParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + super.runParagraph(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams); + } + + runAllParagraphs(noteId: string, paragraphs: SendParagraph[]): void { + super.runAllParagraphs(noteId, paragraphs); + } + + paragraphRemove(paragraphId: string): void { + super.paragraphRemove(paragraphId); + } + + paragraphClearOutput(paragraphId: string): void { + super.paragraphClearOutput(paragraphId); + } + + paragraphClearAllOutput(noteId: string): void { + super.paragraphClearAllOutput(noteId); + } + + completion(paragraphId: string, buf: string, cursor: number): void { + super.completion(paragraphId, buf, cursor); + } + + commitParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphConfig, + noteId: string + ): void { + super.commitParagraph(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams, noteId); + } + + patchParagraph(paragraphId: string, noteId: string, patch: string): void { + super.patchParagraph(paragraphId, noteId, patch); + } + + importNote(note: SendNote): void { + super.importNote(note); + } + + checkpointNote(noteId: string, commitMessage: string): void { + super.checkpointNote(noteId, commitMessage); + } + + setNoteRevision(noteId: string, revisionId: string): void { + super.setNoteRevision(noteId, revisionId); + } + + listRevisionHistory(noteId: string): void { + super.listRevisionHistory(noteId); + } + + noteRevision(noteId: string, revisionId: string): void { + super.noteRevision(noteId, revisionId); + } + + noteRevisionForCompare(noteId: string, revisionId: string, position: string): void { + super.noteRevisionForCompare(noteId, revisionId, position); + } + + editorSetting(paragraphId: string, replName: string): void { + super.editorSetting(paragraphId, replName); + } + + listNoteJobs(): void { + super.listNoteJobs(); + } + + unsubscribeUpdateNoteJobs(): void { + super.unsubscribeUpdateNoteJobs(); + } + + getInterpreterBindings(noteId: string): void { + super.getInterpreterBindings(noteId); + } + + saveInterpreterBindings(noteId, selectedSettingIds): void { + super.saveInterpreterBindings(noteId, selectedSettingIds); + } + + listConfigurations(): void { + super.listConfigurations(); + } + + getInterpreterSettings(): void { + super.getInterpreterSettings(); + } + + saveNoteForms(note: SendNote): void { + super.saveNoteForms(note); + } + + removeNoteForms(note, formName): void { + super.removeNoteForms(note, formName); + } +} diff --git a/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts new file mode 100644 index 00000000000..f965e1dd8e9 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts @@ -0,0 +1,65 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Ng1MigrationComponent } from '@zeppelin/share/ng1-migration/ng1-migration.component'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { Observable } from 'rxjs'; + +export interface NgTemplateCheckResult { + index: number; + match: string; + magic: string; + template: string; + origin: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class NgTemplateAdapterService { + constructor(private nzModalService: NzModalService) {} + preCheck(origin: string): NgTemplateCheckResult | null { + const regexp = /(%angular)([\s\S]*<[\s\S]*>)/im; + const math = regexp.exec(origin); + if (math) { + const index = math.index; + const [output, magic, template] = math; + return { + index, + magic, + template, + origin, + match: output + }; + } + return null; + } + + openMigrationDialog(check: NgTemplateCheckResult): Observable { + const modalRef = this.nzModalService.create({ + nzTitle: 'Angular.js Templates Migration Tool', + nzContent: Ng1MigrationComponent, + nzComponentParams: check, + nzFooter: null, + nzWidth: '980px', + nzStyle: { + top: '45px' + }, + nzBodyStyle: { + padding: '0' + } + }); + + return modalRef.afterClose; + } +} diff --git a/zeppelin-web-angular/src/app/services/ng-z.service.ts b/zeppelin-web-angular/src/app/services/ng-z.service.ts new file mode 100644 index 00000000000..fe1ad9917d3 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/ng-z.service.ts @@ -0,0 +1,85 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class NgZService implements OnDestroy { + private paragraphMap = new Map(); + private contextChange$ = new Subject<{ + paragraphId: string; + key: string; + // tslint:disable-next-line:no-any + value: any; + emit: boolean; + set: boolean; + }>(); + private runParagraph$ = new Subject(); + + constructor() {} + + contextChanged() { + return this.contextChange$.asObservable(); + } + + runParagraphAction() { + return this.runParagraph$.asObservable(); + } + + removeParagraph(paragraphId: string) { + this.paragraphMap.delete(paragraphId); + } + + runParagraph(paragraphId: string) { + this.runParagraph$.next(paragraphId); + } + + bindParagraph(paragraphId: string, context: {}) { + this.paragraphMap.set(paragraphId, context); + } + + setContextValue(key: string, value, paragraphId: string, emit = true) { + const context = this.paragraphMap.get(paragraphId); + if (context) { + context[key] = value; + } + this.contextChange$.next({ + paragraphId, + key, + value, + emit, + set: true + }); + } + + unsetContextValue(key: string, paragraphId: string, emit = true) { + const context = this.paragraphMap.get(paragraphId); + if (context) { + context[key] = undefined; + } + this.contextChange$.next({ + paragraphId, + key, + emit, + value: undefined, + set: false + }); + } + + ngOnDestroy(): void { + this.paragraphMap.clear(); + this.contextChange$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/services/note-action.service.ts b/zeppelin-web-angular/src/app/services/note-action.service.ts new file mode 100644 index 00000000000..44e0ca8861c --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-action.service.ts @@ -0,0 +1,72 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; + +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { FolderRenameComponent } from '@zeppelin/share/folder-rename/folder-rename.component'; +import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; +import { NoteImportComponent } from '@zeppelin/share/note-import/note-import.component'; +import { NoteRenameComponent } from '@zeppelin/share/note-rename/note-rename.component'; + +@Injectable({ + providedIn: 'root' +}) +export class NoteActionService { + renameNote(id: string, path: string, name: string) { + this.nzModalService.create({ + nzTitle: 'Rename note', + nzContent: NoteRenameComponent, + nzComponentParams: { + id, + newName: path || name + }, + nzWidth: '800px', + nzFooter: null + }); + } + + renameFolder(path: string) { + this.nzModalService.create({ + nzTitle: 'Rename folder', + nzContent: FolderRenameComponent, + nzComponentParams: { + folderId: path, + newFolderPath: path + }, + nzWidth: '800px', + nzFooter: null + }); + } + + importNote() { + this.nzModalService.create({ + nzTitle: 'Import New Note', + nzContent: NoteImportComponent, + nzWidth: '800px', + nzFooter: null + }); + } + + createNote(path?: string) { + this.nzModalService.create({ + nzTitle: 'Create New Note', + nzContent: NoteCreateComponent, + nzComponentParams: { path }, + nzWidth: '800px', + nzFooter: null + }); + } + + constructor(private nzModalService: NzModalService) {} +} diff --git a/zeppelin-web-angular/src/app/services/note-list.service.ts b/zeppelin-web-angular/src/app/services/note-list.service.ts new file mode 100644 index 00000000000..83070b51148 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-list.service.ts @@ -0,0 +1,97 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Inject, Injectable } from '@angular/core'; + +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { NotesInfoItem } from '@zeppelin/sdk'; + +import { NodeList } from '../interfaces/node-list'; +import { ArrayOrderingService } from './array-ordering.service'; + +@Injectable({ + providedIn: 'root' +}) +export class NoteListService { + notes: NodeList = { + root: { children: [] }, + flatList: [], + flatFolderMap: {} + }; + + setNotes(notesList: NotesInfoItem[]) { + // a flat list to boost searching + this.notes.flatList = notesList.map(note => { + const isTrash = note.path ? note.path.split('/')[1] === this.TRASH_FOLDER_ID : false; + return { ...note, isTrash }; + }); + + // construct the folder-based tree + this.notes.root = { children: [] }; + this.notes.flatFolderMap = {}; + notesList.reduce((root, note) => { + const notePath = note.path || note.id; + const nodes = notePath.match(/([^\/][^\/]*)/g); + + // recursively add nodes + this.addNode(root, nodes, note.id); + + return root; + }, this.notes.root); + this.notes.root.children.sort(this.arrayOrderingService.noteComparator); + } + + addNode(curDir, nodes, noteId) { + if (nodes.length === 1) { + // the leaf + curDir.children.push({ + id: noteId, + title: nodes[0], + isLeaf: true, + nodeType: 'note', + path: curDir.id ? `${curDir.id}/${nodes[0]}` : nodes[0], + isTrash: curDir.id ? curDir.id.split('/')[0] === this.TRASH_FOLDER_ID : false + }); + } else { + // a folder node + const node = nodes.shift(); + const dir = curDir.children.find(c => { + return c.title === node && c.children !== undefined; + }); + if (dir !== undefined) { + // found an existing dir + this.addNode(dir, nodes, noteId); + } else { + const id = curDir.id ? `${curDir.id}/${node}` : node; + const newDir = { + id, + title: node, + expanded: false, + nodeType: id === this.TRASH_FOLDER_ID ? 'trash' : 'folder', + children: [], + isTrash: curDir.id ? curDir.id.split('/')[0] === this.TRASH_FOLDER_ID : false + }; + + // add the folder to flat folder map + this.notes.flatFolderMap[newDir.id] = newDir; + + curDir.children.push(newDir); + this.addNode(newDir, nodes, noteId); + } + } + } + + constructor( + @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, + private arrayOrderingService: ArrayOrderingService + ) {} +} diff --git a/zeppelin-web-angular/src/app/services/note-status.service.ts b/zeppelin-web-angular/src/app/services/note-status.service.ts new file mode 100644 index 00000000000..e5ff4a90bb6 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-status.service.ts @@ -0,0 +1,65 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Inject, Injectable } from '@angular/core'; + +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { Note, ParagraphItem } from '@zeppelin/sdk'; + +export const ParagraphStatus = { + READY: 'READY', + PENDING: 'PENDING', + RUNNING: 'RUNNING', + FINISHED: 'FINISHED', + ABORT: 'ABORT', + ERROR: 'ERROR' +}; + +@Injectable({ + providedIn: 'root' +}) +export class NoteStatusService { + isParagraphRunning(paragraph: ParagraphItem) { + if (!paragraph) { + return false; + } + const status = paragraph.status; + if (!status) { + return false; + } + + return status === ParagraphStatus.PENDING || status === ParagraphStatus.RUNNING; + } + + isTrash(note: Note['note']) { + // TODO(hsuanxyz) https://github.com/apache/zeppelin/pull/3365/files + return note.name.split('/')[1] === this.TRASH_FOLDER_ID; + } + + viewOnly(note: Note['note']): boolean { + return note.config.looknfeel === 'report'; + } + + isNoteParagraphRunning(note: Note['note']): boolean { + if (!note) { + return false; + } else { + return note.paragraphs.some(p => this.isParagraphRunning(p)); + } + } + + isEntireNoteRunning(note: Note['note']): boolean { + return !!(note.info && note.info.isRunning && note.info.isRunning === true); + } + + constructor(@Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string) {} +} diff --git a/zeppelin-web-angular/src/app/services/note-var-share.service.ts b/zeppelin-web-angular/src/app/services/note-var-share.service.ts new file mode 100644 index 00000000000..edb7bed7fb4 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-var-share.service.ts @@ -0,0 +1,38 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class NoteVarShareService { + private store = new Map(); + + clear() { + this.store.clear(); + } + + set(key, value) { + this.store.set(key, value); + } + + get(key) { + return this.store.get(key); + } + + del(key) { + return this.store.delete(key); + } + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/services/notebook-repos.service.ts b/zeppelin-web-angular/src/app/services/notebook-repos.service.ts new file mode 100644 index 00000000000..624599ae0fd --- /dev/null +++ b/zeppelin-web-angular/src/app/services/notebook-repos.service.ts @@ -0,0 +1,36 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { NotebookRepo, NotebookRepoPutData } from '@zeppelin/interfaces'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class NotebookRepoService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getRepos() { + return this.http.get(this.restUrl`/notebook-repositories`); + } + + updateRepo(repo: NotebookRepoPutData) { + return this.http.put(this.restUrl`/notebook-repositories`, repo); + } +} diff --git a/zeppelin-web-angular/src/app/services/notebook-search.service.ts b/zeppelin-web-angular/src/app/services/notebook-search.service.ts new file mode 100644 index 00000000000..7371eec7362 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/notebook-search.service.ts @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { NotebookSearchResultItem } from '@zeppelin/interfaces'; +import { BaseRest } from '@zeppelin/services/base-rest'; +import { BaseUrlService } from '@zeppelin/services/base-url.service'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class NotebookSearchService extends BaseRest { + private queryStr$ = new BehaviorSubject(null); + + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + queried() { + return this.queryStr$.asObservable(); + } + + clear() { + this.queryStr$.next(null); + } + + search(query: string) { + this.queryStr$.next(query); + return this.http.get(this.restUrl`/notebook/search`, { + params: { + q: query + } + }); + } +} diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts new file mode 100644 index 00000000000..f9bdfe9554f --- /dev/null +++ b/zeppelin-web-angular/src/app/services/public-api.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './base-url.service'; +export * from './ticket.service'; +export * from './message.service'; +export * from './job-manager.service'; +export * from './interpreter.service'; +export * from './security.service'; +export * from './note-status.service'; +export * from './save-as.service'; +export * from './helium.service'; +export * from './note-var-share.service'; +export * from './note-action.service'; +export * from './completion.service'; +export * from './ng-z.service'; +export * from './array-ordering.service'; +export * from './note-list.service'; +export * from './runtime-compiler.service'; +export * from './shortcut.service'; +export * from './configuration.service'; +export * from './credential.service'; +export * from './notebook-repos.service'; diff --git a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts new file mode 100644 index 00000000000..f7f6fc42664 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts @@ -0,0 +1,79 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ChangeDetectionStrategy, + Compiler, + Component, + Injectable, + NgModule, + NgModuleFactory, + NO_ERRORS_SCHEMA, + Type +} from '@angular/core'; + +import { CompileDirectiveMetadata, HtmlParser, TemplateParser } from '@angular/compiler'; +import { RuntimeDynamicModuleModule } from '@zeppelin/core'; +import { NgZService } from './ng-z.service'; + +export class DynamicTemplate { + constructor( + public readonly template: string, + // tslint:disable-next-line:no-any + public readonly component: Type, + // tslint:disable-next-line:no-any + public readonly moduleFactory?: NgModuleFactory + ) {} +} + +export class DynamicTemplateError { + constructor(public message: string) {} +} + +@Injectable({ + providedIn: 'root' +}) +export class RuntimeCompilerService { + public async createAndCompileTemplate(paragraphId: string, template: string): Promise { + const ngZService = this.ngZService; + const dynamicComponent = Component({ template: template, selector: `dynamic-${paragraphId}` })( + class DynamicTemplateComponent { + z = { + set: (key: string, value, id: string) => ngZService.setContextValue(key, value, id), + unset: (key: string, id: string) => ngZService.unsetContextValue(key, id), + run: (id: string) => ngZService.runParagraph(id) + }; + + constructor() { + ngZService.bindParagraph(paragraphId, this); + Object.freeze(this.z); + } + } + ); + const dynamicModule = NgModule({ + declarations: [dynamicComponent], + exports: [dynamicComponent], + entryComponents: [dynamicComponent], + imports: [RuntimeDynamicModuleModule] + })(class DynamicModule {}); + + try { + this.compiler.clearCache(); + const compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule); + return new DynamicTemplate(template, dynamicComponent, compiledModule.ngModuleFactory); + } catch (e) { + throw new DynamicTemplateError(`${e}`); + } + } + + constructor(private compiler: Compiler, private ngZService: NgZService) {} +} diff --git a/zeppelin-web-angular/src/app/services/save-as.service.ts b/zeppelin-web-angular/src/app/services/save-as.service.ts new file mode 100644 index 00000000000..53dc05c9bdd --- /dev/null +++ b/zeppelin-web-angular/src/app/services/save-as.service.ts @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class SaveAsService { + saveAs(content: string, filename: string, extension: string) { + const BOM = '\uFEFF'; + const fileName = `${filename}.${extension}`; + const binaryData = []; + binaryData.push(BOM); + binaryData.push(content); + const blob = new Blob(binaryData, { type: 'octet/stream' }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + document.body.appendChild(a); + a.style.display = 'none'; + a.href = url; + a.download = fileName; + a.click(); + window.URL.revokeObjectURL(url); + } + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/services/security.service.ts b/zeppelin-web-angular/src/app/services/security.service.ts new file mode 100644 index 00000000000..c267ad05fa8 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/security.service.ts @@ -0,0 +1,40 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { Permissions, SecurityUserList } from '@zeppelin/interfaces'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class SecurityService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + searchUsers(term: string) { + return this.http.get(this.restUrl`/security/userlist/${term}`); + } + + getPermissions(id: string) { + return this.http.get(this.restUrl`/notebook/${id}/permissions`); + } + + setPermissions(id: string, permissions: Permissions) { + return this.http.put(this.restUrl`/notebook/${id}/permissions`, permissions); + } +} diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts new file mode 100644 index 00000000000..5bc9a2a2fcd --- /dev/null +++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts @@ -0,0 +1,110 @@ +import { DOCUMENT } from '@angular/common'; +import { Inject, Injectable } from '@angular/core'; +import { EventManager } from '@angular/platform-browser'; +import { Observable } from 'rxjs'; + +export enum ParagraphActions { + EditMode = 'Paragraph:EditMode', + CommandMode = 'Paragraph:CommandMode', + Run = 'Paragraph:Run', + RunBelow = 'Paragraph:RunBelow', + Cancel = 'Paragraph:Cancel', + Clear = 'Paragraph:Clear', + ReduceWidth = 'Paragraph:ReduceWidth', + IncreaseWidth = 'Paragraph:IncreaseWidth', + Delete = 'Paragraph:Delete', + MoveToUp = 'Paragraph:MoveToUp', + MoveToDown = 'Paragraph:MoveToDown', + SelectAbove = 'Paragraph:SelectAbove', + SelectBelow = 'Paragraph:SelectBelow', + InsertAbove = 'Paragraph:InsertAbove', + InsertBelow = 'Paragraph:InsertBelow', + SwitchLineNumber = 'Paragraph:SwitchLineNumber', + SwitchTitleShow = 'Paragraph:SwitchTitleShow', + SwitchOutputShow = 'Paragraph:SwitchOutputShow', + SwitchEditorShow = 'Paragraph:SwitchEditorShow', + SwitchEnable = 'Paragraph:SwitchEnable', + Link = 'Paragraph:Link' +} + +export const ShortcutsMap = { + [ParagraphActions.EditMode]: 'enter', + [ParagraphActions.CommandMode]: 'esc', + [ParagraphActions.Run]: 'shift.enter', + [ParagraphActions.RunBelow]: 'shift.ctrlCmd.enter', + [ParagraphActions.Cancel]: 'shift.ctrlCmd.c', + // Need register special character `¬` in MacOS + [ParagraphActions.Clear]: ['alt.ctrlCmd.l', 'alt.ctrlCmd.¬'], + // Need register special character `†` in MacOS + [ParagraphActions.Link]: ['alt.ctrlCmd.t', 'alt.ctrlCmd.†'], + // Need register special character `®` in MacOS + [ParagraphActions.SwitchEnable]: ['alt.ctrlCmd.r', 'alt.ctrlCmd.®'], + // Need register special character `–` in MacOS + [ParagraphActions.ReduceWidth]: ['alt.ctrlCmd.-', 'alt.ctrlCmd.–'], + // Need register special character `≠` in MacOS + [ParagraphActions.IncreaseWidth]: ['alt.ctrlCmd.+', 'alt.ctrlCmd.≠'], + [ParagraphActions.Delete]: 'shift.delete', + [ParagraphActions.MoveToUp]: ['ctrlCmd.k', 'ctrlCmd.arrowup', 'ctrlCmd.arrowleft'], + [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown', 'ctrlCmd.arrowright'], + [ParagraphActions.SelectAbove]: ['k', 'arrowup', 'arrowleft'], + [ParagraphActions.SelectBelow]: ['j', 'arrowdown', 'arrowright'], + [ParagraphActions.SwitchLineNumber]: 'l', + [ParagraphActions.SwitchTitleShow]: 't', + [ParagraphActions.SwitchOutputShow]: 'o', + [ParagraphActions.SwitchEditorShow]: 'e', + [ParagraphActions.InsertAbove]: 'a', + [ParagraphActions.InsertBelow]: 'b' +}; + +export interface ShortcutEvent { + event: KeyboardEvent; + keybindings: string; +} + +export interface ShortcutOption { + scope?: HTMLElement; + keybindings: string; +} + +function isMacOS() { + return navigator.platform.indexOf('Mac') > -1; +} + +@Injectable({ + providedIn: 'root' +}) +export class ShortcutService { + private element: HTMLElement; + + // tslint:disable-next-line:no-any + constructor(private eventManager: EventManager, @Inject(DOCUMENT) _document: any) { + this.element = _document; + } + + forkByElement(element: HTMLElement) { + return new ShortcutService(this.eventManager, element); + } + + bindShortcut(option: ShortcutOption): Observable { + const host = option.scope || this.element; + // `ctrlCmd` is special symbol, will be replaced `meta` in MacOS, 'control' in Windows/Linux + const keybindings = option.keybindings.replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control'); + const eventName = `keydown.${keybindings}`; + // tslint:disable-next-line:ban-types + let dispose: Function; + return new Observable(observer => { + const handler = event => { + observer.next({ + event, + keybindings: option.keybindings + }); + }; + + dispose = this.eventManager.addEventListener(host, eventName, handler); + + return () => { + dispose(); + }; + }); + } +} diff --git a/zeppelin-web-angular/src/app/services/ticket.service.ts b/zeppelin-web-angular/src/app/services/ticket.service.ts new file mode 100644 index 00000000000..a23bc0d1832 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/ticket.service.ts @@ -0,0 +1,116 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; +import { forkJoin, BehaviorSubject, Subject } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; + +import { NzMessageService } from 'ng-zorro-antd/message'; + +import { ITicket, ITicketWrapped, IZeppelinVersion } from '@zeppelin/interfaces'; +import { ConfigurationsInfo } from '@zeppelin/sdk'; + +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class TicketService { + configuration: ConfigurationsInfo['configurations']; + ticket = new ITicketWrapped(); + originTicket = new ITicket(); + ticket$ = new Subject(); + logout$ = new BehaviorSubject(false); + version: string; + + setConfiguration(conf: ConfigurationsInfo) { + this.configuration = conf.configurations; + } + + getTicket() { + return forkJoin([ + this.httpClient.get(`${this.baseUrlService.getRestApiBase()}/security/ticket`), + this.getZeppelinVersion() + ]).pipe( + tap(data => { + const [ticket, version] = data; + this.version = version; + this.setTicket(ticket); + }) + ); + } + + setTicket(ticket: ITicket) { + if (ticket.redirectURL) { + window.location.href = ticket.redirectURL + window.location.href; + } + let screenUsername = ticket.principal; + if (ticket.principal.indexOf('#Pac4j') === 0) { + const re = ', name=(.*?),'; + screenUsername = ticket.principal.match(re)[1]; + } + this.originTicket = ticket; + this.ticket = { ...ticket, screenUsername, ...{ init: true } }; + this.ticket$.next(this.ticket); + } + + clearTicket() { + this.ticket = new ITicketWrapped(); + this.originTicket = new ITicket(); + } + + logout() { + this.logout$.next(true); + const nextAction = () => { + this.nzMessageService.success('Logout Success'); + this.clearTicket(); + this.logout$.next(false); + this.router.navigate(['/login']).then(); + }; + return this.httpClient + .post(`${this.baseUrlService.getRestApiBase()}/login/logout`, {}) + .pipe(tap(() => nextAction(), () => nextAction())); + } + + login(userName: string, password: string) { + return this.httpClient + .post(`${this.baseUrlService.getRestApiBase()}/login`, `password=${password}&userName=${userName}`, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + }) + .pipe( + tap( + data => { + this.nzMessageService.success('Login Success'); + this.setTicket(data); + }, + () => { + this.nzMessageService.warning("The username and password that you entered don't match."); + } + ) + ); + } + + getZeppelinVersion() { + return this.httpClient + .get(`${this.baseUrlService.getRestApiBase()}/version`) + .pipe(map(data => data.version)); + } + + constructor( + private httpClient: HttpClient, + private baseUrlService: BaseUrlService, + private router: Router, + private nzMessageService: NzMessageService + ) {} +} diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html new file mode 100644 index 00000000000..33a5d87ee68 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html @@ -0,0 +1,28 @@ + + + diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less new file mode 100644 index 00000000000..73be35e8bc8 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less @@ -0,0 +1,38 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .modal { + .about-logo { + img { + width: 95%; + } + } + + .content { + text-align: center; + + h3 { + font-family: 'Patua One', cursive; + color: #3071A9; + font-size: 30px; + margin: 0 auto; + } + + .about-version { + font-weight: 500; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts new file mode 100644 index 00000000000..41e8e777324 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-about-zeppelin', + templateUrl: './about-zeppelin.component.html', + styleUrls: ['./about-zeppelin.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AboutZeppelinComponent implements OnInit { + constructor(public ticketService: TicketService) {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html new file mode 100644 index 00000000000..1b40367eb04 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html @@ -0,0 +1,19 @@ + + +
    + +
    + +
    + +
    diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts new file mode 100644 index 00000000000..2fdbaa5950d --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts @@ -0,0 +1,244 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + forwardRef, + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + EventEmitter, + Input, + NgZone, + OnDestroy, + Output, + TemplateRef, + ViewEncapsulation +} from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { combineLatest, fromEvent, BehaviorSubject, Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, map, takeUntil } from 'rxjs/operators'; + +import { warn, InputBoolean } from 'ng-zorro-antd/core'; + +import { CodeEditorService } from './code-editor.service'; +import { DiffEditorOptions, EditorOptions, JoinedEditorOptions, NzEditorMode } from './nz-code-editor.definitions'; + +// Import types from monaco editor. +import { editor } from 'monaco-editor'; +import IEditor = editor.IEditor; +import IDiffEditor = editor.IDiffEditor; +import ITextModel = editor.ITextModel; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + selector: 'zeppelin-code-editor', + exportAs: 'CodeEditor', + templateUrl: './code-editor.component.html', + host: { + '[class.ant-code-editor]': 'true' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CodeEditorComponent), + multi: true + } + ] +}) +export class CodeEditorComponent implements OnDestroy, AfterViewInit { + @Input() nzEditorMode: NzEditorMode = 'normal'; + @Input() nzOriginalText = ''; + @Input() @InputBoolean() nzLoading = false; + @Input() @InputBoolean() nzFullControl = false; + @Input() nzToolkit: TemplateRef; + + @Input() set nzEditorOption(value: JoinedEditorOptions) { + this.editorOption$.next(value); + } + + @Output() readonly nzEditorInitialized = new EventEmitter(); + + editorOptionCached: JoinedEditorOptions = {}; + + private readonly el: HTMLElement; + private destroy$ = new Subject(); + private resize$ = new Subject(); + private editorOption$ = new BehaviorSubject({}); + private editorInstance: IEditor | IDiffEditor; + private value = ''; + private modelSet = false; + + constructor(private nzCodeEditorService: CodeEditorService, private ngZone: NgZone, elementRef: ElementRef) { + this.el = elementRef.nativeElement; + } + + /** + * Initialize a monaco editor instance. + */ + ngAfterViewInit(): void { + this.nzCodeEditorService.requestToInit().subscribe(option => this.setup(option)); + } + + ngOnDestroy(): void { + if (this.editorInstance) { + this.editorInstance.dispose(); + } + + this.destroy$.next(); + this.destroy$.complete(); + } + + writeValue(value: string): void { + this.value = value; + this.setValue(); + } + + // tslint:disable-next-line no-any + registerOnChange(fn: (value: string) => void): any { + this.onChange = fn; + } + + // tslint:disable-next-line no-any + registerOnTouched(fn: any): void { + this.onTouch = fn; + } + + onChange(_value: string): void {} + + onTouch(): void {} + + layout(): void { + this.resize$.next(); + } + + private setup(option: JoinedEditorOptions): void { + this.editorOptionCached = option; + this.registerOptionChanges(); + this.initMonacoEditorInstance(); + this.registerResizeChange(); + this.setValue(); + + if (!this.nzFullControl) { + this.setValueEmitter(); + } + this.nzEditorInitialized.emit(this.editorInstance); + } + + private registerOptionChanges(): void { + combineLatest([this.editorOption$, this.nzCodeEditorService.option$]) + .pipe(takeUntil(this.destroy$)) + .subscribe(([selfOpt, defaultOpt]) => { + this.editorOptionCached = { + ...this.editorOptionCached, + ...defaultOpt, + ...selfOpt + }; + this.updateOptionToMonaco(); + }); + } + + private initMonacoEditorInstance(): void { + this.ngZone.runOutsideAngular(() => { + this.editorInstance = + this.nzEditorMode === 'normal' + ? editor.create(this.el, { ...this.editorOptionCached }) + : editor.createDiffEditor(this.el, { + ...(this.editorOptionCached as DiffEditorOptions) + }); + }); + } + + private registerResizeChange(): void { + this.ngZone.runOutsideAngular(() => { + fromEvent(window, 'resize') + .pipe( + debounceTime(300), + takeUntil(this.destroy$) + ) + .subscribe(() => { + this.layout(); + }); + + this.resize$ + .pipe( + takeUntil(this.destroy$), + filter(() => !!this.editorInstance), + map(() => ({ + width: this.el.clientWidth, + height: this.el.clientHeight + })), + distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height), + debounceTime(50) + ) + .subscribe(() => { + this.editorInstance.layout(); + }); + }); + } + + private setValue(): void { + if (!this.editorInstance) { + return; + } + + if (this.nzFullControl && this.value) { + warn(`should not set value when you are using full control mode! It would result in ambiguous data flow!`); + return; + } + + if (this.nzEditorMode === 'normal') { + if (this.modelSet) { + (this.editorInstance.getModel() as ITextModel).setValue(this.value); + } else { + (this.editorInstance as IEditor).setModel( + editor.createModel(this.value, (this.editorOptionCached as EditorOptions).language) + ); + this.modelSet = true; + } + } else { + if (this.modelSet) { + const model = (this.editorInstance as IDiffEditor).getModel()!; + model.modified.setValue(this.value); + model.original.setValue(this.nzOriginalText); + } else { + const language = (this.editorOptionCached as EditorOptions).language; + (this.editorInstance as IDiffEditor).setModel({ + original: editor.createModel(this.value, language), + modified: editor.createModel(this.nzOriginalText, language) + }); + } + } + } + + private setValueEmitter(): void { + const model = (this.nzEditorMode === 'normal' + ? (this.editorInstance as IEditor).getModel() + : (this.editorInstance as IDiffEditor).getModel()!.modified) as ITextModel; + + model.onDidChangeContent(() => { + this.emitValue(model.getValue()); + }); + } + + private emitValue(value: string): void { + this.value = value; + this.onChange(value); + } + + private updateOptionToMonaco(): void { + if (this.editorInstance) { + this.editorInstance.updateOptions({ ...this.editorOptionCached }); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts b/zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts new file mode 100644 index 00000000000..6af049bc1b4 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzSpinModule } from 'ng-zorro-antd/spin'; + +import { CodeEditorComponent } from './code-editor.component'; + +@NgModule({ + declarations: [CodeEditorComponent], + imports: [CommonModule, NzIconModule, NzSpinModule], + exports: [CodeEditorComponent] +}) +export class CodeEditorModule {} diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts b/zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts new file mode 100644 index 00000000000..f24d9ec4d89 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts @@ -0,0 +1,104 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DOCUMENT } from '@angular/common'; +import { Inject, Injectable } from '@angular/core'; +import { of as observableOf, BehaviorSubject, Observable, Subject } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; + +import { + JoinedEditorOptions, + NzCodeEditorConfig, + NzCodeEditorLoadingStatus, + NZ_CODE_EDITOR_CONFIG +} from './nz-code-editor.definitions'; + +import { editor } from 'monaco-editor'; + +// tslint:disable no-any +function tryTriggerFunc(fn?: (...args: any[]) => any): (...args: any) => void { + return (...args: any[]) => { + if (fn) { + fn(...args); + } + }; +} +// tslint:enable no-any + +@Injectable({ + providedIn: 'root' +}) +export class CodeEditorService { + private document: Document; + private firstEditorInitialized = false; + private loaded$ = new Subject(); + private loadingStatus = NzCodeEditorLoadingStatus.UNLOAD; + private option: JoinedEditorOptions; + + option$ = new BehaviorSubject(this.option); + + constructor( + @Inject(NZ_CODE_EDITOR_CONFIG) private config: NzCodeEditorConfig, + @Inject(DOCUMENT) _document: any // tslint:disable-line no-any + ) { + this.document = _document; + this.option = this.config.defaultEditorOption || {}; + } + + // TODO(hsuanxyz): use config service later. + updateDefaultOption(option: JoinedEditorOptions): void { + this.option = { ...this.option, ...option }; + this.option$.next(this.option); + + if (option.theme) { + editor.setTheme(option.theme); + } + } + + requestToInit(): Observable { + if (this.loadingStatus === NzCodeEditorLoadingStatus.LOADED) { + this.onInit(); + return observableOf(this.getLatestOption()); + } + + if (this.loadingStatus === NzCodeEditorLoadingStatus.UNLOAD) { + this.loadingStatus = NzCodeEditorLoadingStatus.LOADED; + this.loaded$.next(true); + this.loaded$.complete(); + this.onLoad(); + this.onInit(); + return observableOf(this.getLatestOption()); + } + + return this.loaded$.asObservable().pipe( + tap(() => this.onInit()), + map(() => this.getLatestOption()) + ); + } + + private onInit(): void { + if (!this.firstEditorInitialized) { + this.firstEditorInitialized = true; + tryTriggerFunc(this.config.onFirstEditorInit)(); + } + + tryTriggerFunc(this.config.onInit)(); + } + + private onLoad(): void { + tryTriggerFunc(this.config.onLoad)(); + } + + private getLatestOption(): JoinedEditorOptions { + return { ...this.option }; + } +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/index.ts b/zeppelin-web-angular/src/app/share/code-editor/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts b/zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts new file mode 100644 index 00000000000..103b10db1d4 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InjectionToken } from '@angular/core'; +import { SafeUrl } from '@angular/platform-browser'; +import { editor } from 'monaco-editor'; +import IEditorConstructionOptions = editor.IEditorConstructionOptions; +import IDiffEditorConstructionOptions = editor.IDiffEditorConstructionOptions; + +export type EditorOptions = IEditorConstructionOptions; +export type DiffEditorOptions = IDiffEditorConstructionOptions; +export type JoinedEditorOptions = EditorOptions | DiffEditorOptions; + +export type NzEditorMode = 'normal' | 'diff'; + +export enum NzCodeEditorLoadingStatus { + UNLOAD = 'unload', + LOADING = 'loading', + LOADED = 'LOADED' +} + +export interface NzCodeEditorConfig { + assetsRoot?: string | SafeUrl; + defaultEditorOption?: JoinedEditorOptions; + onLoad?(): void; + onFirstEditorInit?(): void; + onInit?(): void; +} + +export const NZ_CODE_EDITOR_CONFIG = new InjectionToken('nz-code-editor-config', { + providedIn: 'root', + factory: NZ_CODE_EDITOR_CONFIG_FACTORY +}); + +export function NZ_CODE_EDITOR_CONFIG_FACTORY(): NzCodeEditorConfig { + return {}; +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/public-api.ts b/zeppelin-web-angular/src/app/share/code-editor/public-api.ts new file mode 100644 index 00000000000..b2144c936c7 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/public-api.ts @@ -0,0 +1,16 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './nz-code-editor.definitions'; +export * from './code-editor.component'; +export * from './code-editor.module'; +export * from './code-editor.service'; diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html new file mode 100644 index 00000000000..71c4eac1a72 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html @@ -0,0 +1,32 @@ + + +
    + + Please enter a new name + + + + + + + + + + +
    + + + The folder will be merged into {{newFolderPath}}. Are you sure? + diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts new file mode 100644 index 00000000000..4b50f3be374 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts @@ -0,0 +1,80 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { NzModalRef } from 'ng-zorro-antd/modal'; + +import { MessageService } from '@zeppelin/services/message.service'; +import { NoteListService } from '@zeppelin/services/note-list.service'; + +@Component({ + selector: 'zeppelin-folder-rename', + templateUrl: './folder-rename.component.html', + styleUrls: ['./folder-rename.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FolderRenameComponent implements OnInit { + @Input() newFolderPath: string; + @Input() folderId: string; + willMerged = false; + + checkMerged() { + const newFolderPath = this.normalizeFolderId(this.newFolderPath); + this.willMerged = this.folderId !== this.newFolderPath && !!this.noteListService.notes.flatFolderMap[newFolderPath]; + this.cdr.markForCheck(); + } + + rename() { + this.messageService.folderRename(this.folderId, this.newFolderPath); + this.nzModalRef.destroy(); + } + + normalizeFolderId(folderId) { + let normalizeFolderId = folderId.trim(); + + while (normalizeFolderId.indexOf('\\') > -1) { + normalizeFolderId = normalizeFolderId.replace('\\', '/'); + } + + while (normalizeFolderId.indexOf('///') > -1) { + normalizeFolderId = normalizeFolderId.replace('///', '/'); + } + + normalizeFolderId = normalizeFolderId.replace('//', '/'); + + if (normalizeFolderId === '/') { + return '/'; + } + + if (normalizeFolderId[0] === '/') { + normalizeFolderId = normalizeFolderId.substring(1); + } + + if (normalizeFolderId.slice(-1) === '/') { + normalizeFolderId = normalizeFolderId.slice(0, -1); + } + + return normalizeFolderId; + } + + constructor( + private noteListService: NoteListService, + private cdr: ChangeDetectorRef, + private messageService: MessageService, + private nzModalRef: NzModalRef + ) {} + + ngOnInit() { + this.checkMerged(); + } +} diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html new file mode 100644 index 00000000000..76f93c2cef5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -0,0 +1,83 @@ + + +
    + + +
    + + + + + + + +
    + +
    diff --git a/zeppelin-web-angular/src/app/share/header/header.component.less b/zeppelin-web-angular/src/app/share/header/header.component.less new file mode 100644 index 00000000000..e4754b15ec9 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/header/header.component.less @@ -0,0 +1,110 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +.themeMixin({ + .small-icon { + margin-left: 6px; + font-size: 12px; + margin-right: 0; + transform: scale(0.8); + } + .node-list-trigger { + height: 100%; + display: inline-block; + margin: 0 -20px; + padding: 0 20px; + color: @text-color; + } + .header { + position: relative; + z-index: 999; + width: 100%; + height: 50px; + background: @component-background; + padding: 0 15px; + overflow: hidden; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.06) + } + .brand { + float: left; + width: 200px; + } + .logo { + height: 50px; + width: 75px; + background-size: 50px 30px; + background-repeat: no-repeat; + background-position: center; + background-image: url("../../../assets/images/zeppelin_svg_logo.svg"); + float: left; + } + .title { + float: left; + line-height: 50px; + font-family: 'Patua One', cursive; + font-size: 25px; + color: @primary-color; + } + .nav { + float: left; + + ul { + position: relative; + top: 2px; + border-bottom: none; + } + + a { + font-weight: 500; + } + } + .search { + float: right; + padding: 9px; + width: 300px; + margin-right: 24px; + } + .user { + float: right; + + .status { + line-height: 50px; + height: 50px; + display: inline-block; + color: @text-color; + } + } + .modal { + .about-logo { + img { + width: 95%; + } + } + + .content { + text-align: center; + + h3 { + font-family: 'Patua One', cursive; + color: #3071A9; + font-size: 30px; + margin: 0 auto; + } + + .about-version { + font-weight: 500; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts new file mode 100644 index 00000000000..b4c20c242cc --- /dev/null +++ b/zeppelin-web-angular/src/app/share/header/header.component.ts @@ -0,0 +1,101 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; +import { MessageService, TicketService } from '@zeppelin/services'; +import { NotebookSearchService } from '@zeppelin/services/notebook-search.service'; +import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; + +@Component({ + selector: 'zeppelin-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class HeaderComponent extends MessageListenersManager implements OnInit, OnDestroy { + private destroy$ = new Subject(); + connectStatus = 'error'; + noteListVisible = false; + queryStr: string | null = null; + + about() { + this.nzModalService.create({ + nzTitle: 'About Zeppelin', + nzWidth: '600px', + nzContent: AboutZeppelinComponent, + nzFooter: null + }); + } + + logout() { + this.ticketService.logout().subscribe(); + } + + onSearch() { + this.queryStr = this.queryStr.trim(); + if (this.queryStr) { + this.router.navigate(['/search', this.queryStr]); + } + } + + @MessageListener(OP.CONFIGURATIONS_INFO) + getConfiguration(data: MessageReceiveDataTypeMap[OP.CONFIGURATIONS_INFO]) { + this.ticketService.setConfiguration(data); + } + + constructor( + public ticketService: TicketService, + private nzModalService: NzModalService, + public messageService: MessageService, + private router: Router, + private notebookSearchService: NotebookSearchService, + private cdr: ChangeDetectorRef + ) { + super(messageService); + } + + ngOnInit() { + this.messageService.listConfigurations(); + this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(status => { + this.connectStatus = status ? 'success' : 'error'; + this.cdr.markForCheck(); + }); + this.router.events + .pipe( + filter(e => e instanceof NavigationEnd), + takeUntil(this.destroy$) + ) + .subscribe(() => { + this.noteListVisible = false; + this.cdr.markForCheck(); + }); + + this.notebookSearchService + .queried() + .pipe(takeUntil(this.destroy$)) + .subscribe(queryStr => (this.queryStr = queryStr)); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/share/index.ts b/zeppelin-web-angular/src/app/share/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts b/zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts new file mode 100644 index 00000000000..7352122a8da --- /dev/null +++ b/zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AfterViewChecked, Directive, ElementRef } from '@angular/core'; + +@Directive({ + selector: '[zeppelinMathJax]' +}) +export class MathJaxDirective implements AfterViewChecked { + constructor(private el: ElementRef) {} + + ngAfterViewChecked(): void { + MathJax.Hub.Queue(['Typeset', MathJax.Hub, this.el.nativeElement]); + } +} diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html new file mode 100644 index 00000000000..da6ea8525ae --- /dev/null +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html @@ -0,0 +1,65 @@ + +
    + + +
    +
    + +
    + + + + + {{errorCount}} + + + + {{messageDetails.length - errorCount}} + + +
    + +
    + + + ({{(item.pos.line + 1) + ',' + (item.pos.character + 1)}}) + {{item.message}} + more +
    +
    + +
    + + +
    diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less new file mode 100644 index 00000000000..107cfddcc2e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less @@ -0,0 +1,88 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + height: 70vh; + display: flex; + + .code-editor { + flex: auto; + } + + .messages { + overflow: auto; + position: relative; + width: 240px; + border-left: 1px solid #e8e8e8; + + i { + &.error { + color: red; + } + &.close { + color: #1f8ffb; + } + } + + .fix-bar { + padding-right: 16px; + display: flex; + font-size: 12px; + border-bottom: 1px solid #e8e8e8; + height: 25px; + line-height: 25px; + .fix-btn { + flex: 0; + font-size: 12px; + } + .log-counts { + text-align: right; + flex: 1 auto; + } + } + + + .message { + font-family: Consolas, Verdana; + color: #1e1e1e; + padding: 8px 16px 8px 5px; + transition: background-color 0.3s; + word-break: break-all; + line-height: 17px; + cursor: pointer; + font-size: 12px; + .position { + color: #5d5d5d; + } + &:hover { + background-color: #ffb86c; + } + } + } +} + + +::ng-deep { + .monaco-editor { + .scroll-decoration { + box-shadow: none; + } + .decoration-link { + text-decoration-color: red; + text-decoration-line: underline; + text-decoration-style: wavy; + text-decoration-skip-ink: none; + } + .warn-content { + background: rgba(182, 182, 182, .3); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts new file mode 100644 index 00000000000..5eea0712f0c --- /dev/null +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts @@ -0,0 +1,185 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core'; +import { editor, IDisposable, Range } from 'monaco-editor'; +import { NzModalRef } from 'ng-zorro-antd/modal'; +import { + defaultTemplateUpdaterRules, + LogLevel, + Message, + MessageDetail, + TemplateUpdater, + ValueChangeRule +} from 'ng1-template-updater'; +import { combineLatest, Subject } from 'rxjs'; +import IEditor = editor.IEditor; +import ITextModel = editor.ITextModel; +import IStandaloneCodeEditor = editor.IStandaloneCodeEditor; + +const zeppelinFunctionChangeRule: ValueChangeRule = (expression: string, start?: number) => { + let value = expression; + const messages: Message[] = []; + const funChanges = [ + { + regexp: /z\.angularBind/gm, + replace: 'z.set' + }, + { + regexp: /z\.angularUnbind/gm, + replace: 'z.unset' + }, + { + regexp: /z\.runParagraph/gm, + replace: 'z.run' + } + ]; + + funChanges.forEach(change => { + let match = change.regexp.exec(value); + while (match !== null) { + messages.push({ + position: start + match.index, + message: `${match[0]} has been deprecated, using ${change.replace} instead`, + length: match[0].length, + // url: 'https://angular.io/guide/ajs-quick-reference', + level: LogLevel.Info + }); + match = change.regexp.exec(value); + } + value = value.replace(change.regexp, change.replace); + }); + + return { + messages, + value + }; +}; + +@Component({ + selector: 'zeppelin-ng1-migration', + templateUrl: './ng1-migration.component.html', + styleUrls: ['./ng1-migration.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class Ng1MigrationComponent implements OnDestroy { + @Input() origin: string; + @Input() index: number; + @Input() match: string; + @Input() template: string; + + messageDetails: MessageDetail[] = []; + templateUpdater: TemplateUpdater; + errorCount = 0; + decorations: string[] = []; + timeoutId = -1; + editor: IStandaloneCodeEditor; + editorModel: ITextModel; + editorInit$ = new Subject(); + editorChangeDisposable: IDisposable; + + constructor(private nzModalRef: NzModalRef, private cdr: ChangeDetectorRef) { + const updateRules = { + ...defaultTemplateUpdaterRules, + valueChangeRules: [...defaultTemplateUpdaterRules.valueChangeRules, zeppelinFunctionChangeRule] + }; + this.templateUpdater = new TemplateUpdater(updateRules); + combineLatest([this.nzModalRef.afterOpen, this.editorInit$]).subscribe(() => { + if (this.editor) { + this.editorModel = this.editor.getModel() as ITextModel; + this.editor.setValue(this.template); + this.editor.layout(); + this.bindEditorEvents(); + this.check(); + setTimeout(() => { + this.editor.focus(); + }, 150); + } + }); + } + + onEditorInit(_editor: IEditor) { + this.editorInit$.next(); + this.editorInit$.complete(); + this.editor = _editor as IStandaloneCodeEditor; + } + + bindEditorEvents() { + if (this.editorModel) { + this.editorChangeDisposable = this.editorModel.onDidChangeContent(() => { + clearTimeout(this.timeoutId); + this.timeoutId = setTimeout(() => { + this.check(); + }, 300); + }); + } + } + + scrollToLine(failure: MessageDetail) { + const line = failure.pos.line + 1; + const character = failure.pos.character + 1; + const range = new Range(line, character, line, character + failure.length); + this.editor.revealRangeAtTop(range); + this.editor.setSelection(range); + this.editor.focus(); + } + + check() { + const code = this.editor.getValue(); + const { messages } = this.templateUpdater.parse(code); + this.messageDetails = [...messages]; + this.errorCount = messages.filter(f => f.level === LogLevel.Error).length; + this.decorations = this.editor.deltaDecorations( + this.decorations, + messages.map(failure => { + const line = failure.pos.line + 1; + const character = failure.pos.character + 1; + return { + range: new Range(line, character, line, character + failure.length), + options: { + className: failure.level === LogLevel.Error ? '' : 'warn-content', + inlineClassName: failure.level === LogLevel.Error ? 'decoration-link' : '', + stickiness: 1, + hoverMessage: { + value: failure.message + (failure.url ? ` [more](${failure.url})` : '') + } + } + }; + }) + ); + this.cdr.markForCheck(); + } + + fix() { + const code = this.editor.getValue(); + const { template } = this.templateUpdater.parse(code); + this.editor.setValue(template); + } + + updateAndCopy() { + const code = this.editor.getValue(); + const newTemplate = this.origin.replace(this.match, `%ng\n${code}`); + this.nzModalRef.close(newTemplate); + } + + cancel() { + this.nzModalRef.destroy(); + } + + ngOnDestroy(): void { + if (this.editorChangeDisposable) { + this.editorChangeDisposable.dispose(); + } + if (this.editorModel) { + this.editorModel.dispose(); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.html b/zeppelin-web-angular/src/app/share/node-list/node-list.component.html new file mode 100644 index 00000000000..7800443217f --- /dev/null +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.html @@ -0,0 +1,139 @@ + + + diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.less b/zeppelin-web-angular/src/app/share/node-list/node-list.component.less new file mode 100644 index 00000000000..ea197e40200 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.less @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import 'theme-mixin'; + +:host { + display: block; +} + +.themeMixin({ + .content { + width: 100%; + position: relative; + + &.header-mode { + .operation { + display: none; + } + } + } + .rename { + width: 200px; + } + nz-tree { + display: block; + } + nz-input-group { + width: 100%; + margin-top: 12px; + margin-bottom: 6px; + } + .node { + line-height: 24px; + display: inline-block; + width: calc(~"100% - 24px"); + + &.not-matched { + opacity: 0.5; + filter: grayscale(1); + } + + .operation { + margin-left: 12px; + + i { + font-size: 12px; + display: none; + + &:hover { + color: @link-active-color; + } + } + } + + &.active { + .name { + color: @link-active-color; + } + } + + &:hover, &.active { + .operation { + i { + display: inline-block; + } + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts new file mode 100644 index 00000000000..23a70c7f508 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts @@ -0,0 +1,150 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core'; +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; + +import { NzTreeNode } from 'ng-zorro-antd/core'; +import { NzModalService } from 'ng-zorro-antd/modal'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; +import { MessageService, NoteActionService, NoteListService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-node-list', + templateUrl: './node-list.component.html', + providers: [NoteListService], + styleUrls: ['./node-list.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NodeListComponent extends MessageListenersManager implements OnInit { + @Input() headerMode = false; + searchValue: string; + nodes = []; + activatedId: string; + + activeNote(id: string) { + this.activatedId = id; + } + + moveFolderToTrash(id: string) { + return this.messageService.moveFolderToTrash(id); + } + + restoreFolder(id: string) { + return this.messageService.restoreFolder(id); + } + + removeFolder(id: string) { + return this.messageService.removeFolder(id); + } + + paragraphClearAllOutput(id: string) { + return this.messageService.paragraphClearAllOutput(id); + } + + moveNoteToTrash(id: string) { + return this.messageService.moveNoteToTrash(id); + } + + restoreNote(id: string) { + return this.messageService.restoreNote(id); + } + + deleteNote(id: string) { + return this.messageService.deleteNote(id); + } + + restoreAll() { + return this.messageService.restoreAll(); + } + + emptyTrash() { + return this.messageService.emptyTrash(); + } + + toggleFolder(node: NzTreeNode) { + node.isExpanded = !node.isExpanded; + this.cdr.markForCheck(); + } + + renameNote(id: string, path: string, name: string) { + this.noteActionService.renameNote(id, path, name); + } + + renameFolder(path) { + this.noteActionService.renameFolder(path); + } + + importNote() { + this.noteActionService.importNote(); + } + + createNote(path?: string) { + this.noteActionService.createNote(path); + } + + @MessageListener(OP.NOTES_INFO) + getNotes(data: MessageReceiveDataTypeMap[OP.NOTES_INFO]) { + this.noteListService.setNotes(data.notes); + this.nodes = this.noteListService.notes.root.children + .sort((v1, v2) => this.noteComparator(v1, v2)) + .map(item => { + return { ...item, key: item.id }; + }); + this.cdr.markForCheck(); + } + + getNoteName(note) { + if (note.title === undefined || note.title.trim() === '') { + return 'Note ' + note.id; + } else { + return note.title; + } + } + + noteComparator(v1, v2) { + const note1 = v1; + const note2 = v2; + if (note1.id === this.TRASH_FOLDER_ID) { + return 1; + } + if (note2.id === this.TRASH_FOLDER_ID) { + return -1; + } + if (note1.children === undefined && note2.children !== undefined) { + return 1; + } + if (note1.children !== undefined && note2.children === undefined) { + return -1; + } + const noteName1 = this.getNoteName(note1); + const noteName2 = this.getNoteName(note2); + return noteName1.localeCompare(noteName2); + } + + constructor( + private noteListService: NoteListService, + public messageService: MessageService, + @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, + private nzModalService: NzModalService, + private noteActionService: NoteActionService, + private cdr: ChangeDetectorRef + ) { + super(messageService); + } + + ngOnInit() { + this.messageService.listNodes(); + } +} diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.html b/zeppelin-web-angular/src/app/share/note-create/note-create.component.html new file mode 100644 index 00000000000..54fe7cde684 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.html @@ -0,0 +1,44 @@ + + +
    + + + Clone Note + Import As + + + + + + + Default Interpreter + + + + + + + + + + + + + +
    + diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.less b/zeppelin-web-angular/src/app/share/note-create/note-create.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts new file mode 100644 index 00000000000..dfa9af43b7f --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts @@ -0,0 +1,105 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { NzModalRef } from 'ng-zorro-antd/modal'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { InterpreterItem, MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services/message.service'; +import { NoteListService } from '@zeppelin/services/note-list.service'; + +@Component({ + selector: 'zeppelin-note-create', + templateUrl: './note-create.component.html', + styleUrls: ['./note-create.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteCreateComponent extends MessageListenersManager implements OnInit { + @Input() path: string; + @Input() cloneNote: Note['note']; + noteName: string; + defaultInterpreter: string; + listOfInterpreter: InterpreterItem[] = []; + + @MessageListener(OP.INTERPRETER_SETTINGS) + getInterpreterSettings(data: MessageReceiveDataTypeMap[OP.INTERPRETER_SETTINGS]) { + this.listOfInterpreter = data.interpreterSettings; + this.defaultInterpreter = data.interpreterSettings[0].name; + this.cdr.markForCheck(); + } + + @MessageListener(OP.NOTES_INFO) + getNotes() { + this.nzModalRef.destroy(); + } + + newNoteName(path: string) { + let newCount = 1; + this.noteListService.notes.flatList.forEach(note => { + const noteName = note.path; + if (noteName.match(/^\/Untitled Note [0-9]*$/)) { + const lastCount = +noteName.substr(15); + if (newCount <= lastCount) { + newCount = lastCount + 1; + } + } + }); + return `${path ? path + '/' : ''}Untitled Note ${newCount}`; + } + + cloneNoteName() { + let copyCount = 1; + let newCloneName = ''; + const lastIndex = this.cloneNote.name.lastIndexOf(' '); + const endsWithNumber: boolean = !!this.cloneNote.name.match('^.+?\\s\\d$'); + const noteNamePrefix = endsWithNumber ? this.cloneNote.name.substr(0, lastIndex) : this.cloneNote.name; + const regexp = new RegExp(`^${noteNamePrefix}.+`); + + this.noteListService.notes.flatList.forEach(note => { + const noteName = note.path; + if (noteName.match(regexp)) { + const lastCopyCount = parseInt(noteName.substr(lastIndex).trim(), 10); + newCloneName = noteNamePrefix; + if (copyCount <= lastCopyCount) { + copyCount = lastCopyCount + 1; + } + } + }); + + if (!newCloneName) { + newCloneName = this.cloneNote.name; + } + return `${newCloneName} ${copyCount}`; + } + + createNote() { + this.cloneNote + ? this.messageService.cloneNote(this.cloneNote.id, this.noteName) + : this.messageService.newNote(this.noteName, this.defaultInterpreter); + } + + constructor( + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private noteListService: NoteListService, + private nzModalRef: NzModalRef + ) { + super(messageService); + } + + ngOnInit() { + this.messageService.getInterpreterSettings(); + this.noteName = this.cloneNote ? this.cloneNoteName() : this.newNoteName(this.path); + } +} diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.html b/zeppelin-web-angular/src/app/share/note-import/note-import.component.html new file mode 100644 index 00000000000..861da357a90 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.html @@ -0,0 +1,50 @@ + + +
    + + Import As + + + + +
    + + + + +

    + +

    +

    Click or drag JSON file to this area to upload

    +

    + JSON file size cannot exceed {{maxLimit | humanizeBytes}} +

    +
    +
    + +
    + + URL + + + + + + + + + +
    +
    +
    + diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.less b/zeppelin-web-angular/src/app/share/note-import/note-import.component.less new file mode 100644 index 00000000000..bb67745eec8 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.less @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + nz-alert { + margin-top: 12px; + } +}); diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts new file mode 100644 index 00000000000..7317b341157 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts @@ -0,0 +1,111 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HttpClient } from '@angular/common/http'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; + +import { get } from 'lodash'; +import { NzModalRef } from 'ng-zorro-antd/modal'; +import { UploadFile } from 'ng-zorro-antd/upload'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { OP } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services/message.service'; +import { TicketService } from '@zeppelin/services/ticket.service'; + +@Component({ + selector: 'zeppelin-note-import', + templateUrl: './note-import.component.html', + styleUrls: ['./note-import.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteImportComponent extends MessageListenersManager implements OnInit { + noteImportName: string; + importUrl: string; + errorText: string; + importLoading = false; + maxLimit = get(this.ticketService.configuration, ['zeppelin.websocket.max.text.message.size'], null); + + @MessageListener(OP.NOTES_INFO) + getNotes() { + this.nzModalRef.destroy(); + } + + importNote() { + this.errorText = ''; + this.importLoading = true; + this.httpClient.get(this.importUrl).subscribe( + data => { + this.importLoading = false; + this.processImportJson(data); + this.cdr.markForCheck(); + }, + () => { + this.errorText = 'Unable to Fetch URL'; + this.importLoading = false; + this.cdr.markForCheck(); + }, + () => {} + ); + } + + beforeUpload = (file: UploadFile): boolean => { + this.errorText = ''; + if (file.size > this.maxLimit) { + this.errorText = 'File size limit Exceeded!'; + } else { + const reader = new FileReader(); + // tslint:disable-next-line:no-any + reader.readAsText(file as any); + reader.onloadend = () => { + this.processImportJson(reader.result); + }; + } + this.cdr.markForCheck(); + return false; + }; + + processImportJson(data) { + let result = data; + if (typeof result !== 'object') { + try { + result = JSON.parse(result); + } catch (e) { + this.errorText = 'JSON parse exception'; + return; + } + } + if (result.paragraphs && result.paragraphs.length > 0) { + if (!this.noteImportName) { + this.noteImportName = result.name; + } else { + result.name = this.noteImportName; + } + this.messageService.importNote(result); + } else { + this.errorText = 'Invalid JSON'; + } + this.cdr.markForCheck(); + } + + constructor( + private ticketService: TicketService, + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private nzModalRef: NzModalRef, + private httpClient: HttpClient + ) { + super(messageService); + } + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html new file mode 100644 index 00000000000..f37415e04c0 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html @@ -0,0 +1,23 @@ + + +
    + + Please enter a new name + + + + + +
    diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts new file mode 100644 index 00000000000..1413e1db315 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; + +import { NzModalRef } from 'ng-zorro-antd/modal'; + +import { MessageService } from '@zeppelin/services/message.service'; + +@Component({ + selector: 'zeppelin-note-rename', + templateUrl: './note-rename.component.html', + styleUrls: ['./note-rename.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteRenameComponent implements OnInit { + @Input() newName: string; + @Input() id: string; + + rename() { + this.messageService.noteRename(this.id, this.newName); + this.nzModalRef.destroy(); + } + + constructor(private messageService: MessageService, private nzModalRef: NzModalRef) {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.html b/zeppelin-web-angular/src/app/share/page-header/page-header.component.html new file mode 100644 index 00000000000..c214ab41ff4 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.html @@ -0,0 +1,18 @@ + + + +

    {{title}}

    +

    {{description}}

    + + +
    diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.less b/zeppelin-web-angular/src/app/share/page-header/page-header.component.less new file mode 100644 index 00000000000..f0b6ac78b0e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.less @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +:host { + .header-extra { + float: right; + } +} diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts new file mode 100644 index 00000000000..0ec592531f2 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts @@ -0,0 +1,31 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core'; +import { InputBoolean } from 'ng-zorro-antd/core'; + +@Component({ + selector: 'zeppelin-page-header', + templateUrl: './page-header.component.html', + styleUrls: ['./page-header.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PageHeaderComponent implements OnInit { + @Input() title: string; + @Input() description: string | TemplateRef; + @Input() @InputBoolean() divider = false; + @Input() extra: TemplateRef; + + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts b/zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts new file mode 100644 index 00000000000..5460413af8e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts @@ -0,0 +1,40 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'humanizeBytes' +}) +export class HumanizeBytesPipe implements PipeTransform { + transform(value: number): string { + if (value === null || value === undefined) { + return '-'; + } + const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']; + const converter = (v: number, p: number): string => { + const base = Math.pow(1024, p); + if (v < base) { + return `${(v / base).toFixed(2)} ${units[p]}`; + } else if (v < base * 1000) { + return `${(v / base).toPrecision(3)} ${units[p]}`; + } else { + return converter(v, p + 1); + } + }; + if (value < 1000) { + return value + ' B'; + } else { + return converter(value, 1); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/pipes/index.ts b/zeppelin-web-angular/src/app/share/pipes/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/pipes/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/pipes/public-api.ts b/zeppelin-web-angular/src/app/share/pipes/public-api.ts new file mode 100644 index 00000000000..0397f58d260 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/pipes/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './humanize-bytes.pipe'; diff --git a/zeppelin-web-angular/src/app/share/public-api.ts b/zeppelin-web-angular/src/app/share/public-api.ts new file mode 100644 index 00000000000..b8c2732003e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/public-api.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './pipes'; +export * from './resize-handle'; +export * from './share.module'; diff --git a/zeppelin-web-angular/src/app/share/resize-handle/index.ts b/zeppelin-web-angular/src/app/share/resize-handle/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/resize-handle/public-api.ts b/zeppelin-web-angular/src/app/share/resize-handle/public-api.ts new file mode 100644 index 00000000000..3744d417562 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/public-api.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './resize-handle.component'; diff --git a/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html new file mode 100644 index 00000000000..72092e39325 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html @@ -0,0 +1,23 @@ + + + + + diff --git a/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less new file mode 100644 index 00000000000..8eb1214ddb1 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +:host { + width: 24px; + height: 24px; + position: absolute; + right: 1px; + bottom: 1px; + color: #595959; + transition: opacity ease-out .2s; + cursor: se-resize; + z-index: 9; +} diff --git a/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts new file mode 100644 index 00000000000..b9d43322d33 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'zeppelin-resize-handle', + templateUrl: './resize-handle.component.html', + styleUrls: ['./resize-handle.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + role: 'resize-handle' + } +}) +export class ResizeHandleComponent { + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts b/zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts new file mode 100644 index 00000000000..db6a7fc243a --- /dev/null +++ b/zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts @@ -0,0 +1,80 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Directive, ElementRef, Input, NgZone, OnChanges, Renderer2, SimpleChanges } from '@angular/core'; +import { SafeHtml } from '@angular/platform-browser'; +import { take } from 'rxjs/operators'; + +const loadedExternalScripts = new Set(); + +@Directive({ + selector: '[zeppelinRunScripts]' +}) +export class RunScriptsDirective implements OnChanges { + @Input() scriptsContent: string | SafeHtml; + + constructor(private elementRef: ElementRef, private ngZone: NgZone, private renderer: Renderer2) {} + + runScripts(): void { + if (!this.scriptsContent.toString()) { + return; + } + this.ngZone.onStable.pipe(take(1)).subscribe(() => { + this.ngZone.runOutsideAngular(() => { + const scripts = this.elementRef.nativeElement.getElementsByTagName('script'); + const externalScripts = []; + const localScripts = []; + for (let i = 0; i < scripts.length; i++) { + const script = scripts[i]; + if (script.text) { + localScripts.push(script); + } else if (script.src) { + externalScripts.push(script); + } + this.renderer.removeChild(this.elementRef.nativeElement, script); + } + Promise.all(externalScripts.map(s => this.loadExternalScript(s, this.elementRef.nativeElement))).then(() => { + localScripts.forEach(s => this.loadLocalScript(s, this.elementRef.nativeElement)); + }); + }); + }); + } + + loadExternalScript(script: HTMLScriptElement, parentNode: HTMLElement): Promise { + return new Promise(resolve => { + if (loadedExternalScripts.has(script.src)) { + resolve(); + } + const scriptCopy = this.renderer.createElement('script') as HTMLScriptElement; + scriptCopy.type = script.type ? script.type : 'text/javascript'; + scriptCopy.src = script.src; + scriptCopy.onload = () => { + resolve(); + loadedExternalScripts.add(script.src); + }; + parentNode.appendChild(scriptCopy); + }); + } + + loadLocalScript(script: HTMLScriptElement, parentNode: HTMLElement): void { + const scriptCopy = this.renderer.createElement('script') as HTMLScriptElement; + scriptCopy.type = script.type ? script.type : 'text/javascript'; + scriptCopy.text = `(function() { ${script.text} })();`; + parentNode.appendChild(scriptCopy); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.scriptsContent) { + this.runScripts(); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts new file mode 100644 index 00000000000..26047e4fa8a --- /dev/null +++ b/zeppelin-web-angular/src/app/share/share.module.ts @@ -0,0 +1,102 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzAddOnModule } from 'ng-zorro-antd/core'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzNotificationModule } from 'ng-zorro-antd/notification'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzTabsModule } from 'ng-zorro-antd/tabs'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTreeModule } from 'ng-zorro-antd/tree'; +import { NzUploadModule } from 'ng-zorro-antd/upload'; + +import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; +import { CodeEditorModule } from '@zeppelin/share/code-editor'; +import { FolderRenameComponent } from '@zeppelin/share/folder-rename/folder-rename.component'; +import { HeaderComponent } from '@zeppelin/share/header/header.component'; +import { MathJaxDirective } from '@zeppelin/share/math-jax/math-jax.directive'; +import { NodeListComponent } from '@zeppelin/share/node-list/node-list.component'; +import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; +import { NoteImportComponent } from '@zeppelin/share/note-import/note-import.component'; +import { NoteRenameComponent } from '@zeppelin/share/note-rename/note-rename.component'; +import { PageHeaderComponent } from '@zeppelin/share/page-header/page-header.component'; +import { HumanizeBytesPipe } from '@zeppelin/share/pipes'; +import { RunScriptsDirective } from '@zeppelin/share/run-scripts/run-scripts.directive'; +import { SpinComponent } from '@zeppelin/share/spin/spin.component'; +import { Ng1MigrationComponent } from './ng1-migration/ng1-migration.component'; +import { ResizeHandleComponent } from './resize-handle'; + +const MODAL_LIST = [ + AboutZeppelinComponent, + NoteImportComponent, + NoteCreateComponent, + NoteRenameComponent, + FolderRenameComponent, + Ng1MigrationComponent +]; +const EXPORT_LIST = [HeaderComponent, NodeListComponent, PageHeaderComponent, SpinComponent, ResizeHandleComponent]; +const PIPES = [HumanizeBytesPipe]; + +@NgModule({ + declarations: [MODAL_LIST, EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective], + entryComponents: [MODAL_LIST], + exports: [EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective, CodeEditorModule], + imports: [ + FormsModule, + CommonModule, + NzMenuModule, + NzAddOnModule, + NzIconModule, + NzInputModule, + NzDropDownModule, + NzBadgeModule, + NzGridModule, + NzModalModule, + NzTreeModule, + RouterModule, + NzButtonModule, + NzNotificationModule, + NzToolTipModule, + NzDividerModule, + NzMessageModule, + NzCardModule, + NzPopconfirmModule, + NzPopconfirmModule, + NzFormModule, + NzTabsModule, + NzUploadModule, + NzSelectModule, + NzAlertModule, + NzProgressModule, + CodeEditorModule + ] +}) +export class ShareModule {} diff --git a/zeppelin-web-angular/src/app/share/spin/spin.component.html b/zeppelin-web-angular/src/app/share/spin/spin.component.html new file mode 100644 index 00000000000..81b188308b1 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/spin/spin.component.html @@ -0,0 +1,21 @@ + + +
    +
    + +
    +

    Zeppelin

    + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/share/spin/spin.component.less b/zeppelin-web-angular/src/app/share/spin/spin.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/spin/spin.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/share/spin/spin.component.ts b/zeppelin-web-angular/src/app/share/spin/spin.component.ts new file mode 100644 index 00000000000..34e7cedd01a --- /dev/null +++ b/zeppelin-web-angular/src/app/share/spin/spin.component.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'zeppelin-spin', + templateUrl: './spin.component.html', + styleUrls: ['./spin.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SpinComponent implements OnInit { + @Input() transparent = false; + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/spell/spell-result.ts b/zeppelin-web-angular/src/app/spell/spell-result.ts new file mode 100644 index 00000000000..50051d2e94a --- /dev/null +++ b/zeppelin-web-angular/src/app/spell/spell-result.ts @@ -0,0 +1,27 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class SpellResult { + static extractMagic(allParagraphText) { + const pattern = /^\s*%(\S+)\s*/g; + try { + const match = pattern.exec(allParagraphText); + if (match) { + return `%${match[1].trim()}`; + } + } catch (error) { + // failed to parse, ignore + } + + return undefined; + } +} diff --git a/zeppelin-web-angular/src/app/utility/css-unit-conversion.ts b/zeppelin-web-angular/src/app/utility/css-unit-conversion.ts new file mode 100644 index 00000000000..19d4057f45c --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/css-unit-conversion.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function pt2px(pt: number): number { + return pt / (3 / 4); +} diff --git a/zeppelin-web-angular/src/app/utility/element.ts b/zeppelin-web-angular/src/app/utility/element.ts new file mode 100644 index 00000000000..cdae6de0045 --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/element.ts @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function scrollIntoViewIfNeeded(element: HTMLElement, center = true): void { + // tslint:disable-next-line:no-any + if (element && typeof (element as any).scrollIntoViewIfNeeded === 'function') { + // tslint:disable-next-line:no-any + (element as any).scrollIntoViewIfNeeded(center); + } +} diff --git a/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts b/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts new file mode 100644 index 00000000000..c2eb7aa3965 --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { computeLineStartsMap, getLineAndCharacterFromPosition } from '@zeppelin/utility/line-map'; + +export interface KeywordPosition { + line: number; + character: number; + length: number; +} + +export function getKeywordPositions(keywords: string[], str: string): KeywordPosition[] { + const highlightPositions = []; + const lineMap = computeLineStartsMap(str); + + keywords.forEach((keyword: string) => { + const positions = []; + const keywordReg = new RegExp(keyword, 'ig'); + let posMatch = keywordReg.exec(str); + + while (posMatch !== null) { + const { line, character } = getLineAndCharacterFromPosition(lineMap, posMatch.index); + positions.push({ + line, + character, + length: keyword.length + }); + posMatch = keywordReg.exec(str); + } + highlightPositions.push(...positions); + }); + + return highlightPositions; +} diff --git a/zeppelin-web-angular/src/app/utility/line-map.ts b/zeppelin-web-angular/src/app/utility/line-map.ts new file mode 100644 index 00000000000..30c40793c81 --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/line-map.ts @@ -0,0 +1,60 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const LF_CHAR = 10; +const CR_CHAR = 13; +const LINE_SEP_CHAR = 8232; +const PARAGRAPH_CHAR = 8233; + +export function computeLineStartsMap(text) { + const result = [0]; + let pos = 0; + while (pos < text.length) { + const char = text.charCodeAt(pos++); + // Handles the "CRLF" line break. In that case we peek the character + // after the "CR" and check if it is a line feed. + if (char === CR_CHAR) { + if (text.charCodeAt(pos) === LF_CHAR) { + pos++; + } + result.push(pos); + } else if (char === LF_CHAR || char === LINE_SEP_CHAR || char === PARAGRAPH_CHAR) { + result.push(pos); + } + } + result.push(pos); + return result; +} + +function findClosestLineStartPosition(linesMap, position, low = 0, high = linesMap.length - 1) { + let _low = low; + let _high = high; + while (_low <= _high) { + const pivotIdx = Math.floor((_low + _high) / 2); + const pivotEl = linesMap[pivotIdx]; + if (pivotEl === position) { + return pivotIdx; + } else if (position > pivotEl) { + _low = pivotIdx + 1; + } else { + _high = pivotIdx - 1; + } + } + // In case there was no exact match, return the closest "lower" line index. We also + // subtract the index by one because want the index of the previous line start. + return _low - 1; +} + +export function getLineAndCharacterFromPosition(lineStartsMap, position) { + const lineIndex = findClosestLineStartPosition(lineStartsMap, position); + return { character: position - lineStartsMap[lineIndex], line: lineIndex }; +} diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html new file mode 100644 index 00000000000..4b4caf1d140 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html @@ -0,0 +1,35 @@ + + +
    + + + + +
    +
    + + View + + + + + + + + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less new file mode 100644 index 00000000000..b8beb4c3cb5 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.area-chart-setting { + margin: 10px 0; +} diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts new file mode 100644 index 00000000000..07ffb22cc4c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts @@ -0,0 +1,102 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; +import { setChartXAxis } from '../common/util/set-x-axis'; +import { VisualizationXAxisSettingComponent } from '../common/x-axis-setting/x-axis-setting.component'; + +@Component({ + selector: 'zeppelin-area-chart-visualization', + templateUrl: './area-chart-visualization.component.html', + styleUrls: ['./area-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AreaChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationXAxisSettingComponent, { static: false }) + xAxisSettingComponent: VisualizationXAxisSettingComponent; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + style: 'stream' | 'expand' | 'stack' = 'stack'; + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + viewChange() { + this.config.setting.stackedAreaChart.style = this.style; + this.visualization.configChange$.next(this.config); + } + + ngOnInit() {} + + refreshSetting() { + this.style = this.config.setting.stackedAreaChart.style; + this.pivotSettingComponent.init(); + this.xAxisSettingComponent.init(); + this.cdr.markForCheck(); + } + + ngAfterViewInit(): void { + this.render(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore() { + const key = this.getKey(); + this.setScale(); + if (this.style === 'stack') { + // area:stack + this.chart + .areaStack() + .position(`${key}*__value__`) + .color('__key__'); + } else if (this.style === 'stream') { + // area:stream + this.chart + .area() + .position(`${key}*__value__`) + .adjust(['stack', 'symmetric']) + .color('__key__'); + } else { + // area:percent + this.chart + .areaStack() + .position(`${key}*__percent__`) + .color('__key__'); + } + + setChartXAxis(this.visualization, 'stackedAreaChart', this.chart, key); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts new file mode 100644 index 00000000000..a7f1b481c69 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { AreaChartVisualizationComponent } from './area-chart-visualization.component'; + +export class AreaChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + AreaChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html new file mode 100644 index 00000000000..eb798668215 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html @@ -0,0 +1,34 @@ + + +
    + + + + +
    + + View + + + + + + + +
    +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less new file mode 100644 index 00000000000..cd842d1ed23 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + bar-chart-setting { + margin: 10px 0; + } + .field-setting-wrap { + margin-top: 10px; + } + .drag-wrap { + min-height: 23px; + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts new file mode 100644 index 00000000000..22944451cb2 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts @@ -0,0 +1,110 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { get } from 'lodash'; + +import { VisualizationMultiBarChart } from '@zeppelin/sdk'; +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; +import { setChartXAxis } from '../common/util/set-x-axis'; +import { VisualizationXAxisSettingComponent } from '../common/x-axis-setting/x-axis-setting.component'; + +@Component({ + selector: 'zeppelin-bar-chart-visualization', + templateUrl: './bar-chart-visualization.component.html', + styleUrls: ['./bar-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class BarChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationXAxisSettingComponent, { static: false }) + xAxisSettingComponent: VisualizationXAxisSettingComponent; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + stacked = false; + + viewChange() { + if (!this.config.setting.multiBarChart) { + this.config.setting.multiBarChart = new VisualizationMultiBarChart(); + } + this.config.setting.multiBarChart.stacked = this.stacked; + this.visualization.configChange$.next(this.config); + } + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + ngOnInit() {} + + ngAfterViewInit() { + this.render(); + } + + refreshSetting() { + this.stacked = get(this.config.setting, 'multiBarChart.stacked', false); + this.pivotSettingComponent.init(); + this.xAxisSettingComponent.init(); + this.cdr.markForCheck(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore(chart) { + const key = this.getKey(); + this.setScale(); + + this.chart.tooltip({ + shared: false + }); + if (get(this.config.setting, 'multiBarChart.stacked', false)) { + this.chart + .intervalStack() + .position(`${key}*__value__`) + .color('__key__') + .opacity(1); + } else { + this.chart + .interval() + .position(`${key}*__value__`) + .color('__key__') + .opacity(1) + .adjust([ + { + type: 'dodge', + marginRatio: 0 + } + ]); + } + setChartXAxis(this.visualization, 'multiBarChart', this.chart, key); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts new file mode 100644 index 00000000000..736e43dadd1 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts @@ -0,0 +1,31 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { BarChartVisualizationComponent } from './bar-chart-visualization.component'; + +export class BarChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + BarChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html new file mode 100644 index 00000000000..fb1497f43db --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html @@ -0,0 +1,85 @@ + + + +
    + {{item.name}} +
    +
    +
    + +
    + + {{item.name}} + + +
    +
    +
    +
    + +
    + + {{item.name}} + + +
    +
    +
    +
    + +
    + + {{item.name}} {{item.aggr | uppercase}}  + + +
      +
    • + {{aggregate}} +
    • +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less new file mode 100644 index 00000000000..9091c367751 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + display: block; + margin: 10px 0; + .field-setting-wrap { + margin-top: 24px; + } + .drag-wrap { + min-height: 23px; + } + nz-card { + background: #fff; + ::ng-deep { + .ant-card-head { + padding: 0 12px; + background: #fafafa; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts new file mode 100644 index 00000000000..12abf17c79c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts @@ -0,0 +1,89 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { copyArrayItem, moveItemInArray, transferArrayItem, CdkDragDrop } from '@angular/cdk/drag-drop'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { TableData, Visualization } from '@zeppelin/visualization'; + +@Component({ + selector: 'zeppelin-visualization-pivot-setting', + templateUrl: './pivot-setting.component.html', + styleUrls: ['./pivot-setting.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class VisualizationPivotSettingComponent implements OnInit { + @Input() visualization: Visualization; + + tableData: TableData; + config: GraphConfig; + columns = []; + aggregates = ['sum', 'count', 'avg', 'min', 'max']; + + // tslint:disable-next-line + drop(event: CdkDragDrop) { + if (event.container.id === 'columns-list') { + return; + } + if (event.previousContainer === event.container) { + moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); + } else { + if ( + event.container.id !== 'value-list' && + event.container.data.findIndex(e => e.name === event.previousContainer.data[event.previousIndex].name) !== -1 + ) { + return; + } + if (event.previousContainer.id === 'columns-list') { + copyArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); + } else { + transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); + } + } + this.visualization.configChange$.next(this.config); + } + + // tslint:disable-next-line + removeFieldAt(data: any[], index: number): void { + data.splice(index, 1); + this.visualization.configChange$.next(this.config); + this.cdr.markForCheck(); + } + + changeAggregate(aggregates: string, index: number): void { + this.config.values[index].aggr = aggregates; + this.visualization.configChange$.next(this.config); + this.cdr.markForCheck(); + } + + noReturnPredicate() { + return false; + } + + init() { + this.tableData = this.visualization.getTransformation().getTableData() as TableData; + this.config = this.visualization.getConfig(); + this.columns = this.tableData.columns.map((name, index) => ({ + name, + index, + aggr: 'sum' + })); + this.cdr.markForCheck(); + } + + constructor(private cdr: ChangeDetectorRef) {} + + ngOnInit() { + this.init(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html new file mode 100644 index 00000000000..7333cee57ba --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html @@ -0,0 +1,98 @@ + + + +
    + {{item.name}} +
    +
    +
    + +
    + + {{item.name}} + + +
    +
    +
    +
    + +
    + + {{item.name}} + + +
    +
    +
    +
    + +
    + + {{item.name}} + + +
    +
    +
    +
    + +
    + + {{item.name}} + + +
    +
    +
    + +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less new file mode 100644 index 00000000000..35d9c4e3892 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less @@ -0,0 +1,33 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + display: block; + margin: 10px 0; + .field-setting-wrap { + margin-top: 10px; + } + .drag-wrap { + min-height: 23px; + } + nz-card { + background: #fff; + ::ng-deep { + .ant-card-head { + padding: 0 12px; + background: #fafafa; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts new file mode 100644 index 00000000000..e154549e43e --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts @@ -0,0 +1,102 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkDragDrop } from '@angular/cdk/drag-drop'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { get } from 'lodash'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { TableData, Visualization } from '@zeppelin/visualization'; + +@Component({ + selector: 'zeppelin-visualization-scatter-setting', + templateUrl: './scatter-setting.component.html', + styleUrls: ['./scatter-setting.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class VisualizationScatterSettingComponent implements OnInit { + @Input() visualization: Visualization; + + tableData: TableData; + config: GraphConfig; + columns = []; + + field = { + xAxis: [], + yAxis: [], + group: [], + size: [] + }; + + // tslint:disable-next-line + drop(event: CdkDragDrop) { + this.clean(event.container.data, false); + event.container.data.push(event.previousContainer.data[event.previousIndex]); + this.cdr.markForCheck(); + this.updateConfig(); + } + + // tslint:disable-next-line + clean(data: any[], update = true): void { + while (data.length > 0) { + data.splice(0, 1); + } + if (update) { + this.updateConfig(); + } + this.cdr.markForCheck(); + } + + noReturnPredicate() { + return false; + } + + updateConfig() { + if (!this.config.setting.scatterChart) { + this.config.setting.scatterChart = {}; + } + const scatterSetting = this.config.setting.scatterChart; + scatterSetting.xAxis = this.field.xAxis[0]; + scatterSetting.yAxis = this.field.yAxis[0]; + scatterSetting.size = this.field.size[0]; + scatterSetting.group = this.field.group[0]; + this.visualization.configChange$.next(this.config); + } + + constructor(private cdr: ChangeDetectorRef) {} + + init() { + this.tableData = this.visualization.getTransformation().getTableData() as TableData; + this.config = this.visualization.getConfig(); + this.columns = this.tableData.columns.map((name, index) => ({ + name, + index, + aggr: 'sum' + })); + + const xAxis = get(this.config.setting, 'scatterChart.xAxis', this.columns[0]); + const yAxis = get(this.config.setting, 'scatterChart.yAxis', this.columns[1]); + const group = get(this.config.setting, 'scatterChart.group'); + const size = get(this.config.setting, 'scatterChart.size'); + const arrayWrapper = value => (value ? [value] : []); + this.field.xAxis = arrayWrapper(xAxis); + this.field.yAxis = arrayWrapper(yAxis); + this.field.group = arrayWrapper(group); + this.field.size = arrayWrapper(size); + this.cdr.markForCheck(); + } + + ngOnInit() { + this.init(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts b/zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts new file mode 100644 index 00000000000..bfa81a8df81 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts @@ -0,0 +1,22 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const DEFAULT_TICK_COUNT = 16; + +export function calcTickCount(el: HTMLElement) { + if (el && el.getBoundingClientRect) { + const tickCount = Math.round(el.getBoundingClientRect().width / 60); + return Number.isNaN(tickCount) ? DEFAULT_TICK_COUNT : tickCount; + } else { + return DEFAULT_TICK_COUNT; + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts b/zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts new file mode 100644 index 00000000000..e41ad7983a0 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as G2 from '@antv/g2'; +import { get } from 'lodash'; + +import { Visualization } from '@zeppelin/visualization'; + +export function setChartXAxis( + visualization: Visualization, + mode: 'lineChart' | 'multiBarChart' | 'stackedAreaChart', + chart: G2.Chart, + key: string +) { + const config = visualization.getConfig(); + const setting = config.setting[mode]; + chart.axis(key, { + label: { + textStyle: { + rotate: 0 + } + } + }); + switch (setting.xLabelStatus) { + case 'hide': + chart.axis(key, false); + break; + case 'rotate': + chart.axis(key, { + label: { + textStyle: { + rotate: Number.parseInt(get(setting, 'rotate.degree', '-45'), 10) + } + } + }); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html new file mode 100644 index 00000000000..cd11081ab04 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html @@ -0,0 +1,38 @@ + + +
    + + xAxis + + + + + + + + + + degree + + + + + + + +
    diff --git a/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less new file mode 100644 index 00000000000..3e7f1f963ba --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less @@ -0,0 +1,18 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + display: block; + margin: 10px 0; +}); diff --git a/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts new file mode 100644 index 00000000000..0a5d5460de7 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { get } from 'lodash'; + +import { GraphConfig, XAxisSetting, XLabelStatus } from '@zeppelin/sdk'; +import { Visualization } from '@zeppelin/visualization'; + +@Component({ + selector: 'zeppelin-visualization-x-axis-setting', + templateUrl: './x-axis-setting.component.html', + styleUrls: ['./x-axis-setting.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class VisualizationXAxisSettingComponent implements OnInit { + @Input() visualization: Visualization; + @Input() mode: 'lineChart' | 'multiBarChart' | 'stackedAreaChart'; + + setting: XAxisSetting; + config: GraphConfig; + xLabelStatus: XLabelStatus = 'default'; + degree = '-45'; + previousDegree: string; + constructor(private cdr: ChangeDetectorRef) {} + + onStatusChange() { + this.setting.xLabelStatus = this.xLabelStatus; + this.updateConfig(); + } + + onDegreeChange() { + if (this.degree === this.previousDegree) { + return; + } + const degree = Number.parseInt(this.degree, 10); + if (Number.isNaN(degree)) { + this.degree = this.previousDegree; + return; + } else { + this.degree = `${degree}`; + this.previousDegree = this.degree; + } + this.updateConfig(); + } + + updateConfig() { + this.setting.rotate.degree = this.degree; + this.setting.xLabelStatus = this.xLabelStatus; + this.visualization.configChange$.next(this.config); + } + + init() { + this.config = this.visualization.getConfig(); + this.setting = this.config.setting[this.mode]; + if (!this.setting.rotate) { + this.setting.rotate = { degree: '-45' }; + } + this.xLabelStatus = get(this.setting, ['xLabelStatus'], 'default'); + this.degree = get(this.setting, ['rotate', 'degree'], '-45'); + this.previousDegree = this.degree; + this.cdr.markForCheck(); + } + + ngOnInit() { + this.init(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/g2.config.ts b/zeppelin-web-angular/src/app/visualizations/g2.config.ts new file mode 100644 index 00000000000..622d25ddb74 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/g2.config.ts @@ -0,0 +1,129 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as G2 from '@antv/g2'; + +const DEFAULT_COLOR = '#03578c'; +const COLOR_PLATE_8 = ['#03578c', '#179bd4', '#bf4f07', '#005041', '#8543E0', '#57c2e9', '#03138c', '#8c0357']; + +const COLOR_PLATE_16 = [ + '#03588C', + '#82B8D9', + '#025959', + '#FACC14', + '#E6965C', + '#223273', + '#7564CC', + '#8543E0', + '#5C8EE6', + '#13C2C2', + '#5CA3E6', + '#3436C7', + '#B381E6', + '#F04864', + '#D598D9' +]; +const COLOR_PLATE_24 = [ + '#03588C', + '#66B5FF', + '#82B8D9', + '#025959', + '#027368', + '#9AE65C', + '#FACC14', + '#E6965C', + '#57AD71', + '#223273', + '#738AE6', + '#7564CC', + '#8543E0', + '#A877ED', + '#5C8EE6', + '#13C2C2', + '#70E0E0', + '#5CA3E6', + '#3436C7', + '#8082FF', + '#DD81E6', + '#F04864', + '#FA7D92', + '#D598D9' +]; +const COLOR_PIE = ['#03588C', '#13C2C2', '#025959', '#FACC14', '#F04864', '#8543E0', '#3436C7', '#223273']; +const COLOR_PIE_16 = [ + '#03588C', + '#73C9E6', + '#13C2C2', + '#6CD9B3', + '#025959', + '#9DD96C', + '#FACC14', + '#E6965C', + '#F04864', + '#D66BCA', + '#8543E0', + '#8E77ED', + '#3436C7', + '#737EE6', + '#223273', + '#7EA2E6' +]; + +const zeppelinTheme = { + defaultColor: DEFAULT_COLOR, + colors: COLOR_PLATE_8, + colors_16: COLOR_PLATE_16, + colors_24: COLOR_PLATE_24, + colors_pie: COLOR_PIE, + colors_pie_16: COLOR_PIE_16, + shape: { + point: { + fill: DEFAULT_COLOR + }, + hollowPoint: { + stroke: DEFAULT_COLOR + }, + interval: { + fill: DEFAULT_COLOR + }, + hollowInterval: { + stroke: DEFAULT_COLOR + }, + area: { + fill: DEFAULT_COLOR + }, + polygon: { + fill: DEFAULT_COLOR + }, + hollowPolygon: { + stroke: DEFAULT_COLOR + }, + hollowArea: { + stroke: DEFAULT_COLOR + }, + line: { + stroke: DEFAULT_COLOR + }, + edge: { + stroke: DEFAULT_COLOR + }, + schema: { + stroke: DEFAULT_COLOR + } + } +}; + +export function setTheme() { + const theme = G2.Util.deepMix(G2.Global, zeppelinTheme); + // tslint:disable-next-line:no-any + (G2.Global as any).setTheme(theme); +} diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html new file mode 100644 index 00000000000..cb8faab7ed4 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html @@ -0,0 +1,44 @@ + + +
    + + +
    + +
    + +
    + +
    + + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less new file mode 100644 index 00000000000..8e84bc5be30 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.themeMixin({ + .zoom-tips { + color: @text-color-secondary; + } + .line-setting { + margin: 10px 0; + input.format-input { + width: 160px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts new file mode 100644 index 00000000000..02938e55327 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts @@ -0,0 +1,137 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; +import { setChartXAxis } from '../common/util/set-x-axis'; +import { VisualizationXAxisSettingComponent } from '../common/x-axis-setting/x-axis-setting.component'; + +@Component({ + selector: 'zeppelin-line-chart-visualization', + templateUrl: './line-chart-visualization.component.html', + styleUrls: ['./line-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LineChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationXAxisSettingComponent, { static: false }) + xAxisSettingComponent: VisualizationXAxisSettingComponent; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + forceY = false; + lineWithFocus = false; + isDateFormat = false; + dateFormat = ''; + + settingChange(): void { + const setting = this.config.setting.lineChart; + setting.lineWithFocus = this.lineWithFocus; + setting.forceY = this.forceY; + setting.isDateFormat = this.isDateFormat; + setting.dateFormat = this.dateFormat; + this.visualization.configChange$.next(this.config); + } + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + ngOnInit() {} + + refreshSetting() { + const setting = this.config.setting.lineChart; + this.forceY = setting.forceY || false; + this.lineWithFocus = setting.lineWithFocus || false; + this.isDateFormat = setting.isDateFormat || false; + this.dateFormat = setting.dateFormat || ''; + this.pivotSettingComponent.init(); + this.xAxisSettingComponent.init(); + this.cdr.markForCheck(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore() { + const key = this.getKey(); + const setting = this.config.setting.lineChart; + this.setScale(); + this.chart + .line() + .position(`${key}*__value__`) + .color('__key__'); + setChartXAxis(this.visualization, 'lineChart', this.chart, key); + + if (setting.isDateFormat) { + if (this.visualization.transformed && this.visualization.transformed.rows) { + const invalid = this.visualization.transformed.rows.some(r => { + const isInvalidDate = Number.isNaN(new Date(r[key]).valueOf()); + if (isInvalidDate) { + console.warn(`${r[key]} is [Invalid Date]`); + } + return isInvalidDate; + }); + if (invalid) { + return; + } + this.chart.scale({ + [key]: { + type: 'time', + mask: setting.dateFormat || 'YYYY-MM-DD' + } + }); + } + } + + if (setting.forceY) { + this.chart.scale({ + __value__: { + min: 0 + } + }); + } + } + + renderAfter() { + const setting = this.config.setting.lineChart; + if (setting.lineWithFocus) { + // tslint:disable-next-line + (this.chart as any).interact('brush'); + } else { + // tslint:disable-next-line:no-any + (this.chart as any).clearInteraction(); + } + } + + ngAfterViewInit() { + this.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts new file mode 100644 index 00000000000..0be29c7676b --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { LineChartVisualizationComponent } from './line-chart-visualization.component'; + +export class LineChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + LineChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html new file mode 100644 index 00000000000..5ddf300130b --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html @@ -0,0 +1,19 @@ + + +
    + + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts new file mode 100644 index 00000000000..0edebaa9d44 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts @@ -0,0 +1,73 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; + +@Component({ + selector: 'zeppelin-pie-chart-visualization', + templateUrl: './pie-chart-visualization.component.html', + styleUrls: ['./pie-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PieChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + + constructor(@Inject(VISUALIZATION) public visualization: Visualization) { + super(visualization); + } + + ngOnInit() {} + + refreshSetting() { + this.pivotSettingComponent.init(); + } + + setScale() { + // Noop + } + + renderBefore() { + this.chart.tooltip({ + showTitle: false + }); + this.chart.coord('theta', { + radius: 0.75 + }); + this.chart + .intervalStack() + .position('__value__') + .color('__key__') + .style({ + lineWidth: 1, + stroke: '#fff' + }) + .tooltip('__key__*__value__', (name, value) => ({ name, value })); + } + + ngAfterViewInit() { + this.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts new file mode 100644 index 00000000000..d70572dda10 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { PieChartVisualizationComponent } from './pie-chart-visualization.component'; + +export class PieChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + PieChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html new file mode 100644 index 00000000000..ea1e3792c2c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html @@ -0,0 +1,19 @@ + + +
    + + +
    +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less @@ -0,0 +1,12 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts new file mode 100644 index 00000000000..f1b8ae5d8e4 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts @@ -0,0 +1,89 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { get } from 'lodash'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationScatterSettingComponent } from '../common/scatter-setting/scatter-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; + +@Component({ + selector: 'zeppelin-scatter-chart-visualization', + templateUrl: './scatter-chart-visualization.component.html', + styleUrls: ['./scatter-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationScatterSettingComponent, { static: false }) + scatterSettingComponent: VisualizationScatterSettingComponent; + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + refreshSetting() { + this.scatterSettingComponent.init(); + this.cdr.markForCheck(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore() { + const key = this.getKey(); + const size = get(this.config.setting, 'scatterChart.size.name'); + this.setScale(); + this.chart.tooltip({ + crosshairs: { + type: 'cross' + } + }); + this.chart.legend('__value__', false); + // point + const geom = this.chart + .point() + .position(`${key}*__value__`) + .color('__key__') + // .adjust('jitter') + .opacity(0.65) + .shape('circle'); + + if (size) { + geom.size('__value__'); + } + } + + ngOnInit() {} + + ngAfterViewInit() { + this.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts new file mode 100644 index 00000000000..0bfafab328c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { ScatterChartVisualizationComponent } from './scatter-chart-visualization.component'; + +export class ScatterChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + ScatterChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html new file mode 100644 index 00000000000..db43a53f0db --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html @@ -0,0 +1,123 @@ + + + + + + + + + + + {{col}} + + +
      + +
    • +
    • + Type +
        +
      • + {{type | titlecase}} +
      • +
      +
    • +
    • +
    • + Aggregation +
        +
      • + {{aggregation | titlecase}} +
      • +
      +
    • +
    +
    + + + + + + {{data[col]}} + + +
    + +
    + + + {{aggregation}}({{col}}): {{colOptions.get(col).aggregationValue}} + + +
    +
    diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less new file mode 100644 index 00000000000..094ea9ac640 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "theme-mixin"; + +.th-dropdown { + .search-bar.ant-menu-item-group { + padding: 5px 12px; + ::ng-deep .ant-menu-item-group-title{ + display: none; + } + } +} + +.export-dropdown { + margin-bottom: 16px; + position: absolute; + bottom: 0; + left: 0; +} + +.themeMixin({ + display: block; + position: relative; + ::ng-deep .filter-icon svg { + transition: transform 300ms; + } + + .aggregation-wrap { + text-align: right; + .aggregation-item { + margin-left: 10px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts new file mode 100644 index 00000000000..d0986315589 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts @@ -0,0 +1,174 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, ViewChild } from '@angular/core'; + +import { filter, maxBy, minBy, orderBy, sumBy } from 'lodash'; +import { NzTableComponent } from 'ng-zorro-antd/table'; +import { utils, writeFile, WorkSheet } from 'xlsx'; + +import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +type ColType = 'string' | 'date' | 'number'; +type AggregationType = 'count' | 'sum' | 'min' | 'max' | 'avg'; + +class FilterOption { + sort: 'desc' | 'asc' | '' = ''; + type: ColType = 'string'; + visible = true; + pinned?: string; + term = ''; + width: string | '*' = '*'; + aggregation: AggregationType | null = null; + aggregationValue: number | null = null; +} + +function typeCoercion(value: string, type: ColType): string | number | Date { + switch (type) { + case 'number': + const num = Number.parseFloat(value); + return Number.isNaN(num) ? value : num; + case 'date': + const date = new Date(value); + return Number.isNaN(date.valueOf()) ? value : date; + default: + return value; + } +} + +@Component({ + selector: 'zeppelin-visualization-table-visualization', + templateUrl: './table-visualization.component.html', + styleUrls: ['./table-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TableVisualizationComponent implements OnInit { + tableData: TableData; + // tslint:disable-next-line:no-any + rows: any[] = []; + columns: string[] = []; + colOptions = new Map(); + types: ColType[] = ['string', 'number', 'date']; + aggregations: AggregationType[] = ['count', 'sum', 'min', 'max', 'avg']; + @ViewChild(NzTableComponent, { static: false }) nzTable: NzTableComponent; + + exportFile(type: 'csv' | 'xlsx', all = true) { + const wb = utils.book_new(); + let ws: WorkSheet; + if (all) { + ws = utils.json_to_sheet(this.rows); + } else { + ws = utils.json_to_sheet(this.nzTable.data); + } + utils.book_append_sheet(wb, ws, 'Sheet1'); + writeFile(wb, `export.${type}`); + } + + onChangeType(type: ColType, col: string) { + const opt = this.colOptions.get(col); + opt.type = type; + this.filterRows(); + this.aggregate(); + } + + onChangeAggregation(aggregation: AggregationType, col: string) { + const opt = this.colOptions.get(col); + opt.aggregation = opt.aggregation === aggregation ? null : aggregation; + this.aggregate(); + } + + onSearch(): void { + this.filterRows(); + } + + onSortChange(type: 'descend' | 'ascend' | string, key: string): void { + const opt: FilterOption = this.colOptions.get(key); + this.colOptions.delete(key); + if (type) { + opt.sort = type === 'descend' ? 'desc' : 'asc'; + } else { + opt.sort = ''; + } + this.colOptions.set(key, opt); + this.filterRows(); + } + + aggregate() { + this.colOptions.forEach((opt, key) => { + const numValue = row => { + const value = typeCoercion(row[key], opt.type); + if (typeof value === 'number') { + return value; + } + if (value instanceof Date) { + return value.valueOf(); + } + return value; + }; + const getSum = () => + sumBy(this.tableData.rows, row => { + const value = typeCoercion(row[key], 'number'); + return typeof value === 'number' ? value : 0; + }); + + switch (opt.aggregation) { + case 'sum': + opt.aggregationValue = getSum(); + break; + case 'avg': + opt.aggregationValue = getSum() / this.tableData.rows.length; + break; + case 'count': + opt.aggregationValue = this.tableData.rows.length; + break; + case 'max': + opt.aggregationValue = maxBy(this.tableData.rows, numValue)[key]; + break; + case 'min': + opt.aggregationValue = minBy(this.tableData.rows, numValue)[key]; + break; + default: + opt.aggregationValue = null; + } + }); + } + + filterRows() { + const sortKeys = []; + const sortTypes = []; + const terms = []; + this.colOptions.forEach((value, key) => { + if (value.sort) { + sortKeys.push(row => typeCoercion(row[key], value.type)); + sortTypes.push(value.sort); + } + terms.push(row => String(row[key]).search(value.term) !== -1); + }); + this.rows = filter(this.tableData.rows, row => terms.every(term => term(row))); + this.rows = orderBy(this.rows, sortKeys, sortTypes); + this.cdr.markForCheck(); + } + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) {} + + ngOnInit() {} + + render() { + this.tableData = this.visualization.transformed; + this.columns = this.tableData.columns; + this.rows = [...this.tableData.rows]; + this.columns.forEach(col => { + this.colOptions.set(col, new FilterOption()); + }); + this.filterRows(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts new file mode 100644 index 00000000000..c2495b3157a --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts @@ -0,0 +1,60 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { + TableTransformation, + Transformation, + Visualization, + VisualizationComponentPortal +} from '@zeppelin/visualization'; + +import { TableVisualizationComponent } from './table-visualization.component'; + +export class TableVisualization extends Visualization { + tableTransformation = new TableTransformation(this.getConfig()); + componentPortal = new VisualizationComponentPortal( + this, + TableVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } + + destroy(): void { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + } + + getTransformation(): Transformation { + return this.tableTransformation; + } + + refresh(): void {} + + render(data): void { + this.transformed = data; + if (!this.componentRef) { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + this.componentRef.instance.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/visualization.module.ts b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts new file mode 100644 index 00000000000..ab7221078e6 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts @@ -0,0 +1,77 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzTagModule } from 'ng-zorro-antd/tag'; + +import { AreaChartVisualizationComponent } from './area-chart/area-chart-visualization.component'; +import { BarChartVisualizationComponent } from './bar-chart/bar-chart-visualization.component'; +import { VisualizationPivotSettingComponent } from './common/pivot-setting/pivot-setting.component'; +import { VisualizationScatterSettingComponent } from './common/scatter-setting/scatter-setting.component'; +import { VisualizationXAxisSettingComponent } from './common/x-axis-setting/x-axis-setting.component'; +import { LineChartVisualizationComponent } from './line-chart/line-chart-visualization.component'; +import { PieChartVisualizationComponent } from './pie-chart/pie-chart-visualization.component'; +import { ScatterChartVisualizationComponent } from './scatter-chart/scatter-chart-visualization.component'; +import { TableVisualizationComponent } from './table/table-visualization.component'; + +const VisualizationComponents = [ + TableVisualizationComponent, + AreaChartVisualizationComponent, + BarChartVisualizationComponent, + LineChartVisualizationComponent, + PieChartVisualizationComponent, + ScatterChartVisualizationComponent +]; + +@NgModule({ + declarations: [ + ...VisualizationComponents, + VisualizationPivotSettingComponent, + VisualizationScatterSettingComponent, + VisualizationXAxisSettingComponent + ], + entryComponents: [...VisualizationComponents], + exports: [...VisualizationComponents], + imports: [ + CommonModule, + FormsModule, + DragDropModule, + NzTableModule, + NzCardModule, + NzTagModule, + NzFormModule, + NzInputModule, + NzGridModule, + NzIconModule, + NzMenuModule, + NzDropDownModule, + NzRadioModule, + NzCheckboxModule, + NzButtonModule + ] +}) +export class VisualizationModule {} diff --git a/zeppelin-web-angular/src/assets/.gitkeep b/zeppelin-web-angular/src/assets/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/zeppelin-web-angular/src/assets/fonts/patua-one.woff2 b/zeppelin-web-angular/src/assets/fonts/patua-one.woff2 new file mode 100644 index 00000000000..df2b38dc302 Binary files /dev/null and b/zeppelin-web-angular/src/assets/fonts/patua-one.woff2 differ diff --git a/zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js b/zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js new file mode 100644 index 00000000000..23499a03dcd --- /dev/null +++ b/zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js @@ -0,0 +1,589 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + ? (module.exports = factory( + require('@zeppelin/helium'), + require('@angular/core'), + require('@zeppelin/visualization'), + require('@angular/common') + )) + : typeof define === 'function' && define.amd + ? define('helium-vis-example', [ + '@zeppelin/helium', + '@angular/core', + '@zeppelin/visualization', + '@angular/common' + ], factory) + : ((global = global || self), + (global['helium-vis-example'] = factory(global.helium, global.ng.core, global.visualization, global.ng.common))); +})(this, function(helium, core, visualization, common) { + 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = + Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && + function(d, b) { + d.__proto__ = b; + }) || + function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { + this.constructor = d; + } + d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); + } + + var __assign = function() { + __assign = + Object.assign || + function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === 'function') + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; + } + return t; + } + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, + r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc, + d; + if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') + r = Reflect.decorate(decorators, target, key, desc); + else + for (var i = decorators.length - 1; i >= 0; i--) + if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + function __param(paramIndex, decorator) { + return function(target, key) { + decorator(target, key, paramIndex); + }; + } + + function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === 'object' && typeof Reflect.metadata === 'function') + return Reflect.metadata(metadataKey, metadataValue); + } + + function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function(resolve, reject) { + function fulfilled(value) { + try { + step(generator.next(value)); + } catch (e) { + reject(e); + } + } + function rejected(value) { + try { + step(generator['throw'](value)); + } catch (e) { + reject(e); + } + } + function step(result) { + result.done + ? resolve(result.value) + : new P(function(resolve) { + resolve(result.value); + }).then(fulfilled, rejected); + } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); + } + + function __generator(thisArg, body) { + var _ = { + label: 0, + sent: function() { + if (t[0] & 1) throw t[1]; + return t[1]; + }, + trys: [], + ops: [] + }, + f, + y, + t, + g; + return ( + (g = { next: verb(0), throw: verb(1), return: verb(2) }), + typeof Symbol === 'function' && + (g[Symbol.iterator] = function() { + return this; + }), + g + ); + function verb(n) { + return function(v) { + return step([n, v]); + }; + } + function step(op) { + if (f) throw new TypeError('Generator is already executing.'); + while (_) + try { + if ( + ((f = 1), + y && + (t = op[0] & 2 ? y['return'] : op[0] ? y['throw'] || ((t = y['return']) && t.call(y), 0) : y.next) && + !(t = t.call(y, op[1])).done) + ) + return t; + if (((y = 0), t)) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: + case 1: + t = op; + break; + case 4: + _.label++; + return { value: op[1], done: false }; + case 5: + _.label++; + y = op[1]; + op = [0]; + continue; + case 7: + op = _.ops.pop(); + _.trys.pop(); + continue; + default: + if (!((t = _.trys), (t = t.length > 0 && t[t.length - 1])) && (op[0] === 6 || op[0] === 2)) { + _ = 0; + continue; + } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { + _.label = op[1]; + break; + } + if (op[0] === 6 && _.label < t[1]) { + _.label = t[1]; + t = op; + break; + } + if (t && _.label < t[2]) { + _.label = t[2]; + _.ops.push(op); + break; + } + if (t[2]) _.ops.pop(); + _.trys.pop(); + continue; + } + op = body.call(thisArg, _); + } catch (e) { + op = [6, e]; + y = 0; + } finally { + f = t = 0; + } + if (op[0] & 5) throw op[1]; + return { value: op[0] ? op[1] : void 0, done: true }; + } + } + + function __exportStar(m, exports) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; + } + + function __values(o) { + var m = typeof Symbol === 'function' && o[Symbol.iterator], + i = 0; + if (m) return m.call(o); + return { + next: function() { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + } + + function __read(o, n) { + var m = typeof Symbol === 'function' && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), + r, + ar = [], + e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } catch (error) { + e = { error: error }; + } finally { + try { + if (r && !r.done && (m = i['return'])) m.call(i); + } finally { + if (e) throw e.error; + } + } + return ar; + } + + function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); + return ar; + } + + function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; + return r; + } + + function __await(v) { + return this instanceof __await ? ((this.v = v), this) : new __await(v); + } + + function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError('Symbol.asyncIterator is not defined.'); + var g = generator.apply(thisArg, _arguments || []), + i, + q = []; + return ( + (i = {}), + verb('next'), + verb('throw'), + verb('return'), + (i[Symbol.asyncIterator] = function() { + return this; + }), + i + ); + function verb(n) { + if (g[n]) + i[n] = function(v) { + return new Promise(function(a, b) { + q.push([n, v, a, b]) > 1 || resume(n, v); + }); + }; + } + function resume(n, v) { + try { + step(g[n](v)); + } catch (e) { + settle(q[0][3], e); + } + } + function step(r) { + r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); + } + function fulfill(value) { + resume('next', value); + } + function reject(value) { + resume('throw', value); + } + function settle(f, v) { + if ((f(v), q.shift(), q.length)) resume(q[0][0], q[0][1]); + } + } + + function __asyncDelegator(o) { + var i, p; + return ( + (i = {}), + verb('next'), + verb('throw', function(e) { + throw e; + }), + verb('return'), + (i[Symbol.iterator] = function() { + return this; + }), + i + ); + function verb(n, f) { + i[n] = o[n] + ? function(v) { + return (p = !p) ? { value: __await(o[n](v)), done: n === 'return' } : f ? f(v) : v; + } + : f; + } + } + + function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError('Symbol.asyncIterator is not defined.'); + var m = o[Symbol.asyncIterator], + i; + return m + ? m.call(o) + : ((o = typeof __values === 'function' ? __values(o) : o[Symbol.iterator]()), + (i = {}), + verb('next'), + verb('throw'), + verb('return'), + (i[Symbol.asyncIterator] = function() { + return this; + }), + i); + function verb(n) { + i[n] = + o[n] && + function(v) { + return new Promise(function(resolve, reject) { + (v = o[n](v)), settle(resolve, reject, v.done, v.value); + }); + }; + } + function settle(resolve, reject, d, v) { + Promise.resolve(v).then(function(v) { + resolve({ value: v, done: d }); + }, reject); + } + } + + function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { + Object.defineProperty(cooked, 'raw', { value: raw }); + } else { + cooked.raw = raw; + } + return cooked; + } + + function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result.default = mod; + return result; + } + + function __importDefault(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + } + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var JsonVisComponent = /** @class */ (function() { + function JsonVisComponent(visualization, cdr) { + this.visualization = visualization; + this.cdr = cdr; + } + /** + * @return {?} + */ + JsonVisComponent.prototype.ngOnInit = /** + * @return {?} + */ function() {}; + /** + * @return {?} + */ + JsonVisComponent.prototype.render = /** + * @return {?} + */ function() { + this.tableData = this.visualization.transformed; + }; + JsonVisComponent.decorators = [ + { + type: core.Component, + args: [ + { + selector: 'lib-helium-vis-example', + template: '\n
    {{tableData | json}}
    \n ', + changeDetection: core.ChangeDetectionStrategy.OnPush, + styles: [ + '\n pre {\n background: #fff7e7;\n padding: 10px;\n border: 1px solid #ffd278;\n color: #fa7e14;\n border-radius: 3px;\n }\n ' + ] + } + ] + } + ]; + /** @nocollapse */ + JsonVisComponent.ctorParameters = function() { + return [ + { type: visualization.Visualization, decorators: [{ type: core.Inject, args: [visualization.VISUALIZATION] }] }, + { type: core.ChangeDetectorRef } + ]; + }; + return JsonVisComponent; + })(); + if (false) { + /** @type {?} */ + JsonVisComponent.prototype.tableData; + /** @type {?} */ + JsonVisComponent.prototype.visualization; + /** + * @type {?} + * @private + */ + JsonVisComponent.prototype.cdr; + } + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var JsonVisModule = /** @class */ (function() { + function JsonVisModule() {} + JsonVisModule.decorators = [ + { + type: core.NgModule, + args: [ + { + imports: [common.CommonModule], + declarations: [JsonVisComponent], + entryComponents: [JsonVisComponent], + exports: [JsonVisComponent] + } + ] + } + ]; + return JsonVisModule; + })(); + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var JsonVisualization = /** @class */ (function(_super) { + __extends(JsonVisualization, _super); + function JsonVisualization(config, portalOutlet, viewContainerRef, componentFactoryResolver) { + var _this = _super.call(this, config) || this; + _this.portalOutlet = portalOutlet; + _this.viewContainerRef = viewContainerRef; + _this.componentFactoryResolver = componentFactoryResolver; + _this.tableTransformation = new visualization.TableTransformation(_this.getConfig()); + _this.componentPortal = new visualization.VisualizationComponentPortal( + _this, + JsonVisComponent, + _this.portalOutlet, + _this.viewContainerRef, + _this.componentFactoryResolver + ); + return _this; + } + /** + * @return {?} + */ + JsonVisualization.prototype.destroy = /** + * @return {?} + */ function() { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + }; + /** + * @return {?} + */ + JsonVisualization.prototype.getTransformation = /** + * @return {?} + */ function() { + return this.tableTransformation; + }; + /** + * @return {?} + */ + JsonVisualization.prototype.refresh = /** + * @return {?} + */ function() {}; + /** + * @param {?} data + * @return {?} + */ + JsonVisualization.prototype.render = /** + * @param {?} data + * @return {?} + */ function(data) { + this.transformed = data; + if (!this.componentRef) { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + this.componentRef.instance.render(); + }; + return JsonVisualization; + })(visualization.Visualization); + if (false) { + /** @type {?} */ + JsonVisualization.prototype.tableTransformation; + /** @type {?} */ + JsonVisualization.prototype.componentPortal; + /** + * @type {?} + * @private + */ + JsonVisualization.prototype.portalOutlet; + /** + * @type {?} + * @private + */ + JsonVisualization.prototype.viewContainerRef; + /** + * @type {?} + * @private + */ + JsonVisualization.prototype.componentFactoryResolver; + } + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var publicApi = helium.createHeliumPackage({ + name: 'helium-vis-example', + id: 'heliumVisExample', + icon: 'appstore', + type: helium.HeliumPackageType.Visualization, + module: JsonVisModule, + component: JsonVisComponent, + visualization: JsonVisualization + }); + + return publicApi; +}); +//# sourceMappingURL=helium-vis-example.umd.js.map diff --git a/zeppelin-web-angular/src/assets/images/bg.jpg b/zeppelin-web-angular/src/assets/images/bg.jpg new file mode 100644 index 00000000000..cffbba3ff89 Binary files /dev/null and b/zeppelin-web-angular/src/assets/images/bg.jpg differ diff --git a/zeppelin-web-angular/src/assets/images/zeppelin.png b/zeppelin-web-angular/src/assets/images/zeppelin.png new file mode 100644 index 00000000000..aeb0b605654 Binary files /dev/null and b/zeppelin-web-angular/src/assets/images/zeppelin.png differ diff --git a/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo.svg b/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo.svg new file mode 100644 index 00000000000..9601e5dc893 --- /dev/null +++ b/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg b/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg new file mode 100644 index 00000000000..9e0b95d9197 --- /dev/null +++ b/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/zeppelin-web-angular/src/browserslist b/zeppelin-web-angular/src/browserslist new file mode 100644 index 00000000000..37371cb04b9 --- /dev/null +++ b/zeppelin-web-angular/src/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/zeppelin-web-angular/src/environments/environment.prod.ts b/zeppelin-web-angular/src/environments/environment.prod.ts new file mode 100644 index 00000000000..a00527f83a1 --- /dev/null +++ b/zeppelin-web-angular/src/environments/environment.prod.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const environment = { + production: true +}; diff --git a/zeppelin-web-angular/src/environments/environment.ts b/zeppelin-web-angular/src/environments/environment.ts new file mode 100644 index 00000000000..7ed2ad9875b --- /dev/null +++ b/zeppelin-web-angular/src/environments/environment.ts @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/zeppelin-web-angular/src/favicon.ico b/zeppelin-web-angular/src/favicon.ico new file mode 100644 index 00000000000..7e5049a11f6 Binary files /dev/null and b/zeppelin-web-angular/src/favicon.ico differ diff --git a/zeppelin-web-angular/src/index.html b/zeppelin-web-angular/src/index.html new file mode 100644 index 00000000000..9ad5caa094f --- /dev/null +++ b/zeppelin-web-angular/src/index.html @@ -0,0 +1,50 @@ + + + + + + + + + Zeppelin + + + + +
    +
    + +
    +

    Zeppelin

    + +
    +
    +
    +
    + + + + diff --git a/zeppelin-web-angular/src/karma.conf.js b/zeppelin-web-angular/src/karma.conf.js new file mode 100644 index 00000000000..f2d0ea61a85 --- /dev/null +++ b/zeppelin-web-angular/src/karma.conf.js @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function(config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/zeppelin-web-angular/src/main.ts b/zeppelin-web-angular/src/main.ts new file mode 100644 index 00000000000..81b410d13ed --- /dev/null +++ b/zeppelin-web-angular/src/main.ts @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/zeppelin-web-angular/src/polyfills.ts b/zeppelin-web-angular/src/polyfills.ts new file mode 100644 index 00000000000..407a74e8552 --- /dev/null +++ b/zeppelin-web-angular/src/polyfills.ts @@ -0,0 +1,94 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + +// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame +// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick +// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + +/* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +// tslint:disable +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +import 'core-js/es7/reflect'; diff --git a/zeppelin-web-angular/src/styles.less b/zeppelin-web-angular/src/styles.less new file mode 100644 index 00000000000..013b90e3af1 --- /dev/null +++ b/zeppelin-web-angular/src/styles.less @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import './styles/spin'; +@import './styles/base'; +@import './styles/font'; +@import './styles/global'; +@import './styles/rewrite'; +@import "node_modules/ng-zorro-antd/resizable/style/entry.less"; +@import "node_modules/ng-zorro-antd/code-editor/style/entry.less"; diff --git a/zeppelin-web-angular/src/styles/base.less b/zeppelin-web-angular/src/styles/base.less new file mode 100644 index 00000000000..333ba34de73 --- /dev/null +++ b/zeppelin-web-angular/src/styles/base.less @@ -0,0 +1,18 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +* { + box-sizing: border-box; + outline: none; + margin: 0; + padding: 0; +} diff --git a/zeppelin-web-angular/src/styles/font.less b/zeppelin-web-angular/src/styles/font.less new file mode 100644 index 00000000000..ead6bcffa7e --- /dev/null +++ b/zeppelin-web-angular/src/styles/font.less @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* latin */ +@font-face { + font-family: 'Patua One'; + font-style: normal; + font-weight: 400; + src: local('Patua One'), local('PatuaOne-Regular'), url(../assets/fonts/patua-one.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/zeppelin-web-angular/src/styles/global.less b/zeppelin-web-angular/src/styles/global.less new file mode 100644 index 00000000000..42e736228c1 --- /dev/null +++ b/zeppelin-web-angular/src/styles/global.less @@ -0,0 +1,124 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../../node_modules/ng-zorro-antd/src/style/color/colors'; + +.mark-highlight { + color: crimson; +} + +.tips { + &.warning { + color: @volcano-6; + } + + &.error { + color: @red-6; + } +} + +.modal-footer { + padding: 10px 24px; + margin: 24px -24px -24px -24px; +} + +.transparent-button { + background: transparent; + border: none; + box-shadow: none; + + &:hover { + background: transparent; + } +} + +.padding-sm { + padding: 12px !important; +} + +.font-sm { + font-size: 12px; +} + +.opacity-05 { + opacity: 0.5; +} + +.drag-tag { + box-sizing: border-box; + color: rgba(0, 0, 0, 0.65); + font-variant: tabular-nums; + list-style: none; + font-feature-settings: 'tnum'; + display: inline-block; + height: auto; + margin: 0 8px 8px 0; + padding: 0 7px; + font-size: 12px; + line-height: 20px; + white-space: nowrap; + background: #fafafa; + border: 1px solid #d9d9d9; + border-radius: 0px; + cursor: pointer; + opacity: 1; + + &.cdk-drag-preview { + box-shadow: 0 0 6px -2px rgba(0, 0, 0, 0.2); + } + + &.cdk-drag-placeholder { + border-style: dashed; + } +} + +.interpreter-box { + margin-bottom: 12px; + line-height: 32px; + + &:last-child { + margin-bottom: 0; + } + + .refresh { + font-size: 18px; + line-height: 0; + margin-right: 12px; + } + + &.cdk-drag-placeholder { + opacity: 0; + } + + .interpreter-name { + display: inline-block; + + .main-name { + display: inline-block; + margin-right: 6px; + } + + .child-name { + font-size: 12px; + opacity: 0.7; + display: inline-block; + } + } +} + +//.view-lines { +// .view-line { +// &:first-child { +// filter: grayscale(1); +// } +// } +//} diff --git a/zeppelin-web-angular/src/styles/rewrite.less b/zeppelin-web-angular/src/styles/rewrite.less new file mode 100644 index 00000000000..43d7b61f32c --- /dev/null +++ b/zeppelin-web-angular/src/styles/rewrite.less @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +nz-tree { + .ant-tree { + nz-tree-node { + li { + padding: 0; + } + } + } +} + +.ant-tabs-nav .ant-tabs-tab { + font-weight: 500; +} diff --git a/zeppelin-web-angular/src/styles/spin.less b/zeppelin-web-angular/src/styles/spin.less new file mode 100644 index 00000000000..ec8c0a5a88c --- /dev/null +++ b/zeppelin-web-angular/src/styles/spin.less @@ -0,0 +1,150 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.spin { + height: 100vh; + width: 100vw; + position: fixed; + z-index: 1000; + top: 0; + left: 0; + + &:after { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url("../assets/images/bg.jpg"); + background-size: cover; + filter: blur(4px); + background-repeat: no-repeat; + background-position: center; + } + + &.transparent { + &:after { + content: none; + } + } + + & > div { + background: rgba(255, 255, 255, 0.5); + text-align: center; + position: absolute; + z-index: 1; + top: 0; + bottom: 0; + left: 0; + right: 0; + + .logo { + width: 160px; + height: 160px; + margin: -64px auto 0; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + position: absolute; + + &:after { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + animation: opacity 2.0s infinite ease; + background-image: url(../assets/images/zeppelin_svg_logo.svg); + background-repeat: no-repeat; + background-position: center; + background-size: 75% auto; + } + } + + .spin-text { + width: 160px; + height: 160px; + top: 50%; + left: 50%; + transform: translateX(-50%); + position: absolute; + margin: -16px auto 0; + + .brand-title { + text-align: center; + font-family: 'Patua One', cursive; + color: #3071a9; + font-size: 40px; + display: block !important; + } + + .status { + margin: -6px auto 0; + width: 160px; + display: block !important; + color: #ffffff; + line-height: 24px; + height: 24px; + font-size: 12px; + position: relative; + background-color: rgba(48, 113, 169, 0.7); + + &::before { + content: ''; + position: absolute; + z-index: -1; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: #3071a9; + transform-origin: left center; + transform: scaleX(0); + transition: transform 0.2s ease-in-out; + animation: move 1.0s infinite ease; + } + } + } + } +} + +@keyframes opacity { + 0% { + opacity: 0.7; + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0.7; + } +} + + +@keyframes move { + 0% { + transform: scaleX(0); + transform-origin: left center; + } + 100% { + transform-origin: left center; + transform: scaleX(1); + } +} + + diff --git a/zeppelin-web-angular/src/styles/theme/dark/antd-dark.less b/zeppelin-web-angular/src/styles/theme/dark/antd-dark.less new file mode 100644 index 00000000000..16484d60a93 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/dark/antd-dark.less @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +html.dark { + @import '../../../../node_modules/ng-zorro-antd/ng-zorro-antd.less'; + @import 'theme-dark'; + @import '../markdown'; +} diff --git a/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less b/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less new file mode 100644 index 00000000000..26e91867283 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less @@ -0,0 +1,659 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// The prefix to use on all css classes from ant. +@ant-prefix: ant; + +// An override for the html selector for theme prefixes +@html-selector: html; + +// -------- Colors ----------- +@primary-color: @blue-6; +@info-color: @blue-6; +@success-color: @green-6; +@processing-color: @blue-6; +@error-color: @red-6; +@highlight-color: @red-6; +@warning-color: @gold-6; +@normal-color: #d9d9d9; +@white: #fff; +@black: #000; + +// Color used by default to control hover and active backgrounds and for +// alert info backgrounds. +@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) +@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) +@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused +@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-5: color( + ~`colorPalette('@{primary-color}', 5) ` +); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) +@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color +@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) +@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused +@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused +@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused + +// Base Scaffolding Variables +// --- + +// Background color for `` +@body-background: #fff; +// Base background color for most components +@component-background: #fff; +@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', + 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; +@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; +@text-color: fade(@black, 65%); +@text-color-secondary: fade(@black, 45%); +@text-color-warning: @gold-7; +@text-color-danger: @red-7; +@text-color-inverse: @white; +@icon-color: inherit; +@icon-color-hover: fade(@black, 75%); +@heading-color: fade(#000, 85%); +@heading-color-dark: fade(@white, 100%); +@text-color-dark: fade(@white, 85%); +@text-color-secondary-dark: fade(@white, 65%); +@font-variant-base: tabular-nums; +@font-feature-settings-base: 'tnum'; +@font-size-base: 14px; +@font-size-lg: @font-size-base + 2px; +@font-size-sm: 12px; +@heading-1-size: ceil(@font-size-base * 2.71); +@heading-2-size: ceil(@font-size-base * 2.14); +@heading-3-size: ceil(@font-size-base * 1.71); +@heading-4-size: ceil(@font-size-base * 1.42); +@line-height-base: 1.5; +@border-radius-base: 4px; +@border-radius-sm: 2px; + +// vertical paddings +@padding-lg: 24px; // containers +@padding-md: 16px; // small containers and buttons +@padding-sm: 12px; // Form controls and items +@padding-xs: 8px; // small items + +// vertical padding for all form controls +@control-padding-horizontal: @padding-sm; +@control-padding-horizontal-sm: @padding-xs; + +// The background colors for active and hover states for things like +// list items or table cells. +@item-active-bg: @primary-1; +@item-hover-bg: @primary-1; + +// ICONFONT +@iconfont-css-prefix: anticon; + +// LINK +@link-color: @primary-color; +@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); +@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-decoration: none; +@link-hover-decoration: none; + +// Animation +@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); +@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); +@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); +@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); +@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); +@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); +@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); +@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); +@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); +@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); +@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); +@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); +@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); +@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); + +// Border color +@border-color-base: hsv(0, 0, 85%); // base border outline a component +@border-color-split: hsv(0, 0, 91%); // split border inside a component +@border-color-inverse: @white; +@border-width-base: 1px; // width of the border for a component +@border-style-base: solid; // style of a components border + +// Outline +@outline-blur-size: 0; +@outline-width: 2px; +@outline-color: @primary-color; + +@background-color-light: hsv(0, 0, 98%); // background of header and selected item +@background-color-base: hsv(0, 0, 96%); // Default grey background color + +// Disabled states +@disabled-color: fade(#000, 25%); +@disabled-bg: @background-color-base; +@disabled-color-dark: fade(#fff, 35%); + +// Shadow +@shadow-color: rgba(0, 0, 0, 0.15); +@shadow-color-inverse: @component-background; +@box-shadow-base: @shadow-1-down; +@shadow-1-up: 0 -2px 8px @shadow-color; +@shadow-1-down: 0 2px 8px @shadow-color; +@shadow-1-left: -2px 0 8px @shadow-color; +@shadow-1-right: 2px 0 8px @shadow-color; +@shadow-2: 0 4px 12px @shadow-color; + +// Buttons +@btn-font-weight: 400; +@btn-border-radius-base: @border-radius-base; +@btn-border-radius-sm: @border-radius-base; +@btn-border-width: @border-width-base; +@btn-border-style: @border-style-base; +@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); +@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); +@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); + +@btn-primary-color: #fff; +@btn-primary-bg: @primary-color; + +@btn-default-color: @text-color; +@btn-default-bg: #fff; +@btn-default-border: @border-color-base; + +@btn-danger-color: @error-color; +@btn-danger-bg: @background-color-base; +@btn-danger-border: @border-color-base; + +@btn-disable-color: @disabled-color; +@btn-disable-bg: @disabled-bg; +@btn-disable-border: @border-color-base; + +@btn-padding-base: 0 @padding-md - 1px; +@btn-font-size-lg: @font-size-lg; +@btn-font-size-sm: @font-size-base; +@btn-padding-lg: @btn-padding-base; +@btn-padding-sm: 0 @padding-xs - 1px; + +@btn-height-base: 32px; +@btn-height-lg: 40px; +@btn-height-sm: 24px; + +@btn-circle-size: @btn-height-base; +@btn-circle-size-lg: @btn-height-lg; +@btn-circle-size-sm: @btn-height-sm; + +@btn-square-size: @btn-height-base; +@btn-square-size-lg: @btn-height-lg; +@btn-square-size-sm: @btn-height-sm; + +@btn-group-border: @primary-5; + +// Checkbox +@checkbox-size: 16px; +@checkbox-color: @primary-color; +@checkbox-check-color: #fff; +@checkbox-border-width: @border-width-base; + +// Descriptions +@descriptions-bg: #fafafa; + +// Empty +@empty-font-size: @font-size-base; + +// Radio +@radio-size: 16px; +@radio-dot-color: @primary-color; + +// Radio buttons +@radio-button-bg: @btn-default-bg; +@radio-button-checked-bg: @btn-default-bg; +@radio-button-color: @btn-default-color; +@radio-button-hover-color: @primary-5; +@radio-button-active-color: @primary-7; + +// Media queries breakpoints +// Extra small screen / phone +@screen-xs: 480px; +@screen-xs-min: @screen-xs; + +// Small screen / tablet +@screen-sm: 576px; +@screen-sm-min: @screen-sm; + +// Medium screen / desktop +@screen-md: 768px; +@screen-md-min: @screen-md; + +// Large screen / wide desktop +@screen-lg: 992px; +@screen-lg-min: @screen-lg; + +// Extra large screen / full hd +@screen-xl: 1200px; +@screen-xl-min: @screen-xl; + +// Extra extra large screen / large desktop +@screen-xxl: 1600px; +@screen-xxl-min: @screen-xxl; + +// provide a maximum +@screen-xs-max: (@screen-sm-min - 1px); +@screen-sm-max: (@screen-md-min - 1px); +@screen-md-max: (@screen-lg-min - 1px); +@screen-lg-max: (@screen-xl-min - 1px); +@screen-xl-max: (@screen-xxl-min - 1px); + +// Grid system +@grid-columns: 24; +@grid-gutter-width: 0; + +// Layout +@layout-body-background: #f0f2f5; +@layout-header-background: #001529; +@layout-footer-background: @layout-body-background; +@layout-header-height: 64px; +@layout-header-padding: 0 50px; +@layout-footer-padding: 24px 50px; +@layout-sider-background: @layout-header-background; +@layout-trigger-height: 48px; +@layout-trigger-background: #002140; +@layout-trigger-color: #fff; +@layout-zero-trigger-width: 36px; +@layout-zero-trigger-height: 42px; +// Layout light theme +@layout-sider-background-light: #fff; +@layout-trigger-background-light: #fff; +@layout-trigger-color-light: @text-color; + +// z-index list, order by `z-index` +@zindex-table-fixed: auto; +@zindex-affix: 10; +@zindex-back-top: 10; +@zindex-badge: 10; +@zindex-picker-panel: 10; +@zindex-popup-close: 10; +@zindex-modal: 1000; +@zindex-modal-mask: 1000; +@zindex-message: 1010; +@zindex-notification: 1010; +@zindex-popover: 1030; +@zindex-dropdown: 1050; +@zindex-picker: 1050; +@zindex-tooltip: 1060; + +// Animation +@animation-duration-slow: 0.3s; // Modal +@animation-duration-base: 0.2s; +@animation-duration-fast: 0.1s; // Tooltip + +// Form +// --- +@label-required-color: @highlight-color; +@label-color: @heading-color; +@form-item-margin-bottom: 24px; +@form-item-trailing-colon: true; +@form-vertical-label-padding: 0 0 8px; +@form-vertical-label-margin: 0; + +// Input +// --- +@input-height-base: 32px; +@input-height-lg: 40px; +@input-height-sm: 24px; +@input-padding-horizontal: @control-padding-horizontal - 1px; +@input-padding-horizontal-base: @input-padding-horizontal; +@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px; +@input-padding-horizontal-lg: @input-padding-horizontal; +@input-padding-vertical-base: 4px; +@input-padding-vertical-sm: 1px; +@input-padding-vertical-lg: 6px; +@input-placeholder-color: hsv(0, 0, 75%); +@input-color: @text-color; +@input-border-color: @border-color-base; +@input-bg: #fff; +@input-number-handler-active-bg: #f4f4f4; +@input-number-handler-hover-bg: @primary-5; +@input-number-handler-bg: @component-background; +@input-number-handler-border-color: @border-color-base; +@input-addon-bg: @background-color-light; +@input-hover-border-color: @primary-color; +@input-disabled-bg: @disabled-bg; +@input-outline-offset: 0 0; + +// Select +// --- +@select-border-color: @border-color-base; +@select-item-selected-font-weight: 600; +@select-dropdown-bg: @component-background; +@select-item-selected-bg: @background-color-light; +@select-item-active-bg: @item-active-bg; + +// Anchor +// --- +@anchor-border-color: @border-color-split; + +// Tooltip +// --- +// Tooltip max width +@tooltip-max-width: 250px; +// Tooltip text color +@tooltip-color: #fff; +// Tooltip background color +@tooltip-bg: rgba(0, 0, 0, 0.75); +// Tooltip arrow width +@tooltip-arrow-width: 5px; +// Tooltip distance with trigger +@tooltip-distance: @tooltip-arrow-width - 1px + 4px; +// Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + +// Popover +// --- +// Popover body background color +@popover-bg: #fff; +// Popover text color +@popover-color: @text-color; +// Popover maximum width +@popover-min-width: 177px; +// Popover arrow width +@popover-arrow-width: 6px; +// Popover arrow color +@popover-arrow-color: @popover-bg; +// Popover outer arrow width +// Popover outer arrow color +@popover-arrow-outer-color: @popover-bg; +// Popover distance with trigger +@popover-distance: @popover-arrow-width + 4px; + +// Modal +// -- +@modal-body-padding: 24px; +@modal-header-bg: @component-background; +@modal-footer-bg: transparent; +@modal-footer-border-color-split: @border-color-split; +@modal-mask-bg: fade(@black, 45%); + +// Progress +// -- +@progress-default-color: @processing-color; +@progress-remaining-color: @background-color-base; +@progress-text-color: @text-color; + +// Menu +// --- +@menu-inline-toplevel-item-height: 40px; +@menu-item-height: 40px; +@menu-collapsed-width: 80px; +@menu-bg: @component-background; +@menu-popup-bg: @component-background; +@menu-item-color: @text-color; +@menu-highlight-color: @primary-color; +@menu-item-active-bg: @item-active-bg; +@menu-item-active-border-width: 3px; +@menu-item-group-title-color: @text-color-secondary; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; + +@menu-item-vertical-margin: 4px; +@menu-item-font-size: @font-size-base; +@menu-item-boundary-margin: 8px; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@dark-menu-item-hover-bg: transparent; + +// dark theme +@menu-dark-color: @text-color-secondary-dark; +@menu-dark-bg: @layout-header-background; +@menu-dark-arrow-color: #fff; +@menu-dark-submenu-bg: #000c17; +@menu-dark-highlight-color: #fff; +@menu-dark-item-active-bg: @primary-color; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@menu-dark-item-hover-bg: transparent; + +// Spin +// --- +@spin-dot-size-sm: 14px; +@spin-dot-size: 20px; +@spin-dot-size-lg: 32px; + +// Table +// -- +@table-header-bg: @background-color-light; +@table-header-color: @heading-color; +@table-header-sort-bg: @background-color-base; +@table-body-sort-bg: rgba(0, 0, 0, 0.01); +@table-row-hover-bg: @primary-1; +@table-selected-row-bg: #fafafa; +@table-expanded-row-bg: #fbfbfb; +@table-padding-vertical: 16px; +@table-padding-horizontal: 16px; +@table-border-radius-base: @border-radius-base; +@table-footer-bg: @background-color-light; +@table-footer-color: @heading-color; + +// Tag +// -- +@tag-default-bg: @background-color-light; +@tag-default-color: @text-color; +@tag-font-size: @font-size-sm; + +// TimePicker +// --- +@time-picker-panel-column-width: 56px; +@time-picker-panel-width: @time-picker-panel-column-width * 3; +@time-picker-selected-bg: @background-color-base; + +// Carousel +// --- +@carousel-dot-width: 16px; +@carousel-dot-height: 3px; +@carousel-dot-active-width: 24px; + +// Badge +// --- +@badge-height: 20px; +@badge-dot-size: 6px; +@badge-font-size: @font-size-sm; +@badge-font-weight: normal; +@badge-status-size: 6px; +@badge-text-color: @component-background; + +// Rate +// --- +@rate-star-color: @yellow-6; +@rate-star-bg: @border-color-split; + +// Card +// --- +@card-head-color: @heading-color; +@card-head-background: transparent; +@card-head-padding: 16px; +@card-inner-head-padding: 12px; +@card-padding-base: 24px; +@card-actions-background: @background-color-light; +@card-skeleton-bg: #cfd8dc; +@card-background: @component-background; +@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); +@card-radius: @border-radius-sm; + +// Comment +// --- +@comment-padding-base: 16px 0; +@comment-nest-indent: 44px; +@comment-author-name-color: @text-color-secondary; +@comment-author-time-color: #ccc; +@comment-action-color: @text-color-secondary; +@comment-action-hover-color: #595959; + +// Tabs +// --- +@tabs-card-head-background: @background-color-light; +@tabs-card-height: 40px; +@tabs-card-active-color: @primary-color; +@tabs-title-font-size: @font-size-base; +@tabs-title-font-size-lg: @font-size-lg; +@tabs-title-font-size-sm: @font-size-base; +@tabs-ink-bar-color: @primary-color; +@tabs-bar-margin: 0 0 16px 0; +@tabs-horizontal-margin: 0 32px 0 0; +@tabs-horizontal-padding: 12px 16px; +@tabs-horizontal-padding-lg: 16px; +@tabs-horizontal-padding-sm: 8px 16px; +@tabs-vertical-padding: 8px 24px; +@tabs-vertical-margin: 0 0 16px 0; +@tabs-scrolling-size: 32px; +@tabs-highlight-color: @primary-color; +@tabs-hover-color: @primary-5; +@tabs-active-color: @primary-7; + +// BackTop +// --- +@back-top-color: #fff; +@back-top-bg: @text-color-secondary; +@back-top-hover-bg: @text-color; + +// Avatar +// --- +@avatar-size-base: 32px; +@avatar-size-lg: 40px; +@avatar-size-sm: 24px; +@avatar-font-size-base: 18px; +@avatar-font-size-lg: 24px; +@avatar-font-size-sm: 14px; +@avatar-bg: #ccc; +@avatar-color: #fff; +@avatar-border-radius: @border-radius-base; + +// Switch +// --- +@switch-height: 22px; +@switch-sm-height: 16px; +@switch-sm-checked-margin-left: -(@switch-sm-height - 3px); +@switch-disabled-opacity: 0.4; +@switch-color: @primary-color; +@switch-shadow-color: fade(#00230b, 20%); + +// Pagination +// --- +@pagination-item-size: 32px; +@pagination-item-size-sm: 24px; +@pagination-font-family: Arial; +@pagination-font-weight-active: 500; +@pagination-item-bg-active: transparent; + +// PageHeader +// --- +@page-header-padding: 24px; +@page-header-padding-vertical: 16px; @page-header-padding-vertical: 16px; +@page-header-padding-breadcrumb: 12px; +@page-header-back-color: #000; + +// Breadcrumb +// --- +@breadcrumb-base-color: @text-color-secondary; +@breadcrumb-last-item-color: @text-color; +@breadcrumb-font-size: @font-size-base; +@breadcrumb-icon-font-size: @font-size-base; +@breadcrumb-link-color: @text-color-secondary; +@breadcrumb-link-color-hover: @primary-5; +@breadcrumb-separator-color: @text-color-secondary; +@breadcrumb-separator-margin: 0 @padding-xs; + +// Slider +// --- +@slider-margin: 14px 6px 10px; +@slider-rail-background-color: @background-color-base; +@slider-rail-background-color-hover: #e1e1e1; +@slider-track-background-color: @primary-3; +@slider-track-background-color-hover: @primary-4; +@slider-handle-color: @primary-3; +@slider-handle-color-hover: @primary-4; +@slider-handle-color-focus: tint(@primary-color, 20%); +@slider-handle-color-focus-shadow: fade(@primary-color, 20%); +@slider-handle-color-tooltip-open: @primary-color; +@slider-dot-border-color: @border-color-split; +@slider-dot-border-color-active: tint(@primary-color, 50%); +@slider-disabled-color: @disabled-color; +@slider-disabled-background-color: @component-background; + +// Tree +// --- +@tree-title-height: 24px; +@tree-child-padding: 18px; +@tree-directory-selected-color: #fff; +@tree-directory-selected-bg: @primary-color; +@tree-node-hover-bg: @item-hover-bg; +@tree-node-selected-bg: @primary-2; + +// Collapse +// --- +@collapse-header-padding: 12px 16px 12px 40px; +@collapse-header-bg: @background-color-light; +@collapse-content-padding: @padding-md; +@collapse-content-bg: @component-background; + +// Skeleton +// --- +@skeleton-color: #f2f2f2; + +// Transfer +// --- +@transfer-disabled-bg: @disabled-bg; + +// Message +// --- +@message-notice-content-padding: 10px 16px; + +// Motion +// --- +@wave-animation-width: 6px; + +// Alert +// --- +@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; +@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-icon-color: @success-color; +@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; +@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-icon-color: @info-color; +@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; +@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-icon-color: @warning-color; +@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; +@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-icon-color: @error-color; + +// List +// --- +@list-header-background: transparent; +@list-footer-background: transparent; +@list-empty-text-padding: @padding-md; +@list-item-padding: @padding-sm 0; +@list-item-meta-margin-bottom: @padding-md; +@list-item-meta-avatar-margin-right: @padding-md; +@list-item-meta-title-margin-bottom: @padding-sm; + +// Statistic +// --- +@statistic-title-font-size: @font-size-base; +@statistic-content-font-size: 24px; +@statistic-unit-font-size: 16px; +@statistic-font-family: @font-family; + +// Drawer +// --- +@drawer-header-padding: 16px 24px; +@drawer-body-padding: 24px; + +// Typography +// --- +@typography-title-font-weight: 600; diff --git a/zeppelin-web-angular/src/styles/theme/light/antd-light.less b/zeppelin-web-angular/src/styles/theme/light/antd-light.less new file mode 100644 index 00000000000..cb114e64f28 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/light/antd-light.less @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../../../../node_modules/ng-zorro-antd/ng-zorro-antd.less'; +@import 'theme-light'; +@import '../markdown'; diff --git a/zeppelin-web-angular/src/styles/theme/light/theme-light.less b/zeppelin-web-angular/src/styles/theme/light/theme-light.less new file mode 100644 index 00000000000..576517a7604 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/light/theme-light.less @@ -0,0 +1,659 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// The prefix to use on all css classes from ant. +@ant-prefix: ant; + +// An override for the html selector for theme prefixes +@html-selector: html; + +// -------- Colors ----------- +@primary-color: #3071a9; +@info-color: @blue-6; +@success-color: @green-6; +@processing-color: @blue-6; +@error-color: @red-6; +@highlight-color: @red-6; +@warning-color: @gold-6; +@normal-color: #d9d9d9; +@white: #fff; +@black: #000; + +// Color used by default to control hover and active backgrounds and for +// alert info backgrounds. +@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) +@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) +@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused +@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-5: color( + ~`colorPalette('@{primary-color}', 5) ` +); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) +@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color +@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) +@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused +@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused +@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused + +// Base Scaffolding Variables +// --- + +// Background color for `` +@body-background: #fff; +// Base background color for most components +@component-background: #fff; +@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', + 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; +@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; +@text-color: fade(@black, 65%); +@text-color-secondary: fade(@black, 45%); +@text-color-warning: @gold-7; +@text-color-danger: @red-7; +@text-color-inverse: @white; +@icon-color: inherit; +@icon-color-hover: fade(@black, 75%); +@heading-color: fade(#000, 85%); +@heading-color-dark: fade(@white, 100%); +@text-color-dark: fade(@white, 85%); +@text-color-secondary-dark: fade(@white, 65%); +@font-variant-base: tabular-nums; +@font-feature-settings-base: 'tnum'; +@font-size-base: 14px; +@font-size-lg: @font-size-base + 2px; +@font-size-sm: 12px; +@heading-1-size: ceil(@font-size-base * 2.71); +@heading-2-size: ceil(@font-size-base * 2.14); +@heading-3-size: ceil(@font-size-base * 1.71); +@heading-4-size: ceil(@font-size-base * 1.42); +@line-height-base: 1.5; +@border-radius-base: 4px; +@border-radius-sm: 2px; + +// vertical paddings +@padding-lg: 24px; // containers +@padding-md: 16px; // small containers and buttons +@padding-sm: 12px; // Form controls and items +@padding-xs: 8px; // small items + +// vertical padding for all form controls +@control-padding-horizontal: @padding-sm; +@control-padding-horizontal-sm: @padding-xs; + +// The background colors for active and hover states for things like +// list items or table cells. +@item-active-bg: @primary-1; +@item-hover-bg: @primary-1; + +// ICONFONT +@iconfont-css-prefix: anticon; + +// LINK +@link-color: @primary-color; +@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); +@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-decoration: none; +@link-hover-decoration: none; + +// Animation +@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); +@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); +@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); +@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); +@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); +@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); +@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); +@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); +@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); +@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); +@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); +@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); +@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); +@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); + +// Border color +@border-color-base: hsv(0, 0, 85%); // base border outline a component +@border-color-split: hsv(0, 0, 91%); // split border inside a component +@border-color-inverse: @white; +@border-width-base: 1px; // width of the border for a component +@border-style-base: solid; // style of a components border + +// Outline +@outline-blur-size: 0; +@outline-width: 2px; +@outline-color: @primary-color; + +@background-color-light: hsv(0, 0, 98%); // background of header and selected item +@background-color-base: hsv(0, 0, 96%); // Default grey background color + +// Disabled states +@disabled-color: fade(#000, 25%); +@disabled-bg: @background-color-base; +@disabled-color-dark: fade(#fff, 35%); + +// Shadow +@shadow-color: rgba(0, 0, 0, 0.15); +@shadow-color-inverse: @component-background; +@box-shadow-base: @shadow-1-down; +@shadow-1-up: 0 -2px 8px @shadow-color; +@shadow-1-down: 0 2px 8px @shadow-color; +@shadow-1-left: -2px 0 8px @shadow-color; +@shadow-1-right: 2px 0 8px @shadow-color; +@shadow-2: 0 4px 12px @shadow-color; + +// Buttons +@btn-font-weight: 400; +@btn-border-radius-base: @border-radius-base; +@btn-border-radius-sm: @border-radius-base; +@btn-border-width: @border-width-base; +@btn-border-style: @border-style-base; +@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); +@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); +@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); + +@btn-primary-color: #fff; +@btn-primary-bg: @primary-color; + +@btn-default-color: @text-color; +@btn-default-bg: #fff; +@btn-default-border: @border-color-base; + +@btn-danger-color: @error-color; +@btn-danger-bg: @background-color-base; +@btn-danger-border: @border-color-base; + +@btn-disable-color: @disabled-color; +@btn-disable-bg: @disabled-bg; +@btn-disable-border: @border-color-base; + +@btn-padding-base: 0 @padding-md - 1px; +@btn-font-size-lg: @font-size-lg; +@btn-font-size-sm: @font-size-base; +@btn-padding-lg: @btn-padding-base; +@btn-padding-sm: 0 @padding-xs - 1px; + +@btn-height-base: 32px; +@btn-height-lg: 40px; +@btn-height-sm: 24px; + +@btn-circle-size: @btn-height-base; +@btn-circle-size-lg: @btn-height-lg; +@btn-circle-size-sm: @btn-height-sm; + +@btn-square-size: @btn-height-base; +@btn-square-size-lg: @btn-height-lg; +@btn-square-size-sm: @btn-height-sm; + +@btn-group-border: @primary-5; + +// Checkbox +@checkbox-size: 16px; +@checkbox-color: @primary-color; +@checkbox-check-color: #fff; +@checkbox-border-width: @border-width-base; + +// Descriptions +@descriptions-bg: #fafafa; + +// Empty +@empty-font-size: @font-size-base; + +// Radio +@radio-size: 16px; +@radio-dot-color: @primary-color; + +// Radio buttons +@radio-button-bg: @btn-default-bg; +@radio-button-checked-bg: @btn-default-bg; +@radio-button-color: @btn-default-color; +@radio-button-hover-color: @primary-5; +@radio-button-active-color: @primary-7; + +// Media queries breakpoints +// Extra small screen / phone +@screen-xs: 480px; +@screen-xs-min: @screen-xs; + +// Small screen / tablet +@screen-sm: 576px; +@screen-sm-min: @screen-sm; + +// Medium screen / desktop +@screen-md: 768px; +@screen-md-min: @screen-md; + +// Large screen / wide desktop +@screen-lg: 992px; +@screen-lg-min: @screen-lg; + +// Extra large screen / full hd +@screen-xl: 1200px; +@screen-xl-min: @screen-xl; + +// Extra extra large screen / large desktop +@screen-xxl: 1600px; +@screen-xxl-min: @screen-xxl; + +// provide a maximum +@screen-xs-max: (@screen-sm-min - 1px); +@screen-sm-max: (@screen-md-min - 1px); +@screen-md-max: (@screen-lg-min - 1px); +@screen-lg-max: (@screen-xl-min - 1px); +@screen-xl-max: (@screen-xxl-min - 1px); + +// Grid system +@grid-columns: 24; +@grid-gutter-width: 0; + +// Layout +@layout-body-background: #f0f2f5; +@layout-header-background: #001529; +@layout-footer-background: @layout-body-background; +@layout-header-height: 64px; +@layout-header-padding: 0 50px; +@layout-footer-padding: 24px 50px; +@layout-sider-background: @layout-header-background; +@layout-trigger-height: 48px; +@layout-trigger-background: #002140; +@layout-trigger-color: #fff; +@layout-zero-trigger-width: 36px; +@layout-zero-trigger-height: 42px; +// Layout light theme +@layout-sider-background-light: #fff; +@layout-trigger-background-light: #fff; +@layout-trigger-color-light: @text-color; + +// z-index list, order by `z-index` +@zindex-table-fixed: auto; +@zindex-affix: 10; +@zindex-back-top: 10; +@zindex-badge: 10; +@zindex-picker-panel: 10; +@zindex-popup-close: 10; +@zindex-modal: 1000; +@zindex-modal-mask: 1000; +@zindex-message: 1010; +@zindex-notification: 1010; +@zindex-popover: 1030; +@zindex-dropdown: 1050; +@zindex-picker: 1050; +@zindex-tooltip: 1060; + +// Animation +@animation-duration-slow: 0.3s; // Modal +@animation-duration-base: 0.2s; +@animation-duration-fast: 0.1s; // Tooltip + +// Form +// --- +@label-required-color: @highlight-color; +@label-color: @heading-color; +@form-item-margin-bottom: 24px; +@form-item-trailing-colon: true; +@form-vertical-label-padding: 0 0 8px; +@form-vertical-label-margin: 0; + +// Input +// --- +@input-height-base: 32px; +@input-height-lg: 40px; +@input-height-sm: 24px; +@input-padding-horizontal: @control-padding-horizontal - 1px; +@input-padding-horizontal-base: @input-padding-horizontal; +@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px; +@input-padding-horizontal-lg: @input-padding-horizontal; +@input-padding-vertical-base: 4px; +@input-padding-vertical-sm: 1px; +@input-padding-vertical-lg: 6px; +@input-placeholder-color: hsv(0, 0, 75%); +@input-color: @text-color; +@input-border-color: @border-color-base; +@input-bg: #fff; +@input-number-handler-active-bg: #f4f4f4; +@input-number-handler-hover-bg: @primary-5; +@input-number-handler-bg: @component-background; +@input-number-handler-border-color: @border-color-base; +@input-addon-bg: @background-color-light; +@input-hover-border-color: @primary-color; +@input-disabled-bg: @disabled-bg; +@input-outline-offset: 0 0; + +// Select +// --- +@select-border-color: @border-color-base; +@select-item-selected-font-weight: 600; +@select-dropdown-bg: @component-background; +@select-item-selected-bg: @background-color-light; +@select-item-active-bg: @item-active-bg; + +// Anchor +// --- +@anchor-border-color: @border-color-split; + +// Tooltip +// --- +// Tooltip max width +@tooltip-max-width: 250px; +// Tooltip text color +@tooltip-color: #fff; +// Tooltip background color +@tooltip-bg: rgba(0, 0, 0, 0.75); +// Tooltip arrow width +@tooltip-arrow-width: 5px; +// Tooltip distance with trigger +@tooltip-distance: @tooltip-arrow-width - 1px + 4px; +// Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + +// Popover +// --- +// Popover body background color +@popover-bg: #fff; +// Popover text color +@popover-color: @text-color; +// Popover maximum width +@popover-min-width: 177px; +// Popover arrow width +@popover-arrow-width: 6px; +// Popover arrow color +@popover-arrow-color: @popover-bg; +// Popover outer arrow width +// Popover outer arrow color +@popover-arrow-outer-color: @popover-bg; +// Popover distance with trigger +@popover-distance: @popover-arrow-width + 4px; + +// Modal +// -- +@modal-body-padding: 24px; +@modal-header-bg: @component-background; +@modal-footer-bg: transparent; +@modal-footer-border-color-split: @border-color-split; +@modal-mask-bg: fade(@black, 45%); + +// Progress +// -- +@progress-default-color: @processing-color; +@progress-remaining-color: @background-color-base; +@progress-text-color: @text-color; + +// Menu +// --- +@menu-inline-toplevel-item-height: 40px; +@menu-item-height: 40px; +@menu-collapsed-width: 80px; +@menu-bg: @component-background; +@menu-popup-bg: @component-background; +@menu-item-color: @text-color; +@menu-highlight-color: @primary-color; +@menu-item-active-bg: @item-active-bg; +@menu-item-active-border-width: 3px; +@menu-item-group-title-color: @text-color-secondary; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; + +@menu-item-vertical-margin: 4px; +@menu-item-font-size: @font-size-base; +@menu-item-boundary-margin: 8px; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@dark-menu-item-hover-bg: transparent; + +// dark theme +@menu-dark-color: @text-color-secondary-dark; +@menu-dark-bg: @layout-header-background; +@menu-dark-arrow-color: #fff; +@menu-dark-submenu-bg: #000c17; +@menu-dark-highlight-color: #fff; +@menu-dark-item-active-bg: @primary-color; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@menu-dark-item-hover-bg: transparent; + +// Spin +// --- +@spin-dot-size-sm: 14px; +@spin-dot-size: 20px; +@spin-dot-size-lg: 32px; + +// Table +// -- +@table-header-bg: @background-color-light; +@table-header-color: @heading-color; +@table-header-sort-bg: @background-color-base; +@table-body-sort-bg: rgba(0, 0, 0, 0.01); +@table-row-hover-bg: @primary-1; +@table-selected-row-bg: #fafafa; +@table-expanded-row-bg: #fbfbfb; +@table-padding-vertical: 16px; +@table-padding-horizontal: 16px; +@table-border-radius-base: @border-radius-base; +@table-footer-bg: @background-color-light; +@table-footer-color: @heading-color; + +// Tag +// -- +@tag-default-bg: @background-color-light; +@tag-default-color: @text-color; +@tag-font-size: @font-size-sm; + +// TimePicker +// --- +@time-picker-panel-column-width: 56px; +@time-picker-panel-width: @time-picker-panel-column-width * 3; +@time-picker-selected-bg: @background-color-base; + +// Carousel +// --- +@carousel-dot-width: 16px; +@carousel-dot-height: 3px; +@carousel-dot-active-width: 24px; + +// Badge +// --- +@badge-height: 20px; +@badge-dot-size: 6px; +@badge-font-size: @font-size-sm; +@badge-font-weight: normal; +@badge-status-size: 6px; +@badge-text-color: @component-background; + +// Rate +// --- +@rate-star-color: @yellow-6; +@rate-star-bg: @border-color-split; + +// Card +// --- +@card-head-color: @heading-color; +@card-head-background: transparent; +@card-head-padding: 16px; +@card-inner-head-padding: 12px; +@card-padding-base: 24px; +@card-actions-background: @background-color-light; +@card-skeleton-bg: #cfd8dc; +@card-background: @component-background; +@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); +@card-radius: @border-radius-sm; + +// Comment +// --- +@comment-padding-base: 16px 0; +@comment-nest-indent: 44px; +@comment-author-name-color: @text-color-secondary; +@comment-author-time-color: #ccc; +@comment-action-color: @text-color-secondary; +@comment-action-hover-color: #595959; + +// Tabs +// --- +@tabs-card-head-background: @background-color-light; +@tabs-card-height: 40px; +@tabs-card-active-color: @primary-color; +@tabs-title-font-size: @font-size-base; +@tabs-title-font-size-lg: @font-size-lg; +@tabs-title-font-size-sm: @font-size-base; +@tabs-ink-bar-color: @primary-color; +@tabs-bar-margin: 0 0 16px 0; +@tabs-horizontal-margin: 0 32px 0 0; +@tabs-horizontal-padding: 12px 16px; +@tabs-horizontal-padding-lg: 16px; +@tabs-horizontal-padding-sm: 8px 16px; +@tabs-vertical-padding: 8px 24px; +@tabs-vertical-margin: 0 0 16px 0; +@tabs-scrolling-size: 32px; +@tabs-highlight-color: @primary-color; +@tabs-hover-color: @primary-5; +@tabs-active-color: @primary-7; + +// BackTop +// --- +@back-top-color: #fff; +@back-top-bg: @text-color-secondary; +@back-top-hover-bg: @text-color; + +// Avatar +// --- +@avatar-size-base: 32px; +@avatar-size-lg: 40px; +@avatar-size-sm: 24px; +@avatar-font-size-base: 18px; +@avatar-font-size-lg: 24px; +@avatar-font-size-sm: 14px; +@avatar-bg: #ccc; +@avatar-color: #fff; +@avatar-border-radius: @border-radius-base; + +// Switch +// --- +@switch-height: 22px; +@switch-sm-height: 16px; +@switch-sm-checked-margin-left: -(@switch-sm-height - 3px); +@switch-disabled-opacity: 0.4; +@switch-color: @primary-color; +@switch-shadow-color: fade(#00230b, 20%); + +// Pagination +// --- +@pagination-item-size: 32px; +@pagination-item-size-sm: 24px; +@pagination-font-family: Arial; +@pagination-font-weight-active: 500; +@pagination-item-bg-active: transparent; + +// PageHeader +// --- +@page-header-padding: 24px; +@page-header-padding-vertical: 16px; @page-header-padding-vertical: 16px; +@page-header-padding-breadcrumb: 12px; +@page-header-back-color: #000; + +// Breadcrumb +// --- +@breadcrumb-base-color: @text-color-secondary; +@breadcrumb-last-item-color: @text-color; +@breadcrumb-font-size: @font-size-base; +@breadcrumb-icon-font-size: @font-size-base; +@breadcrumb-link-color: @text-color-secondary; +@breadcrumb-link-color-hover: @primary-5; +@breadcrumb-separator-color: @text-color-secondary; +@breadcrumb-separator-margin: 0 @padding-xs; + +// Slider +// --- +@slider-margin: 14px 6px 10px; +@slider-rail-background-color: @background-color-base; +@slider-rail-background-color-hover: #e1e1e1; +@slider-track-background-color: @primary-3; +@slider-track-background-color-hover: @primary-4; +@slider-handle-color: @primary-3; +@slider-handle-color-hover: @primary-4; +@slider-handle-color-focus: tint(@primary-color, 20%); +@slider-handle-color-focus-shadow: fade(@primary-color, 20%); +@slider-handle-color-tooltip-open: @primary-color; +@slider-dot-border-color: @border-color-split; +@slider-dot-border-color-active: tint(@primary-color, 50%); +@slider-disabled-color: @disabled-color; +@slider-disabled-background-color: @component-background; + +// Tree +// --- +@tree-title-height: 24px; +@tree-child-padding: 18px; +@tree-directory-selected-color: #fff; +@tree-directory-selected-bg: @primary-color; +@tree-node-hover-bg: @item-hover-bg; +@tree-node-selected-bg: @primary-2; + +// Collapse +// --- +@collapse-header-padding: 12px 16px 12px 40px; +@collapse-header-bg: @background-color-light; +@collapse-content-padding: @padding-md; +@collapse-content-bg: @component-background; + +// Skeleton +// --- +@skeleton-color: #f2f2f2; + +// Transfer +// --- +@transfer-disabled-bg: @disabled-bg; + +// Message +// --- +@message-notice-content-padding: 10px 16px; + +// Motion +// --- +@wave-animation-width: 6px; + +// Alert +// --- +@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; +@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-icon-color: @success-color; +@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; +@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-icon-color: @info-color; +@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; +@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-icon-color: @warning-color; +@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; +@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-icon-color: @error-color; + +// List +// --- +@list-header-background: transparent; +@list-footer-background: transparent; +@list-empty-text-padding: @padding-md; +@list-item-padding: @padding-sm 0; +@list-item-meta-margin-bottom: @padding-md; +@list-item-meta-avatar-margin-right: @padding-md; +@list-item-meta-title-margin-bottom: @padding-sm; + +// Statistic +// --- +@statistic-title-font-size: @font-size-base; +@statistic-content-font-size: 24px; +@statistic-unit-font-size: 16px; +@statistic-font-family: @font-family; + +// Drawer +// --- +@drawer-header-padding: 16px 24px; +@drawer-body-padding: 24px; + +// Typography +// --- +@typography-title-font-weight: 600; diff --git a/zeppelin-web-angular/src/styles/theme/markdown.less b/zeppelin-web-angular/src/styles/theme/markdown.less new file mode 100644 index 00000000000..d9f26833d6e --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/markdown.less @@ -0,0 +1,166 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.markdown-body { + color: @text-color; + font-size: 14px; + line-height: 1.5; + + h1 { + color: @heading-color; + font-weight: 500; + margin: 0.6em 0 0.6em; + font-family: Avenir, @font-family; + font-size: 30px; + font-variant: tabular-nums; + line-height: 38px; + } + + h2 { + font-size: 24px; + line-height: 32px; + } + + h2, + h3, + h4, + h5, + h6 { + color: @heading-color; + font-family: Avenir, @font-family; + font-variant: tabular-nums; + margin: 0.6em 0 0.6em; + font-weight: 500; + clear: both; + } + + h3 { + font-size: 18px; + } + + h4 { + font-size: 16px; + } + + h5 { + font-size: 14px; + } + + h6 { + font-size: 12px; + } + + hr { + height: 1px; + border: 0; + background: @border-color-split; + margin: 56px 0; + clear: both; + } + + p, + pre { + margin: 1em 0; + } + + ul > li { + list-style-type: circle; + margin-left: 20px; + padding-left: 4px; + + &:empty { + display: none; + } + } + + ol > li { + list-style-type: decimal; + margin-left: 20px; + padding-left: 4px; + } + + ul > li > p, + ol > li > p { + margin: 0.2em 0; + } + + code { + margin: 0 1px; + background: #f2f4f5; + padding: .2em .4em; + border-radius: 3px; + font-size: .9em; + border: 1px solid #eee; + } + + pre { + border-radius: @border-radius-sm; + background: #f2f4f5; + font-family: "Lucida Console", Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + } + + pre code { + border: none; + background: #f2f4f5; + margin: 0; + padding: 0; + font-size: @font-size-base - 1px; + color: @text-color; + overflow: auto; + } + + strong, + b { + font-weight: 500; + } + + > table { + border-collapse: collapse; + border-spacing: 0; + empty-cells: show; + border: 1px solid @border-color-split; + width: 100%; + margin: 8px 0 16px; + } + + > table th { + white-space: nowrap; + color: #5c6b77; + font-weight: 500; + background: rgba(0, 0, 0, 0.02); + } + + & > table th, + & > table td { + border: 1px solid @border-color-split; + padding: 16px 24px; + text-align: left; + } + + blockquote { + font-size: 90%; + color: @text-color-secondary; + border-left: 4px solid @border-color-split; + padding-left: 0.8em; + margin: 1em 0; + } + + blockquote p { + margin: 0; + } + + & > br, + & > p > br { + clear: both; + } + +} diff --git a/zeppelin-web-angular/src/styles/theme/theme-mixin.less b/zeppelin-web-angular/src/styles/theme/theme-mixin.less new file mode 100644 index 00000000000..4daec305409 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/theme-mixin.less @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../../../node_modules/ng-zorro-antd/src/style/color/colors'; + +.themeMixin(@rules) { + :host-context(.light) { + @import 'theme-light'; + @rules(); + } + :host-context(.dark) { + @import 'theme-dark'; + @rules(); + } +} diff --git a/zeppelin-web-angular/src/test.ts b/zeppelin-web-angular/src/test.ts new file mode 100644 index 00000000000..f90345f8e54 --- /dev/null +++ b/zeppelin-web-angular/src/test.ts @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import { getTestBed } from '@angular/core/testing'; +import { platformBrowserDynamicTesting, BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; +// tslint:disable-next-line:no-import-side-effect +import 'zone.js/dist/zone-testing'; + +// tslint:disable-next-line no-any +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/zeppelin-web-angular/src/tsconfig.app.json b/zeppelin-web-angular/src/tsconfig.app.json new file mode 100644 index 00000000000..50958688dbe --- /dev/null +++ b/zeppelin-web-angular/src/tsconfig.app.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": ["mathjax"] + }, + "exclude": ["test.ts", "**/*.spec.ts"] +} diff --git a/zeppelin-web-angular/src/tsconfig.spec.json b/zeppelin-web-angular/src/tsconfig.spec.json new file mode 100644 index 00000000000..70add2d529d --- /dev/null +++ b/zeppelin-web-angular/src/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": ["jasmine", "node"] + }, + "files": ["test.ts", "polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/zeppelin-web-angular/src/tslint.json b/zeppelin-web-angular/src/tslint.json new file mode 100644 index 00000000000..bb3e34a7b6e --- /dev/null +++ b/zeppelin-web-angular/src/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [true, "attribute", "zeppelin", "camelCase"], + "component-selector": [true, "element", "zeppelin", "kebab-case"] + } +} diff --git a/zeppelin-web-angular/tsconfig.app.json b/zeppelin-web-angular/tsconfig.app.json new file mode 100644 index 00000000000..565a11a2156 --- /dev/null +++ b/zeppelin-web-angular/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/test.ts", + "src/**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/tsconfig.json b/zeppelin-web-angular/tsconfig.json new file mode 100644 index 00000000000..45f06cbf7de --- /dev/null +++ b/zeppelin-web-angular/tsconfig.json @@ -0,0 +1,47 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@zeppelin/*": [ + "./src/app/*", + "./src/environments/*" + ], + "@zeppelin/helium": [ + "./dist/zeppelin-helium" + ], + "@zeppelin/helium/*": [ + "./dist/zeppelin-helium/*" + ], + "@zeppelin/visualization": [ + "dist/zeppelin-visualization" + ], + "@zeppelin/visualization/*": [ + "dist/zeppelin-visualization/*" + ], + "@zeppelin/sdk": [ + "dist/zeppelin-sdk" + ], + "@zeppelin/sdk/*": [ + "dist/zeppelin-sdk/*" + ] + }, + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/tsconfig.spec.json b/zeppelin-web-angular/tsconfig.spec.json new file mode 100644 index 00000000000..6400fde7d54 --- /dev/null +++ b/zeppelin-web-angular/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/tslint.json b/zeppelin-web-angular/tslint.json new file mode 100644 index 00000000000..045107bdf2e --- /dev/null +++ b/zeppelin-web-angular/tslint.json @@ -0,0 +1,142 @@ +{ + "rulesDirectory": ["node_modules/codelyzer", "node_modules/nz-tslint-rules"], + "rules": { + "nz-secondary-entry-imports": true, + "banana-in-box": true, + "templates-no-negated-async": true, + "no-life-cycle-call": false, + "prefer-output-readonly": true, + "no-conflicting-life-cycle-hooks": false, + "enforce-component-selector": false, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": false, + "use-view-encapsulation": false, + "no-attribute-parameter-decorator": true, + "no-output-named-after-standard-event": true, + "no-output-rename": true, + "no-output-on-prefix": true, + "no-forward-ref": false, + "use-life-cycle-interface": true, + "contextual-life-cycle": true, + "trackBy-function": false, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true, + "pipe-impure": true, + "angular-whitespace": [false, "check-interpolation"], + "directive-selector": [true, "attribute", ["zeppelin"], ["camelCase", "kebab-case"]], + "component-selector": [true, ["element", "attribute"], ["zeppelin"], "kebab-case"], + "callable-types": true, + "class-name": true, + "comment-format": [true, "check-space"], + "align": [true, "parameters", "statements"], + "array-type": [true, "array-simple"], + "arrow-return-shorthand": true, + "ban-types": [ + true, + ["Object", "Use {} instead."], + ["String", "Use string instead."], + ["Number", "Use number instead."], + ["Boolean", "Use boolean instead."], + ["Function", "Use specific callable interface instead."] + ], + "binary-expression-operand-order": true, + "curly": true, + "encoding": true, + "eofline": true, + "deprecation": { + "severity": "warn" + }, + "import-spacing": true, + "indent": [true, "spaces"], + "interface-name": [true, "never-prefix"], + "interface-over-type-literal": true, + "label-position": true, + "new-parens": true, + "no-angle-bracket-type-assertion": true, + "member-access": false, + "member-ordering": [ + true, + { + "order": ["static-field", "instance-field", "static-method", "instance-method"] + } + ], + "no-any": true, + "no-arg": true, + "no-bitwise": false, + "no-consecutive-blank-lines": [true], + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-duplicate-variable": true, + "no-conditional-assignment": true, + "no-construct": true, + "no-debugger": true, + "no-duplicate-imports": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-floating-promises": false, + "no-for-in-array": true, + "no-import-side-effect": true, + "no-inferrable-types": [true, "ignore-params", "ignore-properties"], + "no-invalid-template-strings": true, + "no-invalid-this": true, + "no-irregular-whitespace": true, + "no-magic-numbers": false, + "no-misused-new": true, + "no-namespace": [true, "allow-declarations"], + "no-non-null-assertion": false, + "no-shadowed-variable": true, + "no-sparse-arrays": true, + "no-string-literal": true, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-this-assignment": true, + "no-trailing-whitespace": true, + "no-parameter-reassignment": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "number-literal-format": true, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "one-variable-per-declaration": [true, "ignore-for-loop"], + "ordered-imports": [ + true, + { + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-first" + } + ], + "prefer-conditional-expression": false, + "prefer-const": true, + "prefer-method-signature": true, + "prefer-object-spread": true, + "prefer-template": [true, "allow-single-concat"], + "radix": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "use-isnan": true, + "variable-name": [true, "ban-keywords", "allow-leading-underscore"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"], + "no-input-rename": true + } +} diff --git a/zeppelin-web-angular/webpack.partial.js b/zeppelin-web-angular/webpack.partial.js new file mode 100644 index 00000000000..c2261441f9c --- /dev/null +++ b/zeppelin-web-angular/webpack.partial.js @@ -0,0 +1,27 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); + +module.exports = { + plugins: [ + new MonacoWebpackPlugin({ + languages: [ + 'bat', 'cpp', 'csharp', 'csp', 'css', 'dockerfile', 'go', 'handlebars', 'html', 'java', 'javascript', 'json', + 'less', 'lua', 'markdown', 'mysql', 'objective', 'perl', 'pgsql', 'php', 'powershell', 'python', 'r', 'ruby', + 'rust', 'scheme', 'scss', 'shell', 'sql', 'swift', 'typescript', 'vb', 'xml', 'yaml' + ], + features: ['!accessibilityHelp'] + }) + ] +}; + diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html index 263ff0679a2..818258523a2 100644 --- a/zeppelin-web/src/components/navbar/navbar.html +++ b/zeppelin-web/src/components/navbar/navbar.html @@ -105,6 +105,8 @@
  • Cluster
  • Logout
  • + +
  • Try the new Zeppelin
  • diff --git a/zeppelin-web/src/components/note-create/visible.directive.js b/zeppelin-web/src/components/note-create/visible.directive.js index 7ba8db72f3d..2128f6ef6de 100644 --- a/zeppelin-web/src/components/note-create/visible.directive.js +++ b/zeppelin-web/src/components/note-create/visible.directive.js @@ -36,7 +36,9 @@ function modalvisible() { }); element.on('shown.bs.modal', function(e) { if (scope.targetinput) { - angular.element(e.target).find('input#' + scope.targetinput).select(); + let ele = angular.element(e.target).find('input#' + scope.targetinput); + ele[0].focus(); + ele[0].setSelectionRange(ele.val().lastIndexOf('/') + 1, ele.val().length); } postVisibleMethod(); }); diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java index 42de70599bd..297271c4151 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java @@ -49,7 +49,6 @@ import org.apache.zeppelin.resource.ResourceId; import org.apache.zeppelin.resource.ResourcePool; import org.apache.zeppelin.resource.ResourceSet; -import org.apache.zeppelin.user.AuthenticationInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -220,6 +219,11 @@ public void updateAppStatus(AppStatusUpdateEvent event) throws TException { appListener.onStatusChange(event.noteId, event.paragraphId, event.appId, event.status); } + @Override + public void checkpointOutput(String noteId, String paragraphId) throws TException { + listener.checkpointOutput(noteId, paragraphId); + } + @Override public void runParagraphs(RunParagraphsEvent event) throws TException { try { diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessListener.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessListener.java index f0772045430..c9c79139a78 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessListener.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcessListener.java @@ -42,4 +42,6 @@ public void onParaInfosReceived(String noteId, String paragraphId, String interpreterSettingId, Map metaInfos); List getParagraphList(String user, String noteId) throws TException, IOException; + + void checkpointOutput(String noteId, String paragraphId); } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java index a9388a65151..dbecbf21a1c 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -641,6 +641,7 @@ public Paragraph removeParagraph(String user, String paragraphId) { public void clearParagraphOutputFields(Paragraph p) { p.setReturn(null, null); p.cleanRuntimeInfos(); + p.cleanOutputBuffer(); } public Paragraph clearPersonalizedParagraphOutput(String paragraphId, String user) { @@ -1094,6 +1095,7 @@ public static Note fromJson(String json) throws IOException { public void postProcessParagraphs() { for (Paragraph p : paragraphs) { p.cleanRuntimeInfos(); + p.cleanOutputBuffer(); p.parseText(); if (p.getStatus() == Status.PENDING || p.getStatus() == Status.RUNNING) { diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java index 5405d9e9c67..e97ea3c4e23 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java @@ -107,6 +107,7 @@ public class Paragraph extends JobWithProgressPoller implemen private transient Map localProperties = new HashMap<>(); // serialize runtimeInfos to frontend but not to note file (via gson's ExclusionStrategy) private Map runtimeInfos = new HashMap<>(); + private transient List outputBuffer = new ArrayList<>(); public static String PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE = "runOnSelectionChange"; private static boolean PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE_DEFAULT = true; @@ -613,6 +614,7 @@ public void onUpdateAll(InterpreterOutput out) { paragraphJobListener.onOutputUpdateAll(self, messages); } updateParagraphResult(messages); + outputBuffer.clear(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); } @@ -816,6 +818,22 @@ public void cleanRuntimeInfos() { this.runtimeInfos.clear(); } + public void cleanOutputBuffer() { + this.outputBuffer.clear(); + } + + /** + * Save the buffered output to InterpreterResults. So that open another tab or refresh + * note you can see the latest checkpoint's output. + */ + public void checkpointOutput() { + LOGGER.info("Checkpoint Paragraph output for paragraph: " + getId()); + this.results = new InterpreterResult(Code.SUCCESS); + for (InterpreterResultMessage buffer : outputBuffer) { + results.add(buffer); + } + } + private GUI getNoteGui() { GUI gui = new GUI(); gui.setParams(this.note.getNoteParams()); @@ -884,4 +902,15 @@ public static Paragraph fromJson(String json) { return Note.getGson().fromJson(json, Paragraph.class); } + public void updateOutputBuffer(int index, InterpreterResult.Type type, String output) { + InterpreterResultMessage interpreterResultMessage = new InterpreterResultMessage(type, output);; + if (outputBuffer.size() == index) { + outputBuffer.add(interpreterResultMessage); + } else if (outputBuffer.size() > index) { + outputBuffer.set(index, interpreterResultMessage); + } else { + LOGGER.warn("Get output of index: " + index + ", but there's only " + + outputBuffer.size() + " output in outputBuffer"); + } + } } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java index cdcfed09861..032773e452e 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java @@ -100,17 +100,14 @@ private String getOldNotebookRepoClassName(String notebookRepoClassName) { */ public OldNotebookRepo loadOldNotebookRepo(String notebookRepoClassName) throws IOException { LOGGER.info("Loading OldNotebookRepo Plugin: " + notebookRepoClassName); - // load plugin from classpath directly when it is test. - // otherwise load it from plugin folder - String isTest = System.getenv("IS_ZEPPELIN_TEST"); - if (isTest != null && isTest.equals("true")) { - try { - OldNotebookRepo notebookRepo = (OldNotebookRepo) - (Class.forName(notebookRepoClassName).newInstance()); - return notebookRepo; - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - LOGGER.warn("Fail to instantiate notebookrepo from classpath directly:" + notebookRepoClassName); - } + // load plugin from classpath directly first for these builtin NotebookRepo (such as VFSNoteBookRepo + // and GitNotebookRepo). If fails, then try to load it from plugin folder + try { + OldNotebookRepo notebookRepo = (OldNotebookRepo) + (Class.forName(notebookRepoClassName).newInstance()); + return notebookRepo; + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + LOGGER.warn("Fail to instantiate notebookrepo from classpath directly:" + notebookRepoClassName); } String simpleClassName = notebookRepoClassName.substring(notebookRepoClassName.lastIndexOf(".") + 1); diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java index 5a3e2258507..d232c259be8 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java @@ -148,4 +148,8 @@ public List getParagraphList(String user, String noteId) { return null; } + @Override + public void checkpointOutput(String noteId, String paragraphId) { + + } } diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java index acba1c85823..c768e543131 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java @@ -294,4 +294,8 @@ public List getParagraphList(String user, String noteId) { return null; } + @Override + public void checkpointOutput(String noteId, String paragraphId) { + + } }