You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by zj...@apache.org on 2020/01/12 06:38:17 UTC

[zeppelin] branch master updated (b200275 -> 3906331)

This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git.


    from b200275  [ZEPPELIN-4541]. Add api to checkpoint paragraph output between interpreter and zeppelin-server
     new 6af0934  [ZEPPELIN-4321] Rework Zeppelin with Latest Angular
     new d3979c2  [ZEPPELIN-4321] Support shortcuts for the paragraphs
     new 1e0177d  [ZEPPELIN-4450] Provide Angular.js Template Migration Tool
     new 66f4dd1  [ZEPPELIN-4403] Support publishable for paragraph
     new 1edc985  [ZEPPELIN-4401] Add configuration page
     new 3aaa111  [ZEPPELIN-4399] Add credential page
     new 5ff4050  [ZEPPELIN-4398] Add notebook repository page
     new bdc2940  [ZEPPELIN-4501] Use secondary entry imports
     new 2c8b852  [ZEPPELIN-4502] Adjust global styles and theming the visualization
     new 6863543  [ZEPPELIN-4503] Support note scope dynamic forms
     new 52392bf  [ZEPPELIN-4516] Fix pie chart does not color by key
     new 6ddc0c6  [ZEPPELIN-4515] Have Jetty Server support multiple wars
     new be80af7  [ZEPPELIN-4530] Support versions switch
     new a62d893  [ZEPPELIN-4542] Websocket client support of auto-reconnect
     new 8f12d52  [ZEPPELIN-4548] Support search notebook
     new 3906331  [ZEPPELIN-4540] Convert code editor font size units

The 16 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .travis.yml                                        |    11 +
 LICENSE                                            |     7 +-
 .../src/main/resources/interpreter-setting.json    |    11 +
 bin/common.sh                                      |    12 +-
 bin/zeppelin-daemon.sh                             |     1 +
 bin/zeppelin.sh                                    |     1 +
 pom.xml                                            |    15 +-
 zeppelin-distribution/pom.xml                      |     6 +
 .../src/assemble/distribution.xml                  |     4 +-
 .../zeppelin/conf/ZeppelinConfiguration.java       |     1 +
 .../org/apache/zeppelin/server/ZeppelinServer.java |    92 +-
 .../apache/zeppelin/rest/AbstractTestRestApi.java  |     3 +
 zeppelin-web-angular/.editorconfig                 |    15 +
 zeppelin-web-angular/.gitignore                    |    47 +
 zeppelin-web-angular/.prettierignore               |     3 +
 zeppelin-web-angular/.prettierrc                   |    15 +
 zeppelin-web-angular/README.md                     |   276 +
 zeppelin-web-angular/WEB-INF/web.xml               |    41 +
 zeppelin-web-angular/angular.json                  |   331 +
 zeppelin-web-angular/browserslist                  |    12 +
 zeppelin-web-angular/e2e/protractor.conf.js        |    44 +
 zeppelin-web-angular/e2e/src/app.e2e-spec.ts       |    23 +
 zeppelin-web-angular/e2e/src/app.po.ts             |    11 +
 zeppelin-web-angular/e2e/tsconfig.json             |    13 +
 zeppelin-web-angular/karma.conf.js                 |    44 +
 zeppelin-web-angular/package-lock.json             | 16043 +++++++++++++++++++
 zeppelin-web-angular/package.json                  |   101 +
 zeppelin-web-angular/pom.xml                       |   174 +
 .../projects/helium-vis-example/README.md          |    36 +
 .../projects/helium-vis-example/karma.conf.js      |    44 +
 .../projects/helium-vis-example/ng-package.json    |     7 +
 .../projects/helium-vis-example/package.json       |     8 +
 .../helium-vis-example/src/json-vis.component.ts   |    43 +
 .../helium-vis-example/src/json-vis.module.ts      |    23 +
 .../helium-vis-example/src/json-visualization.ts   |    64 +
 .../projects/helium-vis-example/src/public-api.ts  |    30 +
 .../projects/helium-vis-example/src/test.ts        |    33 +
 .../projects/helium-vis-example/tsconfig.lib.json  |    26 +
 .../projects/helium-vis-example/tsconfig.spec.json |    17 +
 .../projects/helium-vis-example/tslint.json        |    17 +
 .../projects/zeppelin-helium/README.md             |    36 +
 .../projects/zeppelin-helium/karma.conf.js         |    44 +
 .../projects/zeppelin-helium/ng-package.json       |     7 +
 .../projects/zeppelin-helium/package.json          |    12 +
 .../projects/zeppelin-helium/src/common-deps.ts    |    43 +
 .../projects/zeppelin-helium/src/index.ts          |    13 +
 .../projects/zeppelin-helium/src/public-api.ts     |    18 +
 .../projects/zeppelin-helium/src/test.ts           |    33 +
 .../zeppelin-helium/src/zeppelin-helium.module.ts  |    16 +
 .../zeppelin-helium/src/zeppelin-helium.service.ts |    96 +
 .../projects/zeppelin-helium/tsconfig.lib.json     |    27 +
 .../projects/zeppelin-helium/tsconfig.spec.json    |    17 +
 .../projects/zeppelin-helium/tslint.json           |    17 +
 .../projects/zeppelin-sdk/README.md                |    36 +
 .../projects/zeppelin-sdk/karma.conf.js            |    44 +
 .../projects/zeppelin-sdk/ng-package.json          |     7 +
 .../projects/zeppelin-sdk/package.json             |     8 +
 .../projects/zeppelin-sdk/src/index.ts             |    13 +
 .../projects/zeppelin-sdk/src/interfaces/index.ts  |    13 +
 .../src/interfaces/message-common.interface.ts     |   129 +
 .../interfaces/message-data-type-map.interface.ts  |   164 +
 .../interfaces/message-interpreter.interface.ts    |    70 +
 .../src/interfaces/message-job.interface.ts        |    48 +
 .../src/interfaces/message-notebook.interface.ts   |   210 +
 .../src/interfaces/message-operator.interface.ts   |   482 +
 .../src/interfaces/message-paragraph.interface.ts  |   468 +
 .../zeppelin-sdk/src/interfaces/public-api.ts      |    20 +
 .../src/interfaces/websocket-message.interface.ts  |    21 +
 .../projects/zeppelin-sdk/src/message.ts           |   506 +
 .../projects/zeppelin-sdk/src/public-api.ts        |    15 +
 .../projects/zeppelin-sdk/tsconfig.lib.json        |    27 +
 .../projects/zeppelin-sdk/tsconfig.spec.json       |    17 +
 .../projects/zeppelin-sdk/tslint.json              |    17 +
 .../projects/zeppelin-visualization/README.md      |    36 +
 .../projects/zeppelin-visualization/karma.conf.js  |    44 +
 .../zeppelin-visualization/ng-package.json         |     7 +
 .../projects/zeppelin-visualization/package.json   |     8 +
 .../zeppelin-visualization/src/data-set.ts         |    17 +
 .../src/g2-visualization-base.ts                   |    57 +
 .../src/g2-visualization-component-base.ts         |    93 +
 .../projects/zeppelin-visualization/src/index.ts   |    13 +
 .../src/pivot-transformation.ts                    |   230 +
 .../zeppelin-visualization/src/public-api.ts       |    25 +
 .../zeppelin-visualization/src/table-data.ts       |    35 +
 .../src/table-transformation.ts                    |    26 +
 .../zeppelin-visualization/src/transformation.ts   |    46 +
 .../src/visualization-component-portal.ts          |    46 +
 .../zeppelin-visualization/src/visualization.ts    |    44 +
 .../zeppelin-visualization/tsconfig.lib.json       |    27 +
 .../zeppelin-visualization/tsconfig.spec.json      |    17 +
 .../projects/zeppelin-visualization/tslint.json    |    17 +
 zeppelin-web-angular/proxy.conf.js                 |    59 +
 zeppelin-web-angular/screenshot.png                |   Bin 0 -> 220058 bytes
 zeppelin-web-angular/src/.editorconfig             |    12 +
 zeppelin-web-angular/src/.gitignore                |    43 +
 .../src/app/app-http.interceptor.ts                |    53 +
 .../src/app/app-message.interceptor.ts             |    69 +
 zeppelin-web-angular/src/app/app-routing.module.ts |    36 +
 .../src/app/app-runtime-compiler.providers.ts      |    41 +
 zeppelin-web-angular/src/app/app.component.html    |    15 +
 zeppelin-web-angular/src/app/app.component.less    |    26 +
 zeppelin-web-angular/src/app/app.component.spec.ts |    30 +
 zeppelin-web-angular/src/app/app.component.ts      |    39 +
 zeppelin-web-angular/src/app/app.module.ts         |    90 +
 .../app/core/copy-text/copy-text-to-clipboard.ts   |    65 +
 .../src/app/core/copy-text/index.ts                |    13 +
 .../src/app/core/copy-text/public-api.ts           |    13 +
 .../core/destroy-hook/destroy-hook.component.ts    |    23 +
 .../src/app/core/destroy-hook/index.ts             |    13 +
 .../src/app/core/destroy-hook/public-api.ts        |    13 +
 zeppelin-web-angular/src/app/core/index.ts         |    13 +
 .../src/app/core/message-listener/index.ts         |    13 +
 .../app/core/message-listener/message-listener.ts  |    59 +
 .../src/app/core/message-listener/public-api.ts    |    13 +
 .../src/app/core/paragraph-base/index.ts           |    13 +
 .../src/app/core/paragraph-base/paragraph-base.ts  |   315 +
 .../src/app/core/paragraph-base/public-api.ts      |    14 +
 .../src/app/core/paragraph-base/published.ts       |    17 +
 zeppelin-web-angular/src/app/core/public-api.ts    |    17 +
 .../src/app/core/runtime-dynamic-module/index.ts   |    13 +
 .../runtime-dynamic-module/ng-zorro-antd-module.ts |   148 +
 .../app/core/runtime-dynamic-module/public-api.ts  |    13 +
 .../runtime-dynamic-module.module.ts               |    21 +
 .../app/helium-manager/helium-manager.module.ts    |    27 +
 .../app/helium-manager/helium-manager.service.ts   |    75 +
 .../src/app/helium-manager/index.ts                |    13 +
 .../src/app/helium-manager/public-api.ts           |    14 +
 .../src/app/interfaces/credential.ts               |    28 +
 zeppelin-web-angular/src/app/interfaces/index.ts   |    13 +
 .../src/app/interfaces/interpreter.ts              |   104 +
 .../src/app/interfaces/message-interceptor.ts      |    20 +
 .../src/app/interfaces/node-list.ts                |    41 +
 .../src/app/interfaces/notebook-repo.ts            |    32 +
 .../src/app/interfaces/notebook-search.ts          |    19 +
 .../src/app/interfaces/public-api.ts               |    20 +
 .../src/app/interfaces/security.ts                 |    23 +
 zeppelin-web-angular/src/app/interfaces/ticket.ts  |    29 +
 .../src/app/interfaces/trash-folder-id.ts          |    15 +
 zeppelin-web-angular/src/app/languages/index.ts    |    13 +
 zeppelin-web-angular/src/app/languages/load.ts     |    29 +
 .../src/app/languages/public-api.ts                |    14 +
 zeppelin-web-angular/src/app/languages/scala.ts    |   236 +
 .../src/app/pages/login/login-routing.module.ts    |    29 +
 .../src/app/pages/login/login.component.html       |    46 +
 .../src/app/pages/login/login.component.less       |    69 +
 .../src/app/pages/login/login.component.ts         |    47 +
 .../src/app/pages/login/login.module.ts            |    29 +
 .../configuration/configuration-routing.module.ts  |    27 +
 .../configuration/configuration.component.html     |    37 +
 .../configuration/configuration.component.less     |    22 +
 .../configuration/configuration.component.ts       |    36 +
 .../configuration/configuration.module.ts          |    24 +
 .../credential/credential-routing.module.ts        |    28 +
 .../workspace/credential/credential.component.html |   134 +
 .../workspace/credential/credential.component.less |    39 +
 .../workspace/credential/credential.component.ts   |   202 +
 .../workspace/credential/credential.module.ts      |    54 +
 .../pages/workspace/home/home-routing.module.ts    |    29 +
 .../app/pages/workspace/home/home.component.html   |    41 +
 .../app/pages/workspace/home/home.component.less   |    37 +
 .../src/app/pages/workspace/home/home.component.ts |    48 +
 .../src/app/pages/workspace/home/home.module.ts    |    29 +
 .../create-repository-modal.component.html         |   158 +
 .../create-repository-modal.component.less         |    19 +
 .../create-repository-modal.component.ts           |    78 +
 .../interpreter/interpreter-routing.module.ts      |    29 +
 .../interpreter/interpreter.component.html         |    66 +
 .../interpreter/interpreter.component.less         |    51 +
 .../workspace/interpreter/interpreter.component.ts |   188 +
 .../workspace/interpreter/interpreter.module.ts    |    71 +
 .../workspace/interpreter/item/item.component.html |   447 +
 .../workspace/interpreter/item/item.component.less |   105 +
 .../workspace/interpreter/item/item.component.ts   |   405 +
 .../job-manager/job-manager-routing.module.ts      |    29 +
 .../job-manager/job-manager.component.html         |    75 +
 .../job-manager/job-manager.component.less         |    50 +
 .../workspace/job-manager/job-manager.component.ts |   138 +
 .../workspace/job-manager/job-manager.module.ts    |    70 +
 .../job-status/job-status.component.html           |    17 +
 .../job-status/job-status.component.less           |    23 +
 .../job-manager/job-status/job-status.component.ts |    37 +
 .../workspace/job-manager/job/job.component.html   |    58 +
 .../workspace/job-manager/job/job.component.less   |    70 +
 .../workspace/job-manager/job/job.component.ts     |    83 +
 .../notebook-repos/item/item.component.html        |    79 +
 .../notebook-repos/item/item.component.less        |    37 +
 .../notebook-repos/item/item.component.ts          |    78 +
 .../notebook-repos-routing.module.ts               |    28 +
 .../notebook-repos/notebook-repos.component.html   |    21 +
 .../notebook-repos/notebook-repos.component.less   |    20 +
 .../notebook-repos/notebook-repos.component.ts     |    51 +
 .../notebook-repos/notebook-repos.module.ts        |    47 +
 .../notebook-search-routing.module.ts              |    29 +
 .../notebook-search/notebook-search.component.html |    17 +
 .../notebook-search/notebook-search.component.less |    24 +
 .../notebook-search/notebook-search.component.ts   |    58 +
 .../notebook-search/notebook-search.module.ts      |    29 +
 .../result-item/result-item.component.html         |    22 +
 .../result-item/result-item.component.less         |    19 +
 .../result-item/result-item.component.ts           |   162 +
 .../notebook/action-bar/action-bar.component.html  |   239 +
 .../notebook/action-bar/action-bar.component.less  |   105 +
 .../notebook/action-bar/action-bar.component.ts    |   293 +
 .../add-paragraph/add-paragraph.component.html     |    17 +
 .../add-paragraph/add-paragraph.component.less     |    50 +
 .../add-paragraph/add-paragraph.component.ts       |    34 +
 .../interpreter-binding.component.html             |    55 +
 .../interpreter-binding.component.less             |    30 +
 .../interpreter-binding.component.ts               |    81 +
 .../note-form-block/note-form-block.component.html |    25 +
 .../note-form-block/note-form-block.component.less |    27 +
 .../note-form-block/note-form-block.component.ts   |    43 +
 .../workspace/notebook/notebook-routing.module.ts  |    33 +
 .../workspace/notebook/notebook.component.html     |    66 +
 .../workspace/notebook/notebook.component.less     |    36 +
 .../pages/workspace/notebook/notebook.component.ts |   386 +
 .../pages/workspace/notebook/notebook.module.ts    |   100 +
 .../code-editor/code-editor.component.html         |    17 +
 .../code-editor/code-editor.component.less         |    35 +
 .../paragraph/code-editor/code-editor.component.ts |   232 +
 .../paragraph/control/control.component.html       |    85 +
 .../paragraph/control/control.component.less       |    73 +
 .../paragraph/control/control.component.ts         |   279 +
 .../paragraph/footer/footer.component.html         |    16 +
 .../paragraph/footer/footer.component.less         |    21 +
 .../notebook/paragraph/footer/footer.component.ts  |    74 +
 .../notebook/paragraph/paragraph.component.html    |   105 +
 .../notebook/paragraph/paragraph.component.less    |    77 +
 .../notebook/paragraph/paragraph.component.ts      |   634 +
 .../paragraph/progress/progress.component.html     |    16 +
 .../paragraph/progress/progress.component.less     |    12 +
 .../paragraph/progress/progress.component.ts       |    32 +
 .../permissions/permissions.component.html         |    88 +
 .../permissions/permissions.component.less         |    33 +
 .../notebook/permissions/permissions.component.ts  |   136 +
 .../revisions-comparator.component.html            |    20 +
 .../revisions-comparator.component.less            |    12 +
 .../revisions-comparator.component.ts              |    25 +
 .../elastic-input/elastic-input.component.html     |    23 +
 .../elastic-input/elastic-input.component.less     |    56 +
 .../share/elastic-input/elastic-input.component.ts |    89 +
 .../pages/workspace/notebook/share/share.module.ts |    26 +
 .../published/paragraph/paragraph.component.html   |    15 +
 .../published/paragraph/paragraph.component.less   |     0
 .../published/paragraph/paragraph.component.ts     |    88 +
 .../published/published-ruoting.module.ts          |    28 +
 .../pages/workspace/published/published.module.ts  |    11 +
 .../dynamic-forms/dynamic-forms.component.html     |    63 +
 .../dynamic-forms/dynamic-forms.component.less     |    46 +
 .../share/dynamic-forms/dynamic-forms.component.ts |   126 +
 .../src/app/pages/workspace/share/index.ts         |    13 +
 .../src/app/pages/workspace/share/public-api.ts    |    13 +
 .../workspace/share/result/result.component.html   |    75 +
 .../workspace/share/result/result.component.less   |   114 +
 .../workspace/share/result/result.component.ts     |   373 +
 .../src/app/pages/workspace/share/share.module.ts  |    58 +
 .../pages/workspace/workspace-routing.module.ts    |    75 +
 .../app/pages/workspace/workspace.component.html   |    16 +
 .../app/pages/workspace/workspace.component.less   |    22 +
 .../src/app/pages/workspace/workspace.component.ts |    80 +
 .../src/app/pages/workspace/workspace.guard.ts     |    36 +
 .../src/app/pages/workspace/workspace.module.ts    |    40 +
 .../src/app/services/array-ordering.service.ts     |    62 +
 zeppelin-web-angular/src/app/services/base-rest.ts |    45 +
 .../src/app/services/base-url.service.ts           |    46 +
 .../src/app/services/completion.service.ts         |    97 +
 .../src/app/services/configuration.service.ts      |    30 +
 .../src/app/services/credential.service.ts         |    43 +
 .../src/app/services/helium.service.ts             |    24 +
 zeppelin-web-angular/src/app/services/index.ts     |    13 +
 .../src/app/services/interpreter.service.ts        |    84 +
 .../src/app/services/job-manager.service.ts        |    34 +
 .../src/app/services/message.service.ts            |   331 +
 .../app/services/ng-template-adapter.service.ts    |    65 +
 .../src/app/services/ng-z.service.ts               |    85 +
 .../src/app/services/note-action.service.ts        |    72 +
 .../src/app/services/note-list.service.ts          |    97 +
 .../src/app/services/note-status.service.ts        |    65 +
 .../src/app/services/note-var-share.service.ts     |    38 +
 .../src/app/services/notebook-repos.service.ts     |    36 +
 .../src/app/services/notebook-search.service.ts    |    47 +
 .../src/app/services/public-api.ts                 |    32 +
 .../src/app/services/runtime-compiler.service.ts   |    79 +
 .../src/app/services/save-as.service.ts            |    37 +
 .../src/app/services/security.service.ts           |    40 +
 .../src/app/services/shortcut.service.ts           |   110 +
 .../src/app/services/ticket.service.ts             |   116 +
 .../about-zeppelin/about-zeppelin.component.html   |    28 +
 .../about-zeppelin/about-zeppelin.component.less   |    38 +
 .../about-zeppelin/about-zeppelin.component.ts     |    26 +
 .../share/code-editor/code-editor.component.html   |    19 +
 .../app/share/code-editor/code-editor.component.ts |   244 +
 .../app/share/code-editor/code-editor.module.ts    |    26 +
 .../app/share/code-editor/code-editor.service.ts   |   104 +
 .../src/app/share/code-editor/index.ts             |    13 +
 .../code-editor/nz-code-editor.definitions.ts      |    46 +
 .../src/app/share/code-editor/public-api.ts        |    16 +
 .../folder-rename/folder-rename.component.html     |    32 +
 .../folder-rename/folder-rename.component.less     |    12 +
 .../share/folder-rename/folder-rename.component.ts |    80 +
 .../src/app/share/header/header.component.html     |    83 +
 .../src/app/share/header/header.component.less     |   110 +
 .../src/app/share/header/header.component.ts       |   101 +
 zeppelin-web-angular/src/app/share/index.ts        |    13 +
 .../src/app/share/math-jax/math-jax.directive.ts   |    24 +
 .../ng1-migration/ng1-migration.component.html     |    54 +
 .../ng1-migration/ng1-migration.component.less     |    77 +
 .../share/ng1-migration/ng1-migration.component.ts |   174 +
 .../app/share/node-list/node-list.component.html   |   139 +
 .../app/share/node-list/node-list.component.less   |    78 +
 .../src/app/share/node-list/node-list.component.ts |   118 +
 .../share/note-create/note-create.component.html   |    44 +
 .../share/note-create/note-create.component.less   |    12 +
 .../app/share/note-create/note-create.component.ts |   105 +
 .../share/note-import/note-import.component.html   |    50 +
 .../share/note-import/note-import.component.less   |    19 +
 .../app/share/note-import/note-import.component.ts |   111 +
 .../share/note-rename/note-rename.component.html   |    23 +
 .../share/note-rename/note-rename.component.less   |    12 +
 .../app/share/note-rename/note-rename.component.ts |    37 +
 .../share/page-header/page-header.component.html   |    18 +
 .../share/page-header/page-header.component.less   |    17 +
 .../app/share/page-header/page-header.component.ts |    31 +
 .../src/app/share/pipes/humanize-bytes.pipe.ts     |    40 +
 zeppelin-web-angular/src/app/share/pipes/index.ts  |    13 +
 .../src/app/share/pipes/public-api.ts              |    13 +
 zeppelin-web-angular/src/app/share/public-api.ts   |    15 +
 .../src/app/share/resize-handle/index.ts           |    13 +
 .../src/app/share/resize-handle/public-api.ts      |    13 +
 .../resize-handle/resize-handle.component.html     |    23 +
 .../resize-handle/resize-handle.component.less     |    23 +
 .../share/resize-handle/resize-handle.component.ts |    26 +
 .../app/share/run-scripts/run-scripts.directive.ts |    80 +
 zeppelin-web-angular/src/app/share/share.module.ts |   102 +
 .../src/app/share/spin/spin.component.html         |    21 +
 .../src/app/share/spin/spin.component.less         |    12 +
 .../src/app/share/spin/spin.component.ts           |    26 +
 zeppelin-web-angular/src/app/spell/spell-result.ts |    27 +
 .../src/app/utility/css-unit-conversion.ts         |    15 +
 zeppelin-web-angular/src/app/utility/element.ts    |    19 +
 .../src/app/utility/get-keyword-positions.ts       |    43 +
 zeppelin-web-angular/src/app/utility/line-map.ts   |    60 +
 .../area-chart-visualization.component.html        |    35 +
 .../area-chart-visualization.component.less        |    15 +
 .../area-chart-visualization.component.ts          |   102 +
 .../area-chart/area-chart-visualization.ts         |    32 +
 .../bar-chart-visualization.component.html         |    34 +
 .../bar-chart-visualization.component.less         |    25 +
 .../bar-chart/bar-chart-visualization.component.ts |   110 +
 .../bar-chart/bar-chart-visualization.ts           |    31 +
 .../pivot-setting/pivot-setting.component.html     |    85 +
 .../pivot-setting/pivot-setting.component.less     |    33 +
 .../pivot-setting/pivot-setting.component.ts       |    89 +
 .../scatter-setting/scatter-setting.component.html |    98 +
 .../scatter-setting/scatter-setting.component.less |    33 +
 .../scatter-setting/scatter-setting.component.ts   |   102 +
 .../visualizations/common/util/calc-tick-count.ts  |    22 +
 .../app/visualizations/common/util/set-x-axis.ts   |    46 +
 .../x-axis-setting/x-axis-setting.component.html   |    38 +
 .../x-axis-setting/x-axis-setting.component.less   |    18 +
 .../x-axis-setting/x-axis-setting.component.ts     |    78 +
 .../src/app/visualizations/g2.config.ts            |   129 +
 .../line-chart-visualization.component.html        |    44 +
 .../line-chart-visualization.component.less        |    25 +
 .../line-chart-visualization.component.ts          |   137 +
 .../line-chart/line-chart-visualization.ts         |    32 +
 .../pie-chart-visualization.component.html         |    19 +
 .../pie-chart-visualization.component.less         |    12 +
 .../pie-chart/pie-chart-visualization.component.ts |    73 +
 .../pie-chart/pie-chart-visualization.ts           |    32 +
 .../scatter-chart-visualization.component.html     |    19 +
 .../scatter-chart-visualization.component.less     |    12 +
 .../scatter-chart-visualization.component.ts       |    89 +
 .../scatter-chart/scatter-chart-visualization.ts   |    32 +
 .../table/table-visualization.component.html       |   123 +
 .../table/table-visualization.component.less       |    44 +
 .../table/table-visualization.component.ts         |   174 +
 .../visualizations/table/table-visualization.ts    |    60 +
 .../src/app/visualizations/visualization.module.ts |    77 +
 .../src/assets/.gitkeep                            |     0
 .../src/assets/fonts/patua-one.woff2               |   Bin 0 -> 12844 bytes
 .../helium-packages/helium-vis-example.umd.js      |   589 +
 zeppelin-web-angular/src/assets/images/bg.jpg      |   Bin 0 -> 185723 bytes
 .../src/assets/images/zeppelin.png                 |   Bin 0 -> 3810 bytes
 .../src/assets/images/zeppelin_svg_logo.svg        |    77 +
 .../src/assets/images/zeppelin_svg_logo_bg.svg     |    77 +
 zeppelin-web-angular/src/browserslist              |    11 +
 .../src/environments/environment.prod.ts           |    15 +
 .../src/environments/environment.ts                |    28 +
 .../src/favicon.ico                                |   Bin
 zeppelin-web-angular/src/index.html                |    50 +
 zeppelin-web-angular/src/karma.conf.js             |    43 +
 zeppelin-web-angular/src/main.ts                   |    25 +
 zeppelin-web-angular/src/polyfills.ts              |    94 +
 zeppelin-web-angular/src/styles.less               |    19 +
 zeppelin-web-angular/src/styles/base.less          |    18 +
 zeppelin-web-angular/src/styles/font.less          |    20 +
 zeppelin-web-angular/src/styles/global.less        |   124 +
 zeppelin-web-angular/src/styles/rewrite.less       |    25 +
 zeppelin-web-angular/src/styles/spin.less          |   150 +
 .../src/styles/theme/dark/antd-dark.less           |    17 +
 .../src/styles/theme/dark/theme-dark.less          |   659 +
 .../src/styles/theme/light/antd-light.less         |    15 +
 .../src/styles/theme/light/theme-light.less        |   659 +
 .../src/styles/theme/markdown.less                 |   166 +
 .../src/styles/theme/theme-mixin.less              |    24 +
 zeppelin-web-angular/src/test.ts                   |    28 +
 zeppelin-web-angular/src/tsconfig.app.json         |     8 +
 zeppelin-web-angular/src/tsconfig.spec.json        |     9 +
 zeppelin-web-angular/src/tslint.json               |     7 +
 zeppelin-web-angular/tsconfig.app.json             |    18 +
 zeppelin-web-angular/tsconfig.json                 |    47 +
 zeppelin-web-angular/tsconfig.spec.json            |    18 +
 zeppelin-web-angular/tslint.json                   |   142 +
 zeppelin-web-angular/webpack.partial.js            |    27 +
 zeppelin-web/src/components/navbar/navbar.html     |     2 +
 416 files changed, 42161 insertions(+), 52 deletions(-)
 create mode 100644 zeppelin-web-angular/.editorconfig
 create mode 100644 zeppelin-web-angular/.gitignore
 create mode 100644 zeppelin-web-angular/.prettierignore
 create mode 100644 zeppelin-web-angular/.prettierrc
 create mode 100644 zeppelin-web-angular/README.md
 create mode 100644 zeppelin-web-angular/WEB-INF/web.xml
 create mode 100644 zeppelin-web-angular/angular.json
 create mode 100644 zeppelin-web-angular/browserslist
 create mode 100644 zeppelin-web-angular/e2e/protractor.conf.js
 create mode 100644 zeppelin-web-angular/e2e/src/app.e2e-spec.ts
 create mode 100644 zeppelin-web-angular/e2e/src/app.po.ts
 create mode 100644 zeppelin-web-angular/e2e/tsconfig.json
 create mode 100644 zeppelin-web-angular/karma.conf.js
 create mode 100644 zeppelin-web-angular/package-lock.json
 create mode 100644 zeppelin-web-angular/package.json
 create mode 100644 zeppelin-web-angular/pom.xml
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/README.md
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/karma.conf.js
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/ng-package.json
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/package.json
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/test.ts
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json
 create mode 100644 zeppelin-web-angular/projects/helium-vis-example/tslint.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/README.md
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/ng-package.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/package.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/index.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/test.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/tslint.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/README.md
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/package.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tslint.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/README.md
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/package.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json
 create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/tslint.json
 create mode 100644 zeppelin-web-angular/proxy.conf.js
 create mode 100644 zeppelin-web-angular/screenshot.png
 create mode 100644 zeppelin-web-angular/src/.editorconfig
 create mode 100644 zeppelin-web-angular/src/.gitignore
 create mode 100644 zeppelin-web-angular/src/app/app-http.interceptor.ts
 create mode 100644 zeppelin-web-angular/src/app/app-message.interceptor.ts
 create mode 100644 zeppelin-web-angular/src/app/app-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts
 create mode 100644 zeppelin-web-angular/src/app/app.component.html
 create mode 100644 zeppelin-web-angular/src/app/app.component.less
 create mode 100644 zeppelin-web-angular/src/app/app.component.spec.ts
 create mode 100644 zeppelin-web-angular/src/app/app.component.ts
 create mode 100644 zeppelin-web-angular/src/app/app.module.ts
 create mode 100644 zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts
 create mode 100644 zeppelin-web-angular/src/app/core/copy-text/index.ts
 create mode 100644 zeppelin-web-angular/src/app/core/copy-text/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts
 create mode 100644 zeppelin-web-angular/src/app/core/destroy-hook/index.ts
 create mode 100644 zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/core/index.ts
 create mode 100644 zeppelin-web-angular/src/app/core/message-listener/index.ts
 create mode 100644 zeppelin-web-angular/src/app/core/message-listener/message-listener.ts
 create mode 100644 zeppelin-web-angular/src/app/core/message-listener/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/index.ts
 create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts
 create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/published.ts
 create mode 100644 zeppelin-web-angular/src/app/core/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts
 create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts
 create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts
 create mode 100644 zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts
 create mode 100644 zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts
 create mode 100644 zeppelin-web-angular/src/app/helium-manager/index.ts
 create mode 100644 zeppelin-web-angular/src/app/helium-manager/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/credential.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/index.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/interpreter.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/message-interceptor.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/node-list.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/notebook-repo.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/notebook-search.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/security.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/ticket.ts
 create mode 100644 zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts
 create mode 100644 zeppelin-web-angular/src/app/languages/index.ts
 create mode 100644 zeppelin-web-angular/src/app/languages/load.ts
 create mode 100644 zeppelin-web-angular/src/app/languages/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/languages/scala.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/login/login-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/login/login.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/login/login.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/login/login.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/login/login.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html
 copy zeppelin-zengine/src/test/resources/flink-conf.yaml => zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less (100%)
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/index.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts
 create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
 create mode 100644 zeppelin-web-angular/src/app/services/array-ordering.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/base-rest.ts
 create mode 100644 zeppelin-web-angular/src/app/services/base-url.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/completion.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/configuration.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/credential.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/helium.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/index.ts
 create mode 100644 zeppelin-web-angular/src/app/services/interpreter.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/job-manager.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/message.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/ng-z.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/note-action.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/note-list.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/note-status.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/note-var-share.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/notebook-repos.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/notebook-search.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/save-as.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/security.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/shortcut.service.ts
 create mode 100644 zeppelin-web-angular/src/app/services/ticket.service.ts
 create mode 100644 zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/index.ts
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts
 create mode 100644 zeppelin-web-angular/src/app/share/code-editor/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/header/header.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/header/header.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/header/header.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/index.ts
 create mode 100644 zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts
 create mode 100644 zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/node-list/node-list.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/node-list/node-list.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/node-list/node-list.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/note-create/note-create.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/note-create/note-create.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/note-create/note-create.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/note-import/note-import.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/note-import/note-import.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/page-header/page-header.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/page-header/page-header.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/page-header/page-header.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts
 create mode 100644 zeppelin-web-angular/src/app/share/pipes/index.ts
 create mode 100644 zeppelin-web-angular/src/app/share/pipes/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/share/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/index.ts
 create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/public-api.ts
 create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts
 create mode 100644 zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts
 create mode 100644 zeppelin-web-angular/src/app/share/share.module.ts
 create mode 100644 zeppelin-web-angular/src/app/share/spin/spin.component.html
 create mode 100644 zeppelin-web-angular/src/app/share/spin/spin.component.less
 create mode 100644 zeppelin-web-angular/src/app/share/spin/spin.component.ts
 create mode 100644 zeppelin-web-angular/src/app/spell/spell-result.ts
 create mode 100644 zeppelin-web-angular/src/app/utility/css-unit-conversion.ts
 create mode 100644 zeppelin-web-angular/src/app/utility/element.ts
 create mode 100644 zeppelin-web-angular/src/app/utility/get-keyword-positions.ts
 create mode 100644 zeppelin-web-angular/src/app/utility/line-map.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/g2.config.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html
 create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less
 create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts
 create mode 100644 zeppelin-web-angular/src/app/visualizations/visualization.module.ts
 copy zeppelin-zengine/src/test/resources/flink-conf.yaml => zeppelin-web-angular/src/assets/.gitkeep (100%)
 create mode 100644 zeppelin-web-angular/src/assets/fonts/patua-one.woff2
 create mode 100644 zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js
 create mode 100644 zeppelin-web-angular/src/assets/images/bg.jpg
 create mode 100644 zeppelin-web-angular/src/assets/images/zeppelin.png
 create mode 100644 zeppelin-web-angular/src/assets/images/zeppelin_svg_logo.svg
 create mode 100644 zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg
 create mode 100644 zeppelin-web-angular/src/browserslist
 create mode 100644 zeppelin-web-angular/src/environments/environment.prod.ts
 create mode 100644 zeppelin-web-angular/src/environments/environment.ts
 copy {zeppelin-web => zeppelin-web-angular}/src/favicon.ico (100%)
 create mode 100644 zeppelin-web-angular/src/index.html
 create mode 100644 zeppelin-web-angular/src/karma.conf.js
 create mode 100644 zeppelin-web-angular/src/main.ts
 create mode 100644 zeppelin-web-angular/src/polyfills.ts
 create mode 100644 zeppelin-web-angular/src/styles.less
 create mode 100644 zeppelin-web-angular/src/styles/base.less
 create mode 100644 zeppelin-web-angular/src/styles/font.less
 create mode 100644 zeppelin-web-angular/src/styles/global.less
 create mode 100644 zeppelin-web-angular/src/styles/rewrite.less
 create mode 100644 zeppelin-web-angular/src/styles/spin.less
 create mode 100644 zeppelin-web-angular/src/styles/theme/dark/antd-dark.less
 create mode 100644 zeppelin-web-angular/src/styles/theme/dark/theme-dark.less
 create mode 100644 zeppelin-web-angular/src/styles/theme/light/antd-light.less
 create mode 100644 zeppelin-web-angular/src/styles/theme/light/theme-light.less
 create mode 100644 zeppelin-web-angular/src/styles/theme/markdown.less
 create mode 100644 zeppelin-web-angular/src/styles/theme/theme-mixin.less
 create mode 100644 zeppelin-web-angular/src/test.ts
 create mode 100644 zeppelin-web-angular/src/tsconfig.app.json
 create mode 100644 zeppelin-web-angular/src/tsconfig.spec.json
 create mode 100644 zeppelin-web-angular/src/tslint.json
 create mode 100644 zeppelin-web-angular/tsconfig.app.json
 create mode 100644 zeppelin-web-angular/tsconfig.json
 create mode 100644 zeppelin-web-angular/tsconfig.spec.json
 create mode 100644 zeppelin-web-angular/tslint.json
 create mode 100644 zeppelin-web-angular/webpack.partial.js


[zeppelin] 02/16: [ZEPPELIN-4321] Support shortcuts for the paragraphs

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit d3979c2709d95ff17a10f3f3bbca91150f645a78
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Nov 8 17:20:59 2019 +0800

    [ZEPPELIN-4321] Support shortcuts for the paragraphs
    
    ### What is this PR for?
    
    We are using Angular Latest to refactor Zeppelin's front-end. When implementing the features of the shortcuts, we found that the current shortcuts is somewhat complicated and did not distinguish the Command/Ctrl key between Mac and Windows.
    
    So we compared the following applications:
    
    - [Jupyter](https://github.com/jupyter/jupyter)
    - [JupyterLab](https://github.com/jupyterlab/jupyterlab)
    - [Google Colaboratory](https://colab.research.google.com/)
    
    They can distinguish between edit-mode and command-mode, which will simplify the shortcuts complexity. Meanwhile, we use the [Monaco editor](https://github.com/microsoft/monaco-editor) in the refactor version, it is the core library of [VSCode](https://github.com/microsoft/vscode). We think it is a good choice to use its shortcuts design.
    
    Therefore, for the above reasons, we proposed to redesign Zeppelin's shortcuts according to the table following.
    
    | Actions                                               | Mode    | Mac              | Windows / Linux       | Old(Mac)         |
    |-------------------------------------------------------|---------|------------------|-----------------------|------------------|
    | Command mode                                          | Edit    | ESC              | ESC                   | -                |
    | Edit mode                                             | Command | Enter            | Enter                 | -                |
    | Run                                                   | -       | ⇧ + Enter        | ⇧ + Enter             | ⇧ + Enter        |
    | Run all below                                         | -       | ⇧ + ⌘ + Enter    | ⇧ + Ctrl + Enter      | ⇧ + Ctrl + Enter |
    | Run all above                                         | -       | ⇧ + ⌥ + Enter    | ⇧ + Alt + Enter       | ⇧ + Ctrl + Enter |
    | Cancel                                                | -       | ⇧ + ⌘ + C        | ⇧ + Ctrl + C          | ⌥ + Ctrl + C     |
    | Switch all line number                                | -       | ⇧ + ⌘ + L        | ⇧ + Ctrl + L          | -                |
    | Show / Hide all output                                | -       | ⇧ + ⌘ + O        | ⇧ + Ctrl + O          | -                |
    | Show / Hide all title                                 | -       | ⇧ + ⌘ + T        | ⇧ + Ctrl + T          | -                |
    | Clear output                                          | -       | ⌘ + ⌥ + L        | Ctrl + Alt + L        | ⌥ + Ctrl + L     |
    | Enable/Disable                                        | -       | ⌘ + ⌥ + R        | Ctrl + Alt + R        | ⌥ + Ctrl + R     |
    | Reduce width                                          | -       | ⌘ + ⌥ + +        | Ctrl + Alt + -        | ⇧ + Ctrl + -     |
    | Increase width                                        | -       | ⌘ + ⌥ + -        | Ctrl + Alt + +        | ⇧ + Ctrl + +     |
    | Delete                                                | Command | ⇧ + Del            | ⇧ + Del                  | ⌥ + Ctrl + D     |
    | Move to up                                            | Command | ⌘ + K / Up       | Ctrl + K / Up         | ⌥ + Ctrl + K     |
    | Move to down                                          | Command | ⌘ + J / Down     | Ctrl + J / Down       | ⌥ + Ctrl + J     |
    | Select above                                          | Command | K / Up           | K / Up                | -                |
    | Select below                                          | Command | J / Down         | J / Down              | -                |
    | Switch line number                                    | Command | L                | L                     | ⌥ + Ctrl + M     |
    | Show / Hide title                                     | Command | T                | T                     | ⌥ + Ctrl + T     |
    | Show / Hide output                                    | Command | O                | O                     | ⌥ + Ctrl + O     |
    | Show / Hide editor                                    | Command | E                | E                     | ⌥ + Ctrl + E     |
    | Insert above                                          | Command | A                | A                     | ⌥ + Ctrl + A     |
    | Insert below                                          | Command | B                | B                     | ⌥ + Ctrl + B     |
    | Search                                                | Edit    | ⌘ + F            | Ctrl + F              | ⌥ + Ctrl + F     |
    | Increase Indent                                       | Edit    | Tab              | Tab                   | -                |
    | Decrease Indent                                       | Edit    | ⇧ + Tab          | ⇧ + Tab               | -                |
    | Comment Out / In                                      | Edit    | ⌘ + /            | Ctrl + /              | Ctrl + /         |
    | Undo                                                  | Edit    | ⌘ + Z            | Ctrl + Z              | Ctrl + Z         |
    | Redo                                                  | Edit    | ⇧ + ⌘ + Z        | Ctrl + Y              | -                |
    | Increase font size                                    | Edit    | ⌘ + .            | Ctrl + .              | -                |
    | Decrease font size                                    | Edit    | ⌘ + ,            | Ctrl + ,              | -                |
    | Decrease Indent                                       | Edit    | ⌘ + [            | Ctrl + [              | -                |
    | Increase Indent                                       | Edit    | ⌘ + ]            | Ctrl + ]              | -                |
    | Move the line down                                    | Edit    | ⌥ + Down         | Alt + Down            | ⌥ + Down         |
    | Move the line up                                      | Edit    | ⌥ + Up           | Alt + Up              | ⌥ + Down         |
    | Replace                                               | Edit    | ⌘ + ⌥ + F        | Ctrl + F              | -                |
    | Select all                                            | Edit    | ⌘ + A            | Ctrl + A              | ⌘ + A            |
    | Select downward                                       | Edit    | ⇧ + Down         | ⇧ + Down              | ⇧ + Down         |
    | Select right                                          | Edit    | ⇧ + Right        | ⇧ + Right             | ⇧ + Right        |
    | Select left                                           | Edit    | ⇧ + Left         | ⇧ + Left              | ⇧ + Left         |
    | Select upward                                         | Edit    | ⇧ + Up           | ⇧ + Up                | ⇧ + Up           |
    | Select to the end                                     | Edit    | ⌘ + ⇧ + Right    | Alt + ⇧ + Right       | ⌘ + ⇧ + Right    |
    | Select to the start                                   | Edit    | ⌘ + ⇧ + Left     | Alt + ⇧ + Left        | ⌘ + ⇧ + Left     |
    | Align text right                                      | Edit    | ⌥ + Right        | Ctrl + ⇧ + Right      | ⌥ + Right        |
    | Align text left                                       | Edit    | ⌥ + Left         | Ctrl + ⇧ + Left       | ⌥ + Left         |
    | Add multi-cursor above                                | Edit    | ⌘ + ⌥ + Up       | Ctrl + Alt + Up       | -                |
    | Add multi-cursor below                                | Edit    | ⌘ + ⌥ + Down     | Ctrl + Alt + Down     | -                |
    | Move multi-cursor from current line to the line above | Edit    | ⌘ + ⌥ + ⇧ + Up   | Ctrl + Alt + ⇧ + Up   | -                |
    | Move multi-cursor from current line to the line below | Edit    | ⌘ + ⌥ + ⇧ + Down | Ctrl + Alt + ⇧ + Down | -                |
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4402
    https://issues.apache.org/jira/browse/ZEPPELIN-4321
    
    ### How should this be tested?
    * First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration
    * Strongly recommended: add automated unit tests for any new or changed behavior
    * Outline any manual steps to test the PR here.
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3517 from hsuanxyz/feat/hot-key and squashes the following commits:
    
    0dec67601 [Hsuan Lee] feat(paragraph): support shortcut
---
 zeppelin-web-angular/package-lock.json             |  76 +++++--
 zeppelin-web-angular/package.json                  |   6 +-
 .../workspace/notebook/notebook.component.html     |   6 +-
 .../pages/workspace/notebook/notebook.component.ts |  16 +-
 .../paragraph/code-editor/code-editor.component.ts |  13 ++
 .../paragraph/control/control.component.ts         |  24 +--
 .../notebook/paragraph/paragraph.component.html    |   9 +-
 .../notebook/paragraph/paragraph.component.less    |   5 +
 .../notebook/paragraph/paragraph.component.ts      | 227 ++++++++++++++++++++-
 .../notebook/paragraph/result/result.component.ts  |   3 +
 .../src/app/services/public-api.ts                 |   1 +
 .../src/app/services/shortcut.service.ts           | 109 ++++++++++
 12 files changed, 436 insertions(+), 59 deletions(-)

diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json
index 46c0a07..85ad2a6 100644
--- a/zeppelin-web-angular/package-lock.json
+++ b/zeppelin-web-angular/package-lock.json
@@ -6852,23 +6852,54 @@
       }
     },
     "husky": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/husky/-/husky-2.7.0.tgz",
-      "integrity": "sha512-LIi8zzT6PyFpcYKdvWRCn/8X+6SuG2TgYYMrM6ckEYhlp44UcEduVymZGIZNLiwOUjrEud+78w/AsAiqJA/kRg==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.9.tgz",
+      "integrity": "sha512-Yolhupm7le2/MqC1VYLk/cNmYxsSsqKkTyBhzQHhPK1jFnC89mmmNVuGtLNabjDI6Aj8UNIr0KpRNuBkiC4+sg==",
       "dev": true,
       "requires": {
-        "cosmiconfig": "^5.2.0",
+        "chalk": "^2.4.2",
+        "ci-info": "^2.0.0",
+        "cosmiconfig": "^5.2.1",
         "execa": "^1.0.0",
-        "find-up": "^3.0.0",
         "get-stdin": "^7.0.0",
-        "is-ci": "^2.0.0",
-        "pkg-dir": "^4.1.0",
-        "please-upgrade-node": "^3.1.1",
-        "read-pkg": "^5.1.1",
+        "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",
@@ -6900,18 +6931,6 @@
           "dev": true,
           "requires": {
             "find-up": "^4.0.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"
-              }
-            }
           }
         },
         "slash": {
@@ -6919,6 +6938,15 @@
           "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"
+          }
         }
       }
     },
@@ -10409,6 +10437,12 @@
         "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",
diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json
index ae96fe7..63b6be1 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -44,8 +44,6 @@
     "zone.js": "~0.9.1"
   },
   "devDependencies": {
-    "monaco-editor-webpack-plugin": "^1.7.0",
-    "ngx-build-plus": "^8.1.5",
     "@angular-devkit/build-angular": "^0.803.9",
     "@angular-devkit/build-ng-packagr": "~0.803.6",
     "@angular/cli": "~8.3.9",
@@ -61,7 +59,7 @@
     "codelyzer": "^5.0.0",
     "dotenv": "^8.0.0",
     "https-proxy-agent": "^2.2.1",
-    "husky": "^2.2.0",
+    "husky": "^3.0.9",
     "jasmine-core": "~3.4.0",
     "jasmine-spec-reporter": "~4.2.1",
     "karma": "~4.1.0",
@@ -70,7 +68,9 @@
     "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",
     "prettier": "^1.17.0",
     "protractor": "~5.4.0",
     "ts-node": "~7.0.0",
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
index 3bad5ee..c447a59 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
@@ -36,8 +36,10 @@
   <div class="paragraph-area">
     <div class="paragraph-inner" nz-row>
       <zeppelin-notebook-paragraph nz-col
-                                   *ngFor="let p of note.paragraphs;let first = first; let last = last;"
+                                   *ngFor="let p of note.paragraphs;let first = first; let last = last; index as i"
                                    [nzSpan]="p.config.colWidth * 2"
+                                   [select]="p.id === selectId"
+                                   [index]="i"
                                    [paragraph]="p"
                                    [note]="note"
                                    [looknfeel]="note.config.looknfeel"
@@ -47,6 +49,8 @@
                                    [revisionView]="revisionView"
                                    [first]="first"
                                    [last]="last"
+                                   (selectAtIndex)="onSelectAtIndex($event)"
+                                   (selected)="onParagraphSelect($event)"
                                    (triggerSaveParagraph)="saveParagraph($event)"
                                    (saveNoteTimer)="startSaveTimer()"></zeppelin-notebook-paragraph>
     </div>
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
index a894971..97479a7 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -21,7 +21,7 @@ import {
 } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 import { isNil } from 'lodash';
-import { Subject } from 'rxjs';
+import { Subject} from 'rxjs';
 import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
@@ -48,6 +48,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
   private destroy$ = new Subject();
   note: Note['note'];
   permissions: Permissions;
+  selectId: string | null = null;
   isOwner = true;
   noteRevisions: RevisionListItem[] = [];
   currentRevision: string;
@@ -216,6 +217,17 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
     }, 10000);
   }
 
+  onParagraphSelect(id: string) {
+    this.selectId = 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 => {
@@ -276,7 +288,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
     private noteVarShareService: NoteVarShareService,
     private ticketService: TicketService,
     private securityService: SecurityService,
-    private router: Router
+    private router: Router,
   ) {
     super(messageService);
   }
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
index 6dabb4b..0711e81 100644
--- 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
@@ -55,6 +55,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
   @Input() pid: string;
   @Output() readonly textChanged = new EventEmitter<string>();
   @Output() readonly editorBlur = new EventEmitter<void>();
+  @Output() readonly editorFocus = new EventEmitter<void>();
   private editor: IStandaloneCodeEditor;
   private monacoDisposables: IDisposable[] = [];
   height = 0;
@@ -76,6 +77,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
     this.monacoDisposables.push(
       editor.onDidFocusEditorText(() => {
         this.ngZone.runOutsideAngular(() => {
+          this.editorFocus.emit();
           editor.updateOptions({ renderLineHighlight: 'all' });
         });
       }),
@@ -85,6 +87,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
           editor.updateOptions({ renderLineHighlight: 'none' });
         });
       }),
+
       editor.onDidChangeModelContent(() => {
         this.ngZone.run(() => {
           this.text = editor.getModel().getValue();
@@ -123,6 +126,16 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
       });
     }
 
+    this.editor.addCommand(
+      monaco.KeyCode.Escape,
+      () => {
+        if (document.activeElement instanceof HTMLElement) {
+          document.activeElement.blur();
+        }
+      },
+      '!suggestWidgetVisible'
+    );
+
     this.updateEditorOptions();
     this.setParagraphMode();
     this.initEditorListener();
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
index 085fa26..5b95953 100644
--- 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
@@ -71,6 +71,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
   @Output() readonly runAllAbove = new EventEmitter<void>();
   @Output() readonly runAllBelowAndCurrent = new EventEmitter<void>();
   @Output() readonly cloneParagraph = new EventEmitter<void>();
+  @Output() readonly removeParagraph = new EventEmitter<void>();
   fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
   dropdownVisible = false;
   isMac = navigator.appVersion.indexOf('Mac') !== -1;
@@ -190,7 +191,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         show: this.paragraphLength > 1,
         disabled: this.isEntireNoteRunning,
         icon: 'delete',
-        trigger: () => this.removeParagraph(),
+        trigger: () => this.onRemoveParagraph(),
         shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+D`,
         keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_D] : []
       }
@@ -258,25 +259,8 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
     }
   }
 
-  removeParagraph() {
-    if (!this.isEntireNoteRunning) {
-      if (this.paragraphLength === 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.pid);
-            this.cdr.markForCheck();
-            // TODO(hsuanxyz) moveFocusToNextParagraph
-          }
-        });
-      }
-    }
+  onRemoveParagraph() {
+    this.removeParagraph.emit();
   }
 
   trigger(event: EventEmitter<void>) {
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
index 861f955..1c42f87 100644
--- 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
@@ -14,7 +14,10 @@
   <zeppelin-notebook-add-paragraph *ngIf="!revisionView && looknfeel !== 'report'"
                                    [disabled]="isEntireNoteRunning"
                                    (addParagraph)="insertParagraph('above')"></zeppelin-notebook-add-paragraph>
-  <div class="paragraph" [class.simple]="looknfeel !== 'default'" [class.report]="looknfeel === 'report'">
+  <div class="paragraph"
+       [class.focused]="select"
+       [class.simple]="looknfeel !== 'default'"
+       [class.report]="looknfeel === 'report'">
     <zeppelin-elastic-input *ngIf="paragraph.config.title"
                             [value]="paragraph.title"
                             [min]="true"
@@ -39,6 +42,7 @@
                                          [(editorHide)]="paragraph.config.editorHide"
                                          [(runOnSelectionChange)]="paragraph.config.runOnSelectionChange"
                                          (tableHideChange)="commitParagraph()"
+                                         (removeParagraph)="removeParagraph()"
                                          (colWidthChange)="changeColWidth(true)"
                                          (fontSizeChange)="commitParagraph()"
                                          (editorHideChange)="commitParagraph()"
@@ -65,7 +69,8 @@
                                              [lineNumbers]="paragraph.config.lineNumbers"
                                              [readOnly]="isEntireNoteRunning || isParagraphRunning || revisionView"
                                              [language]="paragraph.config.editorSetting?.language"
-                                             (editorBlur)="saveParagraph()"
+                                             (editorBlur)="onEditorBlur()"
+                                             (editorFocus)="onEditorFocus()"
                                              (textChanged)="textChanged($event)"></zeppelin-notebook-paragraph-code-editor>
     <zeppelin-notebook-paragraph-progress *ngIf="paragraph.status === 'RUNNING'"
                                           [progress]="progress"></zeppelin-notebook-paragraph-progress>
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
index f24d693..60cc5ac 100644
--- 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
@@ -18,6 +18,7 @@
 }
 
 .themeMixin({
+
   .paragraph {
     background: @component-background;
     border: 1px solid @border-color-split;
@@ -25,6 +26,10 @@
     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;
     }
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
index 21d57bb..1dde62d 100644
--- 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
@@ -13,7 +13,7 @@
 import {
   ChangeDetectionStrategy,
   ChangeDetectorRef,
-  Component,
+  Component, ElementRef,
   EventEmitter,
   Input,
   OnChanges,
@@ -21,15 +21,16 @@ import {
   OnInit,
   Output,
   QueryList,
+  SimpleChanges,
   ViewChild,
   ViewChildren
 } from '@angular/core';
-import { Subject } from 'rxjs';
-import { takeUntil } from 'rxjs/operators';
+import {merge, Observable, Subject} from 'rxjs';
+import {map, takeUntil} from 'rxjs/operators';
 
 import DiffMatchPatch from 'diff-match-patch';
 import { isEmpty, isEqual } from 'lodash';
-import { NzModalService } from 'ng-zorro-antd';
+import { NzModalService } from 'ng-zorro-antd/modal';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import {
@@ -52,7 +53,10 @@ import {
   NgZService,
   NoteStatusService,
   NoteVarShareService,
-  ParagraphStatus
+  ParagraphActions,
+  ParagraphStatus,
+  ShortcutsMap,
+  ShortcutService
 } from '@zeppelin/services';
 import { SpellResult } from '@zeppelin/spell/spell-result';
 
@@ -60,10 +64,16 @@ import { NzResizeEvent } from 'ng-zorro-antd/resizable';
 import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component';
 import { NotebookParagraphResultComponent } from './result/result.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 MessageListenersManager implements OnInit, OnChanges, OnDestroy {
@@ -76,6 +86,8 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
   @Input() note: Note['note'];
   @Input() looknfeel: string;
   @Input() revisionView: boolean;
+  @Input() select: boolean = false;
+  @Input() index: number = -1;
   @Input() viewOnly: boolean;
   @Input() last: boolean;
   @Input() collaborativeMode = false;
@@ -83,8 +95,12 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
   @Input() interpreterBindings: InterpreterBindingItem[] = [];
   @Output() readonly saveNoteTimer = new EventEmitter();
   @Output() readonly triggerSaveParagraph = new EventEmitter<string>();
+  @Output() readonly selected = new EventEmitter<string>();
+  @Output() readonly selectAtIndex = new EventEmitter<number>();
 
   private destroy$ = new Subject();
+  private mode: Mode = 'command';
+  waitConfirmFromEdit = false;
   dirtyText: string;
   originalText: string;
   isEntireNoteRunning = false;
@@ -185,6 +201,19 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     }
   }
 
+  switchMode(mode: Mode): void {
+    if (mode === this.mode) {
+      return;
+    }
+    this.mode = mode;
+    if (mode === 'edit') {
+      this.focusEditor();
+    } else {
+      this.blurEditor();
+      (this.host.nativeElement as HTMLElement).focus();
+    }
+  }
+
   updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) {
     // 1. can't update on revision view
     if (!this.revisionView) {
@@ -237,6 +266,34 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     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) {
@@ -248,6 +305,27 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     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);
@@ -298,7 +376,11 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
       nzOnOk: () => {
         this.messageService.runAllParagraphs(this.note.id, paragraphs);
       }
-    });
+    }).afterClose
+      .pipe(takeUntil(this.destroy$))
+      .subscribe(() => {
+        this.waitConfirmFromEdit = false;
+      });
     // TODO(hsuanxyz): save cursor
   }
 
@@ -486,7 +568,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
   setTitle(title: string) {
     this.paragraph.title = title;
     this.commitParagraph();
-    this.cdr.markForCheck();
   }
 
   commitParagraph() {
@@ -498,6 +579,7 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
       settings: { params }
     } = this.paragraph;
     this.messageService.commitParagraph(id, title, text, config, params, this.note.id);
+    this.cdr.markForCheck();
   }
 
   initializeDefault(config: ParagraphConfig) {
@@ -586,7 +668,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
   onConfigChange(configResult: ParagraphConfigResult, index: number) {
     this.paragraph.config.results[index] = configResult;
     this.commitParagraph();
-    this.cdr.markForCheck();
   }
 
   setEditorHide(editorHide: boolean) {
@@ -610,12 +691,128 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     private nzModalService: NzModalService,
     private noteVarShareService: NoteVarShareService,
     private cdr: ChangeDetectorRef,
-    private ngZService: NgZService
+    private ngZService: NgZService,
+    private shortcutService: ShortcutService,
+    private host: ElementRef
   ) {
     super(messageService);
   }
 
   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:
+            this.moveUpParagraph();
+            break;
+          case ParagraphActions.MoveToDown:
+            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.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);
@@ -644,7 +841,17 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
       });
   }
 
-  ngOnChanges(): void {}
+  ngOnChanges(changes: SimpleChanges): void {
+    const { index, select } = changes;
+    if (index && index.currentValue !== index.previousValue && this.select
+    || select && select.currentValue === true && select.previousValue !== true) {
+      if (this.host.nativeElement) {
+        setTimeout(() => {
+          (this.host.nativeElement as HTMLElement).focus();
+        })
+      }
+    }
+  }
 
   ngOnDestroy(): void {
     super.ngOnDestroy();
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
index 850bc18..903f72b 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
@@ -254,6 +254,9 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
   }
 
   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;
diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts
index d56ec7e..d6709ac 100644
--- a/zeppelin-web-angular/src/app/services/public-api.ts
+++ b/zeppelin-web-angular/src/app/services/public-api.ts
@@ -26,3 +26,4 @@ export * from './ng-z.service';
 export * from './array-ordering.service';
 export * from './note-list.service';
 export * from './runtime-compiler.service';
+export * from './shortcut.service';
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 0000000..b6d6a3a
--- /dev/null
+++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts
@@ -0,0 +1,109 @@
+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'
+}
+
+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.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'],
+  [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown'],
+  [ParagraphActions.SelectAbove]: ['k', 'arrowup'],
+  [ParagraphActions.SelectBelow]: ['j', 'arrowdown'],
+  [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;
+
+  constructor(private eventManager: EventManager,
+              @Inject(DOCUMENT) _document: any) {
+    this.element = _document;
+  }
+
+  forkByElement(element: HTMLElement) {
+    return new ShortcutService(this.eventManager, element);
+  }
+
+  bindShortcut(option: ShortcutOption): Observable<ShortcutEvent> {
+    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 event = `keydown.${keybindings}`;
+    let dispose: Function;
+    return new Observable<ShortcutEvent>(observer => {
+      const handler = event => {
+        observer.next({
+          event,
+          keybindings: option.keybindings
+        });
+      };
+
+      dispose = this.eventManager.addEventListener(host, event, handler);
+
+      return () => {
+        dispose();
+      };
+    })
+  }
+
+}


[zeppelin] 04/16: [ZEPPELIN-4403] Support publishable for paragraph

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 66f4dd1489ca738bdee7757ff64a6e63b348589d
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Nov 29 17:16:34 2019 +0800

    [ZEPPELIN-4403] Support publishable for paragraph
    
    ### What is this PR for?
    A few sentences describing the overall goals of the pull request's commits.
    First time? Check out the contributing guide - https://zeppelin.apache.org/contribution/contributions.html
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    *
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4403
    
    ### How should this be tested?
    * First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration
    * Strongly recommended: add automated unit tests for any new or changed behavior
    * Outline any manual steps to test the PR here.
    
    ### Screenshots (if appropriate)
    
    ![publish](https://user-images.githubusercontent.com/22736418/69940879-4770d300-151e-11ea-9ed1-2925ce825e58.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3530 from hsuanxyz/paragraph-publishable and squashes the following commits:
    
    a9b974c1d [Hsuan Lee] feat: support paragraph publishable
---
 .../{public-api.ts => paragraph-base/index.ts}     |   4 +-
 .../src/app/core/paragraph-base/paragraph-base.ts  | 315 +++++++++++++++++++++
 .../app/core/{ => paragraph-base}/public-api.ts    |   5 +-
 .../{public-api.ts => paragraph-base/published.ts} |   8 +-
 zeppelin-web-angular/src/app/core/public-api.ts    |   1 +
 .../workspace/notebook/notebook-routing.module.ts  |   4 -
 .../pages/workspace/notebook/notebook.component.ts |  13 +-
 .../pages/workspace/notebook/notebook.module.ts    |  14 +-
 .../paragraph/code-editor/code-editor.component.ts |  14 -
 .../paragraph/control/control.component.ts         |  17 +-
 .../notebook/paragraph/paragraph.component.html    |   1 +
 .../notebook/paragraph/paragraph.component.ts      | 305 ++------------------
 .../published/paragraph/paragraph.component.html   |  15 +
 .../published/paragraph/paragraph.component.less   |   0
 .../published/paragraph/paragraph.component.ts     |  88 ++++++
 .../published-ruoting.module.ts}                   |  17 +-
 .../pages/workspace/published/published.module.ts  |  11 +
 .../dynamic-forms/dynamic-forms.component.html     |   0
 .../dynamic-forms/dynamic-forms.component.less     |   0
 .../dynamic-forms/dynamic-forms.component.ts       |   0
 .../workspace/share/index.ts}                      |   4 +-
 .../{core => pages/workspace/share}/public-api.ts  |   4 +-
 .../result/result.component.html                   |   6 +-
 .../result/result.component.less                   |   0
 .../paragraph => share}/result/result.component.ts |   4 +
 .../src/app/pages/workspace/share/share.module.ts  |  56 ++++
 .../pages/workspace/workspace-routing.module.ts    |   4 +
 .../app/pages/workspace/workspace.component.html   |   4 +-
 .../src/app/pages/workspace/workspace.component.ts |  11 +-
 .../src/app/services/shortcut.service.ts           |  37 +--
 30 files changed, 581 insertions(+), 381 deletions(-)

diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/index.ts
index c514103..49e4740 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts
@@ -10,6 +10,4 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+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 0000000..f8f9a1b
--- /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<NotebookParagraphResultComponent>;
+
+  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/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
index c514103..a6ba532 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
@@ -10,6 +10,5 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './paragraph-base';
+export * from './published';
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts
similarity index 82%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/published.ts
index c514103..0f41577 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts
@@ -10,6 +10,8 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+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
index c514103..3bcd355 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/public-api.ts
@@ -13,3 +13,4 @@
 export * from './message-listener';
 export * from './destroy-hook';
 export * from './copy-text';
+export * from './paragraph-base';
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
index 6c177b6..321b788 100644
--- 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
@@ -21,10 +21,6 @@ const routes: Routes = [
     component: NotebookComponent
   },
   {
-    path: ':noteId/paragraph/:paragraphId',
-    component: NotebookComponent
-  },
-  {
     path: ':noteId/revision/:revisionId',
     component: NotebookComponent
   }
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
index 97479a7..e0c17a1 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -21,7 +21,7 @@ import {
 } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 import { isNil } from 'lodash';
-import { Subject} from 'rxjs';
+import { Subject } from 'rxjs';
 import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
@@ -29,6 +29,7 @@ import { Permissions } from '@zeppelin/interfaces';
 import { InterpreterBindingItem, MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from '@zeppelin/sdk';
 import {
   MessageService,
+  NgZService,
   NoteStatusService,
   NoteVarShareService,
   SecurityService,
@@ -66,6 +67,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
     if (isNil(note)) {
       this.router.navigate(['/']).then();
     } else {
+      this.removeParagraphFromNgZ();
       this.note = note;
       const { paragraphId } = this.activatedRoute.snapshot.params;
       if (paragraphId) {
@@ -289,6 +291,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
     private ticketService: TicketService,
     private securityService: SecurityService,
     private router: Router,
+    protected ngZService: NgZService
   ) {
     super(messageService);
   }
@@ -317,6 +320,14 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
     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();
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
index ccdd4de..0258bbe 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -18,7 +18,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
 import {
   NzButtonModule,
-  NzCheckboxModule,
   NzDividerModule,
   NzDropDownModule,
   NzFormModule,
@@ -35,23 +34,20 @@ import {
   NzToolTipModule
 } from 'ng-zorro-antd';
 import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';
-import { NzResizableModule } from 'ng-zorro-antd/resizable';
 
 import { ShareModule } from '@zeppelin/share';
 
-import { VisualizationModule } from 'src/app/visualizations/visualization.module';
 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 { NotebookParagraphDynamicFormsComponent } from './paragraph/dynamic-forms/dynamic-forms.component';
 import { NotebookParagraphFooterComponent } from './paragraph/footer/footer.component';
 import { NotebookParagraphComponent } from './paragraph/paragraph.component';
 import { NotebookParagraphProgressComponent } from './paragraph/progress/progress.component';
-import { NotebookParagraphResultComponent } from './paragraph/result/result.component';
 import { NotebookPermissionsComponent } from './permissions/permissions.component';
 import { NotebookRevisionsComparatorComponent } from './revisions-comparator/revisions-comparator.component';
 
+import { WorkspaceShareModule } from '../../workspace/share/share.module';
 import { NotebookActionBarComponent } from './action-bar/action-bar.component';
 import { NotebookRoutingModule } from './notebook-routing.module';
 import { NotebookComponent } from './notebook.component';
@@ -67,18 +63,16 @@ import { NotebookShareModule } from './share/share.module';
     NotebookParagraphComponent,
     NotebookAddParagraphComponent,
     NotebookParagraphCodeEditorComponent,
-    NotebookParagraphResultComponent,
     NotebookParagraphProgressComponent,
     NotebookParagraphFooterComponent,
-    NotebookParagraphControlComponent,
-    NotebookParagraphDynamicFormsComponent
+    NotebookParagraphControlComponent
   ],
   imports: [
     CommonModule,
     PortalModule,
+    WorkspaceShareModule,
     NotebookRoutingModule,
     ShareModule,
-    VisualizationModule,
     NotebookShareModule,
     NzButtonModule,
     NzIconModule,
@@ -92,14 +86,12 @@ import { NotebookShareModule } from './share/share.module';
     FormsModule,
     ReactiveFormsModule,
     NzDividerModule,
-    NzCheckboxModule,
     NzProgressModule,
     NzSwitchModule,
     NzSelectModule,
     NzGridModule,
     NzRadioModule,
     DragDropModule,
-    NzResizableModule,
     NzCodeEditorModule
   ]
 })
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
index 916afef..8cf4bd7 100644
--- 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
@@ -104,20 +104,6 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
 
   initializedEditor(editor: IEditor) {
     this.editor = editor as IStandaloneCodeEditor;
-    if (this.paragraphControl) {
-      this.paragraphControl.listOfMenu.forEach((item, index) => {
-        this.editor.addAction({
-          id: item.icon,
-          label: item.label,
-          precondition: null,
-          keybindingContext: null,
-          contextMenuGroupId: 'navigation',
-          contextMenuOrder: index,
-          run: () => item.trigger()
-        });
-      });
-    }
-
     this.editor.addCommand(
       monaco.KeyCode.Escape,
       () => {
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
index bda003d..eacf2da 100644
--- 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
@@ -72,6 +72,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
   @Output() readonly runAllBelowAndCurrent = new EventEmitter<void>();
   @Output() readonly cloneParagraph = new EventEmitter<void>();
   @Output() readonly removeParagraph = new EventEmitter<void>();
+  @Output() readonly openSingleParagraph = new EventEmitter<string>();
   fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
   dropdownVisible = false;
   isMac = navigator.appVersion.indexOf('Mac') !== -1;
@@ -115,8 +116,10 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         show: true,
         disabled: false,
         icon: 'export',
-        trigger: () => this.goToSingleParagraph(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`
+        trigger: () => {
+          this.openSingleParagraph.emit(this.pid);
+        },
+        shortCut: this.isMac ? '⌥+⌘+T' : 'Alt+Ctrl+T'
       },
       {
         label: 'Clear output',
@@ -225,13 +228,6 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
     }
   }
 
-  goToSingleParagraph() {
-    // TODO(hsuanxyz) asIframe
-    const { noteId } = this.activatedRoute.snapshot.params;
-    const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${this.pid}`;
-    window.open(redirectToUrl);
-  }
-
   changeColWidth(colWidth: number) {
     this.colWidth = +colWidth;
     this.colWidthChange.emit(this.colWidth);
@@ -269,8 +265,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
     private cdr: ChangeDetectorRef,
     private nzMessageService: NzMessageService,
     private activatedRoute: ActivatedRoute,
-    private messageService: MessageService,
-    private nzModalService: NzModalService
+    private messageService: MessageService
   ) {}
 
   ngOnInit() {
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
index 1c42f87..e286627 100644
--- 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
@@ -48,6 +48,7 @@
                                          (editorHideChange)="commitParagraph()"
                                          (enabledChange)="commitParagraph()"
                                          (titleChange)="commitParagraph()"
+                                         (openSingleParagraph)="openSingleParagraph($event)"
                                          (runOnSelectionChangeChange)="commitParagraph()"
                                          (runParagraph)="runParagraph()"
                                          (moveUp)="moveUpParagraph()"
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
index f5b61e8..246d09e 100644
--- 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
@@ -29,25 +29,10 @@ import {
 import { merge, Observable, Subject } from 'rxjs';
 import { map, takeUntil } from 'rxjs/operators';
 
-import DiffMatchPatch from 'diff-match-patch';
-import { isEmpty, isEqual } from 'lodash';
 import { NzModalService } from 'ng-zorro-antd/modal';
 
-import { MessageListener, MessageListenersManager } from '@zeppelin/core';
-import {
-  AngularObjectRemove,
-  AngularObjectUpdate,
-  GraphConfig,
-  InterpreterBindingItem,
-  MessageReceiveDataTypeMap,
-  Note,
-  OP,
-  ParagraphConfig,
-  ParagraphConfigResult,
-  ParagraphEditorSetting,
-  ParagraphItem,
-  ParagraphIResultsMsgItem
-} from '@zeppelin/sdk';
+import { ParagraphBase } from '@zeppelin/core';
+import { InterpreterBindingItem, Note, ParagraphConfigResult, ParagraphItem } from '@zeppelin/sdk';
 import {
   HeliumService,
   MessageService,
@@ -55,7 +40,6 @@ import {
   NoteStatusService,
   NoteVarShareService,
   ParagraphActions,
-  ParagraphStatus,
   ShortcutsMap,
   ShortcutService
 } from '@zeppelin/services';
@@ -63,8 +47,8 @@ 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';
-import { NotebookParagraphResultComponent } from './result/result.component';
 
 type Mode = 'edit' | 'command';
 
@@ -78,7 +62,7 @@ type Mode = 'edit' | 'command';
   },
   changeDetection: ChangeDetectionStrategy.OnPush
 })
-export class NotebookParagraphComponent extends MessageListenersManager implements OnInit, OnChanges, OnDestroy {
+export class NotebookParagraphComponent extends ParagraphBase implements OnInit, OnChanges, OnDestroy {
   @ViewChild(NotebookParagraphCodeEditorComponent, { static: false })
   notebookParagraphCodeEditorComponent: NotebookParagraphCodeEditorComponent;
   @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList<
@@ -103,105 +87,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
   private destroy$ = new Subject();
   private mode: Mode = 'command';
   waitConfirmFromEdit = false;
-  dirtyText: string;
-  originalText: string;
-  isEntireNoteRunning = 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 = {};
-
-  @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);
-    }
-  }
 
   switchMode(mode: Mode): void {
     if (mode === this.mode) {
@@ -215,35 +100,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     }
   }
 
-  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();
-    }
-  }
-
   textChanged(text: string) {
     this.dirtyText = text;
     this.paragraph.text = text;
@@ -472,94 +328,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     }
   }
 
-  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);
-    }
-  }
-
-  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();
-  }
-
-  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))
-    );
-  }
-
   insertParagraph(position: string) {
     if (this.revisionView === true) {
       return;
@@ -584,16 +352,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     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 = {};
-    }
-  }
-
   setTitle(title: string) {
     this.paragraph.title = title;
     this.commitParagraph();
@@ -611,42 +369,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     this.cdr.markForCheck();
   }
 
-  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;
-    }
-  }
-
   moveUpParagraph() {
     const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1;
     if (newIndex < 0 || newIndex >= this.note.paragraphs.length) {
@@ -709,23 +431,29 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     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,
-    private noteStatusService: NoteStatusService,
     public messageService: MessageService,
     private nzModalService: NzModalService,
     private noteVarShareService: NoteVarShareService,
-    private cdr: ChangeDetectorRef,
-    private ngZService: NgZService,
     private shortcutService: ShortcutService,
     private host: ElementRef,
     private ngTemplateAdapterService: NgTemplateAdapterService
   ) {
-    super(messageService);
+    super(messageService, noteStatusService, ngZService, cdr);
   }
 
   ngOnInit() {
@@ -823,6 +551,9 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
           }
         }
         switch (action) {
+          case ParagraphActions.Link:
+            this.openSingleParagraph(this.paragraph.id);
+            break;
           case ParagraphActions.EditMode:
             if (this.mode === 'command') {
               event.preventDefault();
@@ -847,7 +578,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
             break;
         }
       });
-
     this.setResults();
     this.originalText = this.paragraph.text;
     this.isEntireNoteRunning = this.noteStatusService.isEntireNoteRunning(this.note);
@@ -894,6 +624,5 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
 
   ngOnDestroy(): void {
     super.ngOnDestroy();
-    this.ngZService.removeParagraph(this.paragraph.id);
   }
 }
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 0000000..d69a0f4
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html
@@ -0,0 +1,15 @@
+<zeppelin-notebook-paragraph-dynamic-forms
+  *ngIf="paragraph"
+  [disable]="paragraph.status == 'RUNNING' || paragraph.status == 'PENDING'"
+  [paramDefs]="paragraph.settings.params"
+  [formDefs]="paragraph.settings.forms"
+  [runOnChange]="paragraph.config.runOnSelectionChange"
+  (formChange)="runParagraph()">
+</zeppelin-notebook-paragraph-dynamic-forms>
+<zeppelin-notebook-paragraph-result *ngFor="let result of results; index as i; trackBy: trackByIndexFn"
+                                    [id]="paragraph.id"
+                                    [published]="true"
+                                    [currentCol]="paragraph.config.colWidth"
+                                    [config]="configs[i]"
+                                    [result]="result">
+</zeppelin-notebook-paragraph-result>
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 0000000..e69de29
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 0000000..12e10de
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
@@ -0,0 +1,88 @@
+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/notebook/notebook-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
similarity index 70%
copy from zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
copy to zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
index 6c177b6..eaf001f 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts
@@ -12,21 +12,12 @@
 
 import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
-
-import { NotebookComponent } from './notebook.component';
+import { PublishedParagraphComponent } from './paragraph/paragraph.component';
 
 const routes: Routes = [
   {
-    path: ':noteId',
-    component: NotebookComponent
-  },
-  {
-    path: ':noteId/paragraph/:paragraphId',
-    component: NotebookComponent
-  },
-  {
-    path: ':noteId/revision/:revisionId',
-    component: NotebookComponent
+    path: ':paragraphId',
+    component: PublishedParagraphComponent
   }
 ];
 
@@ -34,4 +25,4 @@ const routes: Routes = [
   imports: [RouterModule.forChild(routes)],
   exports: [RouterModule]
 })
-export class NotebookRoutingModule {}
+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 0000000..f6474d9
--- /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/notebook/paragraph/dynamic-forms/dynamic-forms.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html
rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less
rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts
rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/share/index.ts
index c514103..49e4740 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts
@@ -10,6 +10,4 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
similarity index 85%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
index c514103..e865360 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts
@@ -10,6 +10,4 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
+export * from './share.module';
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
similarity index 95%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
index fe34a37..0b246b0 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html
@@ -10,7 +10,7 @@
   ~ limitations under the License.
   -->
 
-<div class="setting-bar" *ngIf="result.type === datasetType.TABLE">
+<div class="setting-bar" *ngIf="result.type === datasetType.TABLE && !published">
   <div class="visualization-selector">
     <nz-radio-group [(ngModel)]="config?.graph.mode" (ngModelChange)="switchMode($event)" nzButtonStyle="solid">
       <label *ngFor="let item of visualizations"
@@ -54,7 +54,7 @@
      [nzGridColumnCount]="12"
      [nzMinColumn]="1"
      nzBounds="window">
-  <nz-resize-handle nzDirection="bottomRight">
+  <nz-resize-handle nzDirection="bottomRight" *ngIf="!published">
     <zeppelin-resize-handle></zeppelin-resize-handle>
   </nz-resize-handle>
   <ng-template cdkPortalOutlet></ng-template>
@@ -65,7 +65,7 @@
          zeppelinRunScripts
          [scriptsContent]="innerHTML"
          [innerHTML]="innerHTML"></div>
-    <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre>{{plainText}}</pre></div>
+    <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre [innerHTML]="plainText"></pre></div>
     <div *ngSwitchCase="datasetType.IMG" class="img"><img [src]="imgData" alt="img"></div>
   </ng-container>
   <div *ngIf="angularComponent">
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less
similarity index 100%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less
rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
similarity index 99%
rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
index 742a9fb..86d94cc 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
@@ -68,6 +68,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
   @Input() result: ParagraphIResultsMsgItem;
   @Input() config: ParagraphConfigResult;
   @Input() id: string;
+  @Input() published = false;
   @Input() currentCol = 12;
   @Output() readonly configChange = new EventEmitter<ParagraphConfigResult>();
   @Output() readonly sizeChange = new EventEmitter<NzResizeEvent>();
@@ -223,6 +224,9 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
         break;
     }
     this.cdr.markForCheck();
+    if (this.published) {
+      this.cdr.detectChanges();
+    }
   }
 
   renderHTML(): void {
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 0000000..4c7ef1d
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
@@ -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 { PortalModule } from '@angular/cdk/portal';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+
+import {
+  NzButtonModule,
+  NzCheckboxModule,
+  NzDropDownModule,
+  NzIconModule,
+  NzRadioModule,
+  NzSelectModule,
+  NzSwitchModule,
+  NzToolTipModule
+} from 'ng-zorro-antd';
+import { NzResizableModule } from 'ng-zorro-antd/resizable';
+
+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
+  ]
+})
+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
index 0340a8d..9315443 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
@@ -31,6 +31,10 @@ const routes: Routes = [
         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: 'jobmanager',
         loadChildren: () =>
           import('@zeppelin/pages/workspace/job-manager/job-manager.module').then(m => m.JobManagerModule)
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
index 6bcae47..c41cf78 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
@@ -11,7 +11,7 @@
   -->
 
 <div class="content" [class.blur]="!websocketConnected">
-  <zeppelin-header></zeppelin-header>
-  <router-outlet></router-outlet>
+  <zeppelin-header *ngIf="!publishMode"></zeppelin-header>
+  <router-outlet (activate)="onActivate($event)"></router-outlet>
 </div>
 <zeppelin-spin *ngIf="!websocketConnected" [transparent]="true">Connecting WebSocket ...</zeppelin-spin>
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index 03c5b9b..c89d287e 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -12,10 +12,13 @@
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
 import { Subject } from 'rxjs';
-import { takeUntil } from 'rxjs/operators';
+import { filter, map, startWith, takeUntil, tap } from 'rxjs/operators';
 
+import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router';
+import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published';
 import { HeliumManagerService } from '@zeppelin/helium-manager';
 import { MessageService } from '@zeppelin/services';
+import { log } from 'ng-zorro-antd';
 
 @Component({
   selector: 'zeppelin-workspace',
@@ -26,6 +29,7 @@ import { MessageService } from '@zeppelin/services';
 export class WorkspaceComponent implements OnInit, OnDestroy {
   private destroy$ = new Subject();
   websocketConnected = false;
+  publishMode = false;
 
   constructor(
     public messageService: MessageService,
@@ -33,6 +37,11 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
     private heliumManagerService: HeliumManagerService
   ) {}
 
+  onActivate(e) {
+    this.publishMode = e && e[publishedSymbol];
+    this.cdr.markForCheck();
+  }
+
   ngOnInit() {
     this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => {
       this.websocketConnected = data;
diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts
index b6d6a3a..4b2a626 100644
--- a/zeppelin-web-angular/src/app/services/shortcut.service.ts
+++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts
@@ -1,7 +1,7 @@
-import {DOCUMENT} from "@angular/common";
-import {Inject, Injectable} from '@angular/core';
-import {EventManager} from "@angular/platform-browser";
-import {Observable} from "rxjs";
+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',
@@ -23,7 +23,8 @@ export enum ParagraphActions {
   SwitchTitleShow = 'Paragraph:SwitchTitleShow',
   SwitchOutputShow = 'Paragraph:SwitchOutputShow',
   SwitchEditorShow = 'Paragraph:SwitchEditorShow',
-  SwitchEnable = 'Paragraph:SwitchEnable'
+  SwitchEnable = 'Paragraph:SwitchEnable',
+  Link = 'Paragraph:Link'
 }
 
 export const ShortcutsMap = {
@@ -34,6 +35,8 @@ export const ShortcutsMap = {
   [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
@@ -54,28 +57,27 @@ export const ShortcutsMap = {
 };
 
 export interface ShortcutEvent {
-  event: KeyboardEvent
+  event: KeyboardEvent;
   keybindings: string;
 }
 
 export interface ShortcutOption {
-  scope?: HTMLElement,
-  keybindings: string
+  scope?: HTMLElement;
+  keybindings: string;
 }
 
 function isMacOS() {
-  return navigator.platform.indexOf('Mac') > -1
+  return navigator.platform.indexOf('Mac') > -1;
 }
 
 @Injectable({
   providedIn: 'root'
 })
 export class ShortcutService {
-
   private element: HTMLElement;
 
-  constructor(private eventManager: EventManager,
-              @Inject(DOCUMENT) _document: any) {
+  // tslint:disable-next-line:no-any
+  constructor(private eventManager: EventManager, @Inject(DOCUMENT) _document: any) {
     this.element = _document;
   }
 
@@ -86,9 +88,9 @@ export class ShortcutService {
   bindShortcut(option: ShortcutOption): Observable<ShortcutEvent> {
     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 event = `keydown.${keybindings}`;
+    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<ShortcutEvent>(observer => {
       const handler = event => {
@@ -98,12 +100,11 @@ export class ShortcutService {
         });
       };
 
-      dispose = this.eventManager.addEventListener(host, event, handler);
+      dispose = this.eventManager.addEventListener(host, eventName, handler);
 
       return () => {
         dispose();
       };
-    })
+    });
   }
-
 }


[zeppelin] 11/16: [ZEPPELIN-4516] Fix pie chart does not color by key

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 52392bf1e62a7008a5b65eb8054e94ceba4b357c
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Dec 27 11:06:20 2019 +0800

    [ZEPPELIN-4516] Fix pie chart does not color by key
    
    ### What is this PR for?
    
    Fix pie chart does not color by key
    
    ### What type of PR is it?
    [Bug Fix]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4516
    
    ### How should this be tested?
    
    N/A
    
    ### Screenshots (if appropriate)
    
    ![Kapture 2019-12-27 at 11 19 06](https://user-images.githubusercontent.com/22736418/71499297-ceedff80-289a-11ea-809f-1d2e0a30776f.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3574 from hsuanxyz/fix/pie-chart and squashes the following commits:
    
    1ca2dc935 [Hsuan Lee] fix: fix the pie chart's color
---
 .../src/pivot-transformation.ts                    | 49 ++++++++++++++++++----
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts
index cade722..963cc48 100644
--- a/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts
+++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts
@@ -16,7 +16,6 @@ import { get } from 'lodash';
 import { TableData } from './table-data';
 import { Transformation } from './transformation';
 
-// tslint:disable-next-line:no-any
 export class PivotTransformation extends Transformation {
   constructor(config) {
     super(config);
@@ -87,6 +86,8 @@ export class PivotTransformation extends Transformation {
     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);
@@ -101,6 +102,7 @@ export class PivotTransformation extends Transformation {
       groups = group ? [group] : [];
     }
 
+    // try coercion to number type
     dv.transform({
       type: 'map',
       callback: row => {
@@ -114,7 +116,10 @@ export class PivotTransformation extends Transformation {
       }
     });
 
+    // not applicable with type scatter chart
     if (config.mode !== 'scatterChart') {
+
+      // aggregate values
       dv.transform({
         type: 'aggregate',
         fields: config.values.map(v => v.name),
@@ -123,19 +128,36 @@ export class PivotTransformation extends Transformation {
         groupBy: [...keys, ...groups]
       });
 
-      // dv.transform({
-      //   type: 'fill-rows',
-      //   groupBy: groups,
-      //   orderBy: keys,
-      //   fillBy: 'order'
-      // });
-
+      // 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 => {
@@ -165,9 +187,17 @@ export class PivotTransformation extends Transformation {
     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__: groupName ? `${row.__key__}.${groupName}` : row.__key__
+          __key__: getKey()
         });
       });
     });
@@ -177,6 +207,7 @@ export class PivotTransformation extends Transformation {
         dv.origin.findIndex(o => o[firstKey] === a[firstKey]) - dv.origin.findIndex(o => o[firstKey] === b[firstKey])
     );
 
+    console.log(groupsData);
     dv = ds
       .createView({
         state: {


[zeppelin] 10/16: [ZEPPELIN-4503] Support note scope dynamic forms

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 68635436d28a5f46918c25b80b5d6a7019329b2b
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Dec 24 10:06:54 2019 +0800

    [ZEPPELIN-4503] Support note scope dynamic forms
    
    ### What is this PR for?
    
    Support note scope dynamic forms
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4503
    
    ### How should this be tested?
    
    Not applicable
    
    ### Screenshots (if appropriate)
    
    ![Kapture 2019-12-24 at 10 05 11](https://user-images.githubusercontent.com/22736418/71389013-a3b6a680-2635-11ea-8439-a4b81cc3277e.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3565 from hsuanxyz/feat/note-dynamic-forms and squashes the following commits:
    
    342aecfd8 [Hsuan Lee] chore: add component modules in share
    b8208937c [Hsuan Lee] feat: support note scope dynamaic forms
---
 .../src/interfaces/message-notebook.interface.ts   |  1 +
 .../src/interfaces/message-paragraph.interface.ts  |  1 +
 .../note-form-block.component.html}                | 24 +++++----
 .../note-form-block.component.less}                | 21 ++++----
 .../note-form-block/note-form-block.component.ts   | 43 +++++++++++++++
 .../workspace/notebook/notebook.component.html     |  8 +++
 .../pages/workspace/notebook/notebook.component.ts | 42 ++++++++++++++-
 .../pages/workspace/notebook/notebook.module.ts    |  4 +-
 .../elastic-input/elastic-input.component.html     |  2 +-
 .../share/elastic-input/elastic-input.component.ts |  3 +-
 .../dynamic-forms/dynamic-forms.component.html     | 62 +++++++++++++---------
 .../dynamic-forms/dynamic-forms.component.less     | 24 ++++++++-
 .../share/dynamic-forms/dynamic-forms.component.ts |  6 +++
 .../src/app/pages/workspace/share/share.module.ts  |  8 +--
 14 files changed, 195 insertions(+), 54 deletions(-)

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
index f7b22de..649a312 100644
--- 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
@@ -197,6 +197,7 @@ export interface NotesInfoItem extends ID {
 export interface NoteConfig {
   cron?: string;
   releaseresource: boolean;
+  noteFormTitle?: string;
   cronExecutingRoles?: string;
   cronExecutingUser?: string;
   isZeppelinNotebookCronEnable: boolean;
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
index bcc0199..2e04b22 100644
--- 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
@@ -23,6 +23,7 @@ export interface DynamicFormsItem {
   defaultValue: string | string[];
   hidden: boolean;
   name: string;
+  displayName?: string;
   type: DynamicFormsType;
   argument?: string;
   options?: Array<{ value: string; displayName?: string }>;
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/note-form-block/note-form-block.component.html
similarity index 52%
copy from zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html
copy to zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html
index c605d28..2ca5851 100644
--- 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/note-form-block/note-form-block.component.html
@@ -9,15 +9,17 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<div class="elastic" #elasticElement [class.min]="min">
-  <input #inputElement
-         [ngModel]="editValue"
-         (ngModelChange)="updateValue($event)"
-         *ngIf="showEditor"
-         (blur)="setEditorState(false)"
-         (keydown.esc)="cancelEdit()"
-         (keydown.enter)="setEditorState(false)"
-         (input)="updateInputWidth()">
-  <p #pElement *ngIf="!showEditor" (click)="setEditorState(true)">{{value || 'Untitled'}}</p>
+<div class="forms-wrap">
+  <zeppelin-elastic-input [value]="noteTitle"
+                          defaultTitle="Untitled Form"
+                          [min]="true"
+                          (valueUpdate)="setTitle($event)"></zeppelin-elastic-input>
+  <zeppelin-notebook-paragraph-dynamic-forms
+    [runOnChange]="true"
+    [removable]="true"
+    [paramDefs]="paramDefs"
+    [formDefs]="formDefs"
+    (formRemove)="onFormRemove($event)"
+    (formChange)="onFormChange()">
+  </zeppelin-notebook-paragraph-dynamic-forms>
 </div>
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/notebook/note-form-block/note-form-block.component.less
similarity index 71%
copy from zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
copy to zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less
index 060b2f8..896b6f8 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less
@@ -9,16 +9,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+@import "theme-mixin";
 
 :host {
   display: block;
-  .form-item {
-    margin-bottom: 24px;
-    nz-select {
-      width: 100%;
-    }
-    ::ng-deep .ant-checkbox-wrapper {
-      margin-left: 0;
-    }
-  }
+  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 0000000..9eb0b72
--- /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<string>();
+  @Output() readonly noteFormChange = new EventEmitter<DynamicFormParams>();
+  @Output() readonly noteFormNameRemove = new EventEmitter<string>();
+  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.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
index c447a59..d9574db 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
@@ -34,6 +34,14 @@
     <zeppelin-notebook-revisions-comparator *ngSwitchCase="'revisions'"></zeppelin-notebook-revisions-comparator>
   </div>
   <div class="paragraph-area">
+    <zeppelin-note-form-block *ngIf="isShowNoteForms"
+                              [formDefs]="note.noteForms"
+                              [paramDefs]="note.noteParams"
+                              [noteTitle]="note.config?.noteFormTitle"
+                              (noteFormChange)="onNoteFormChange($event)"
+                              (noteFormNameRemove)="onFormNameRemove($event)"
+                              (noteTitleChange)="onNoteTitleChange($event)">
+    </zeppelin-note-form-block>
     <div class="paragraph-inner" nz-row>
       <zeppelin-notebook-paragraph nz-col
                                    *ngFor="let p of note.paragraphs;let first = first; let last = last; index as i"
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
index 404fc28..0ca7546 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -26,7 +26,14 @@ import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { Permissions } from '@zeppelin/interfaces';
-import { InterpreterBindingItem, MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from '@zeppelin/sdk';
+import {
+  DynamicFormParams,
+  InterpreterBindingItem,
+  MessageReceiveDataTypeMap,
+  Note,
+  OP,
+  RevisionListItem
+} from '@zeppelin/sdk';
 import {
   MessageService,
   NgZService,
@@ -58,6 +65,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
   revisionView = false;
   collaborativeModeUsers = [];
   isNoteDirty = false;
+  isShowNoteForms = false;
   saveTimer = null;
   interpreterBindings: InterpreterBindingItem[] = [];
   activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide';
@@ -81,6 +89,14 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
         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();
     }
   }
@@ -125,6 +141,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
   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)
@@ -290,6 +307,29 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
     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,
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
index 4b71d3d..49a6230 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -48,6 +48,7 @@ import { NotebookRevisionsComparatorComponent } from './revisions-comparator/rev
 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';
@@ -64,7 +65,8 @@ import { NotebookShareModule } from './share/share.module';
     NotebookParagraphCodeEditorComponent,
     NotebookParagraphProgressComponent,
     NotebookParagraphFooterComponent,
-    NotebookParagraphControlComponent
+    NotebookParagraphControlComponent,
+    NoteFormBlockComponent
   ],
   imports: [
     CommonModule,
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
index c605d28..aa7b5e7 100644
--- 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
@@ -19,5 +19,5 @@
          (keydown.esc)="cancelEdit()"
          (keydown.enter)="setEditorState(false)"
          (input)="updateInputWidth()">
-  <p #pElement *ngIf="!showEditor" (click)="setEditorState(true)">{{value || 'Untitled'}}</p>
+  <p #pElement *ngIf="!showEditor" (click)="setEditorState(true)">{{value || defaultTitle}}</p>
 </div>
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
index ef4dce4..2057a87 100644
--- 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
@@ -33,6 +33,7 @@ export class ElasticInputComponent implements OnChanges {
   @Input() value: string;
   @Input() readonly = false;
   @Input() min = false;
+  @Input() defaultTitle = 'Untitled';
   @Output() readonly valueUpdate = new EventEmitter<string>();
   @ViewChild('inputElement', { read: ElementRef, static: false }) inputElement: ElementRef;
   @ViewChild('pElement', { read: ElementRef, static: false }) pElement: ElementRef;
@@ -47,7 +48,7 @@ export class ElasticInputComponent implements OnChanges {
 
   updateValue(value: string) {
     const trimmedNewName = value.trim();
-    if (trimmedNewName.length > 0 && this.value !== trimmedNewName) {
+    if (typeof value === 'string') {
       this.editValue = trimmedNewName;
     }
   }
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
index 3a4cfdd..330b3e8 100644
--- 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
@@ -20,32 +20,44 @@
     nzLg="8"
     nzMd="12"
     nzSm="24">
-    <ng-container [ngSwitch]="form.type">
-      <input *ngSwitchCase="formType.TextBox"
-             nz-input
-             [(ngModel)]="paramDefs[form.name]"
-             [disabled]="disable"
-             (ngModelChange)="onFormChange()">
-      <input *ngSwitchCase="formType.Password"
-             nz-input
-             type="password"
-             [(ngModel)]="paramDefs[form.name]"
-             [disabled]="disable"
-             (ngModelChange)="onFormChange()">
-      <nz-select *ngSwitchCase="formType.Select"
-                 [nzDisabled]="disable"
+    <div nz-row nzType="flex">
+      <label class="item-label" *ngIf="form.displayName" nz-col nzSpan="6">{{form.displayName}}: </label>
+      <div class="control-wrap" nz-col [nzSpan]="form.displayName ? 16 : 24">
+        <ng-container [ngSwitch]="form.type">
+          <input *ngSwitchCase="formType.TextBox"
+                 nz-input
                  [(ngModel)]="paramDefs[form.name]"
+                 [disabled]="disable"
                  (ngModelChange)="onFormChange()">
-        <nz-option *ngFor="let opt of form.options"
-                   [nzLabel]="opt.displayName || opt.value"
-                   [nzValue]="opt.value">
-        </nz-option>
-      </nz-select>
-      <nz-checkbox-group *ngSwitchCase="formType.CheckBox"
-                         [nzDisabled]="disable"
-                         [(ngModel)]="checkboxGroups[form.name]"
-                         (ngModelChange)="checkboxChange($event, form.name)">
-      </nz-checkbox-group>
-    </ng-container>
+          <input *ngSwitchCase="formType.Password"
+                 nz-input
+                 type="password"
+                 [(ngModel)]="paramDefs[form.name]"
+                 [disabled]="disable"
+                 (ngModelChange)="onFormChange()">
+          <nz-select *ngSwitchCase="formType.Select"
+                     [nzDisabled]="disable"
+                     [(ngModel)]="paramDefs[form.name]"
+                     (ngModelChange)="onFormChange()">
+            <nz-option *ngFor="let opt of form.options"
+                       [nzLabel]="opt.displayName || opt.value"
+                       [nzValue]="opt.value">
+            </nz-option>
+          </nz-select>
+          <nz-checkbox-group *ngSwitchCase="formType.CheckBox"
+                             [nzDisabled]="disable"
+                             [(ngModel)]="checkboxGroups[form.name]"
+                             (ngModelChange)="checkboxChange($event, form.name)">
+          </nz-checkbox-group>
+        </ng-container>
+        <button *ngIf="removable"
+                nz-button
+                nzType="link"
+                class="remove-button"
+                (click)="remove(form)">
+          <i nz-icon nzType="close" nzTheme="outline"></i>
+        </button>
+      </div>
+    </div>
   </div>
 </div>
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
index 060b2f8..a9a4b88 100644
--- 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
@@ -10,15 +10,37 @@
  * 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
index 338a434..b6eb9f9 100644
--- 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
@@ -42,7 +42,9 @@ export class NotebookParagraphDynamicFormsComponent implements OnInit, OnChanges
   @Input() paramDefs: DynamicFormParams;
   @Input() runOnChange = false;
   @Input() disable = false;
+  @Input() removable = false;
   @Output() readonly formChange = new EventEmitter<void>();
+  @Output() readonly formRemove = new EventEmitter<DynamicFormsItem>();
 
   formChange$ = new Subject<void>();
   forms: DynamicFormsItem[] = [];
@@ -97,6 +99,10 @@ export class NotebookParagraphDynamicFormsComponent implements OnInit, OnChanges
     }
   }
 
+  remove(item: DynamicFormsItem) {
+    this.formRemove.emit(item);
+  }
+
   constructor() {}
 
   ngOnInit() {
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
index 37bebf3..dfc2c4c 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
@@ -18,7 +18,9 @@ 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';
@@ -28,8 +30,6 @@ import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
 import { ShareModule } from '@zeppelin/share';
 import { VisualizationModule } from '@zeppelin/visualizations/visualization.module';
 
-import { NzGridModule } from 'ng-zorro-antd/grid';
-import { NzInputModule } from 'ng-zorro-antd/input';
 import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component';
 import { NotebookParagraphResultComponent } from './result/result.component';
 
@@ -51,8 +51,8 @@ import { NotebookParagraphResultComponent } from './result/result.component';
     NzCheckboxModule,
     NzSelectModule,
     NzSwitchModule,
-    NzInputModule,
-    NzGridModule
+    NzGridModule,
+    NzInputModule
   ]
 })
 export class WorkspaceShareModule {}


[zeppelin] 13/16: [ZEPPELIN-4530] Support versions switch

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit be80af7ce3d75977452ef8e366537ee4d07505b8
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Jan 3 09:44:06 2020 +0800

    [ZEPPELIN-4530] Support versions switch
    
    ### What is this PR for?
    
    Add the versions switch button in the top drop-down menu
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4530
    
    ### How should this be tested?
    
    N/A
    
    ### Screenshots (if appropriate)
    
    ![image](https://user-images.githubusercontent.com/22736418/71655910-192c2080-2d74-11ea-85da-295521d5e919.png)
    
    ---
    
    ![image](https://user-images.githubusercontent.com/22736418/71655912-1d583e00-2d74-11ea-9663-90a86c32f85a.png)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3584 from hsuanxyz/feat/version-switch and squashes the following commits:
    
    215dc2c5b [Hsuan Lee] chore: hidden the helium link
    3af3f53fa [Hsuan Lee] feat: add support switch versions
---
 zeppelin-web-angular/src/app/share/header/header.component.html | 8 +++++---
 zeppelin-web/src/components/navbar/navbar.html                  | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html
index 645da9a..33d8ecd 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.html
+++ b/zeppelin-web-angular/src/app/share/header/header.component.html
@@ -56,9 +56,9 @@
             [routerLink]="['/credential']">Credential
           </a>
         </li>
-        <li nz-menu-item routerLinkActive="ant-dropdown-menu-item-selected">
-          <a [routerLink]="['/helium']">Helium</a>
-        </li>
+<!--        <li nz-menu-item routerLinkActive="ant-dropdown-menu-item-selected">-->
+<!--          <a [routerLink]="['/helium']">Helium</a>-->
+<!--        </li>-->
         <li nz-menu-item routerLinkActive="ant-dropdown-menu-item-selected">
           <a [routerLink]="['/configuration']">Configuration</a>
         </li>
@@ -66,6 +66,8 @@
           <li nz-menu-divider></li>
           <li nz-menu-item (click)="logout()">Logout</li>
         </ng-container>
+        <li nz-menu-divider></li>
+        <li nz-menu-item><a href="/">Old Version</a></li>
       </ul>
     </nz-dropdown-menu>
   </div>
diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html
index 263ff06..8182585 100644
--- a/zeppelin-web/src/components/navbar/navbar.html
+++ b/zeppelin-web/src/components/navbar/navbar.html
@@ -105,6 +105,8 @@ limitations under the License.
               <li ng-if="clusterAddr !== ''"><a href="#/cluster">Cluster</a> </li>
               <li ng-if="ticket.principal && ticket.principal !== 'anonymous'" role="separator" style="margin: 5px 0;" class="divider"></li>
               <li ng-if="ticket.principal && ticket.principal !== 'anonymous'"><a ng-click="navbar.logout()">Logout</a></li>
+              <li role="separator" style="margin: 5px 0;" class="divider"></li>
+              <li><a href="/next">Try the new Zeppelin</a></li>
             </ul>
           </div>
         </li>


[zeppelin] 03/16: [ZEPPELIN-4450] Provide Angular.js Template Migration Tool

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 1e0177d132f8458aa6beff570c380b7b4740399f
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Nov 26 11:28:28 2019 +0800

    [ZEPPELIN-4450] Provide Angular.js Template Migration Tool
    
    ### What is this PR for?
    
    We have implemented the frontend API of Angular.js using the latest Angular. But the templates some [differences](https://angular.io/guide/ajs-quick-reference) between Angular.js and Angular.
    
    So to help users migrate templates, we provide a migration tool that will be integrated into the Zeppelin web. This is its [DEMO](https://ng1-updater.hsuan.xyz/) it can quickly fix these differences.
    
    We plan to do the following work:
    
    1. Add a new type `%ng` (official abbreviation) to distinguish between Angular.js and Angular templates.
    2. When the user runs a paragraph with the `%angular` type, the upgrade dialog will be open.
    3. Upgrade the template in the dialog and click the `Update and Copy` button.
    4. Automatically create a paragraph of type `%ng` template in below
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4321
    https://issues.apache.org/jira/browse/ZEPPELIN-4450
    
    ### How should this be tested?
    * First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration
    * Strongly recommended: add automated unit tests for any new or changed behavior
    * Outline any manual steps to test the PR here.
    
    ### Screenshots (if appropriate)
    
    ![ng1-template](https://user-images.githubusercontent.com/22736418/69597301-78de3000-1040-11ea-85a6-830d573f1305.gif)
    
    ### Questions:
    * Does the licenses files need update? NO
    * Is there breaking changes for older versions? NO
    * Does this needs documentation? NO
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3528 from hsuanxyz/angularjs-template-compatible and squashes the following commits:
    
    3474f81c5 [Hsuan Lee] fix: fix editor focus
    d639a2b13 [Hsuan Lee] fix: fix focus bar
    38d0c4659 [Hsuan Lee] chore: update code editor actions
    1a28a7a9f [Hsuan Lee] feat: provide Angular.js template migration tool
---
 .../src/main/resources/interpreter-setting.json    |  11 +
 zeppelin-web-angular/package-lock.json             |  18 +-
 zeppelin-web-angular/package.json                  |   3 +
 .../code-editor/code-editor.component.html         |   5 +-
 .../code-editor/code-editor.component.less         |   6 +-
 .../paragraph/code-editor/code-editor.component.ts |  10 +-
 .../paragraph/control/control.component.ts         | 117 ++++----
 .../notebook/paragraph/paragraph.component.ts      | 297 ++++++++++++---------
 .../paragraph/result/result.component.html         |   2 +-
 .../notebook/paragraph/result/result.component.ts  |  17 +-
 .../app/services/ng-template-adapter.service.ts    |  65 +++++
 .../ng1-migration/ng1-migration.component.html     |  54 ++++
 .../ng1-migration/ng1-migration.component.less     |  77 ++++++
 .../share/ng1-migration/ng1-migration.component.ts | 174 ++++++++++++
 zeppelin-web-angular/src/app/share/share.module.ts |   4 +-
 15 files changed, 646 insertions(+), 214 deletions(-)

diff --git a/angular/src/main/resources/interpreter-setting.json b/angular/src/main/resources/interpreter-setting.json
index 723348d..957295f 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/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json
index 85ad2a6..cd5fb2f 100644
--- a/zeppelin-web-angular/package-lock.json
+++ b/zeppelin-web-angular/package-lock.json
@@ -2370,6 +2370,12 @@
       "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",
@@ -9967,6 +9973,11 @@
         "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",
@@ -10695,10 +10706,9 @@
       "integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes="
     },
     "parse5": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
-      "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
-      "optional": true
+      "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",
diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json
index 63b6be1..9d9aa93 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -37,6 +37,8 @@
     "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",
@@ -56,6 +58,7 @@
     "@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",
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
index 4d382f2..d543e67 100644
--- 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
@@ -11,6 +11,7 @@
   -->
 
 <zeppelin-code-editor [style.height.px]="height"
-                     [class.dirty]="dirty"
-                     (nzEditorInitialized)="initializedEditor($event)">
+                      [class.focused]="focus"
+                      [class.dirty]="dirty"
+                      (nzEditorInitialized)="initializedEditor($event)">
 </zeppelin-code-editor>
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
index 72a1f68..8f61bd5 100644
--- 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
@@ -18,7 +18,7 @@
 
 .themeMixin({
 
-  zeppelin-monaco-editor {
+  zeppelin-code-editor {
     display: block;
     border-left: 4px solid @border-color-split;
     overflow: hidden;
@@ -26,6 +26,10 @@
     &.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
index 0711e81..916afef 100644
--- 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
@@ -76,16 +76,10 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
     const editor = this.editor;
     this.monacoDisposables.push(
       editor.onDidFocusEditorText(() => {
-        this.ngZone.runOutsideAngular(() => {
-          this.editorFocus.emit();
-          editor.updateOptions({ renderLineHighlight: 'all' });
-        });
+        this.editorFocus.emit();
       }),
       editor.onDidBlurEditorText(() => {
         this.editorBlur.emit();
-        this.ngZone.runOutsideAngular(() => {
-          editor.updateOptions({ renderLineHighlight: 'none' });
-        });
       }),
 
       editor.onDidChangeModelContent(() => {
@@ -110,13 +104,11 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
 
   initializedEditor(editor: IEditor) {
     this.editor = editor as IStandaloneCodeEditor;
-    this.paragraphControl.updateListOfMenu(monaco);
     if (this.paragraphControl) {
       this.paragraphControl.listOfMenu.forEach((item, index) => {
         this.editor.addAction({
           id: item.icon,
           label: item.label,
-          keybindings: item.keyBindings,
           precondition: null,
           keybindingContext: null,
           contextMenuGroupId: 'navigation',
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
index 5b95953..bda003d 100644
--- 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
@@ -81,20 +81,66 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
     disabled: boolean;
     icon: string;
     shortCut: string;
-    keyBindings: number[];
     trigger(): void;
   }> = [];
 
-  updateListOfMenu(monaco?) {
+  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.goToSingleParagraph(),
+        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`
+      },
+      {
+        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: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+K`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_K] : []
+        shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+K (Command)`
       },
       {
         label: 'Move down',
@@ -102,8 +148,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         disabled: this.isEntireNoteRunning,
         icon: 'down',
         trigger: () => this.trigger(this.moveDown),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+J`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_J] : []
+        shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+J (Command)`
       },
       {
         label: 'Insert new',
@@ -111,26 +156,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         disabled: this.isEntireNoteRunning,
         icon: 'plus',
         trigger: () => this.trigger(this.insertNew),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+B`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_B] : []
-      },
-      {
-        label: 'Run all above',
-        show: !this.first,
-        disabled: this.isEntireNoteRunning,
-        icon: 'up-square',
-        trigger: () => this.trigger(this.runAllAbove),
-        shortCut: `Ctrl+Shift+Enter`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : []
-      },
-      {
-        label: 'Run all below',
-        show: !this.last,
-        disabled: this.isEntireNoteRunning,
-        icon: 'down-square',
-        trigger: () => this.trigger(this.runAllBelowAndCurrent),
-        shortCut: `Ctrl+Shift+Enter`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : []
+        shortCut: `B (Command)`
       },
       {
         label: 'Clone paragraph',
@@ -138,8 +164,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         disabled: this.isEntireNoteRunning,
         icon: 'copy',
         trigger: () => this.trigger(this.cloneParagraph),
-        shortCut: `Ctrl+Shift+C`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_C] : []
+        shortCut: `C (Command)`
       },
       {
         label: this.title ? 'Hide Title' : 'Show Title',
@@ -147,8 +172,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         disabled: false,
         icon: 'font-colors',
         trigger: () => this.toggleTitle(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+T`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_T] : []
+        shortCut: `T (Command)`
       },
       {
         label: this.lineNumbers ? 'Hide line numbers' : 'Show line numbers',
@@ -156,8 +180,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         disabled: false,
         icon: 'ordered-list',
         trigger: () => this.toggleLineNumbers(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+M`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_M] : []
+        shortCut: `L (Command)`
       },
       {
         label: this.enabled ? 'Disable run' : 'Enable run',
@@ -165,35 +188,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges {
         disabled: this.isEntireNoteRunning,
         icon: 'api',
         trigger: () => this.toggleEnabled(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+R`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_R] : []
-      },
-      {
-        label: 'Link this paragraph',
-        show: true,
-        disabled: false,
-        icon: 'export',
-        trigger: () => this.goToSingleParagraph(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_W] : []
-      },
-      {
-        label: 'Clear output',
-        show: true,
-        disabled: this.isEntireNoteRunning,
-        icon: 'fire',
-        trigger: () => this.clearParagraphOutput(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+L`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_L] : []
-      },
-      {
-        label: 'Remove',
-        show: this.paragraphLength > 1,
-        disabled: this.isEntireNoteRunning,
-        icon: 'delete',
-        trigger: () => this.onRemoveParagraph(),
-        shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+D`,
-        keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_D] : []
+        shortCut: `R (Command)`
       }
     ];
   }
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
index 1dde62d..f5b61e8 100644
--- 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
@@ -13,7 +13,8 @@
 import {
   ChangeDetectionStrategy,
   ChangeDetectorRef,
-  Component, ElementRef,
+  Component,
+  ElementRef,
   EventEmitter,
   Input,
   OnChanges,
@@ -25,8 +26,8 @@ import {
   ViewChild,
   ViewChildren
 } from '@angular/core';
-import {merge, Observable, Subject} from 'rxjs';
-import {map, takeUntil} from 'rxjs/operators';
+import { merge, Observable, Subject } from 'rxjs';
+import { map, takeUntil } from 'rxjs/operators';
 
 import DiffMatchPatch from 'diff-match-patch';
 import { isEmpty, isEqual } from 'lodash';
@@ -60,6 +61,7 @@ import {
 } 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 { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component';
 import { NotebookParagraphResultComponent } from './result/result.component';
@@ -71,7 +73,7 @@ type Mode = 'edit' | 'command';
   templateUrl: './paragraph.component.html',
   styleUrls: ['./paragraph.component.less'],
   host: {
-    'tabindex': '-1',
+    tabindex: '-1',
     '(focusin)': 'onFocus()'
   },
   changeDetection: ChangeDetectionStrategy.OnPush
@@ -210,7 +212,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
       this.focusEditor();
     } else {
       this.blurEditor();
-      (this.host.nativeElement as HTMLElement).focus();
     }
   }
 
@@ -370,21 +371,22 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
         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$))
+    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') {
+  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) {
@@ -408,12 +410,30 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     this.messageService.copyParagraph(
       newIndex,
       this.paragraph.title,
-      this.paragraph.text,
+      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) {
@@ -421,25 +441,34 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
 
       if (this.heliumService.getSpellByMagic(magic)) {
         this.runParagraphUsingSpell(text, magic, propagated);
+        this.runParagraphAfter(text);
       } else {
-        this.runParagraphUsingBackendInterpreter(text);
-      }
-
-      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();
+        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.' +
+                ' (<a href="https://angular.io/guide/ajs-quick-reference" target="_blank">more info</a>)',
+              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));
+        }
       }
-      this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick;
     }
   }
 
@@ -693,125 +722,131 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
     private cdr: ChangeDetectorRef,
     private ngZService: NgZService,
     private shortcutService: ShortcutService,
-    private host: ElementRef
+    private host: ElementRef,
+    private ngTemplateAdapterService: NgTemplateAdapterService
   ) {
     super(messageService);
   }
 
   ngOnInit() {
     const shortcutService = this.shortcutService.forkByElement(this.host.nativeElement);
-    const observables: Array<Observable<{
-      action: ParagraphActions,
-      event: KeyboardEvent
-    }>> = [];
+    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
-            }
-          }))
+          shortcutService
+            .bindShortcut({
+              keybindings: key
+            })
+            .pipe(
+              takeUntil(this.destroy$),
+              map(({ event }) => {
+                return {
+                  event,
+                  action: action as ParagraphActions
+                };
+              })
+            )
         );
       });
     });
 
     merge<{
-      action: ParagraphActions,
-      event: KeyboardEvent
+      action: ParagraphActions;
+      event: KeyboardEvent;
     }>(...observables)
       .pipe(takeUntil(this.destroy$))
-      .subscribe(({action, event}) => {
-      if (this.mode === 'command') {
+      .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:
+              this.moveUpParagraph();
+              break;
+            case ParagraphActions.MoveToDown:
+              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.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:
-            this.moveUpParagraph();
-            break;
-          case ParagraphActions.MoveToDown:
-            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();
+          case ParagraphActions.EditMode:
+            if (this.mode === 'command') {
+              event.preventDefault();
+            }
+            if (!this.paragraph.config.editorHide) {
+              this.switchMode('edit');
+            }
             break;
-          case ParagraphActions.SelectAbove:
+          case ParagraphActions.Run:
             event.preventDefault();
-            this.selectAtIndex.emit(this.index - 1);
+            this.runParagraph();
+            break;
+          case ParagraphActions.RunBelow:
+            this.waitConfirmFromEdit = true;
+            this.runAllBelowAndCurrent();
             break;
-          case ParagraphActions.SelectBelow:
+          case ParagraphActions.Cancel:
             event.preventDefault();
-            this.selectAtIndex.emit(this.index + 1);
+            this.cancelParagraph();
             break;
           default:
             break;
         }
-      }
-      switch (action) {
-        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;
@@ -843,12 +878,16 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen
 
   ngOnChanges(changes: SimpleChanges): void {
     const { index, select } = changes;
-    if (index && index.currentValue !== index.previousValue && this.select
-    || select && select.currentValue === true && select.previousValue !== true) {
+    if (
+      (index && index.currentValue !== index.previousValue && this.select) ||
+      (select && select.currentValue === true && select.previousValue !== true)
+    ) {
       if (this.host.nativeElement) {
         setTimeout(() => {
-          (this.host.nativeElement as HTMLElement).focus();
-        })
+          if (this.mode === 'command') {
+            (this.host.nativeElement as HTMLElement).focus();
+          }
+        });
       }
     }
   }
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
index 028c3e5..fe34a37 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html
@@ -65,7 +65,7 @@
          zeppelinRunScripts
          [scriptsContent]="innerHTML"
          [innerHTML]="innerHTML"></div>
-    <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre [innerHTML]="plainText"></pre></div>
+    <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre>{{plainText}}</pre></div>
     <div *ngSwitchCase="datasetType.IMG" class="img"><img [src]="imgData" alt="img"></div>
   </ng-container>
   <div *ngIf="angularComponent">
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
index 903f72b..742a9fb 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts
@@ -16,7 +16,6 @@ import {
   ChangeDetectionStrategy,
   ChangeDetectorRef,
   Component,
-  ElementRef,
   EventEmitter,
   Injector,
   Input,
@@ -81,6 +80,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
   plainText: string | SafeHtml = '';
   imgData: string | SafeUrl = '';
   tableData = new TableData();
+  frontEndError: string;
   // tslint:disable-next-line:no-any
   visualizations: any[] = [
     {
@@ -236,11 +236,16 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
   }
 
   renderAngular(): void {
-    this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => {
-      this.angularComponent = data;
-      // this.angularComponent.moduleFactory
-      this.cdr.markForCheck();
-    });
+    try {
+      this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => {
+        this.angularComponent = data;
+        // this.angularComponent.moduleFactory
+        this.cdr.markForCheck();
+      });
+    } catch (e) {
+      this.frontEndError = e.message;
+      console.log(e);
+    }
   }
 
   renderText(): void {
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 0000000..651b709
--- /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';
+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<string> {
+    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/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 0000000..34d948a
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html
@@ -0,0 +1,54 @@
+<div class="code-editor">
+  <zeppelin-code-editor
+    (nzEditorInitialized)="onEditorInit($event)"
+    [nzEditorOption]="{
+    language: 'html' ,
+    minimap: {
+    enabled: false
+    }
+  }">
+  </zeppelin-code-editor>
+</div>
+<div class="messages">
+
+  <div class="fix-bar">
+    <button nz-button
+            [disabled]="(messageDetails.length - errorCount) === 0"
+            class="fix-btn"
+            nzSize="small"
+            nzType="link"
+            (click)="fix()">
+      Quick Fix
+    </button>
+    <span class="log-counts">
+      <span>
+        <i nz-icon class="error" nzType="stop" nzTheme="outline"></i>
+        {{errorCount}}
+      </span>
+       <span>
+        <i nz-icon class="close" nzType="issues-close" nzTheme="outline"></i>
+         {{messageDetails.length - errorCount}}
+      </span>
+    </span>
+  </div>
+
+  <div class="message"
+       (click)="scrollToLine(item)"
+       *ngFor="let item of messageDetails">
+    <i *ngIf="item.level === 0" nz-icon class="error" nzType="stop" nzTheme="outline"></i>
+    <i *ngIf="item.level === 2" nz-icon class="close" nzType="issues-close" nzTheme="outline"></i>
+    <span class="position"> ({{(item.pos.line + 1) + ',' + (item.pos.character + 1)}})</span>
+    {{item.message}}
+    <a *ngIf="item.url" [href]="item.url" target="_blank">more</a>
+  </div>
+</div>
+
+<div *nzModalFooter>
+  <button nz-button (click)="cancel()">Cancel</button>
+  <button nz-button
+          nzType="primary"
+          [disabled]="this.messageDetails.length"
+          (click)="updateAndCopy()">
+    Update and Copy
+  </button>
+</div>
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 0000000..cb1fdc2
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less
@@ -0,0 +1,77 @@
+: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 0000000..340330e
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts
@@ -0,0 +1,174 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core';
+import { editor, IDisposable, Range } from 'monaco-editor';
+import { NzModalRef } from 'ng-zorro-antd';
+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/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts
index ed5d191..fcb0375 100644
--- a/zeppelin-web-angular/src/app/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/share/share.module.ts
@@ -52,6 +52,7 @@ import { PageHeaderComponent } from '@zeppelin/share/page-header/page-header.com
 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 = [
@@ -59,7 +60,8 @@ const MODAL_LIST = [
   NoteImportComponent,
   NoteCreateComponent,
   NoteRenameComponent,
-  FolderRenameComponent
+  FolderRenameComponent,
+  Ng1MigrationComponent
 ];
 const EXPORT_LIST = [HeaderComponent, NodeListComponent, PageHeaderComponent, SpinComponent, ResizeHandleComponent];
 const PIPES = [HumanizeBytesPipe];


[zeppelin] 14/16: [ZEPPELIN-4542] Websocket client support of auto-reconnect

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit a62d89345985d66d7f381b45d6870a255fa5b9c4
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Jan 7 14:35:47 2020 +0800

    [ZEPPELIN-4542] Websocket client support of auto-reconnect
    
    ### What is this PR for?
    
    Websocket client support of auto-reconnect
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4542
    
    ### How should this be tested?
    
    N/A
    
    ### Screenshots (if appropriate)
    
    N/A
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3590 from hsuanxyz/feat/network-reconnect and squashes the following commits:
    
    ab8da4584 [Hsuan Lee] feat: support the websocket reconnect
---
 .../projects/zeppelin-sdk/src/message.ts           |  4 +++
 .../app/pages/workspace/workspace.component.html   |  3 +-
 .../app/pages/workspace/workspace.component.less   |  4 ---
 .../src/app/pages/workspace/workspace.component.ts | 41 ++++++++++++++++------
 .../src/app/pages/workspace/workspace.module.ts    |  7 ++--
 .../about-zeppelin/about-zeppelin.component.html   |  2 +-
 6 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
index 65ceec6..4505e36 100644
--- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
@@ -116,6 +116,10 @@ export class Message {
     this.send<OP.PING>(OP.PING);
   }
 
+  close() {
+    this.close$.next();
+  }
+
   opened(): Observable<Event> {
     return this.open$.asObservable();
   }
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
index c41cf78..a955afa 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html
@@ -10,8 +10,7 @@
   ~ limitations under the License.
   -->
 
-<div class="content" [class.blur]="!websocketConnected">
+<div class="content">
   <zeppelin-header *ngIf="!publishMode"></zeppelin-header>
   <router-outlet (activate)="onActivate($event)"></router-outlet>
 </div>
-<zeppelin-spin *ngIf="!websocketConnected" [transparent]="true">Connecting WebSocket ...</zeppelin-spin>
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
index 63064aa..dfe293f 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less
@@ -18,9 +18,5 @@
     min-height: 100vh;
     display: block;
     position: relative;
-
-    &.blur {
-      filter: blur(4px);
-    }
   }
 });
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index 410ef17..19175cb 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -10,16 +10,15 @@
  * limitations under the License.
  */
 
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit } from '@angular/core';
 import { Subject } from 'rxjs';
-import { filter, map, startWith, takeUntil, tap } from 'rxjs/operators';
+import { takeUntil } from 'rxjs/operators';
 
-import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router';
-import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published';
+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 { log } from 'ng-zorro-antd/core';
+import { NzMessageService } from 'ng-zorro-antd/message';
 
 @Component({
   selector: 'zeppelin-workspace',
@@ -29,26 +28,48 @@ import { log } from 'ng-zorro-antd/core';
 })
 export class WorkspaceComponent implements OnInit, OnDestroy {
   private destroy$ = new Subject();
-  websocketConnected = false;
+  private messageId = null;
   publishMode = false;
 
   constructor(
     public messageService: MessageService,
     private cdr: ChangeDetectorRef,
+    private nzMessageService: NzMessageService,
     private heliumManagerService: HeliumManagerService
   ) {}
 
-  onActivate(e) {
-    this.publishMode = e && e[publishedSymbol];
+  onActivate(component) {
+    this.publishMode = component && component[publishedSymbol];
     this.cdr.markForCheck();
   }
 
-  ngOnInit() {
+  /**
+   * 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 => {
-      this.websocketConnected = 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();
   }
 
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
index f6e01e2..3be5f54 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts
@@ -19,9 +19,11 @@ import { RouterModule } from '@angular/router';
 import { HeliumManagerModule } from '@zeppelin/helium-manager';
 import { ShareModule } from '@zeppelin/share';
 
-import { WorkspaceRoutingModule } from './workspace-routing.module';
+import { NzMessageModule } from 'ng-zorro-antd/message';
 import { WorkspaceComponent } from './workspace.component';
 
+import { WorkspaceRoutingModule } from './workspace-routing.module';
+
 @NgModule({
   declarations: [WorkspaceComponent],
   imports: [
@@ -31,7 +33,8 @@ import { WorkspaceComponent } from './workspace.component';
     HttpClientModule,
     ShareModule,
     RouterModule,
-    HeliumManagerModule
+    HeliumManagerModule,
+    NzMessageModule
   ]
 })
 export class WorkspaceModule {}
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
index c7d8cc5..33a5d87 100644
--- 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
@@ -12,7 +12,7 @@
 
 <div nz-row class="modal">
   <div nz-col [nzSm]="8" [nzXs]="0" class="about-logo">
-    <img src="../../assets/images/zeppelin_svg_logo.svg" alt="Apache Zeppelin" title="Apache Zeppelin"/>
+    <img src="assets/images/zeppelin_svg_logo.svg" alt="Apache Zeppelin" title="Apache Zeppelin"/>
   </div>
   <div nz-col [nzSm]="16" [nzXs]="24" class="content">
     <h3>Apache Zeppelin</h3>


[zeppelin] 06/16: [ZEPPELIN-4399] Add credential page

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 3aaa1113cc9c35e6fe13289df4612a4e30041444
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Wed Dec 4 15:08:11 2019 +0800

    [ZEPPELIN-4399] Add credential page
    
    ### What is this PR for?
    
    Add the credential page on the reworked with Angular project
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4399
    
    ### How should this be tested?
    
    Not applicable
    
    ### Screenshots (if appropriate)
    
    ![credential](https://user-images.githubusercontent.com/22736418/70136543-2697b180-16c7-11ea-9aa3-0e44b3312b78.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3537 from hsuanxyz/feat/credential and squashes the following commits:
    
    9fc6a9d24 [Hsuan Lee] feat: add credential page
---
 .../interfaces/{public-api.ts => credential.ts}    |  21 ++-
 .../src/app/interfaces/public-api.ts               |   1 +
 .../credential/credential-routing.module.ts}       |  21 ++-
 .../workspace/credential/credential.component.html | 134 ++++++++++++++
 .../credential/credential.component.less}          |  32 +++-
 .../workspace/credential/credential.component.ts   | 201 +++++++++++++++++++++
 .../workspace/credential/credential.module.ts      |  56 ++++++
 .../pages/workspace/workspace-routing.module.ts    |   5 +
 .../src/app/services/credential.service.ts         |  43 +++++
 .../src/app/services/public-api.ts                 |   1 +
 10 files changed, 500 insertions(+), 15 deletions(-)

diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/credential.ts
similarity index 67%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/interfaces/credential.ts
index 1e07b8e..533b120 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/credential.ts
@@ -10,8 +10,19 @@
  * limitations under the License.
  */
 
-export * from './ticket';
-export * from './trash-folder-id';
-export * from './interpreter';
-export * from './message-interceptor';
-export * from './security';
+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/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts
index 1e07b8e..f00e442 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts
@@ -15,3 +15,4 @@ export * from './trash-folder-id';
 export * from './interpreter';
 export * from './message-interceptor';
 export * from './security';
+export * from './credential';
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts
similarity index 59%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts
index 1e07b8e..5624c7e 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts
@@ -9,9 +9,20 @@
  * 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';
 
-export * from './ticket';
-export * from './trash-folder-id';
-export * from './interpreter';
-export * from './message-interceptor';
-export * from './security';
+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 0000000..51b0c84
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html
@@ -0,0 +1,134 @@
+<!--
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<zeppelin-page-header
+  title="Credentials"
+  [extra]="headerExtra"
+  [description]="credentialsDescription">
+  <ng-template #credentialsDescription>
+    Manage your credentials. You can add new credential information. <a [href]="docsLink" target="_blank">
+    <i
+      nz-icon
+      nz-tooltip
+      nzTitle="Learn more"
+      nzType="question-circle"
+      nzTheme="outline"
+    ></i>
+  </a>
+
+  </ng-template>
+  <ng-template #headerExtra>
+    <button
+      class="repository-trigger"
+      nz-button
+      [nzType]="showAdd ? 'primary' : 'default'"
+      (click)="triggerAdd()">
+      <i nz-icon nzType="plus" nzTheme="outline"></i>
+      Add
+    </button>
+  </ng-template>
+  <div [@collapseMotion]="showAdd ? 'expanded' : 'collapsed' ">
+    <nz-divider nzType="horizontal"></nz-divider>
+    <h2>Add new credential</h2>
+    <form nz-form nzLayout="inline" [formGroup]="addForm" (ngSubmit)="submitForm()">
+      <div nz-row>
+        <div nz-col [nzSpan]="16">
+          <nz-form-item>
+            <nz-form-label>Entity</nz-form-label>
+            <nz-form-control nzErrorTip="Please input entity!">
+              <input [nzAutocomplete]="auto"
+                     (input)="onEntityInput($event)"
+                     formControlName="entity"
+                     nz-input
+                     placeholder="[Group].[Name]"/>
+              <nz-autocomplete nzBackfill #auto>
+                <nz-auto-option *ngFor="let option of interpreterFilteredNames" [nzValue]="option">
+                  {{ option }}
+                </nz-auto-option>
+              </nz-autocomplete>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label>Username</nz-form-label>
+            <nz-form-control nzErrorTip="Please input username!">
+              <input formControlName="username" nz-input placeholder="Username"/>
+            </nz-form-control>
+          </nz-form-item>
+          <nz-form-item>
+            <nz-form-label>Password</nz-form-label>
+            <nz-form-control nzErrorTip="Please input Password!">
+              <input formControlName="password" nz-input type="password" placeholder="Password"/>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div class="new-actions" nz-col [nzSpan]="8">
+          <nz-form-item>
+            <nz-form-control>
+              <button nz-button nzType="primary" [disabled]="!addForm.valid || adding">Save</button>
+              <button nz-button type="button" (click)="cancelAdd()">Cancel</button>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+      </div>
+    </form>
+  </div>
+</zeppelin-page-header>
+<div class="content">
+  <nz-table nzSize="small"
+            [nzData]="credentialControls"
+            [nzFrontPagination]="false"
+            [nzShowPagination]="false">
+    <thead>
+    <tr>
+      <th>Entity</th>
+      <th>Username</th>
+      <th>Password</th>
+      <th nzWidth="225px" class="actions-head">Actions</th>
+    </tr>
+    </thead>
+    <tbody>
+    <tr *ngFor="let control of credentialControls">
+      <ng-container *ngIf="control.get('entity')?.value as entity" [formGroup]="control">
+        <td>{{entity}}</td>
+
+        <ng-container *ngIf="isEditing(control); else credentialDisplay">
+          <td><input nz-input formControlName="username"></td>
+          <td><input nz-input type="password" formControlName="password"></td>
+          <td class="credential-actions">
+            <button nz-button nzType="primary" (click)="saveCredential(control)"><i nz-icon nzType="save"
+                                                                                    nzTheme="outline"></i> Save
+            </button>
+            <button nz-button (click)="unsetEditable(control)"><i nz-icon nzType="close" nzTheme="outline"></i> Cancel
+            </button>
+          </td>
+        </ng-container>
+
+        <ng-template #credentialDisplay>
+          <td>{{control.get('username')?.value}}</td>
+          <td><strong>**********</strong></td>
+          <td class="credential-actions">
+            <button nz-button (click)="setEditable(control)"><i nz-icon nzType="edit" nzTheme="outline"></i> Edit
+            </button>
+            <button nz-button
+                    nz-popconfirm
+                    nzPopconfirmTitle="Do you want to delete this credential information?"
+                    (nzOnConfirm)="removeCredential(control)">
+              <i nz-icon nzType="delete" nzTheme="outline"></i> Remove
+            </button>
+          </td>
+        </ng-template>
+      </ng-container>
+    </tr>
+
+    </tbody>
+  </nz-table>
+</div>
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less
similarity index 56%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less
index 1e07b8e..87649ca 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less
@@ -10,8 +10,30 @@
  * limitations under the License.
  */
 
-export * from './ticket';
-export * from './trash-folder-id';
-export * from './interpreter';
-export * from './message-interceptor';
-export * from './security';
+@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 0000000..47150db
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts
@@ -0,0 +1,201 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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, NzMessageService } from 'ng-zorro-antd';
+
+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<string, CredentialForm> = 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 0000000..a126980
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts
@@ -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 { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { ShareModule } from '@zeppelin/share';
+import {
+  NzAutocompleteModule,
+  NzButtonModule,
+  NzCardModule,
+  NzDividerModule,
+  NzFormModule,
+  NzGridModule,
+  NzIconModule,
+  NzInputModule,
+  NzMessageModule,
+  NzPopconfirmModule,
+  NzTableModule,
+  NzToolTipModule
+} from 'ng-zorro-antd';
+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/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
index 1b6bedf..6815b80 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
@@ -48,6 +48,11 @@ const routes: Routes = [
         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)
       }
     ]
   }
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 0000000..0e08f7b
--- /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<Credential>(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/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts
index 155a3b2..6c3dbc0 100644
--- a/zeppelin-web-angular/src/app/services/public-api.ts
+++ b/zeppelin-web-angular/src/app/services/public-api.ts
@@ -28,3 +28,4 @@ export * from './note-list.service';
 export * from './runtime-compiler.service';
 export * from './shortcut.service';
 export * from './configuration.service';
+export * from './credential.service';


[zeppelin] 08/16: [ZEPPELIN-4501] Use secondary entry imports

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit bdc2940d4faa134769d440f30e9539059a26b29e
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Thu Dec 12 11:35:34 2019 +0800

    [ZEPPELIN-4501] Use secondary entry imports
    
    ### What is this PR for?
    
    Use secondary entry to speed up the build
    
    ### What type of PR is it?
    [Refactoring]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4501
    
    ### How should this be tested?
    
    Not applicable
    
    ### Screenshots (if appropriate)
    
    Not applicable
    
    ### Questions:
    * Does the licenses files need update? no
    * Is there breaking changes for older versions? no
    * Does this needs documentation? no
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3561 from hsuanxyz/refactor/use-secondary-entry and squashes the following commits:
    
    3c3e6e0be [Hsuan Lee] refactor: use secondary entry imports
---
 zeppelin-web-angular/package-lock.json             |   6 +
 zeppelin-web-angular/package.json                  |   1 +
 .../src/app/app-message.interceptor.ts             |   3 +-
 zeppelin-web-angular/src/app/app.module.ts         |   4 +-
 zeppelin-web-angular/src/app/core/public-api.ts    |   1 +
 .../index.ts}                                      |   5 +-
 .../runtime-dynamic-module/ng-zorro-antd-module.ts | 148 +++++++++++++++++++++
 .../{ => runtime-dynamic-module}/public-api.ts     |   5 +-
 .../runtime-dynamic-module.module.ts               |  10 ++
 .../src/app/pages/login/login.module.ts            |   5 +-
 .../configuration/configuration.module.ts          |   2 +-
 .../workspace/credential/credential.component.ts   |   3 +-
 .../workspace/credential/credential.module.ts      |  26 ++--
 .../src/app/pages/workspace/home/home.module.ts    |   4 +-
 .../create-repository-modal.component.ts           |   2 +-
 .../workspace/interpreter/interpreter.component.ts |   4 +-
 .../workspace/interpreter/interpreter.module.ts    |  38 +++---
 .../workspace/job-manager/job-manager.component.ts |   2 +-
 .../workspace/job-manager/job-manager.module.ts    |  31 ++---
 .../notebook-repos/notebook-repos.module.ts        |  16 +--
 .../notebook/action-bar/action-bar.component.ts    |   3 +-
 .../interpreter-binding.component.ts               |   2 +-
 .../pages/workspace/notebook/notebook.module.ts    |  32 +++--
 .../paragraph/control/control.component.ts         |   3 +-
 .../notebook/permissions/permissions.component.ts  |   3 +-
 .../pages/workspace/notebook/share/share.module.ts |   2 +-
 .../share/dynamic-forms/dynamic-forms.component.ts |   2 +-
 .../src/app/pages/workspace/share/share.module.ts  |  18 ++-
 .../src/app/pages/workspace/workspace.component.ts |   2 +-
 .../app/services/ng-template-adapter.service.ts    |   2 +-
 .../src/app/services/note-action.service.ts        |   2 +-
 .../src/app/services/runtime-compiler.service.ts   |   7 +-
 .../src/app/services/ticket.service.ts             |   2 +-
 .../share/folder-rename/folder-rename.component.ts |   2 +-
 .../src/app/share/header/header.component.ts       |   2 +-
 .../share/ng1-migration/ng1-migration.component.ts |   2 +-
 .../src/app/share/node-list/node-list.component.ts |   3 +-
 .../app/share/note-create/note-create.component.ts |   2 +-
 .../app/share/note-import/note-import.component.ts |   3 +-
 .../app/share/note-rename/note-rename.component.ts |   2 +-
 .../app/share/page-header/page-header.component.ts |   2 +-
 zeppelin-web-angular/src/app/share/share.module.ts |  46 +++----
 .../table/table-visualization.component.ts         |   2 +-
 .../src/app/visualizations/visualization.module.ts |  26 ++--
 zeppelin-web-angular/tslint.json                   |   3 +-
 45 files changed, 324 insertions(+), 167 deletions(-)

diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json
index cd5fb2f..da898b0 100644
--- a/zeppelin-web-angular/package-lock.json
+++ b/zeppelin-web-angular/package-lock.json
@@ -10311,6 +10311,12 @@
       "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",
diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json
index 9d9aa93..670c73c 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -74,6 +74,7 @@
     "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",
diff --git a/zeppelin-web-angular/src/app/app-message.interceptor.ts b/zeppelin-web-angular/src/app/app-message.interceptor.ts
index 0e9843d..02fdf96 100644
--- a/zeppelin-web-angular/src/app/app-message.interceptor.ts
+++ b/zeppelin-web-angular/src/app/app-message.interceptor.ts
@@ -13,7 +13,8 @@
 import { Injectable } from '@angular/core';
 import { Router } from '@angular/router';
 
-import { NzModalService, NzNotificationService } from 'ng-zorro-antd';
+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';
diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts
index ae3347c..06be7f4 100644
--- a/zeppelin-web-angular/src/app/app.module.ts
+++ b/zeppelin-web-angular/src/app/app.module.ts
@@ -20,7 +20,9 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { Router, RouterModule } from '@angular/router';
 
 import { ZeppelinHeliumModule } from '@zeppelin/helium';
-import { en_US, NzModalService, NzNotificationService, NZ_I18N } from 'ng-zorro-antd';
+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 { loadMonacoLanguage } from '@zeppelin/languages';
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/public-api.ts
index 3bcd355..3f334c8 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/public-api.ts
@@ -14,3 +14,4 @@ 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/public-api.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts
similarity index 80%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts
index 3bcd355..49e4740 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts
@@ -10,7 +10,4 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
-export * from './copy-text';
-export * from './paragraph-base';
+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 0000000..42c2d11
--- /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/public-api.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts
similarity index 80%
copy from zeppelin-web-angular/src/app/core/public-api.ts
copy to zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts
index 3bcd355..a8a0702 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts
@@ -10,7 +10,4 @@
  * 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.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 0000000..d6cb44c
--- /dev/null
+++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts
@@ -0,0 +1,10 @@
+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/pages/login/login.module.ts b/zeppelin-web-angular/src/app/pages/login/login.module.ts
index 46f40a0..7a040a6 100644
--- a/zeppelin-web-angular/src/app/pages/login/login.module.ts
+++ b/zeppelin-web-angular/src/app/pages/login/login.module.ts
@@ -14,7 +14,10 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 
-import { NzButtonModule, NzFormModule, NzIconModule, NzInputModule } from 'ng-zorro-antd';
+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';
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
index ff64f89..9540170 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts
@@ -13,7 +13,7 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 
 import { ShareModule } from '@zeppelin/share';
-import { NzTableModule } from 'ng-zorro-antd';
+import { NzTableModule } from 'ng-zorro-antd/table';
 import { ConfigurationRoutingModule } from './configuration-routing.module';
 import { ConfigurationComponent } from './configuration.component';
 
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
index 47150db..b28a6a6 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts
@@ -12,7 +12,8 @@
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
 import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
-import { collapseMotion, NzMessageService } from 'ng-zorro-antd';
+import { collapseMotion } from 'ng-zorro-antd/core';
+import { NzMessageService } from 'ng-zorro-antd/message';
 
 import { finalize } from 'rxjs/operators';
 
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
index a126980..39756ed 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts
@@ -14,20 +14,18 @@ import { NgModule } from '@angular/core';
 
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { ShareModule } from '@zeppelin/share';
-import {
-  NzAutocompleteModule,
-  NzButtonModule,
-  NzCardModule,
-  NzDividerModule,
-  NzFormModule,
-  NzGridModule,
-  NzIconModule,
-  NzInputModule,
-  NzMessageModule,
-  NzPopconfirmModule,
-  NzTableModule,
-  NzToolTipModule
-} from 'ng-zorro-antd';
+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';
 
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
index 24e59a7..49a2973 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts
@@ -13,7 +13,9 @@
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 
-import { NzGridModule, NzIconModule, NzToolTipModule } from 'ng-zorro-antd';
+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';
 
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
index 8dd38c9..90e02a7 100644
--- 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
@@ -14,7 +14,7 @@ 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';
+import { NzModalRef } from 'ng-zorro-antd/modal';
 
 import { DestroyHookComponent } from '@zeppelin/core';
 import { CreateInterpreterRepositoryForm } from '@zeppelin/interfaces';
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
index 8e21628..0507cd8 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts
@@ -14,7 +14,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnIni
 import { Subject } from 'rxjs';
 import { debounceTime } from 'rxjs/operators';
 
-import { collapseMotion, NzMessageService, NzModalService } from 'ng-zorro-antd';
+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';
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
index 37a9a0e..6ed202f 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts
@@ -13,26 +13,24 @@
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import {
-  NzAlertModule,
-  NzBadgeModule,
-  NzButtonModule,
-  NzCardModule,
-  NzCheckboxModule,
-  NzDividerModule,
-  NzDropDownModule,
-  NzFormModule,
-  NzIconModule,
-  NzInputModule,
-  NzMessageModule,
-  NzModalModule,
-  NzRadioModule,
-  NzSelectModule,
-  NzSwitchModule,
-  NzTableModule,
-  NzTagModule,
-  NzToolTipModule
-} from 'ng-zorro-antd';
+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';
 
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
index 8e426fd..fef8441 100644
--- 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
@@ -13,7 +13,7 @@
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
 import { FormBuilder, FormGroup } from '@angular/forms';
 
-import { NzModalService } from 'ng-zorro-antd';
+import { NzModalService } from 'ng-zorro-antd/modal';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { JobsItem, JobStatus, ListNoteJobs, ListUpdateNoteJobs, OP } from '@zeppelin/sdk';
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
index 5ce1f07..c8b1b18 100644
--- 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
@@ -16,23 +16,20 @@ 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,
-  NzCardModule,
-  NzDividerModule,
-  NzEmptyModule,
-  NzFormModule,
-  NzGridModule,
-  NzHighlightModule,
-  NzIconModule,
-  NzInputModule,
-  NzModalModule,
-  NzProgressModule,
-  NzSelectModule,
-  NzSkeletonModule,
-  NzToolTipModule,
-  NZ_ICONS
-} from 'ng-zorro-antd';
+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';
 
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
index 2bb9d25..9f30074 100644
--- 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
@@ -14,15 +14,13 @@ import { NgModule } from '@angular/core';
 
 import { ShareModule } from '@zeppelin/share';
 
-import {
-  NzButtonModule,
-  NzCardModule,
-  NzFormModule,
-  NzIconModule,
-  NzInputModule,
-  NzSelectModule,
-  NzTableModule
-} from 'ng-zorro-antd';
+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';
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
index f4968d7..994acc1 100644
--- 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
@@ -21,7 +21,8 @@ import {
   Output
 } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
-import { NzMessageService, NzModalService } from 'ng-zorro-antd';
+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';
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
index 377a869..34a9990 100644
--- 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
@@ -13,7 +13,7 @@
 import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop';
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core';
 
-import { NzModalService } from 'ng-zorro-antd';
+import { NzModalService } from 'ng-zorro-antd/modal';
 
 import { InterpreterBindingItem } from '@zeppelin/sdk';
 import { InterpreterService, MessageService } from '@zeppelin/services';
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
index 0258bbe..64cfdee 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -16,24 +16,22 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
-import {
-  NzButtonModule,
-  NzDividerModule,
-  NzDropDownModule,
-  NzFormModule,
-  NzGridModule,
-  NzIconModule,
-  NzInputModule,
-  NzNoAnimationModule,
-  NzPopconfirmModule,
-  NzPopoverModule,
-  NzProgressModule,
-  NzRadioModule,
-  NzSelectModule,
-  NzSwitchModule,
-  NzToolTipModule
-} from 'ng-zorro-antd';
+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';
 
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
index eacf2da..846a46d 100644
--- 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
@@ -23,7 +23,8 @@ import {
 } from '@angular/core';
 import { copyTextToClipboard } from '@zeppelin/core';
 
-import { NzMessageService, NzModalService } from 'ng-zorro-antd';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
 
 import { ActivatedRoute } from '@angular/router';
 import { RuntimeInfos } from '@zeppelin/sdk';
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
index eb749c1..6ceaaeb 100644
--- 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
@@ -21,7 +21,8 @@ import {
   Output
 } from '@angular/core';
 
-import { NzMessageService, NzModalService } from 'ng-zorro-antd';
+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';
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
index c97c48e..b8ae9a7 100644
--- 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
@@ -14,7 +14,7 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 
-import { NzInputModule } from 'ng-zorro-antd';
+import { NzInputModule } from 'ng-zorro-antd/input';
 
 import { ElasticInputComponent } from './elastic-input/elastic-input.component';
 
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
index 0dab7ec..338a434 100644
--- 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
@@ -25,7 +25,7 @@ import {
 import { Subject } from 'rxjs';
 import { debounceTime, takeUntil } from 'rxjs/operators';
 
-import { NzCheckBoxOptionInterface } from 'ng-zorro-antd';
+import { NzCheckBoxOptionInterface } from 'ng-zorro-antd/checkbox';
 
 import { DynamicForms, DynamicFormsItem, DynamicFormsType, DynamicFormParams } from '@zeppelin/sdk';
 
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
index 4c7ef1d..a381779 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
@@ -15,17 +15,15 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 
-import {
-  NzButtonModule,
-  NzCheckboxModule,
-  NzDropDownModule,
-  NzIconModule,
-  NzRadioModule,
-  NzSelectModule,
-  NzSwitchModule,
-  NzToolTipModule
-} from 'ng-zorro-antd';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
+import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
+import { NzIconModule } from 'ng-zorro-antd/icon';
+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';
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index c89d287e..976e44b 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -18,7 +18,7 @@ import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router';
 import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published';
 import { HeliumManagerService } from '@zeppelin/helium-manager';
 import { MessageService } from '@zeppelin/services';
-import { log } from 'ng-zorro-antd';
+import { log } from 'ng-zorro-antd/core';
 
 @Component({
   selector: 'zeppelin-workspace',
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
index 651b709..f965e1d 100644
--- a/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts
+++ b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts
@@ -12,7 +12,7 @@
 
 import { Injectable } from '@angular/core';
 import { Ng1MigrationComponent } from '@zeppelin/share/ng1-migration/ng1-migration.component';
-import { NzModalService } from 'ng-zorro-antd';
+import { NzModalService } from 'ng-zorro-antd/modal';
 import { Observable } from 'rxjs';
 
 export interface NgTemplateCheckResult {
diff --git a/zeppelin-web-angular/src/app/services/note-action.service.ts b/zeppelin-web-angular/src/app/services/note-action.service.ts
index 8a2bd10..44e0ca8 100644
--- a/zeppelin-web-angular/src/app/services/note-action.service.ts
+++ b/zeppelin-web-angular/src/app/services/note-action.service.ts
@@ -12,7 +12,7 @@
 
 import { Injectable } from '@angular/core';
 
-import { NzModalService } from 'ng-zorro-antd';
+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';
diff --git a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
index 9c91b69..8ec7f2c 100644
--- a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
+++ b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
@@ -10,7 +10,6 @@
  * limitations under the License.
  */
 
-import { CommonModule } from '@angular/common';
 import {
   Compiler,
   Component,
@@ -20,10 +19,8 @@ import {
   NgModuleFactory,
   Type
 } from '@angular/core';
-import { FormsModule } from '@angular/forms';
-
-import { NgZorroAntdModule } from 'ng-zorro-antd';
 
+import { RuntimeDynamicModuleModule } from '@zeppelin/core';
 import { NgZService } from './ng-z.service';
 
 export class DynamicTemplate {
@@ -63,7 +60,7 @@ export class RuntimeCompilerService {
       declarations: [dynamicComponent],
       exports: [dynamicComponent],
       entryComponents: [dynamicComponent],
-      imports: [CommonModule, NgZorroAntdModule, FormsModule]
+      imports: [RuntimeDynamicModuleModule]
     })(class DynamicModule {});
 
     this.compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule);
diff --git a/zeppelin-web-angular/src/app/services/ticket.service.ts b/zeppelin-web-angular/src/app/services/ticket.service.ts
index 9254cdc..a23bc0d 100644
--- a/zeppelin-web-angular/src/app/services/ticket.service.ts
+++ b/zeppelin-web-angular/src/app/services/ticket.service.ts
@@ -16,7 +16,7 @@ import { Router } from '@angular/router';
 import { forkJoin, BehaviorSubject, Subject } from 'rxjs';
 import { map, tap } from 'rxjs/operators';
 
-import { NzMessageService } from 'ng-zorro-antd';
+import { NzMessageService } from 'ng-zorro-antd/message';
 
 import { ITicket, ITicketWrapped, IZeppelinVersion } from '@zeppelin/interfaces';
 import { ConfigurationsInfo } from '@zeppelin/sdk';
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
index 250dac3..4b50f3b 100644
--- 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
@@ -12,7 +12,7 @@
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
 
-import { NzModalRef } from 'ng-zorro-antd';
+import { NzModalRef } from 'ng-zorro-antd/modal';
 
 import { MessageService } from '@zeppelin/services/message.service';
 import { NoteListService } from '@zeppelin/services/note-list.service';
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts
index d9e4cc7..e69b89e 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.ts
+++ b/zeppelin-web-angular/src/app/share/header/header.component.ts
@@ -12,7 +12,7 @@
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
 import { NavigationEnd, Router } from '@angular/router';
-import { NzModalService } from 'ng-zorro-antd';
+import { NzModalService } from 'ng-zorro-antd/modal';
 
 import { Subject } from 'rxjs';
 import { filter, takeUntil } from 'rxjs/operators';
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
index 340330e..eaf32db 100644
--- 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
@@ -1,6 +1,6 @@
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core';
 import { editor, IDisposable, Range } from 'monaco-editor';
-import { NzModalRef } from 'ng-zorro-antd';
+import { NzModalRef } from 'ng-zorro-antd/modal';
 import {
   defaultTemplateUpdaterRules,
   LogLevel,
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
index c9206fd..5d9abb4 100644
--- 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
@@ -12,7 +12,8 @@
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
 
-import { NzModalService, NzTreeNode } from 'ng-zorro-antd';
+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';
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
index 42d9a95..dfa9af4 100644
--- 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
@@ -12,7 +12,7 @@
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
 
-import { NzModalRef } from 'ng-zorro-antd';
+import { NzModalRef } from 'ng-zorro-antd/modal';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { InterpreterItem, MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk';
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
index 4e928c9..7317b34 100644
--- 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
@@ -14,7 +14,8 @@ import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
 
 import { get } from 'lodash';
-import { NzModalRef, UploadFile } from 'ng-zorro-antd';
+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';
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
index 3b07b8d..1413e1d 100644
--- 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
@@ -12,7 +12,7 @@
 
 import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 
-import { NzModalRef } from 'ng-zorro-antd';
+import { NzModalRef } from 'ng-zorro-antd/modal';
 
 import { MessageService } from '@zeppelin/services/message.service';
 
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
index 601726e..0ec5925 100644
--- 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
@@ -11,7 +11,7 @@
  */
 
 import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core';
-import { InputBoolean } from 'ng-zorro-antd';
+import { InputBoolean } from 'ng-zorro-antd/core';
 
 @Component({
   selector: 'zeppelin-page-header',
diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts
index 3f7a003..26047e4 100644
--- a/zeppelin-web-angular/src/app/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/share/share.module.ts
@@ -15,30 +15,28 @@ import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 
-import {
-  NzAddOnModule,
-  NzAlertModule,
-  NzBadgeModule,
-  NzButtonModule,
-  NzCardModule,
-  NzDividerModule,
-  NzDropDownModule,
-  NzFormModule,
-  NzGridModule,
-  NzIconModule,
-  NzInputModule,
-  NzMenuModule,
-  NzMessageModule,
-  NzModalModule,
-  NzNotificationModule,
-  NzPopconfirmModule,
-  NzProgressModule,
-  NzSelectModule,
-  NzTabsModule,
-  NzToolTipModule,
-  NzTreeModule,
-  NzUploadModule
-} from 'ng-zorro-antd';
+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';
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
index 09fa077..d098631 100644
--- a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts
+++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts
@@ -13,7 +13,7 @@
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, ViewChild } from '@angular/core';
 
 import { filter, maxBy, minBy, orderBy, sumBy } from 'lodash';
-import { NzTableComponent } from 'ng-zorro-antd';
+import { NzTableComponent } from 'ng-zorro-antd/table';
 import { utils, writeFile, WorkSheet } from 'xlsx';
 
 import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization';
diff --git a/zeppelin-web-angular/src/app/visualizations/visualization.module.ts b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts
index fe2f4a1..ab72210 100644
--- a/zeppelin-web-angular/src/app/visualizations/visualization.module.ts
+++ b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts
@@ -15,20 +15,18 @@ import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 
-import {
-  NzButtonModule,
-  NzCardModule,
-  NzCheckboxModule,
-  NzDropDownModule,
-  NzFormModule,
-  NzGridModule,
-  NzIconModule,
-  NzInputModule,
-  NzMenuModule,
-  NzRadioModule,
-  NzTableModule,
-  NzTagModule
-} from 'ng-zorro-antd';
+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';
diff --git a/zeppelin-web-angular/tslint.json b/zeppelin-web-angular/tslint.json
index 74aed25..045107b 100644
--- a/zeppelin-web-angular/tslint.json
+++ b/zeppelin-web-angular/tslint.json
@@ -1,6 +1,7 @@
 {
-  "rulesDirectory": ["node_modules/codelyzer"],
+  "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,


[zeppelin] 05/16: [ZEPPELIN-4401] Add configuration page

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 1edc985da91d054208e83f98244711bda5913d9c
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Dec 3 15:18:13 2019 +0800

    [ZEPPELIN-4401] Add configuration page
    
    ### What is this PR for?
    
    Add the configuration page on the reworked  with Angular project
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4401
    
    ### How should this be tested?
    
    Not applicable
    
    ### Screenshots (if appropriate)
    
    ![image](https://user-images.githubusercontent.com/22736418/70121058-cb56c680-16a8-11ea-9ee5-3375a2bc76d6.png)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3532 from hsuanxyz/feat/configuration and squashes the following commits:
    
    2e2ee0c2b [Hsuan Lee] feat: add configuration page
---
 .../configuration/configuration-routing.module.ts  | 27 ++++++++++++++++
 .../configuration/configuration.component.html     | 37 ++++++++++++++++++++++
 .../configuration/configuration.component.less     | 22 +++++++++++++
 .../configuration/configuration.component.ts       | 36 +++++++++++++++++++++
 .../configuration/configuration.module.ts          | 24 ++++++++++++++
 .../pages/workspace/workspace-routing.module.ts    |  5 +++
 .../configuration.service.ts}                      | 29 ++++++++---------
 .../src/app/services/public-api.ts                 |  1 +
 .../share/page-header/page-header.component.html   |  2 +-
 .../app/share/page-header/page-header.component.ts |  2 +-
 zeppelin-web-angular/src/app/share/share.module.ts |  2 ++
 11 files changed, 170 insertions(+), 17 deletions(-)

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 0000000..6d499a0
--- /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 0000000..6708f34
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html
@@ -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.
+  -->
+
+<zeppelin-page-header [description]="configDesc" title="Configurations"></zeppelin-page-header>
+<ng-template #configDesc>
+  Shows current configurations for Zeppelin Server.
+  <br>
+  Note: For security reasons, some key/value pairs including passwords would not be shown.
+</ng-template>
+<div class="content">
+  <nz-table nzSize="small"
+            [nzData]="configEntries"
+            [nzFrontPagination]="false"
+            [nzShowPagination]="false">
+    <thead>
+    <tr>
+      <th>Name</th>
+      <th>Value</th>
+    </tr>
+    </thead>
+    <tbody>
+    <tr *ngFor="let data of configEntries">
+      <td>{{data[0]}}</td>
+      <td>{{data[1]}}</td>
+    </tr>
+    </tbody>
+  </nz-table>
+</div>
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 0000000..b3c4ee2
--- /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 0000000..fb3b120
--- /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<string>(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 0000000..ff64f89
--- /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';
+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/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
index 9315443..1b6bedf 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
@@ -43,6 +43,11 @@ const routes: Routes = [
         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)
       }
     ]
   }
diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts b/zeppelin-web-angular/src/app/services/configuration.service.ts
similarity index 50%
copy from zeppelin-web-angular/src/app/share/page-header/page-header.component.ts
copy to zeppelin-web-angular/src/app/services/configuration.service.ts
index 1c03ee6..b8c392f 100644
--- a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts
+++ b/zeppelin-web-angular/src/app/services/configuration.service.ts
@@ -10,22 +10,21 @@
  * limitations under the License.
  */
 
-import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core';
-import { InputBoolean } from 'ng-zorro-antd';
+import { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/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;
-  @Input() @InputBoolean() divider = false;
-  @Input() extra: TemplateRef<void>;
+import { BaseRest } from './base-rest';
+import { BaseUrlService } from './base-url.service';
 
-  constructor() {}
+@Injectable({
+  providedIn: 'root'
+})
+export class ConfigurationService extends BaseRest {
+  constructor(baseUrlService: BaseUrlService, private http: HttpClient) {
+    super(baseUrlService);
+  }
 
-  ngOnInit() {}
+  getAll() {
+    return this.http.get<{ [key: string]: string }>(this.restUrl`/configurations/all`);
+  }
 }
diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts
index d6709ac..155a3b2 100644
--- a/zeppelin-web-angular/src/app/services/public-api.ts
+++ b/zeppelin-web-angular/src/app/services/public-api.ts
@@ -27,3 +27,4 @@ export * from './array-ordering.service';
 export * from './note-list.service';
 export * from './runtime-compiler.service';
 export * from './shortcut.service';
+export * from './configuration.service';
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
index 430f7e2..c214ab4 100644
--- 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
@@ -12,7 +12,7 @@
 
 <nz-card class="header">
   <h2>{{title}} <span class="header-extra"><ng-container [ngTemplateOutlet]="extra"></ng-container></span></h2>
-  <p>{{description}}</p>
+  <p><ng-container *nzStringTemplateOutlet="description">{{description}}</ng-container></p>
   <nz-divider *ngIf="divider" nzType="horizontal"></nz-divider>
   <ng-content></ng-content>
 </nz-card>
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
index 1c03ee6..601726e 100644
--- 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
@@ -21,7 +21,7 @@ import { InputBoolean } from 'ng-zorro-antd';
 })
 export class PageHeaderComponent implements OnInit {
   @Input() title: string;
-  @Input() description: string;
+  @Input() description: string | TemplateRef<void>;
   @Input() @InputBoolean() divider = false;
   @Input() extra: TemplateRef<void>;
 
diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts
index fcb0375..3f7a003 100644
--- a/zeppelin-web-angular/src/app/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/share/share.module.ts
@@ -16,6 +16,7 @@ import { FormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 
 import {
+  NzAddOnModule,
   NzAlertModule,
   NzBadgeModule,
   NzButtonModule,
@@ -74,6 +75,7 @@ const PIPES = [HumanizeBytesPipe];
     FormsModule,
     CommonModule,
     NzMenuModule,
+    NzAddOnModule,
     NzIconModule,
     NzInputModule,
     NzDropDownModule,


[zeppelin] 01/16: [ZEPPELIN-4321] Rework Zeppelin with Latest Angular

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 6af0934c6ee9706437c28431be55ab3763bb850a
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Oct 29 17:32:14 2019 +0800

    [ZEPPELIN-4321] Rework Zeppelin with Latest Angular
    
    ### What is this PR for?
    
    The old version of zeppelin was written with AngularJS, there exist many issues related to the zeppelin-web and could not resolve due to the low version of AngularJS.
    
    So we rework the zeppelin-web with the latest Angular (8.0).
    
    ### What type of PR is it?
    
    Feature
    
    ### 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 |
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4321
    https://issues.apache.org/jira/browse/ZEPPELIN-4215
    
    ### How should this be tested?
    
    #### 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
    
    ```bash
    $ cd zeppelin-frontend
    $ npm install
    ```
    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
    
    ```bash
    $ npm start
    ```
    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.
    
    ### Screenshots (if appropriate)
    
    **Login**
    
    ![login](https://user-images.githubusercontent.com/22736418/67387927-62206580-f5ca-11e9-8268-e7036f32ea1c.png)
    
    **Home**
    
    ![image](https://user-images.githubusercontent.com/22736418/67388288-f4286e00-f5ca-11e9-9265-c9290830a5cd.png)
    ![image](https://user-images.githubusercontent.com/22736418/67388304-f8ed2200-f5ca-11e9-9368-09b00edd1d67.png)
    
    **Interpreter**
    
    ![zp-interpreter](https://user-images.githubusercontent.com/22736418/67388335-086c6b00-f5cb-11e9-9d03-add1054c3aeb.gif)
    
    **Job Manager**
    
    ![zp-jm](https://user-images.githubusercontent.com/22736418/67388392-21751c00-f5cb-11e9-8170-f311fd0dced4.gif)
    
    **Dynamic Form**
    
    ![zp-df](https://user-images.githubusercontent.com/22736418/67388447-3ce02700-f5cb-11e9-90dd-cee932fa685c.gif)
    
    **Frontend API(latest Angular)**
    
    ![zp-ng](https://user-images.githubusercontent.com/22736418/67388538-70bb4c80-f5cb-11e9-921d-6c34a4a99711.gif)
    
    ** Visualization**
    
    ![zp-vis](https://user-images.githubusercontent.com/22736418/67388602-8c265780-f5cb-11e9-9de9-e198878bee09.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? Maybe
    * Does this needs documentation? YES
    
    Author: Hsuan Lee <hs...@gmail.com>
    Author: Wendell <we...@gmail.com>
    Author: vthinkxie <ya...@alibaba-inc.com>
    
    Closes #3490 from hsuanxyz/frontend-next and squashes the following commits:
    
    cb673df36 [Hsuan Lee] chore: named TODOs
    826b6d4c3 [Hsuan Lee] ci: add exclude item
    10ea71e45 [Hsuan Lee] ci: fix ci config
    d48b8f9dd [Hsuan Lee] chore: rename the dirname to zeppelin-web-angular
    ec4475ca6 [Hsuan Lee] chore: update LICENSE and add pom.xml in zeppelin-frontend
    d0dc19493 [Hsuan Lee] chore: add `package-lock.json` to version control
    06efeda1f [Hsuan Lee] docs: update frontend README
    e7f10d201 [Hsuan Lee] chore: add license header in `*.(js|md)`
    564930676 [Hsuan Lee] chore: add license header
    8a07902ad [Hsuan Lee] chore: update theme variables
    10f7c78e0 [Hsuan Lee] chore: remove commit-lint
    03ff8d58a [Hsuan Lee] fix: code editor language highlight
    f53ad5450 [Hsuan Lee] docs: update frontend README
    95bccaf45 [Wendell] feat: add code editor
    4ea8b5046 [Hsuan Lee] feat: add visualizations
    3d02d0e9e [vthinkxie] chore: support basic features of zeppelin
    eafc5194e [Hsuan Lee] feat: add base services
    27c5bdf25 [Hsuan Lee] feat: add common projects
    0c39614c3 [Hsuan Lee] zeppelin-frontend init commit
---
 .travis.yml                                        |    11 +
 LICENSE                                            |     7 +-
 pom.xml                                            |    15 +-
 zeppelin-web-angular/.editorconfig                 |    15 +
 zeppelin-web-angular/.gitignore                    |    47 +
 zeppelin-web-angular/.prettierignore               |     3 +
 zeppelin-web-angular/.prettierrc                   |    15 +
 zeppelin-web-angular/README.md                     |   276 +
 zeppelin-web-angular/WEB-INF/web.xml               |    41 +
 zeppelin-web-angular/angular.json                  |   330 +
 zeppelin-web-angular/browserslist                  |    12 +
 zeppelin-web-angular/e2e/protractor.conf.js        |    44 +
 zeppelin-web-angular/e2e/src/app.e2e-spec.ts       |    23 +
 zeppelin-web-angular/e2e/src/app.po.ts             |    11 +
 zeppelin-web-angular/e2e/tsconfig.json             |    13 +
 zeppelin-web-angular/karma.conf.js                 |    44 +
 zeppelin-web-angular/package-lock.json             | 15996 +++++++++++++++++++
 zeppelin-web-angular/package.json                  |    96 +
 zeppelin-web-angular/pom.xml                       |   174 +
 .../projects/helium-vis-example/README.md          |    36 +
 .../projects/helium-vis-example/karma.conf.js      |    44 +
 .../projects/helium-vis-example/ng-package.json    |     7 +
 .../projects/helium-vis-example/package.json       |     8 +
 .../helium-vis-example/src/json-vis.component.ts   |    43 +
 .../helium-vis-example/src/json-vis.module.ts      |    23 +
 .../helium-vis-example/src/json-visualization.ts   |    64 +
 .../projects/helium-vis-example/src/public-api.ts  |    30 +
 .../projects/helium-vis-example/src/test.ts        |    33 +
 .../projects/helium-vis-example/tsconfig.lib.json  |    26 +
 .../projects/helium-vis-example/tsconfig.spec.json |    17 +
 .../projects/helium-vis-example/tslint.json        |    17 +
 .../projects/zeppelin-helium/README.md             |    36 +
 .../projects/zeppelin-helium/karma.conf.js         |    44 +
 .../projects/zeppelin-helium/ng-package.json       |     7 +
 .../projects/zeppelin-helium/package.json          |    12 +
 .../projects/zeppelin-helium/src/common-deps.ts    |    43 +
 .../projects/zeppelin-helium/src/index.ts          |    13 +
 .../projects/zeppelin-helium/src/public-api.ts     |    18 +
 .../projects/zeppelin-helium/src/test.ts           |    33 +
 .../zeppelin-helium/src/zeppelin-helium.module.ts  |    16 +
 .../zeppelin-helium/src/zeppelin-helium.service.ts |    96 +
 .../projects/zeppelin-helium/tsconfig.lib.json     |    27 +
 .../projects/zeppelin-helium/tsconfig.spec.json    |    17 +
 .../projects/zeppelin-helium/tslint.json           |    17 +
 .../projects/zeppelin-sdk/README.md                |    36 +
 .../projects/zeppelin-sdk/karma.conf.js            |    44 +
 .../projects/zeppelin-sdk/ng-package.json          |     7 +
 .../projects/zeppelin-sdk/package.json             |     8 +
 .../projects/zeppelin-sdk/src/index.ts             |    13 +
 .../projects/zeppelin-sdk/src/interfaces/index.ts  |    13 +
 .../src/interfaces/message-common.interface.ts     |   129 +
 .../interfaces/message-data-type-map.interface.ts  |   164 +
 .../interfaces/message-interpreter.interface.ts    |    70 +
 .../src/interfaces/message-job.interface.ts        |    48 +
 .../src/interfaces/message-notebook.interface.ts   |   209 +
 .../src/interfaces/message-operator.interface.ts   |   482 +
 .../src/interfaces/message-paragraph.interface.ts  |   467 +
 .../zeppelin-sdk/src/interfaces/public-api.ts      |    20 +
 .../src/interfaces/websocket-message.interface.ts  |    21 +
 .../projects/zeppelin-sdk/src/message.ts           |   502 +
 .../projects/zeppelin-sdk/src/public-api.ts        |    15 +
 .../projects/zeppelin-sdk/tsconfig.lib.json        |    27 +
 .../projects/zeppelin-sdk/tsconfig.spec.json       |    17 +
 .../projects/zeppelin-sdk/tslint.json              |    17 +
 .../projects/zeppelin-visualization/README.md      |    36 +
 .../projects/zeppelin-visualization/karma.conf.js  |    44 +
 .../zeppelin-visualization/ng-package.json         |     7 +
 .../projects/zeppelin-visualization/package.json   |     8 +
 .../zeppelin-visualization/src/data-set.ts         |    17 +
 .../src/g2-visualization-base.ts                   |    57 +
 .../src/g2-visualization-component-base.ts         |    93 +
 .../projects/zeppelin-visualization/src/index.ts   |    13 +
 .../src/pivot-transformation.ts                    |   199 +
 .../zeppelin-visualization/src/public-api.ts       |    25 +
 .../zeppelin-visualization/src/table-data.ts       |    35 +
 .../src/table-transformation.ts                    |    26 +
 .../zeppelin-visualization/src/transformation.ts   |    46 +
 .../src/visualization-component-portal.ts          |    46 +
 .../zeppelin-visualization/src/visualization.ts    |    44 +
 .../zeppelin-visualization/tsconfig.lib.json       |    27 +
 .../zeppelin-visualization/tsconfig.spec.json      |    17 +
 .../projects/zeppelin-visualization/tslint.json    |    17 +
 zeppelin-web-angular/proxy.conf.js                 |    59 +
 zeppelin-web-angular/screenshot.png                |   Bin 0 -> 220058 bytes
 zeppelin-web-angular/src/.editorconfig             |    12 +
 zeppelin-web-angular/src/.gitignore                |    43 +
 .../src/app/app-http.interceptor.ts                |    53 +
 .../src/app/app-message.interceptor.ts             |    68 +
 zeppelin-web-angular/src/app/app-routing.module.ts |    36 +
 .../src/app/app-runtime-compiler.providers.ts      |    41 +
 zeppelin-web-angular/src/app/app.component.html    |    15 +
 zeppelin-web-angular/src/app/app.component.less    |    26 +
 zeppelin-web-angular/src/app/app.component.spec.ts |    30 +
 zeppelin-web-angular/src/app/app.component.ts      |    39 +
 zeppelin-web-angular/src/app/app.module.ts         |    88 +
 .../app/core/copy-text/copy-text-to-clipboard.ts   |    65 +
 .../src/app/core/copy-text/index.ts                |    13 +
 .../src/app/core/copy-text/public-api.ts           |    13 +
 .../core/destroy-hook/destroy-hook.component.ts    |    23 +
 .../src/app/core/destroy-hook/index.ts             |    13 +
 .../src/app/core/destroy-hook/public-api.ts        |    13 +
 zeppelin-web-angular/src/app/core/index.ts         |    13 +
 .../src/app/core/message-listener/index.ts         |    13 +
 .../app/core/message-listener/message-listener.ts  |    59 +
 .../src/app/core/message-listener/public-api.ts    |    13 +
 zeppelin-web-angular/src/app/core/public-api.ts    |    15 +
 .../app/helium-manager/helium-manager.module.ts    |    27 +
 .../app/helium-manager/helium-manager.service.ts   |    75 +
 .../src/app/helium-manager/index.ts                |    13 +
 .../src/app/helium-manager/public-api.ts           |    14 +
 zeppelin-web-angular/src/app/interfaces/index.ts   |    13 +
 .../src/app/interfaces/interpreter.ts              |   104 +
 .../src/app/interfaces/message-interceptor.ts      |    20 +
 .../src/app/interfaces/node-list.ts                |    41 +
 .../src/app/interfaces/public-api.ts               |    17 +
 .../src/app/interfaces/security.ts                 |    23 +
 zeppelin-web-angular/src/app/interfaces/ticket.ts  |    29 +
 .../src/app/interfaces/trash-folder-id.ts          |    15 +
 zeppelin-web-angular/src/app/languages/index.ts    |    13 +
 zeppelin-web-angular/src/app/languages/load.ts     |    20 +
 .../src/app/languages/public-api.ts                |    14 +
 zeppelin-web-angular/src/app/languages/scala.ts    |   236 +
 .../src/app/pages/login/login-routing.module.ts    |    29 +
 .../src/app/pages/login/login.component.html       |    46 +
 .../src/app/pages/login/login.component.less       |    69 +
 .../src/app/pages/login/login.component.ts         |    47 +
 .../src/app/pages/login/login.module.ts            |    26 +
 .../pages/workspace/home/home-routing.module.ts    |    29 +
 .../app/pages/workspace/home/home.component.html   |    41 +
 .../app/pages/workspace/home/home.component.less   |    37 +
 .../src/app/pages/workspace/home/home.component.ts |    48 +
 .../src/app/pages/workspace/home/home.module.ts    |    27 +
 .../create-repository-modal.component.html         |   158 +
 .../create-repository-modal.component.less         |    19 +
 .../create-repository-modal.component.ts           |    78 +
 .../interpreter/interpreter-routing.module.ts      |    29 +
 .../interpreter/interpreter.component.html         |    66 +
 .../interpreter/interpreter.component.less         |    51 +
 .../workspace/interpreter/interpreter.component.ts |   186 +
 .../workspace/interpreter/interpreter.module.ts    |    73 +
 .../workspace/interpreter/item/item.component.html |   447 +
 .../workspace/interpreter/item/item.component.less |   105 +
 .../workspace/interpreter/item/item.component.ts   |   405 +
 .../job-manager/job-manager-routing.module.ts      |    29 +
 .../job-manager/job-manager.component.html         |    75 +
 .../job-manager/job-manager.component.less         |    50 +
 .../workspace/job-manager/job-manager.component.ts |   138 +
 .../workspace/job-manager/job-manager.module.ts    |    73 +
 .../job-status/job-status.component.html           |    17 +
 .../job-status/job-status.component.less           |    23 +
 .../job-manager/job-status/job-status.component.ts |    37 +
 .../workspace/job-manager/job/job.component.html   |    58 +
 .../workspace/job-manager/job/job.component.less   |    70 +
 .../workspace/job-manager/job/job.component.ts     |    83 +
 .../notebook/action-bar/action-bar.component.html  |   239 +
 .../notebook/action-bar/action-bar.component.less  |   105 +
 .../notebook/action-bar/action-bar.component.ts    |   293 +
 .../add-paragraph/add-paragraph.component.html     |    17 +
 .../add-paragraph/add-paragraph.component.less     |    50 +
 .../add-paragraph/add-paragraph.component.ts       |    34 +
 .../interpreter-binding.component.html             |    55 +
 .../interpreter-binding.component.less             |    30 +
 .../interpreter-binding.component.ts               |    81 +
 .../workspace/notebook/notebook-routing.module.ts  |    37 +
 .../workspace/notebook/notebook.component.html     |    54 +
 .../workspace/notebook/notebook.component.less     |    36 +
 .../pages/workspace/notebook/notebook.component.ts |   315 +
 .../pages/workspace/notebook/notebook.module.ts    |   106 +
 .../code-editor/code-editor.component.html         |    16 +
 .../code-editor/code-editor.component.less         |    31 +
 .../paragraph/code-editor/code-editor.component.ts |   238 +
 .../paragraph/control/control.component.html       |    85 +
 .../paragraph/control/control.component.less       |    73 +
 .../paragraph/control/control.component.ts         |   304 +
 .../dynamic-forms/dynamic-forms.component.html     |    51 +
 .../dynamic-forms/dynamic-forms.component.less     |    24 +
 .../dynamic-forms/dynamic-forms.component.ts       |   120 +
 .../paragraph/footer/footer.component.html         |    16 +
 .../paragraph/footer/footer.component.less         |    21 +
 .../notebook/paragraph/footer/footer.component.ts  |    74 +
 .../notebook/paragraph/paragraph.component.html    |    99 +
 .../notebook/paragraph/paragraph.component.less    |    72 +
 .../notebook/paragraph/paragraph.component.ts      |   653 +
 .../paragraph/progress/progress.component.html     |    16 +
 .../paragraph/progress/progress.component.less     |    12 +
 .../paragraph/progress/progress.component.ts       |    32 +
 .../paragraph/result/result.component.html         |    74 +
 .../paragraph/result/result.component.less         |    78 +
 .../notebook/paragraph/result/result.component.ts  |   360 +
 .../permissions/permissions.component.html         |    88 +
 .../permissions/permissions.component.less         |    33 +
 .../notebook/permissions/permissions.component.ts  |   135 +
 .../revisions-comparator.component.html            |    20 +
 .../revisions-comparator.component.less            |    12 +
 .../revisions-comparator.component.ts              |    25 +
 .../elastic-input/elastic-input.component.html     |    23 +
 .../elastic-input/elastic-input.component.less     |    56 +
 .../share/elastic-input/elastic-input.component.ts |    88 +
 .../pages/workspace/notebook/share/share.module.ts |    26 +
 .../pages/workspace/workspace-routing.module.ts    |    51 +
 .../app/pages/workspace/workspace.component.html   |    17 +
 .../app/pages/workspace/workspace.component.less   |    26 +
 .../src/app/pages/workspace/workspace.component.ts |    48 +
 .../src/app/pages/workspace/workspace.guard.ts     |    36 +
 .../src/app/pages/workspace/workspace.module.ts    |    37 +
 .../src/app/services/array-ordering.service.ts     |    62 +
 zeppelin-web-angular/src/app/services/base-rest.ts |    45 +
 .../src/app/services/base-url.service.ts           |    46 +
 .../src/app/services/completion.service.ts         |    97 +
 .../src/app/services/helium.service.ts             |    24 +
 zeppelin-web-angular/src/app/services/index.ts     |    13 +
 .../src/app/services/interpreter.service.ts        |    84 +
 .../src/app/services/job-manager.service.ts        |    34 +
 .../src/app/services/message.service.ts            |   331 +
 .../src/app/services/ng-z.service.ts               |    85 +
 .../src/app/services/note-action.service.ts        |    72 +
 .../src/app/services/note-list.service.ts          |    97 +
 .../src/app/services/note-status.service.ts        |    65 +
 .../src/app/services/note-var-share.service.ts     |    38 +
 .../src/app/services/public-api.ts                 |    28 +
 .../src/app/services/runtime-compiler.service.ts   |    74 +
 .../src/app/services/save-as.service.ts            |    37 +
 .../src/app/services/security.service.ts           |    40 +
 .../src/app/services/ticket.service.ts             |   116 +
 .../about-zeppelin/about-zeppelin.component.html   |    28 +
 .../about-zeppelin/about-zeppelin.component.less   |    38 +
 .../about-zeppelin/about-zeppelin.component.ts     |    26 +
 .../share/code-editor/code-editor.component.html   |    19 +
 .../app/share/code-editor/code-editor.component.ts |   244 +
 .../app/share/code-editor/code-editor.module.ts    |    26 +
 .../app/share/code-editor/code-editor.service.ts   |   104 +
 .../src/app/share/code-editor/index.ts             |    13 +
 .../code-editor/nz-code-editor.definitions.ts      |    46 +
 .../src/app/share/code-editor/public-api.ts        |    16 +
 .../folder-rename/folder-rename.component.html     |    32 +
 .../folder-rename/folder-rename.component.less     |    12 +
 .../share/folder-rename/folder-rename.component.ts |    80 +
 .../src/app/share/header/header.component.html     |    77 +
 .../src/app/share/header/header.component.less     |   110 +
 .../src/app/share/header/header.component.ts       |    86 +
 zeppelin-web-angular/src/app/share/index.ts        |    13 +
 .../src/app/share/math-jax/math-jax.directive.ts   |    24 +
 .../app/share/node-list/node-list.component.html   |   139 +
 .../app/share/node-list/node-list.component.less   |    82 +
 .../src/app/share/node-list/node-list.component.ts |   117 +
 .../share/note-create/note-create.component.html   |    44 +
 .../share/note-create/note-create.component.less   |    12 +
 .../app/share/note-create/note-create.component.ts |   105 +
 .../share/note-import/note-import.component.html   |    50 +
 .../share/note-import/note-import.component.less   |    19 +
 .../app/share/note-import/note-import.component.ts |   110 +
 .../share/note-rename/note-rename.component.html   |    23 +
 .../share/note-rename/note-rename.component.less   |    12 +
 .../app/share/note-rename/note-rename.component.ts |    37 +
 .../share/page-header/page-header.component.html   |    18 +
 .../share/page-header/page-header.component.less   |    17 +
 .../app/share/page-header/page-header.component.ts |    31 +
 .../src/app/share/pipes/humanize-bytes.pipe.ts     |    40 +
 zeppelin-web-angular/src/app/share/pipes/index.ts  |    13 +
 .../src/app/share/pipes/public-api.ts              |    13 +
 zeppelin-web-angular/src/app/share/public-api.ts   |    15 +
 .../src/app/share/resize-handle/index.ts           |    13 +
 .../src/app/share/resize-handle/public-api.ts      |    13 +
 .../resize-handle/resize-handle.component.html     |    23 +
 .../resize-handle/resize-handle.component.less     |    23 +
 .../share/resize-handle/resize-handle.component.ts |    26 +
 .../app/share/run-scripts/run-scripts.directive.ts |    80 +
 zeppelin-web-angular/src/app/share/share.module.ts |   100 +
 .../src/app/share/spin/spin.component.html         |    21 +
 .../src/app/share/spin/spin.component.less         |    12 +
 .../src/app/share/spin/spin.component.ts           |    26 +
 zeppelin-web-angular/src/app/spell/spell-result.ts |    27 +
 .../area-chart-visualization.component.html        |    35 +
 .../area-chart-visualization.component.less        |    15 +
 .../area-chart-visualization.component.ts          |   102 +
 .../area-chart/area-chart-visualization.ts         |    32 +
 .../bar-chart-visualization.component.html         |    34 +
 .../bar-chart-visualization.component.less         |    25 +
 .../bar-chart/bar-chart-visualization.component.ts |   107 +
 .../bar-chart/bar-chart-visualization.ts           |    31 +
 .../pivot-setting/pivot-setting.component.html     |    85 +
 .../pivot-setting/pivot-setting.component.less     |    27 +
 .../pivot-setting/pivot-setting.component.ts       |    89 +
 .../scatter-setting/scatter-setting.component.html |    98 +
 .../scatter-setting/scatter-setting.component.less |    27 +
 .../scatter-setting/scatter-setting.component.ts   |   102 +
 .../visualizations/common/util/calc-tick-count.ts  |    22 +
 .../app/visualizations/common/util/set-x-axis.ts   |    46 +
 .../x-axis-setting/x-axis-setting.component.html   |    38 +
 .../x-axis-setting/x-axis-setting.component.less   |    18 +
 .../x-axis-setting/x-axis-setting.component.ts     |    78 +
 .../line-chart-visualization.component.html        |    44 +
 .../line-chart-visualization.component.less        |    25 +
 .../line-chart-visualization.component.ts          |   137 +
 .../line-chart/line-chart-visualization.ts         |    32 +
 .../pie-chart-visualization.component.html         |    19 +
 .../pie-chart-visualization.component.less         |    12 +
 .../pie-chart/pie-chart-visualization.component.ts |    73 +
 .../pie-chart/pie-chart-visualization.ts           |    32 +
 .../scatter-chart-visualization.component.html     |    19 +
 .../scatter-chart-visualization.component.less     |    12 +
 .../scatter-chart-visualization.component.ts       |    89 +
 .../scatter-chart/scatter-chart-visualization.ts   |    32 +
 .../table/table-visualization.component.html       |   123 +
 .../table/table-visualization.component.less       |    44 +
 .../table/table-visualization.component.ts         |   174 +
 .../visualizations/table/table-visualization.ts    |    60 +
 .../src/app/visualizations/visualization.module.ts |    79 +
 zeppelin-web-angular/src/assets/.gitkeep           |     0
 .../src/assets/fonts/patua-one.woff2               |   Bin 0 -> 12844 bytes
 .../helium-packages/helium-vis-example.umd.js      |   589 +
 zeppelin-web-angular/src/assets/images/bg.jpg      |   Bin 0 -> 185723 bytes
 .../src/assets/images/zeppelin.png                 |   Bin 0 -> 3810 bytes
 .../src/assets/images/zeppelin_svg_logo.svg        |    77 +
 .../src/assets/images/zeppelin_svg_logo_bg.svg     |    77 +
 zeppelin-web-angular/src/browserslist              |    11 +
 .../src/environments/environment.prod.ts           |    15 +
 .../src/environments/environment.ts                |    28 +
 zeppelin-web-angular/src/favicon.ico               |   Bin 0 -> 4286 bytes
 zeppelin-web-angular/src/index.html                |    50 +
 zeppelin-web-angular/src/karma.conf.js             |    43 +
 zeppelin-web-angular/src/main.ts                   |    25 +
 zeppelin-web-angular/src/polyfills.ts              |    94 +
 zeppelin-web-angular/src/styles.less               |    19 +
 zeppelin-web-angular/src/styles/base.less          |    18 +
 zeppelin-web-angular/src/styles/font.less          |    20 +
 zeppelin-web-angular/src/styles/global.less        |   124 +
 zeppelin-web-angular/src/styles/rewrite.less       |    25 +
 zeppelin-web-angular/src/styles/spin.less          |   150 +
 .../src/styles/theme/dark/antd-dark.less           |    17 +
 .../src/styles/theme/dark/theme-dark.less          |   659 +
 .../src/styles/theme/light/antd-light.less         |    15 +
 .../src/styles/theme/light/theme-light.less        |   659 +
 .../src/styles/theme/markdown.less                 |   166 +
 .../src/styles/theme/theme-mixin.less              |    24 +
 zeppelin-web-angular/src/test.ts                   |    28 +
 zeppelin-web-angular/src/tsconfig.app.json         |     8 +
 zeppelin-web-angular/src/tsconfig.spec.json        |     9 +
 zeppelin-web-angular/src/tslint.json               |     7 +
 zeppelin-web-angular/tsconfig.app.json             |    18 +
 zeppelin-web-angular/tsconfig.json                 |    47 +
 zeppelin-web-angular/tsconfig.spec.json            |    18 +
 zeppelin-web-angular/tslint.json                   |   141 +
 zeppelin-web-angular/webpack.partial.js            |    27 +
 344 files changed, 38558 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index d2979a4..aee4ece 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 add447e..2edb8a8 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/pom.xml b/pom.xml
index 7ef1665..bfac15e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -96,6 +96,7 @@
     <module>zeppelin-jupyter</module>
     <module>zeppelin-plugins</module>
     <module>zeppelin-distribution</module>
+    <module>zeppelin-web-angular</module>
   </modules>
 
   <properties>
@@ -109,8 +110,8 @@
     <scalacheck.version>1.12.5</scalacheck.version>
 
     <!-- frontend maven plugin related versions-->
-    <node.version>v8.9.3</node.version>
-    <npm.version>5.5.1</npm.version>
+    <node.version>v12.3.1</node.version>
+    <npm.version>6.9.0</npm.version>
     <plugin.frontend.version>1.6</plugin.frontend.version>
 
     <!-- common library versions -->
@@ -1032,6 +1033,16 @@
               <exclude>**/e2e/**/**.spec.js</exclude>
               <exclude>package-lock.json</exclude>
 
+              <!-- bundled from zeppelin-web-angular -->
+              <exclude>**/*.json</exclude>
+              <exclude>**/browserslist</exclude>
+              <exclude>**/.prettierrc</exclude>
+              <exclude>**/.prettierignore</exclude>
+              <exclude>**/.editorconfig</exclude>
+              <exclude>**/src/**/*.svg</exclude>
+              <exclude>**/.gitkeep</exclude>
+
+
               <!-- from SQLLine 1.0.2, see ZEPPELIN-2135 -->
               <exclude>**/src/main/java/org/apache/zeppelin/jdbc/SqlCompleter.java</exclude>
 
diff --git a/zeppelin-web-angular/.editorconfig b/zeppelin-web-angular/.editorconfig
new file mode 100644
index 0000000..c220b31
--- /dev/null
+++ b/zeppelin-web-angular/.editorconfig
@@ -0,0 +1,15 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset=utf-8
+end_of_line=lf
+trim_trailing_whitespace=true
+insert_final_newline=false
+indent_style=space
+indent_size=2
+
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/zeppelin-web-angular/.gitignore b/zeppelin-web-angular/.gitignore
new file mode 100644
index 0000000..22b094f
--- /dev/null
+++ b/zeppelin-web-angular/.gitignore
@@ -0,0 +1,47 @@
+# 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
+
+#
+.env
+yarn.lock
\ No newline at end of file
diff --git a/zeppelin-web-angular/.prettierignore b/zeppelin-web-angular/.prettierignore
new file mode 100644
index 0000000..b9f1979
--- /dev/null
+++ b/zeppelin-web-angular/.prettierignore
@@ -0,0 +1,3 @@
+**/*.md
+**/*.less
+**/*.svg
diff --git a/zeppelin-web-angular/.prettierrc b/zeppelin-web-angular/.prettierrc
new file mode 100644
index 0000000..4b9bb8a
--- /dev/null
+++ b/zeppelin-web-angular/.prettierrc
@@ -0,0 +1,15 @@
+{
+  "singleQuote": true,
+  "printWidth": 120,
+  "tabWidth": 2,
+  "useTabs": false,
+  "htmlWhitespaceSensitivity": "ignore",
+  "overrides": [
+    {
+      "files": ".prettierrc",
+      "options": {
+        "parser": "json"
+      }
+    }
+  ]
+}
diff --git a/zeppelin-web-angular/README.md b/zeppelin-web-angular/README.md
new file mode 100644
index 0000000..dea1a0d
--- /dev/null
+++ b/zeppelin-web-angular/README.md
@@ -0,0 +1,276 @@
+<!--
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+  
+# 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 0000000..f40bf86
--- /dev/null
+++ b/zeppelin-web-angular/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+	version="3.0">
+
+ <display-name>zeppelin-web-angular</display-name>
+	<servlet>
+		<servlet-name>default</servlet-name>
+    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+    <init-param>
+      <param-name>jersey.config.server.provider.packages</param-name>
+      <param-value>org.apache.zeppelin.rest</param-value>
+    </init-param>
+
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+	<context-param>
+		<param-name>configuration</param-name>
+		<param-value>deployment</param-value>
+	</context-param>
+
+  <session-config>
+    <cookie-config>
+      <http-only>true</http-only>
+      <secure>true</secure>
+    </cookie-config>
+  </session-config>
+</web-app>
diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json
new file mode 100644
index 0000000..37904c1
--- /dev/null
+++ b/zeppelin-web-angular/angular.json
@@ -0,0 +1,330 @@
+{
+  "$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"
+            ],
+            "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 0000000..8084853
--- /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 0000000..1be6b53
--- /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 0000000..d788f85
--- /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 0000000..b8498c2
--- /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<any>;
+  }
+
+  getTitleText() {
+    return element(by.css('app-root .content span')).getText() as Promise<string>;
+  }
+}
diff --git a/zeppelin-web-angular/e2e/tsconfig.json b/zeppelin-web-angular/e2e/tsconfig.json
new file mode 100644
index 0000000..39b800f
--- /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 0000000..67c6820
--- /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 0000000..46c0a07
--- /dev/null
+++ b/zeppelin-web-angular/package-lock.json
@@ -0,0 +1,15996 @@
+{
+  "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/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-to-html": {
+      "version": "0.6.12",
+      "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.12.tgz",
+      "integrity": "sha512-qBkIqLW979675mP76yB7yVkzeAWtATegdnDQ0RA3CZzknx0yUlNxMSML4xFdBfTs2GWYFQ1FELfbGbVSPzJ+LA==",
+      "requires": {
+        "entities": "^1.1.2"
+      }
+    },
+    "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
+    },
+    "entities": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+    },
+    "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"
+      }
+    },
+    "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": "2.7.0",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-2.7.0.tgz",
+      "integrity": "sha512-LIi8zzT6PyFpcYKdvWRCn/8X+6SuG2TgYYMrM6ckEYhlp44UcEduVymZGIZNLiwOUjrEud+78w/AsAiqJA/kRg==",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^5.2.0",
+        "execa": "^1.0.0",
+        "find-up": "^3.0.0",
+        "get-stdin": "^7.0.0",
+        "is-ci": "^2.0.0",
+        "pkg-dir": "^4.1.0",
+        "please-upgrade-node": "^3.1.1",
+        "read-pkg": "^5.1.1",
+        "run-node": "^1.0.0",
+        "slash": "^3.0.0"
+      },
+      "dependencies": {
+        "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"
+          },
+          "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"
+              }
+            }
+          }
+        },
+        "slash": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+          "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+          "dev": true
+        }
+      }
+    },
+    "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
+                }
+              }
... 31196 lines suppressed ...


[zeppelin] 09/16: [ZEPPELIN-4502] Adjust global styles and theming the visualization

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 2c8b852e19ba117dbd0fdc8718a4ea97d6f32acc
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Dec 20 16:36:26 2019 +0800

    [ZEPPELIN-4502] Adjust global styles and theming the visualization
    
    ### What is this PR for?
    
    Adjust global styles and theming the visualization
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4502
    
    ### How should this be tested?
    
    Not applicable
    
    ### Screenshots (if appropriate)
    
    ![image](https://user-images.githubusercontent.com/22736418/71349913-06af2b80-25ab-11ea-9356-d160f20cf8c1.png)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3563 from hsuanxyz/feat/theme and squashes the following commits:
    
    73271f24d [Hsuan Lee] chore: add visualization theme config
    757154965 [Hsuan Lee] chore: reset the editor theme
    410e0644e [Hsuan Lee] chore: adjust styles
    ad6fc5a52 [Hsuan Lee] feat: styling table in the HTML result
    1ec33b652 [Hsuan Lee] fix: quartz url
    507b2b732 [Hsuan Lee] fix: notebook cron model error
    c95ef6b54 [Hsuan Lee] feat: show front-end error in result
    df24cc074 [Hsuan Lee] feat: scroll to the paragraph when the position is moved
---
 zeppelin-web-angular/angular.json                  |   3 +-
 zeppelin-web-angular/package-lock.json             |  21 ++--
 zeppelin-web-angular/package.json                  |   3 +-
 zeppelin-web-angular/src/app/app.module.ts         |   4 +-
 .../runtime-dynamic-module.module.ts               |  11 ++
 zeppelin-web-angular/src/app/languages/load.ts     |  13 ++-
 .../workspace/interpreter/item/item.component.less |   2 +-
 .../notebook-repos/item/item.component.less        |   2 +-
 .../notebook/action-bar/action-bar.component.html  |  14 +--
 .../notebook/action-bar/action-bar.component.ts    |   1 -
 .../pages/workspace/notebook/notebook.component.ts |   8 ++
 .../pages/workspace/notebook/notebook.module.ts    |   4 +-
 .../notebook/paragraph/paragraph.component.ts      |   6 +
 .../workspace/share/result/result.component.html   |   1 +
 .../workspace/share/result/result.component.less   |  36 ++++++
 .../workspace/share/result/result.component.ts     |  23 ++--
 .../src/app/pages/workspace/share/share.module.ts  |   6 +-
 .../src/app/pages/workspace/workspace.component.ts |   2 +
 .../src/app/services/runtime-compiler.service.ts   |  22 ++--
 .../src/app/services/shortcut.service.ts           |   8 +-
 .../app/share/node-list/node-list.component.html   |   2 +-
 .../app/share/node-list/node-list.component.less   |   4 -
 .../element.ts}                                    |  20 +---
 .../bar-chart/bar-chart-visualization.component.ts |   3 +
 .../pivot-setting/pivot-setting.component.html     |   2 +-
 .../pivot-setting/pivot-setting.component.less     |   6 +
 .../scatter-setting/scatter-setting.component.html |   2 +-
 .../scatter-setting/scatter-setting.component.less |   6 +
 .../src/app/visualizations/g2.config.ts            | 130 +++++++++++++++++++++
 .../src/styles/theme/light/theme-light.less        |   4 +-
 30 files changed, 294 insertions(+), 75 deletions(-)

diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json
index 37904c1..095c388 100644
--- a/zeppelin-web-angular/angular.json
+++ b/zeppelin-web-angular/angular.json
@@ -72,7 +72,8 @@
               "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/monaco-editor/min/vs/editor/editor.main.css",
+              "./node_modules/github-markdown-css/github-markdown.css"
             ],
             "stylePreprocessorOptions": {
               "includePaths": [
diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json
index da898b0..8c82716 100644
--- a/zeppelin-web-angular/package-lock.json
+++ b/zeppelin-web-angular/package-lock.json
@@ -2844,13 +2844,10 @@
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
       "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
     },
-    "ansi-to-html": {
-      "version": "0.6.12",
-      "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.12.tgz",
-      "integrity": "sha512-qBkIqLW979675mP76yB7yVkzeAWtATegdnDQ0RA3CZzknx0yUlNxMSML4xFdBfTs2GWYFQ1FELfbGbVSPzJ+LA==",
-      "requires": {
-        "entities": "^1.1.2"
-      }
+    "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",
@@ -5538,11 +5535,6 @@
       "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
       "dev": true
     },
-    "entities": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
-      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
-    },
     "err-code": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
@@ -6396,6 +6388,11 @@
         "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",
diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json
index 670c73c..9d8cafe 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -28,10 +28,11 @@
     "@angular/router": "~8.2.10",
     "@antv/data-set": "^0.10.2",
     "@antv/g2": "^3.5.4",
-    "ansi-to-html": "^0.6.11",
+    "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",
diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts
index 06be7f4..5f65102 100644
--- a/zeppelin-web-angular/src/app/app.module.ts
+++ b/zeppelin-web-angular/src/app/app.module.ts
@@ -25,7 +25,7 @@ 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 { loadMonacoLanguage } from '@zeppelin/languages';
+import { loadMonacoBefore } from '@zeppelin/languages';
 import { TicketService } from '@zeppelin/services';
 import { ShareModule } from '@zeppelin/share';
 
@@ -37,7 +37,7 @@ import { RUNTIME_COMPILER_PROVIDERS } from './app-runtime-compiler.providers';
 import { AppComponent } from './app.component';
 
 export const loadMonaco = () => {
-  loadMonacoLanguage();
+  loadMonacoBefore();
 };
 
 registerLocaleData(en);
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
index d6cb44c..27d08f9 100644
--- 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
@@ -1,3 +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.
+ */
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { FormsModule } from '@angular/forms';
diff --git a/zeppelin-web-angular/src/app/languages/load.ts b/zeppelin-web-angular/src/app/languages/load.ts
index 5dad459..64c617a 100644
--- a/zeppelin-web-angular/src/app/languages/load.ts
+++ b/zeppelin-web-angular/src/app/languages/load.ts
@@ -10,10 +10,19 @@
  * limitations under the License.
  */
 
-import { languages } from 'monaco-editor';
+import { editor, languages } from 'monaco-editor';
 import { conf as ScalaConf, language as ScalaLanguage } from './scala';
 
-export const loadMonacoLanguage = () => {
+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/pages/workspace/interpreter/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less
index 856506e..746967d 100644
--- 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
@@ -19,7 +19,7 @@
 
   ::ng-deep .interpreter-item {
     &.edit {
-      background: @orange-1;
+      //background: @orange-1;
     }
     .ant-card-body {
       margin-top: -@card-padding-base;
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
index bc6d280..7e24239 100644
--- 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
@@ -20,7 +20,7 @@
 
   ::ng-deep .repo-item {
     &.edit {
-      background: @orange-1;
+      //background: @orange-1;
     }
   }
 
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
index 0238f17..1da21e6 100644
--- 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
@@ -125,11 +125,9 @@
               (click)="toggleExtension('revisions')">
         <i nz-icon nzType="swap" nzTheme="outline"></i>
       </button>
-      <nz-button-group nzSize="small">
-        <button nz-button nz-dropdown [nzDropdownMenu]="revisionsMenu" nzTrigger="click">
-          {{currentRevision}}
-        </button>
-      </nz-button-group>
+      <button nz-button nz-dropdown [nzDropdownMenu]="revisionsMenu" nzTrigger="click">
+        {{currentRevision}}
+      </button>
       <nz-dropdown-menu #revisionsMenu="nzDropdownMenu">
         <ul nz-menu>
           <li nz-menu-item *ngFor="let r of noteRevisions" (click)="visitRevision(r)">
@@ -188,7 +186,8 @@
         <div class="ant-dropdown-menu padding-sm scheduler">
           Run note with cron scheduler.
           Either choose from preset or write your own
-          <a href="http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/crontrigger" target="_blank">
+          <a href="https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html"
+             target="_blank">
             cron expression
           </a>
           .
@@ -226,7 +225,8 @@
       <button nz-button nzNoAnimation (click)="togglePermissions()">
         <i nz-icon nzType="lock" [nzTheme]="activatedExtension === 'permissions' ? 'fill' : 'outline'"></i>
       </button>
-      <button [nzDropdownMenu]="menu" nz-button nzNoAnimation nzSize="small" nz-dropdown nzTrigger="click">{{note.config.looknfeel}}
+      <button [nzDropdownMenu]="menu" nz-button nzNoAnimation nzSize="small" nz-dropdown
+              nzTrigger="click">{{note.config.looknfeel}}
         <i nz-icon nzType="down"></i>
       </button>
       <nz-dropdown-menu #menu="nzDropdownMenu">
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
index 994acc1..9ec5ded 100644
--- 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
@@ -69,7 +69,6 @@ export class NotebookActionBarComponent extends MessageListenersManager implemen
     { 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) {
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
index e0c17a1..404fc28 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -36,6 +36,7 @@ import {
   TicketService
 } from '@zeppelin/services';
 
+import { scrollIntoViewIfNeeded } from '@zeppelin/utility/element';
 import { NotebookParagraphComponent } from './paragraph/paragraph.component';
 
 @Component({
@@ -151,7 +152,14 @@ export class NotebookComponent extends MessageListenersManager implements OnInit
       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());
+          });
+        }
       }
     }
   }
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
index 64cfdee..4b71d3d 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -45,6 +45,7 @@ import { NotebookParagraphProgressComponent } from './paragraph/progress/progres
 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 { NotebookRoutingModule } from './notebook-routing.module';
@@ -90,7 +91,8 @@ import { NotebookShareModule } from './share/share.module';
     NzGridModule,
     NzRadioModule,
     DragDropModule,
-    NzCodeEditorModule
+    NzCodeEditorModule,
+    NzCheckboxModule
   ]
 })
 export class NotebookModule {}
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
index 246d09e..ad9691e 100644
--- 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
@@ -516,9 +516,11 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit,
               this.commitParagraph();
               break;
             case ParagraphActions.MoveToUp:
+              event.preventDefault();
               this.moveUpParagraph();
               break;
             case ParagraphActions.MoveToDown:
+              event.preventDefault();
               this.moveDownParagraph();
               break;
             case ParagraphActions.SwitchEnable:
@@ -622,6 +624,10 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit,
     }
   }
 
+  getElement(): HTMLElement {
+    return this.host && this.host.nativeElement;
+  }
+
   ngOnDestroy(): void {
     super.ngOnDestroy();
   }
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
index 0b246b0..cb8369f 100644
--- 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
@@ -68,6 +68,7 @@
     <div *ngSwitchCase="datasetType.TEXT" class="text-plain"><pre [innerHTML]="plainText"></pre></div>
     <div *ngSwitchCase="datasetType.IMG" class="img"><img [src]="imgData" alt="img"></div>
   </ng-container>
+  <div *ngIf="frontEndError" class="text-plain"><pre>{{frontEndError}}</pre></div>
   <div *ngIf="angularComponent">
     <ng-container *ngComponentOutlet="angularComponent.component;ngModuleFactory: angularComponent.moduleFactory;injector: injector"></ng-container>
   </div>
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
index f197072..37f0dcb 100644
--- 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
@@ -29,6 +29,11 @@
   }
 
   ::ng-deep {
+
+    .visualization-selector .ant-radio-button-wrapper {
+      padding: 0 10px;
+    }
+
     .inner-html, .text-plain {
 
       overflow: auto;
@@ -42,6 +47,37 @@
         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;
+      }
     }
   }
 
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
index 86d94cc..c8b75b9 100644
--- 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
@@ -29,7 +29,7 @@ import { DomSanitizer, SafeHtml, SafeUrl } from '@angular/platform-browser';
 import { Subject, Subscription } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
 
-import * as Convert from 'ansi-to-html';
+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';
@@ -206,6 +206,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
   }
 
   renderDefaultDisplay() {
+    this.frontEndError = '';
     switch (this.result.type) {
       case DatasetType.TABLE:
         this.renderGraph();
@@ -240,22 +241,22 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit,
   }
 
   renderAngular(): void {
-    try {
-      this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => {
+    this.runtimeCompilerService
+      .createAndCompileTemplate(this.id, this.result.data)
+      .then(data => {
         this.angularComponent = data;
-        // this.angularComponent.moduleFactory
+        this.cdr.markForCheck();
+      })
+      .catch(error => {
+        this.angularComponent = null;
+        this.frontEndError = error.message;
         this.cdr.markForCheck();
       });
-    } catch (e) {
-      this.frontEndError = e.message;
-      console.log(e);
-    }
   }
 
   renderText(): void {
-    // tslint:disable-next-line:no-any
-    const convert: any = new Convert();
-    this.plainText = this.sanitizer.bypassSecurityTrustHtml(convert.toHtml(this.result.data));
+    const ansiUp = new AnsiUp();
+    this.plainText = this.sanitizer.bypassSecurityTrustHtml(ansiUp.ansi_to_html(this.result.data));
   }
 
   renderImg(): void {
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
index a381779..37bebf3 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
@@ -28,6 +28,8 @@ import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
 import { ShareModule } from '@zeppelin/share';
 import { VisualizationModule } from '@zeppelin/visualizations/visualization.module';
 
+import { NzGridModule } from 'ng-zorro-antd/grid';
+import { NzInputModule } from 'ng-zorro-antd/input';
 import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component';
 import { NotebookParagraphResultComponent } from './result/result.component';
 
@@ -48,7 +50,9 @@ import { NotebookParagraphResultComponent } from './result/result.component';
     NzIconModule,
     NzCheckboxModule,
     NzSelectModule,
-    NzSwitchModule
+    NzSwitchModule,
+    NzInputModule,
+    NzGridModule
   ]
 })
 export class WorkspaceShareModule {}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index 976e44b..410ef17 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -18,6 +18,7 @@ import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router';
 import { publishedSymbol, Published } 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 { log } from 'ng-zorro-antd/core';
 
 @Component({
@@ -47,6 +48,7 @@ export class WorkspaceComponent implements OnInit, OnDestroy {
       this.websocketConnected = data;
       this.cdr.markForCheck();
     });
+    setTheme();
     this.heliumManagerService.initPackages();
   }
 
diff --git a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
index 8ec7f2c..f7f6fc4 100644
--- a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
+++ b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts
@@ -11,15 +11,17 @@
  */
 
 import {
+  ChangeDetectionStrategy,
   Compiler,
   Component,
   Injectable,
-  ModuleWithComponentFactories,
   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';
 
@@ -33,16 +35,17 @@ export class DynamicTemplate {
   ) {}
 }
 
+export class DynamicTemplateError {
+  constructor(public message: string) {}
+}
+
 @Injectable({
   providedIn: 'root'
 })
 export class RuntimeCompilerService {
-  // tslint:disable-next-line:no-any
-  private compiledModule?: ModuleWithComponentFactories<any>;
-
   public async createAndCompileTemplate(paragraphId: string, template: string): Promise<DynamicTemplate> {
     const ngZService = this.ngZService;
-    const dynamicComponent = Component({ template: template })(
+    const dynamicComponent = Component({ template: template, selector: `dynamic-${paragraphId}` })(
       class DynamicTemplateComponent {
         z = {
           set: (key: string, value, id: string) => ngZService.setContextValue(key, value, id),
@@ -63,8 +66,13 @@ export class RuntimeCompilerService {
       imports: [RuntimeDynamicModuleModule]
     })(class DynamicModule {});
 
-    this.compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule);
-    return new DynamicTemplate(template, dynamicComponent, this.compiledModule.ngModuleFactory);
+    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/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts
index 4b2a626..5bc9a2a 100644
--- a/zeppelin-web-angular/src/app/services/shortcut.service.ts
+++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts
@@ -44,10 +44,10 @@ export const ShortcutsMap = {
   // Need register special character `≠` in MacOS
   [ParagraphActions.IncreaseWidth]: ['alt.ctrlCmd.+', 'alt.ctrlCmd.≠'],
   [ParagraphActions.Delete]: 'shift.delete',
-  [ParagraphActions.MoveToUp]: ['ctrlCmd.k', 'ctrlCmd.arrowup'],
-  [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown'],
-  [ParagraphActions.SelectAbove]: ['k', 'arrowup'],
-  [ParagraphActions.SelectBelow]: ['j', 'arrowdown'],
+  [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',
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
index 70be691..7800443 100644
--- 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
@@ -72,7 +72,7 @@
         </span>
         <span class="file" *ngSwitchCase="'note'">
           <a class="name">
-            <i nz-icon nzType="file-text" nzTheme="fill"></i>
+            <i nz-icon nzType="file" nzTheme="outline"></i>
             <a [routerLink]="['/notebook',node.origin.id]">
               {{ node.title }}
             </a>
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
index aec40c1..ea197e4 100644
--- 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
@@ -48,10 +48,6 @@
       filter: grayscale(1);
     }
 
-    i {
-      margin-right: 6px;
-    }
-
     .operation {
       margin-left: 12px;
 
diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less b/zeppelin-web-angular/src/app/utility/element.ts
similarity index 65%
copy from zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
copy to zeppelin-web-angular/src/app/utility/element.ts
index 87bb382..cdae6de 100644
--- a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less
+++ b/zeppelin-web-angular/src/app/utility/element.ts
@@ -10,18 +10,10 @@
  * 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;
+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/visualizations/bar-chart/bar-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts
index 82ed55f..2294445 100644
--- 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
@@ -83,6 +83,9 @@ export class BarChartVisualizationComponent extends G2VisualizationComponentBase
     const key = this.getKey();
     this.setScale();
 
+    this.chart.tooltip({
+      shared: false
+    });
     if (get(this.config.setting, 'multiBarChart.stacked', false)) {
       this.chart
         .intervalStack()
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
index 2a91d7b..fb1497f 100644
--- 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
@@ -10,7 +10,7 @@
   ~ limitations under the License.
   -->
 
-<nz-card id="fields-drop-group" nzTitle="Available Fields" cdkDropListGroup>
+<nz-card id="fields-drop-group" nzTitle="Available Fields" nzSize="small" cdkDropListGroup>
   <div cdkDropList
        id="columns-list"
        [cdkDropListData]="columns"
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
index 87bb382..9091c36 100644
--- 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
@@ -23,5 +23,11 @@
   }
   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.html b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html
index ff03338..7333cee 100644
--- 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
@@ -10,7 +10,7 @@
   ~ limitations under the License.
   -->
 
-<nz-card id="fields-drop-group" nzTitle="Available Fields" cdkDropListGroup>
+<nz-card id="fields-drop-group" nzTitle="Available Fields" nzSize="small" cdkDropListGroup>
   <div cdkDropList
        id="columns-list"
        [cdkDropListData]="columns"
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
index 0142785..35d9c4e 100644
--- 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
@@ -23,5 +23,11 @@
   }
   nz-card {
     background: #fff;
+    ::ng-deep {
+      .ant-card-head {
+        padding: 0 12px;
+        background: #fafafa;
+      }
+    }
   }
 });
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 0000000..aa5a4e9
--- /dev/null
+++ b/zeppelin-web-angular/src/app/visualizations/g2.config.ts
@@ -0,0 +1,130 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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);
+  console.log(zeppelinTheme);
+  // tslint:disable-next-line:no-any
+  (G2.Global as any).setTheme(theme);
+}
diff --git a/zeppelin-web-angular/src/styles/theme/light/theme-light.less b/zeppelin-web-angular/src/styles/theme/light/theme-light.less
index 6f071e5..576517a 100644
--- a/zeppelin-web-angular/src/styles/theme/light/theme-light.less
+++ b/zeppelin-web-angular/src/styles/theme/light/theme-light.less
@@ -74,8 +74,8 @@
 @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: 0px;
-@border-radius-sm: 0px;
+@border-radius-base: 4px;
+@border-radius-sm: 2px;
 
 // vertical paddings
 @padding-lg: 24px; // containers


[zeppelin] 15/16: [ZEPPELIN-4548] Support search notebook

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 8f12d520e2fabfb923ad5805a556ac18b5dde686
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Wed Jan 8 16:23:25 2020 +0800

    [ZEPPELIN-4548] Support search notebook
    
    ### What is this PR for?
    
    support search notebook
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4548
    
    ### How should this be tested?
    
    N/A
    
    ### Screenshots (if appropriate)
    
    ![image](https://user-images.githubusercontent.com/22736418/71962091-ad462e00-3233-11ea-9d85-5b579f280953.png)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3592 from hsuanxyz/feat/search and squashes the following commits:
    
    6e41f3e36 [Hsuan Lee] feat: support search notebook
---
 .../{public-api.ts => notebook-search.ts}          |  14 +-
 .../src/app/interfaces/public-api.ts               |   1 +
 .../notebook-search-routing.module.ts}             |  24 ++-
 .../notebook-search/notebook-search.component.html |  17 +++
 .../notebook-search.component.less}                |  19 ++-
 .../notebook-search/notebook-search.component.ts   |  58 ++++++++
 .../notebook-search/notebook-search.module.ts      |  29 ++++
 .../result-item/result-item.component.html         |  22 +++
 .../result-item/result-item.component.less}        |  14 +-
 .../result-item/result-item.component.ts           | 162 +++++++++++++++++++++
 .../paragraph/code-editor/code-editor.component.ts |   4 +-
 .../pages/workspace/workspace-routing.module.ts    |   5 +
 .../src/app/services/notebook-search.service.ts    |  47 ++++++
 .../src/app/share/header/header.component.html     |   6 +-
 .../src/app/share/header/header.component.ts       |  15 ++
 .../src/app/utility/get-keyword-positions.ts       |  43 ++++++
 zeppelin-web-angular/src/app/utility/line-map.ts   |  60 ++++++++
 .../src/app/visualizations/g2.config.ts            |   1 -
 18 files changed, 510 insertions(+), 31 deletions(-)

diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/notebook-search.ts
similarity index 71%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/interfaces/notebook-search.ts
index 8c54e3d..267ee94 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/notebook-search.ts
@@ -10,10 +10,10 @@
  * 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 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
index 8c54e3d..e762a5c 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts
@@ -17,3 +17,4 @@ 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/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts
similarity index 58%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts
index 8c54e3d..9127792 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search-routing.module.ts
@@ -10,10 +10,20 @@
  * 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';
+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 0000000..e1db6d9
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html
@@ -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.
+  -->
+<div class="main">
+  <zeppelin-notebook-search-result-item *ngFor="let item of results"
+                                        [result]="item">
+  </zeppelin-notebook-search-result-item>
+</div>
+
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less
similarity index 71%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less
index 8c54e3d..108b1a4 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.less
@@ -10,10 +10,15 @@
  * 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';
+@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 0000000..2036d23
--- /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 0000000..69dafa8
--- /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 0000000..dcd78dc
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html
@@ -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.
+  -->
+
+<nz-card [nzTitle]="titleTemplateRef">
+  <ng-template #titleTemplateRef>
+    <a [routerLink]="routerLink">{{displayName}}</a>
+  </ng-template>
+  <zeppelin-code-editor
+    [style.height.px]="height"
+    [nzEditorOption]="editorOption"
+    (nzEditorInitialized)="initializedEditor($event)">
+  </zeppelin-code-editor>
+</nz-card>
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less
similarity index 71%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less
index 8c54e3d..cb24d4e 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less
@@ -10,10 +10,10 @@
  * 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';
+::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 0000000..e911a66
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts
@@ -0,0 +1,162 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 { 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;
+
+  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) {}
+
+  setDisplayNameAndRouterLink(): void {
+    const noteId = this.result.id.split('/', 2)[0];
+    this.displayName = this.result.name ? this.result.name : `Note ${noteId}`;
+
+    this.routerLink = `/notebook/${noteId}`;
+  }
+
+  setHighlightKeyword(): void {
+    let mergedStr = this.result.header ? `${this.result.header}\n\n${this.result.snippet}` : this.result.snippet;
+
+    const regexp = /<B>(.+?)<\/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/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
index 8cf4bd7..bfae433 100644
--- 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
@@ -145,7 +145,9 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
         lineNumbers: this.lineNumbers ? 'on' : 'off',
         glyphMargin: false,
         folding: false,
-        scrollBeyondLastLine: false
+        scrollBeyondLastLine: false,
+        contextmenu: false,
+        matchBrackets: false
       });
     }
   }
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
index 16928a3..d4faf20 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
@@ -35,6 +35,11 @@ const routes: Routes = [
         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)
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 0000000..7371eec
--- /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<string | null>(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<NotebookSearchResultItem[]>(this.restUrl`/notebook/search`, {
+      params: {
+        q: query
+      }
+    });
+  }
+}
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html
index 33d8ecd..76f93c2 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.html
+++ b/zeppelin-web-angular/src/app/share/header/header.component.html
@@ -73,7 +73,11 @@
   </div>
   <div class="search">
     <nz-input-group [nzPrefixIcon]="'search'">
-      <input type="text" nz-input placeholder="Search"/>
+      <input type="text"
+             nz-input
+             placeholder="Search"
+             (keyup.enter)="onSearch()"
+             [(ngModel)]="queryStr"/>
     </nz-input-group>
   </div>
 </div>
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts
index e69b89e..b4c20c2 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.ts
+++ b/zeppelin-web-angular/src/app/share/header/header.component.ts
@@ -20,6 +20,7 @@ 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({
@@ -32,6 +33,7 @@ export class HeaderComponent extends MessageListenersManager implements OnInit,
   private destroy$ = new Subject();
   connectStatus = 'error';
   noteListVisible = false;
+  queryStr: string | null = null;
 
   about() {
     this.nzModalService.create({
@@ -46,6 +48,13 @@ export class HeaderComponent extends MessageListenersManager implements OnInit,
     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);
@@ -56,6 +65,7 @@ export class HeaderComponent extends MessageListenersManager implements OnInit,
     private nzModalService: NzModalService,
     public messageService: MessageService,
     private router: Router,
+    private notebookSearchService: NotebookSearchService,
     private cdr: ChangeDetectorRef
   ) {
     super(messageService);
@@ -76,6 +86,11 @@ export class HeaderComponent extends MessageListenersManager implements OnInit,
         this.noteListVisible = false;
         this.cdr.markForCheck();
       });
+
+    this.notebookSearchService
+      .queried()
+      .pipe(takeUntil(this.destroy$))
+      .subscribe(queryStr => (this.queryStr = queryStr));
   }
 
   ngOnDestroy() {
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 0000000..c2eb7aa
--- /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 0000000..30c4079
--- /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/g2.config.ts b/zeppelin-web-angular/src/app/visualizations/g2.config.ts
index aa5a4e9..622d25d 100644
--- a/zeppelin-web-angular/src/app/visualizations/g2.config.ts
+++ b/zeppelin-web-angular/src/app/visualizations/g2.config.ts
@@ -124,7 +124,6 @@ const zeppelinTheme = {
 
 export function setTheme() {
   const theme = G2.Util.deepMix(G2.Global, zeppelinTheme);
-  console.log(zeppelinTheme);
   // tslint:disable-next-line:no-any
   (G2.Global as any).setTheme(theme);
 }


[zeppelin] 16/16: [ZEPPELIN-4540] Convert code editor font size units

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 39063312791ce31d65c687be66a4258fbd2a8c8f
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Tue Jan 7 09:47:56 2020 +0800

    [ZEPPELIN-4540] Convert code editor font size units
    
    ### What is this PR for?
    
    Convert code editor font size units (from pt to px).
    
    ### What type of PR is it?
    [Bug Fix]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4540
    
    ### How should this be tested?
    
    N/A
    
    ### Screenshots (if appropriate)
    
    N/A
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3588 from hsuanxyz/fix/code-editor-font-size and squashes the following commits:
    
    3778a12ce [Hsuan Lee] fix: convert code editor font size units
---
 .../paragraph/code-editor/code-editor.component.ts        |  3 ++-
 .../src/app/utility/css-unit-conversion.ts                | 15 +++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

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
index bfae433..99cc97d 100644
--- 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
@@ -31,6 +31,7 @@ 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({
@@ -139,7 +140,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro
     if (this.editor) {
       this.editor.updateOptions({
         readOnly: this.readOnly,
-        fontSize: this.fontSize,
+        fontSize: pt2px(this.fontSize),
         renderLineHighlight: this.focus ? 'all' : 'none',
         minimap: { enabled: false },
         lineNumbers: this.lineNumbers ? 'on' : 'off',
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 0000000..19d4057
--- /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);
+}


[zeppelin] 07/16: [ZEPPELIN-4398] Add notebook repository page

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 5ff4050285f4511b033c4ef09760cffccf932d8d
Author: Hsuan Lee <hs...@gmail.com>
AuthorDate: Fri Dec 6 16:18:18 2019 +0800

    [ZEPPELIN-4398] Add notebook repository page
    
    ### What is this PR for?
    
    Add the notebook repository page
    
    ### What type of PR is it?
    [Feature]
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-4398
    
    ### How should this be tested?
    
    Not applicable
    
    ### Screenshots (if appropriate)
    
    ![repos](https://user-images.githubusercontent.com/22736418/70308435-338edf00-1846-11ea-9030-bcf4ecaf22bb.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Hsuan Lee <hs...@gmail.com>
    
    Closes #3543 from hsuanxyz/feat/notebook-repos and squashes the following commits:
    
    d148902f2 [Hsuan Lee] feat: add notebook repository page
---
 .../interfaces/{public-api.ts => notebook-repo.ts} | 26 +++++--
 .../src/app/interfaces/public-api.ts               |  1 +
 .../notebook-repos/item/item.component.html        | 79 ++++++++++++++++++++++
 .../notebook-repos/item/item.component.less}       | 31 +++++++--
 .../notebook-repos/item/item.component.ts          | 78 +++++++++++++++++++++
 .../notebook-repos-routing.module.ts}              | 22 ++++--
 .../notebook-repos/notebook-repos.component.html   | 21 ++++++
 .../notebook-repos/notebook-repos.component.less}  | 14 ++--
 .../notebook-repos/notebook-repos.component.ts     | 51 ++++++++++++++
 .../notebook-repos/notebook-repos.module.ts        | 49 ++++++++++++++
 .../pages/workspace/workspace-routing.module.ts    |  5 ++
 .../src/app/services/notebook-repos.service.ts     | 36 ++++++++++
 .../src/app/services/public-api.ts                 |  1 +
 .../src/app/share/header/header.component.html     |  2 +-
 14 files changed, 391 insertions(+), 25 deletions(-)

diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts
similarity index 60%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/interfaces/notebook-repo.ts
index f00e442..de03778 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts
@@ -10,9 +10,23 @@
  * 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 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/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts
index f00e442..8c54e3d 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts
@@ -16,3 +16,4 @@ export * from './interpreter';
 export * from './message-interceptor';
 export * from './security';
 export * from './credential';
+export * from './notebook-repo';
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 0000000..3f4875a
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html
@@ -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.
+  -->
+
+<nz-card class="repo-item"
+         [class.edit]="editMode"
+         [nzTitle]="repo.name"
+         [nzExtra]="extraTemplate">
+  <ng-template #extraTemplate>
+    <div class="extra-wrap" *ngIf="!editMode">
+      <button nz-button
+              nzSize="small"
+              (click)="triggerEditMode()">
+        <i nz-icon nzType="edit"></i>
+        Edit
+      </button>
+    </div>
+    <div class="extra-wrap" *ngIf="editMode">
+      <button nz-button
+              nzType="primary"
+              nzSize="small"
+              [disabled]="!settingFormArray.valid"
+              (click)="save()">
+        <i nz-icon nzType="save" nzTheme="outline"></i>
+        Save
+      </button>
+      <button nz-button
+              nzSize="small"
+              (click)="cancel()">
+        <i nz-icon nzType="close" nzTheme="outline"></i>
+        Cancel
+      </button>
+    </div>
+  </ng-template>
+  <h3>Setting</h3>
+  <form nz-form>
+    <nz-table nzTemplateMode nzSize="small">
+      <thead>
+      <tr>
+        <th>Name</th>
+        <th>Value</th>
+      </tr>
+      </thead>
+      <tbody>
+      <tr *ngFor="let setting of repo.settings; index as i">
+        <td>{{setting.name}}</td>
+        <ng-container *ngIf="!editMode">
+          <td>{{setting.selected}}</td>
+        </ng-container>
+        <ng-container *ngIf="editMode">
+          <td>
+            <input *ngIf="setting.type === 'INPUT'"
+                   nzSize="small"
+                   nz-input
+                   [formControl]="settingFormArray.controls[i]">
+
+            <nz-select *ngIf="setting.type === 'DROPDOWN'" [formControl]="settingFormArray.controls[i]">
+              <nz-option
+                *ngFor="let option of setting.value"
+                [nzLabel]="option"
+                [nzValue]="option">
+              </nz-option>
+            </nz-select>
+          </td>
+        </ng-container>
+      </tr>
+      </tbody>
+    </nz-table>
+  </form>
+
+</nz-card>
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less
similarity index 62%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less
index f00e442..bc6d280 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less
@@ -10,9 +10,28 @@
  * 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';
+@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 0000000..f66247c
--- /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<NotebookRepo>();
+
+  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/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts
similarity index 59%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts
index f00e442..e7e7ca1 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts
@@ -9,10 +9,20 @@
  * 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';
 
-export * from './ticket';
-export * from './trash-folder-id';
-export * from './interpreter';
-export * from './message-interceptor';
-export * from './security';
-export * from './credential';
+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 0000000..d47ad87
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html
@@ -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.
+  -->
+<zeppelin-page-header title="Notebook Repository" description="Manage your Notebook Repositories' settings.">
+</zeppelin-page-header>
+<div class="content">
+  <zeppelin-notebook-repo-item
+    *ngFor="let repo of repositories"
+    (repoChange)="updateRepoSetting($event)"
+    [repo]="repo">
+
+  </zeppelin-notebook-repo-item>
+</div>
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less
similarity index 74%
copy from zeppelin-web-angular/src/app/interfaces/public-api.ts
copy to zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less
index f00e442..5a3f8f0 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less
@@ -10,9 +10,11 @@
  * 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';
+@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 0000000..1faffee
--- /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 0000000..2bb9d25
--- /dev/null
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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,
+  NzCardModule,
+  NzFormModule,
+  NzIconModule,
+  NzInputModule,
+  NzSelectModule,
+  NzTableModule
+} from 'ng-zorro-antd';
+
+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/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
index 6815b80..16928a3 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts
@@ -53,6 +53,11 @@ const routes: Routes = [
         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)
       }
     ]
   }
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 0000000..624599a
--- /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<NotebookRepo[]>(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/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts
index 6c3dbc0..f9bdfe9 100644
--- a/zeppelin-web-angular/src/app/services/public-api.ts
+++ b/zeppelin-web-angular/src/app/services/public-api.ts
@@ -29,3 +29,4 @@ 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/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html
index 71e8cd7..645da9a 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.html
+++ b/zeppelin-web-angular/src/app/share/header/header.component.html
@@ -47,7 +47,7 @@
           <a [routerLink]="['/interpreter']">Interpreter</a>
         </li>
         <li nz-menu-item routerLinkActive="ant-dropdown-menu-item-selected">
-          <a [routerLink]="['/notebookRepos']">Notebook
+          <a [routerLink]="['/notebook-repos']">Notebook
                                                Repos
           </a>
         </li>


[zeppelin] 12/16: [ZEPPELIN-4515] Have Jetty Server support multiple wars

Posted by zj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git

commit 6ddc0c685f9c684c3b79b803cf238266bfd0a669
Author: fdai <fd...@twitter.com>
AuthorDate: Tue Dec 31 17:25:14 2019 -0800

    [ZEPPELIN-4515] Have Jetty Server support multiple wars
    
    ### What is this PR for?
    We have a new UI with version angular 8, which will be retiring the old angularjs.
    both of the angular frameworks may need to co-exist for a while until the new UI is stable.
    Have the Jetty server support multiple wars with different port (8080 and 9090)
    
    ### What type of PR is it?
    [Feature ]
    
    ### Todos
    retire angularJS completely in the future.
    
    ### What is the Jira issue?
    * [ZEPPELIN-4515](https://issues.apache.org/jira/browse/ZEPPELIN-4515) Have Jetty Server support multiple wars
    Add multiple war support for the Zeppelin Server.
    two ports (default is 8080 and 9090) will be living for a while until we are comfortable with the new UI.
    
    ### How should this be tested?
    The default port for new UI is 9090, testing via http://localhost:9090
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? **No**
    * Is there breaking changes for older versions? **No**
    * Does this needs documentation? **No**
    
    Author: fdai <fd...@twitter.com>
    
    Closes #3571 from fred521/add_angular_to_jetty and squashes the following commits:
    
    196547605 [fdai] add next context path
    93e2a4fdc [fdai] clean the code
    8606ce064 [fdai] use one port two support multiple wars in jetty
    f08602e20 [fdai] remove unrelated notebook
    0f9c10367 [fdai] add angular support for jetty
---
 bin/common.sh                                      | 12 ++-
 bin/zeppelin-daemon.sh                             |  1 +
 bin/zeppelin.sh                                    |  1 +
 zeppelin-distribution/pom.xml                      |  6 ++
 .../src/assemble/distribution.xml                  |  4 +-
 .../zeppelin/conf/ZeppelinConfiguration.java       |  1 +
 .../org/apache/zeppelin/server/ZeppelinServer.java | 92 +++++++++++-----------
 .../apache/zeppelin/rest/AbstractTestRestApi.java  |  3 +
 zeppelin-web-angular/package.json                  |  2 +-
 zeppelin-web-angular/pom.xml                       |  2 +-
 10 files changed, 74 insertions(+), 50 deletions(-)

diff --git a/bin/common.sh b/bin/common.sh
index 0ebae66..4e86ce9 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 e898849..0ce9808 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 a13f9db..5509e4f 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/zeppelin-distribution/pom.xml b/zeppelin-distribution/pom.xml
index 2710670..380e7a2 100644
--- a/zeppelin-distribution/pom.xml
+++ b/zeppelin-distribution/pom.xml
@@ -85,6 +85,12 @@
       <version>${project.version}</version>
       <type>war</type>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>zeppelin-web-angular</artifactId>
+      <version>${project.version}</version>
+      <type>war</type>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/zeppelin-distribution/src/assemble/distribution.xml b/zeppelin-distribution/src/assemble/distribution.xml
index 0c5e8b6..0b18b4a 100644
--- a/zeppelin-distribution/src/assemble/distribution.xml
+++ b/zeppelin-distribution/src/assemble/distribution.xml
@@ -26,7 +26,7 @@
   </formats>
   <includeBaseDirectory>true</includeBaseDirectory>
   <baseDirectory>zeppelin-${project.version}</baseDirectory>
- 
+
   <dependencySets>
     <dependencySet>
       <!-- Enable access to all projects in the current multimodule build!
@@ -34,6 +34,7 @@
       <!-- Now, select which projects to include in this module-set. -->
       <includes>
         <include>${project.groupId}:zeppelin-web</include>
+        <include>${project.groupId}:zeppelin-web-angular</include>
       </includes>
       <useProjectArtifact>false</useProjectArtifact>
       <useTransitiveDependencies>false</useTransitiveDependencies>
@@ -42,6 +43,7 @@
       <outputDirectory>/lib</outputDirectory>
       <excludes>
         <exclude>${project.groupId}:zeppelin-web</exclude>
+        <exclude>${project.groupId}:zeppelin-web-angular</exclude>
       </excludes>
       <useProjectArtifact>false</useProjectArtifact>
       <useTransitiveFiltering>true</useTransitiveFiltering>
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 2a6e0bb..a6123ec 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 class ZeppelinConfiguration extends XMLConfiguration {
     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-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
index f9d8e8b..966f5b5 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 @@ import org.slf4j.LoggerFactory;
 /** 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 class ZeppelinServer extends ResourceConfig {
     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 @@ public class ZeppelinServer extends ResourceConfig {
           }
         });
 
-    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 @@ public class ZeppelinServer extends ResourceConfig {
                            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 @@ public class ZeppelinServer extends ResourceConfig {
       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 @@ public class ZeppelinServer extends ResourceConfig {
   }
 
   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 @@ public class ZeppelinServer extends ResourceConfig {
     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/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
index ca8ff95..d107547 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
@@ -191,6 +191,8 @@ public abstract class AbstractTestRestApi {
           zeppelinHome.getAbsolutePath());
       System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_WAR.getVarName(),
           new File("../zeppelin-web/dist").getAbsolutePath());
+      System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_ANGULAR_WAR.getVarName(),
+              new File("../zeppelin-web-angular/dist").getAbsolutePath());
       System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_CONF_DIR.getVarName(),
           confDir.getAbsolutePath());
       System.setProperty(
@@ -208,6 +210,7 @@ public abstract class AbstractTestRestApi {
       // some test profile does not build zeppelin-web.
       // to prevent zeppelin starting up fail, create zeppelin-web/dist directory
       new File("../zeppelin-web/dist").mkdirs();
+      new File("../zeppelin-web-angular/dist").mkdirs();
 
       LOG.info("Staring test Zeppelin up...");
       ZeppelinConfiguration conf = ZeppelinConfiguration.create();
diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json
index 9d8cafe..5459ffd 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -5,7 +5,7 @@
     "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",
+    "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",
diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml
index e0a1f7b..cae5214 100644
--- a/zeppelin-web-angular/pom.xml
+++ b/zeppelin-web-angular/pom.xml
@@ -26,7 +26,7 @@
   <artifactId>zeppelin-web-angular</artifactId>
   <packaging>war</packaging>
   <version>0.9.0-SNAPSHOT</version>
-  <name>Zeppelin: web Application</name>
+  <name>Zeppelin: web angular Application</name>
 
   <!-- See https://github.com/eirslett/frontend-maven-plugin/issues/229 -->
   <prerequisites>