Repository: wix/quix Branch: master Commit: dca0b4b6f10e Files: 1185 Total size: 3.1 MB Directory structure: gitextract_w_z6e63k/ ├── .dockerignore ├── .github/ │ └── workflows/ │ ├── quix-backend-build.yml │ ├── quix-documentation-publish.yml │ ├── quix-frontend-publish.yml │ └── quix-frontend-release.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build-selector.sh ├── docker-compose.prebuilt.yml ├── docker-compose.yml ├── documentation/ │ ├── docs/ │ │ ├── about.md │ │ ├── architecture.md │ │ ├── athena.md │ │ ├── bigquery.md │ │ ├── clickhouse.md │ │ ├── installation.md │ │ ├── jdbc.md │ │ ├── mariadb.md │ │ ├── mysql.md │ │ ├── oracle.md │ │ ├── postgresql.md │ │ ├── presto.md │ │ ├── python.md │ │ └── redshift.md │ └── website/ │ ├── README.md │ ├── blog/ │ │ └── 2019-11-25-first-release.md │ ├── core/ │ │ └── Footer.js │ ├── i18n/ │ │ └── en.json │ ├── package.json │ ├── pages/ │ │ └── en/ │ │ ├── help.js │ │ ├── index.js │ │ └── users.js │ ├── sidebars.json │ ├── siteConfig.js │ └── static/ │ └── css/ │ └── custom.css ├── env-example ├── quix-backend/ │ ├── Dockerfile │ ├── README.md │ ├── build.sbt │ ├── quix-api/ │ │ └── src/ │ │ └── main/ │ │ └── scala/ │ │ └── quix/ │ │ └── api/ │ │ ├── v1/ │ │ │ ├── db/ │ │ │ │ └── Db.scala │ │ │ ├── execute/ │ │ │ │ ├── Api.scala │ │ │ │ ├── Batch.scala │ │ │ │ ├── ExecutionEngine.scala │ │ │ │ └── ExecutionProtocol.scala │ │ │ ├── module/ │ │ │ │ └── ExecutionModule.scala │ │ │ └── users/ │ │ │ └── Users.scala │ │ └── v2/ │ │ └── execute/ │ │ ├── Builder.scala │ │ ├── ExecutionModule.scala │ │ ├── Executor.scala │ │ ├── Session.scala │ │ └── SubQuery.scala │ ├── quix-core/ │ │ └── src/ │ │ ├── main/ │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── core/ │ │ │ ├── db/ │ │ │ │ ├── DbOps.scala │ │ │ │ ├── RefreshableAutocomplete.scala │ │ │ │ ├── RefreshableCatalogs.scala │ │ │ │ ├── RefreshableDb.scala │ │ │ │ └── State.scala │ │ │ ├── download/ │ │ │ │ ├── DownloadConfig.scala │ │ │ │ └── DownloadableBuilder.scala │ │ │ ├── executions/ │ │ │ │ ├── DelegatingBuilder.scala │ │ │ │ ├── SingleQueryExecutor.scala │ │ │ │ └── SqlModule.scala │ │ │ ├── history/ │ │ │ │ ├── Execution.scala │ │ │ │ ├── HistoryBuilder.scala │ │ │ │ └── dao/ │ │ │ │ ├── HistoryReadDao.scala │ │ │ │ ├── HistoryWriteDao.scala │ │ │ │ ├── InMemoryHistoryDao.scala │ │ │ │ └── MySqlHistoryDao.scala │ │ │ ├── results/ │ │ │ │ ├── MultiBuilder.scala │ │ │ │ └── SingleBuilder.scala │ │ │ ├── sql/ │ │ │ │ ├── PrestoSqlOps.scala │ │ │ │ └── SqlSplitter.scala │ │ │ └── utils/ │ │ │ ├── Chores.scala │ │ │ ├── JsonOps.scala │ │ │ └── TaskOps.scala │ │ └── test/ │ │ ├── resources/ │ │ │ └── db/ │ │ │ └── 001_init.sql │ │ └── scala/ │ │ └── quix/ │ │ └── core/ │ │ ├── db/ │ │ │ ├── DbOpsTest.scala │ │ │ └── DbQueryTest.scala │ │ ├── executions/ │ │ │ └── SqlModuleTest.scala │ │ ├── history/ │ │ │ ├── ExecutionMatchers.scala │ │ │ ├── FakeBuilder.scala │ │ │ ├── FakeClock.scala │ │ │ ├── HistoryBuilderTest.scala │ │ │ └── dao/ │ │ │ ├── HistoryDaoContractTest.scala │ │ │ ├── InMemoryHistoryDaoTest.scala │ │ │ └── MySqlHistoryDaoTest.scala │ │ ├── results/ │ │ │ └── MultiBuilderTest.scala │ │ └── sql/ │ │ ├── PrestoSqlOpsTest.scala │ │ └── StopWordsSplitterTest.scala │ ├── quix-modules/ │ │ ├── quix-athena-module/ │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── scala/ │ │ │ │ └── quix/ │ │ │ │ └── athena/ │ │ │ │ ├── AthenaAutocomplete.scala │ │ │ │ ├── AthenaCatalogs.scala │ │ │ │ ├── AthenaClient.scala │ │ │ │ ├── AthenaConfig.scala │ │ │ │ ├── AthenaQueryExecutor.scala │ │ │ │ ├── AthenaTables.scala │ │ │ │ ├── AwsAthenaClient.scala │ │ │ │ └── TryAthena.scala │ │ │ └── test/ │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── athena/ │ │ │ └── AthenaQueryExecutorTest.scala │ │ ├── quix-bigquery-module/ │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── scala/ │ │ │ │ └── quix/ │ │ │ │ └── bigquery/ │ │ │ │ ├── BigQueryClient.scala │ │ │ │ ├── BigQueryConfig.scala │ │ │ │ ├── BigQueryQueryExecutor.scala │ │ │ │ ├── BigQueryTestQueryExecutor.scala │ │ │ │ ├── GoogleBigQueryClient.scala │ │ │ │ ├── TryBigQuery.scala │ │ │ │ └── db/ │ │ │ │ ├── BigQueryAutocomplete.scala │ │ │ │ ├── BigQueryCatalogs.scala │ │ │ │ └── BigQueryTables.scala │ │ │ └── test/ │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── bigquery/ │ │ │ └── BigQueryQueryExecutorTest.scala │ │ ├── quix-dummy-module/ │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── scala/ │ │ │ │ └── quix/ │ │ │ │ └── dummy/ │ │ │ │ └── DummyQueryExecutor.scala │ │ │ └── test/ │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── dummy/ │ │ │ └── DummyQueryExecutorTest.scala │ │ ├── quix-jdbc-module/ │ │ │ └── src/ │ │ │ ├── it/ │ │ │ │ ├── resources/ │ │ │ │ │ └── db/ │ │ │ │ │ └── 001_init.sql │ │ │ │ └── scala/ │ │ │ │ └── quix/ │ │ │ │ └── jdbc/ │ │ │ │ ├── EmbeddedMysqlDb.scala │ │ │ │ ├── MysqlJdbcIntegrationTest.scala │ │ │ │ ├── MysqlJdbcQueryExecutorIntegrationTest.scala │ │ │ │ └── MysqlJdbcTablesIntegrationTest.scala │ │ │ └── main/ │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── jdbc/ │ │ │ ├── JdbcAutocomplete.scala │ │ │ ├── JdbcCatalogs.scala │ │ │ ├── JdbcQueryExecutor.scala │ │ │ └── JdbcTables.scala │ │ ├── quix-presto-module/ │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── scala/ │ │ │ │ └── quix/ │ │ │ │ └── presto/ │ │ │ │ ├── PrestoConfig.scala │ │ │ │ ├── QueryExecutor.scala │ │ │ │ ├── TestQueryExecutor.scala │ │ │ │ ├── TryPresto.scala │ │ │ │ ├── db/ │ │ │ │ │ ├── PrestoAutocomplete.scala │ │ │ │ │ ├── PrestoCatalogs.scala │ │ │ │ │ └── PrestoTables.scala │ │ │ │ └── rest/ │ │ │ │ ├── PrestoRestApi.scala │ │ │ │ ├── PrestoStateClient.scala │ │ │ │ ├── ScalaJPrestoOps.scala │ │ │ │ └── ScalaJPrestoStateClient.scala │ │ │ └── test/ │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── presto/ │ │ │ ├── QueryExecutorTest.scala │ │ │ ├── db/ │ │ │ │ ├── PrestoAutocompleteTest.scala │ │ │ │ ├── PrestoCatalogsTest.scala │ │ │ │ └── PrestoTablesTest.scala │ │ │ └── rest/ │ │ │ ├── ScalaJPrestoOpsTest.scala │ │ │ └── ScalaJPrestoStateClientTest.scala │ │ └── quix-python-module/ │ │ └── src/ │ │ ├── main/ │ │ │ ├── resources/ │ │ │ │ ├── activator.py │ │ │ │ ├── packages.py │ │ │ │ └── quix.py │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── python/ │ │ │ ├── PythonApi.scala │ │ │ ├── PythonBridge.scala │ │ │ ├── PythonConfig.scala │ │ │ ├── PythonExecutor.scala │ │ │ ├── PythonModule.scala │ │ │ ├── PythonProcessHandler.scala │ │ │ ├── PythonRunningProcess.scala │ │ │ └── TryPython.scala │ │ └── test/ │ │ └── scala/ │ │ └── quix/ │ │ └── python/ │ │ ├── PythonBridgeTest.scala │ │ └── PythonExecutorTest.scala │ ├── quix-webapps/ │ │ └── quix-web-spring/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── resources/ │ │ │ │ ├── application.properties │ │ │ │ └── logback-spring.xml │ │ │ └── scala/ │ │ │ └── quix/ │ │ │ └── web/ │ │ │ ├── Server.scala │ │ │ ├── auth/ │ │ │ │ ├── DemoUsers.scala │ │ │ │ └── JwtUsers.scala │ │ │ ├── controllers/ │ │ │ │ ├── DbController.scala │ │ │ │ ├── DownloadController.scala │ │ │ │ ├── HealthController.scala │ │ │ │ ├── HistoryController.scala │ │ │ │ └── SqlStreamingController.scala │ │ │ └── spring/ │ │ │ ├── HistoryDaoConfig.scala │ │ │ ├── SpringConfig.scala │ │ │ └── WebsocketsConfig.scala │ │ └── test/ │ │ ├── resources/ │ │ │ ├── db/ │ │ │ │ └── 001_init.sql │ │ │ ├── logback-test.xml │ │ │ └── test.properties │ │ └── scala/ │ │ └── quix/ │ │ └── web/ │ │ ├── E2EContext.scala │ │ ├── SpringConfigWithTestExecutor.scala │ │ ├── auth/ │ │ │ ├── DemoUsersTest.scala │ │ │ └── JwtUsersTest.scala │ │ └── controllers/ │ │ ├── DownloadControllerTest.scala │ │ ├── EmbeddedMySql.scala │ │ ├── ExecutionEventTest.scala │ │ ├── HealthControllerTest.scala │ │ ├── HistoryControllerTest.scala │ │ ├── JdbcSqlStreamingControllerTest.scala │ │ ├── PrestoDbControllerTest.scala │ │ ├── PythonStreamingControllerTest.scala │ │ └── SqlStreamingControllerTest.scala │ └── version.sbt ├── quix-frontend/ │ ├── .dockerignore │ ├── .nvmrc │ ├── Dockerfile │ ├── README.md │ ├── client/ │ │ ├── .dockerignore │ │ ├── .gitignore │ │ ├── .npmignore │ │ ├── .npmrc │ │ ├── .nvmrc │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── app.scss │ │ │ ├── app.ts │ │ │ ├── bootstrap.ts │ │ │ ├── components/ │ │ │ │ ├── User/ │ │ │ │ │ ├── UserAvatar.tsx │ │ │ │ │ └── UserAvatarAndName.tsx │ │ │ │ ├── actions/ │ │ │ │ │ ├── actions-testkit.ts │ │ │ │ │ ├── actions-types.ts │ │ │ │ │ ├── actions.html │ │ │ │ │ ├── actions.scss │ │ │ │ │ └── actions.ts │ │ │ │ ├── breadcrumbs/ │ │ │ │ │ ├── breadcrumbs-testkit.ts │ │ │ │ │ ├── breadcrumbs-types.ts │ │ │ │ │ ├── breadcrumbs.html │ │ │ │ │ ├── breadcrumbs.scss │ │ │ │ │ └── breadcrumbs.ts │ │ │ │ ├── db-sidebar/ │ │ │ │ │ ├── db-sidebar-testkit.ts │ │ │ │ │ ├── db-sidebar-types.ts │ │ │ │ │ ├── db-sidebar.html │ │ │ │ │ ├── db-sidebar.scss │ │ │ │ │ └── db-sidebar.ts │ │ │ │ ├── destination-picker/ │ │ │ │ │ ├── destination-picker-testkit.ts │ │ │ │ │ ├── destination-picker-types.ts │ │ │ │ │ ├── destination-picker.html │ │ │ │ │ ├── destination-picker.scss │ │ │ │ │ └── destination-picker.ts │ │ │ │ ├── files-sidebar/ │ │ │ │ │ ├── files-sidebar-testkit.ts │ │ │ │ │ ├── files-sidebar-types.ts │ │ │ │ │ ├── files-sidebar.html │ │ │ │ │ ├── files-sidebar.scss │ │ │ │ │ └── files-sidebar.ts │ │ │ │ ├── header/ │ │ │ │ │ ├── header-testkit.ts │ │ │ │ │ ├── header-types.ts │ │ │ │ │ ├── header.html │ │ │ │ │ ├── header.scss │ │ │ │ │ └── header.ts │ │ │ │ ├── image/ │ │ │ │ │ ├── image-types.ts │ │ │ │ │ ├── image.html │ │ │ │ │ ├── image.scss │ │ │ │ │ └── image.ts │ │ │ │ ├── index.ts │ │ │ │ ├── meta/ │ │ │ │ │ ├── meta-testkit.ts │ │ │ │ │ ├── meta-types.ts │ │ │ │ │ ├── meta.html │ │ │ │ │ ├── meta.scss │ │ │ │ │ └── meta.ts │ │ │ │ ├── note/ │ │ │ │ │ ├── note-events.ts │ │ │ │ │ ├── note-testkit.ts │ │ │ │ │ ├── note-types.ts │ │ │ │ │ ├── note.html │ │ │ │ │ ├── note.scss │ │ │ │ │ └── note.ts │ │ │ │ ├── note-hints/ │ │ │ │ │ ├── note-hints.html │ │ │ │ │ ├── note-hints.scss │ │ │ │ │ └── note-hints.ts │ │ │ │ ├── note-share/ │ │ │ │ │ ├── note-share-testkit.ts │ │ │ │ │ ├── note-share-types.ts │ │ │ │ │ ├── note-share.html │ │ │ │ │ ├── note-share.scss │ │ │ │ │ └── note-share.ts │ │ │ │ ├── npc/ │ │ │ │ │ ├── npc.html │ │ │ │ │ ├── npc.scss │ │ │ │ │ └── npc.ts │ │ │ │ ├── plugin-picker/ │ │ │ │ │ ├── plugin-picker-testkit.ts │ │ │ │ │ ├── plugin-picker-types.ts │ │ │ │ │ ├── plugin-picker.html │ │ │ │ │ ├── plugin-picker.scss │ │ │ │ │ └── plugin-picker.ts │ │ │ │ ├── runner/ │ │ │ │ │ ├── runner-results-formatter.ts │ │ │ │ │ ├── runner-testkit.ts │ │ │ │ │ ├── runner-types.ts │ │ │ │ │ ├── runner.html │ │ │ │ │ ├── runner.scss │ │ │ │ │ └── runner.ts │ │ │ │ ├── search-results/ │ │ │ │ │ ├── search-results-testkit.ts │ │ │ │ │ ├── search-results-types.ts │ │ │ │ │ ├── search-results.html │ │ │ │ │ ├── search-results.scss │ │ │ │ │ └── search-results.ts │ │ │ │ └── temp-query/ │ │ │ │ ├── temp-query-testkit.ts │ │ │ │ ├── temp-query-types.ts │ │ │ │ ├── temp-query.html │ │ │ │ ├── temp-query.scss │ │ │ │ └── temp-query.ts │ │ │ ├── config.ts │ │ │ ├── custom.d.ts │ │ │ ├── data/ │ │ │ │ ├── examples-notebook.ts │ │ │ │ ├── index.ts │ │ │ │ └── quix-folder.ts │ │ │ ├── external-types.d.ts │ │ │ ├── hooks.ts │ │ │ ├── index.vm │ │ │ ├── lib/ │ │ │ │ ├── app/ │ │ │ │ │ ├── bootstrap.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── directives/ │ │ │ │ │ │ ├── app/ │ │ │ │ │ │ │ ├── app.html │ │ │ │ │ │ │ ├── app.scss │ │ │ │ │ │ │ └── app.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── login/ │ │ │ │ │ │ ├── login.html │ │ │ │ │ │ ├── login.scss │ │ │ │ │ │ └── login.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── app.ts │ │ │ │ │ │ ├── appStoreProvider.tsx │ │ │ │ │ │ ├── builder.ts │ │ │ │ │ │ ├── navigator.ts │ │ │ │ │ │ ├── plugin-builder.ts │ │ │ │ │ │ ├── sso.ts │ │ │ │ │ │ └── user.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── typings/ │ │ │ │ │ │ ├── story-builder.ts │ │ │ │ │ │ ├── types.d.ts │ │ │ │ │ │ └── window.ts │ │ │ │ │ └── utils/ │ │ │ │ │ └── scope-utils.ts │ │ │ │ ├── code-editor/ │ │ │ │ │ ├── ace-extensions/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── language-tools.ts │ │ │ │ │ │ ├── presto-snippets.ts │ │ │ │ │ │ ├── presto.mode.ts │ │ │ │ │ │ └── searchbox.ts │ │ │ │ │ ├── bootstrap.ts │ │ │ │ │ ├── directives/ │ │ │ │ │ │ ├── code-editor.html │ │ │ │ │ │ ├── code-editor.scss │ │ │ │ │ │ ├── code-editor.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ └── services/ │ │ │ │ │ ├── code-editor-annotator.ts │ │ │ │ │ ├── code-editor-completer.ts │ │ │ │ │ ├── code-editor-instance.ts │ │ │ │ │ ├── code-editor-params.ts │ │ │ │ │ ├── code-editor-selection.ts │ │ │ │ │ ├── code-editor-service.ts │ │ │ │ │ ├── code-editor-shortcuts.ts │ │ │ │ │ └── param-parser/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── param-renderers/ │ │ │ │ │ │ ├── boolean-param-renderer.ts │ │ │ │ │ │ ├── datetime-param-renderer.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── input-param-renderer.ts │ │ │ │ │ │ ├── list-param-renderer.ts │ │ │ │ │ │ ├── option-param-renderer.ts │ │ │ │ │ │ └── textarea-param-renderer.ts │ │ │ │ │ ├── param-serializers/ │ │ │ │ │ │ ├── default-param-serializer.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── param-serializer.ts │ │ │ │ │ │ └── python-param-serializer.ts │ │ │ │ │ ├── param-types.ts │ │ │ │ │ ├── params-parser.ts │ │ │ │ │ └── params-predefined-types.ts │ │ │ │ ├── core/ │ │ │ │ │ ├── ang/ │ │ │ │ │ │ ├── drv/ │ │ │ │ │ │ │ ├── bi-options.drv.ts │ │ │ │ │ │ │ └── bi-validator.drv.ts │ │ │ │ │ │ └── srv/ │ │ │ │ │ │ ├── ng-model/ │ │ │ │ │ │ │ ├── ng-model-test.drv.ts │ │ │ │ │ │ │ ├── ng-model.test.ts │ │ │ │ │ │ │ └── ng-model.ts │ │ │ │ │ │ └── scope/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── scope.test.ts │ │ │ │ │ │ └── scope.ts │ │ │ │ │ ├── config/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── main.angular.ts │ │ │ │ │ ├── srv/ │ │ │ │ │ │ ├── collections/ │ │ │ │ │ │ │ ├── buffered-collection.test.ts │ │ │ │ │ │ │ ├── buffered-collection.ts │ │ │ │ │ │ │ ├── collection.test.ts │ │ │ │ │ │ │ ├── collection.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── partitioned-collection.test.ts │ │ │ │ │ │ │ └── partitioned-collection.ts │ │ │ │ │ │ ├── event-emitter/ │ │ │ │ │ │ │ ├── event-emitter.test.ts │ │ │ │ │ │ │ ├── event-emitter.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── injector/ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── local-storage/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── local-storage.test.ts │ │ │ │ │ │ │ └── local-storage.ts │ │ │ │ │ │ ├── model/ │ │ │ │ │ │ │ ├── model.test.ts │ │ │ │ │ │ │ └── model.ts │ │ │ │ │ │ ├── socket/ │ │ │ │ │ │ │ └── socket.ts │ │ │ │ │ │ ├── state/ │ │ │ │ │ │ │ ├── localstorage-state-provider.test.ts │ │ │ │ │ │ │ ├── localstorage-state-provider.ts │ │ │ │ │ │ │ ├── state-wrapper.test.ts │ │ │ │ │ │ │ ├── state-wrapper.ts │ │ │ │ │ │ │ ├── state.test.ts │ │ │ │ │ │ │ ├── state.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ ├── url-params.test.ts │ │ │ │ │ │ │ ├── url-params.ts │ │ │ │ │ │ │ ├── url-state-provider.test.ts │ │ │ │ │ │ │ └── url-state-provider.ts │ │ │ │ │ │ └── view-model/ │ │ │ │ │ │ ├── view-model.test.ts │ │ │ │ │ │ └── view-model.ts │ │ │ │ │ ├── types/ │ │ │ │ │ │ └── angular-promise.d.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── lodash4-polyfill.ts │ │ │ │ │ ├── lodash4-polyfill.types.ts │ │ │ │ │ ├── utils.test-prepare.ts │ │ │ │ │ └── utils.test.ts │ │ │ │ ├── file-explorer/ │ │ │ │ │ ├── bootstrap.ts │ │ │ │ │ ├── directives/ │ │ │ │ │ │ ├── file-explorer-dynamic.html │ │ │ │ │ │ ├── file-explorer-static.html │ │ │ │ │ │ ├── file-explorer-vm.ts │ │ │ │ │ │ ├── file-explorer.scss │ │ │ │ │ │ ├── file-explorer.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ └── services/ │ │ │ │ │ ├── file-explorer-controller.ts │ │ │ │ │ ├── file-explorer-instance.ts │ │ │ │ │ ├── file-explorer-models.ts │ │ │ │ │ ├── file-explorer-tools.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── language-parsers/ │ │ │ │ │ ├── presto-grammar/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── lang/ │ │ │ │ │ │ └── presto/ │ │ │ │ │ │ ├── SqlBase.tokens │ │ │ │ │ │ ├── SqlBaseLexer.tokens │ │ │ │ │ │ ├── SqlBaseLexer.ts │ │ │ │ │ │ ├── SqlBaseListener.ts │ │ │ │ │ │ ├── SqlBaseParser.ts │ │ │ │ │ │ └── SqlBaseVisitor.ts │ │ │ │ │ ├── python-grammar/ │ │ │ │ │ │ └── lang/ │ │ │ │ │ │ └── python/ │ │ │ │ │ │ ├── Python3Lexer.js │ │ │ │ │ │ ├── Python3Lexer.tokens │ │ │ │ │ │ ├── Python3Listener.js │ │ │ │ │ │ ├── Python3Parser.js │ │ │ │ │ │ ├── Python3Visitor.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── python-parser/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── parser/ │ │ │ │ │ │ │ ├── errors-listener.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── parser.spec.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── tokenizer/ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── types/ │ │ │ │ │ │ │ ├── 3rd-party.d.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── web-worker/ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ ├── web-worker-entry.ts │ │ │ │ │ │ ├── web-worker-manager.ts │ │ │ │ │ │ └── web-worker.ts │ │ │ │ │ └── sql-parser/ │ │ │ │ │ ├── auto-format/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── parser/ │ │ │ │ │ │ ├── errors-listener.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── parser.spec.ts │ │ │ │ │ │ ├── presto-listener.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── tokenizer/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── tokenizer.spec.ts │ │ │ │ │ │ └── tokensMap.ts │ │ │ │ │ ├── types/ │ │ │ │ │ │ ├── 3rd-party.d.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── web-worker/ │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── web-worker-entry.ts │ │ │ │ │ ├── web-worker-manager.ts │ │ │ │ │ └── web-worker.ts │ │ │ │ ├── runner/ │ │ │ │ │ ├── bootstrap.ts │ │ │ │ │ ├── config/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── directives/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── python-runner/ │ │ │ │ │ │ │ ├── python-runner-init.ts │ │ │ │ │ │ │ ├── python-runner.html │ │ │ │ │ │ │ ├── python-runner.scss │ │ │ │ │ │ │ └── python-runner.ts │ │ │ │ │ │ ├── results/ │ │ │ │ │ │ │ └── console/ │ │ │ │ │ │ │ ├── console-result-testkit.ts │ │ │ │ │ │ │ ├── console-result.html │ │ │ │ │ │ │ ├── console-result.scss │ │ │ │ │ │ │ ├── console-result.ts │ │ │ │ │ │ │ └── console-types.ts │ │ │ │ │ │ ├── runner/ │ │ │ │ │ │ │ ├── runner.html │ │ │ │ │ │ │ ├── runner.scss │ │ │ │ │ │ │ └── runner.ts │ │ │ │ │ │ └── sql-runner/ │ │ │ │ │ │ ├── sql-runner.html │ │ │ │ │ │ ├── sql-runner.scss │ │ │ │ │ │ └── sql-runner.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── autocomplete/ │ │ │ │ │ │ │ ├── autocomplete-service.ts │ │ │ │ │ │ │ ├── autocomplete-utils.ts │ │ │ │ │ │ │ ├── highlight-and-score.ts │ │ │ │ │ │ │ └── old-autocomplete-service.ts │ │ │ │ │ │ ├── db/ │ │ │ │ │ │ │ └── db-service.ts │ │ │ │ │ │ ├── permissions/ │ │ │ │ │ │ │ └── permissions-service.ts │ │ │ │ │ │ ├── runner-event.ts │ │ │ │ │ │ ├── runner-events.ts │ │ │ │ │ │ ├── runner-query.ts │ │ │ │ │ │ ├── runner-service.ts │ │ │ │ │ │ ├── runner-socket.ts │ │ │ │ │ │ ├── runner-state.ts │ │ │ │ │ │ ├── syntax-valdator/ │ │ │ │ │ │ │ └── syntax-validator-service.ts │ │ │ │ │ │ └── workers/ │ │ │ │ │ │ ├── python-parser-worker.ts │ │ │ │ │ │ └── sql-parser-worker.ts │ │ │ │ │ └── typings/ │ │ │ │ │ ├── angular-promise.d.ts │ │ │ │ │ ├── runner-types.ts │ │ │ │ │ └── types.d.ts │ │ │ │ ├── sql-autocomplete/ │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ ├── sql-autocomplete-adapter-utills.ts │ │ │ │ │ │ ├── sql-autocomplete-adapter.ts │ │ │ │ │ │ ├── tests/ │ │ │ │ │ │ │ ├── get-completion-tests/ │ │ │ │ │ │ │ │ ├── expected-results.ts │ │ │ │ │ │ │ │ ├── get-completion-Items.spec.ts │ │ │ │ │ │ │ │ └── test-inputs/ │ │ │ │ │ │ │ │ ├── input-query-context.ts │ │ │ │ │ │ │ │ └── input-table.ts │ │ │ │ │ │ │ └── test-utils/ │ │ │ │ │ │ │ ├── mock-db-config.ts │ │ │ │ │ │ │ ├── test-getCompletionItemsFromQueryContext.spec.ts │ │ │ │ │ │ │ └── tests-utils.ts │ │ │ │ │ │ ├── trinoToJs.spec.ts │ │ │ │ │ │ ├── trinoToJs.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── db-info/ │ │ │ │ │ │ ├── db-info-service.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── languge/ │ │ │ │ │ │ └── reserved-words.ts │ │ │ │ │ └── sql-context-evaluator/ │ │ │ │ │ ├── context-evaluator.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── position-evaluator.ts │ │ │ │ │ ├── presto-context-listener.ts │ │ │ │ │ ├── tests/ │ │ │ │ │ │ ├── queries-spec/ │ │ │ │ │ │ │ ├── basic-queries.spec.ts │ │ │ │ │ │ │ ├── join-queries.spec.ts │ │ │ │ │ │ │ ├── nested-queries.spec.ts │ │ │ │ │ │ │ ├── union-queries.spec.ts │ │ │ │ │ │ │ ├── utils.ts │ │ │ │ │ │ │ └── with-queries.spec.ts │ │ │ │ │ │ └── result-options/ │ │ │ │ │ │ ├── basic-results.ts │ │ │ │ │ │ ├── nested-results.ts │ │ │ │ │ │ ├── utils.ts │ │ │ │ │ │ └── with-results.ts │ │ │ │ │ ├── tree-analyzer.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── with-clause-analyzer.ts │ │ │ │ ├── sql-formatter/ │ │ │ │ │ ├── LICENSE │ │ │ │ │ ├── core/ │ │ │ │ │ │ ├── Formatter.ts │ │ │ │ │ │ ├── Indentation.ts │ │ │ │ │ │ ├── InlineBlock.ts │ │ │ │ │ │ ├── Params.ts │ │ │ │ │ │ ├── Tokenizer.ts │ │ │ │ │ │ └── tokenTypes.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── languages/ │ │ │ │ │ │ ├── SqlWithQuixVarFormmater.ts │ │ │ │ │ │ └── StandardSqlFormatter.ts │ │ │ │ │ └── sqlFormatter.ts │ │ │ │ ├── store/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── services/ │ │ │ │ │ ├── store-cache.ts │ │ │ │ │ ├── store-logger.ts │ │ │ │ │ └── store.ts │ │ │ │ ├── ui/ │ │ │ │ │ ├── app.scss │ │ │ │ │ ├── assets/ │ │ │ │ │ │ └── css/ │ │ │ │ │ │ ├── action.scss │ │ │ │ │ │ ├── alert.scss │ │ │ │ │ │ ├── align.scss │ │ │ │ │ │ ├── animations.scss │ │ │ │ │ │ ├── app/ │ │ │ │ │ │ │ ├── app-header.scss │ │ │ │ │ │ │ └── app-menu.scss │ │ │ │ │ │ ├── badge.scss │ │ │ │ │ │ ├── border.scss │ │ │ │ │ │ ├── button.scss │ │ │ │ │ │ ├── caret.scss │ │ │ │ │ │ ├── colors.scss │ │ │ │ │ │ ├── def/ │ │ │ │ │ │ │ ├── action.def.scss │ │ │ │ │ │ │ ├── alert.def.scss │ │ │ │ │ │ │ ├── align.def.scss │ │ │ │ │ │ │ ├── animations.def.scss │ │ │ │ │ │ │ ├── app/ │ │ │ │ │ │ │ │ ├── app-header.def.scss │ │ │ │ │ │ │ │ └── app-menu.def.scss │ │ │ │ │ │ │ ├── badge.def.scss │ │ │ │ │ │ │ ├── border.def.scss │ │ │ │ │ │ │ ├── button.def.scss │ │ │ │ │ │ │ ├── caret.def.scss │ │ │ │ │ │ │ ├── colors.def.scss │ │ │ │ │ │ │ ├── content.def.scss │ │ │ │ │ │ │ ├── defaults.def.scss │ │ │ │ │ │ │ ├── dropdown.def.scss │ │ │ │ │ │ │ ├── empty-state.def.scss │ │ │ │ │ │ │ ├── flex.def.scss │ │ │ │ │ │ │ ├── header.def.scss │ │ │ │ │ │ │ ├── heading.def.scss │ │ │ │ │ │ │ ├── hint.def.scss │ │ │ │ │ │ │ ├── icon.def.scss │ │ │ │ │ │ │ ├── input.def.scss │ │ │ │ │ │ │ ├── label.def.scss │ │ │ │ │ │ │ ├── link.def.scss │ │ │ │ │ │ │ ├── media.def.scss │ │ │ │ │ │ │ ├── morph.def.scss │ │ │ │ │ │ │ ├── nav-tabs.def.scss │ │ │ │ │ │ │ ├── panel.def.scss │ │ │ │ │ │ │ ├── section.def.scss │ │ │ │ │ │ │ ├── space.def.scss │ │ │ │ │ │ │ ├── spinner.def.scss │ │ │ │ │ │ │ ├── state.def.scss │ │ │ │ │ │ │ ├── table.def.scss │ │ │ │ │ │ │ ├── tag.def.scss │ │ │ │ │ │ │ ├── theme.def.scss │ │ │ │ │ │ │ ├── toggle.def.scss │ │ │ │ │ │ │ └── trim.def.scss │ │ │ │ │ │ ├── dialog.scss │ │ │ │ │ │ ├── dropdown.scss │ │ │ │ │ │ ├── empty-state.scss │ │ │ │ │ │ ├── flex.scss │ │ │ │ │ │ ├── fonts.scss │ │ │ │ │ │ ├── form.scss │ │ │ │ │ │ ├── heading.scss │ │ │ │ │ │ ├── hint.scss │ │ │ │ │ │ ├── home-action.scss │ │ │ │ │ │ ├── hover.scss │ │ │ │ │ │ ├── icon.scss │ │ │ │ │ │ ├── input.scss │ │ │ │ │ │ ├── label.scss │ │ │ │ │ │ ├── link.scss │ │ │ │ │ │ ├── media.scss │ │ │ │ │ │ ├── mouse.scss │ │ │ │ │ │ ├── nav-tabs.scss │ │ │ │ │ │ ├── no-select.scss │ │ │ │ │ │ ├── panel.scss │ │ │ │ │ │ ├── reset.scss │ │ │ │ │ │ ├── scroll.scss │ │ │ │ │ │ ├── section.scss │ │ │ │ │ │ ├── space.scss │ │ │ │ │ │ ├── spinner.scss │ │ │ │ │ │ ├── state.scss │ │ │ │ │ │ ├── table.scss │ │ │ │ │ │ ├── tag.scss │ │ │ │ │ │ ├── text.scss │ │ │ │ │ │ ├── theme.scss │ │ │ │ │ │ ├── toggle.scss │ │ │ │ │ │ └── wrap.scss │ │ │ │ │ ├── bootstrap.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── Highlighter.tsx │ │ │ │ │ │ ├── autocomplete/ │ │ │ │ │ │ │ ├── Autocomplete.tsx │ │ │ │ │ │ │ └── autocomplete.hook.ts │ │ │ │ │ │ ├── date-picker/ │ │ │ │ │ │ │ ├── DatePicker.tsx │ │ │ │ │ │ │ ├── date-picker-utils.ts │ │ │ │ │ │ │ └── date-picker.hook.ts │ │ │ │ │ │ ├── dropdown/ │ │ │ │ │ │ │ ├── Dropdown.tsx │ │ │ │ │ │ │ └── dropdown.scss │ │ │ │ │ │ ├── hoc/ │ │ │ │ │ │ │ └── makePagination.tsx │ │ │ │ │ │ ├── input/ │ │ │ │ │ │ │ ├── Input.tsx │ │ │ │ │ │ │ └── input.scss │ │ │ │ │ │ ├── panel/ │ │ │ │ │ │ │ └── Panel.tsx │ │ │ │ │ │ ├── states/ │ │ │ │ │ │ │ ├── EmptyState.tsx │ │ │ │ │ │ │ ├── ErrorState.tsx │ │ │ │ │ │ │ ├── FilterInitialState.tsx │ │ │ │ │ │ │ ├── InitialState.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── table/ │ │ │ │ │ │ ├── Table.scss │ │ │ │ │ │ ├── Table.tsx │ │ │ │ │ │ ├── TableRow.tsx │ │ │ │ │ │ └── table-testkit.ts │ │ │ │ │ ├── directives/ │ │ │ │ │ │ ├── breadcrumbs/ │ │ │ │ │ │ │ ├── breadcrumbs.html │ │ │ │ │ │ │ ├── breadcrumbs.scss │ │ │ │ │ │ │ ├── breadcrumbs.story.ts │ │ │ │ │ │ │ └── breadcrumbs.ts │ │ │ │ │ │ ├── common/ │ │ │ │ │ │ │ └── dropdown-list.ts │ │ │ │ │ │ ├── content-editable/ │ │ │ │ │ │ │ ├── content-editable.scss │ │ │ │ │ │ │ └── content-editable.ts │ │ │ │ │ │ ├── copy-to-clipboard/ │ │ │ │ │ │ │ ├── copy-to-clipboard.html │ │ │ │ │ │ │ ├── copy-to-clipboard.scss │ │ │ │ │ │ │ ├── copy-to-clipboard.story.ts │ │ │ │ │ │ │ └── copy-to-clipboard.ts │ │ │ │ │ │ ├── date-picker/ │ │ │ │ │ │ │ ├── date-picker.scss │ │ │ │ │ │ │ ├── date-picker.story.ts │ │ │ │ │ │ │ └── date-picker.ts │ │ │ │ │ │ ├── draggable/ │ │ │ │ │ │ │ ├── draggable.story.ts │ │ │ │ │ │ │ └── draggable.ts │ │ │ │ │ │ ├── dropdown/ │ │ │ │ │ │ │ ├── dropdown.html │ │ │ │ │ │ │ ├── dropdown.scss │ │ │ │ │ │ │ ├── dropdown.story.ts │ │ │ │ │ │ │ └── dropdown.ts │ │ │ │ │ │ ├── droppable/ │ │ │ │ │ │ │ ├── droppable.story.ts │ │ │ │ │ │ │ └── droppable.ts │ │ │ │ │ │ ├── dual-action/ │ │ │ │ │ │ │ ├── dual-action.html │ │ │ │ │ │ │ ├── dual-action.scss │ │ │ │ │ │ │ └── dual-action.ts │ │ │ │ │ │ ├── editable/ │ │ │ │ │ │ │ ├── editable.html │ │ │ │ │ │ │ ├── editable.scss │ │ │ │ │ │ │ ├── editable.story.ts │ │ │ │ │ │ │ └── editable.ts │ │ │ │ │ │ ├── filter/ │ │ │ │ │ │ │ ├── filter-items.ts │ │ │ │ │ │ │ ├── filter-term.ts │ │ │ │ │ │ │ ├── filter.story.ts │ │ │ │ │ │ │ ├── filter.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── focus/ │ │ │ │ │ │ │ ├── focus-if.ts │ │ │ │ │ │ │ ├── focus.story.ts │ │ │ │ │ │ │ ├── focus.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── foldable/ │ │ │ │ │ │ │ ├── foldable.html │ │ │ │ │ │ │ ├── foldable.scss │ │ │ │ │ │ │ ├── foldable.story.ts │ │ │ │ │ │ │ └── foldable.ts │ │ │ │ │ │ ├── html/ │ │ │ │ │ │ │ └── html.ts │ │ │ │ │ │ ├── icon-badge/ │ │ │ │ │ │ │ ├── icon-badge.html │ │ │ │ │ │ │ ├── icon-badge.scss │ │ │ │ │ │ │ └── icon-badge.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── infinite-scroll/ │ │ │ │ │ │ │ └── infinite-scroll.ts │ │ │ │ │ │ ├── info/ │ │ │ │ │ │ │ ├── info.html │ │ │ │ │ │ │ ├── info.scss │ │ │ │ │ │ │ └── info.ts │ │ │ │ │ │ ├── key-nav/ │ │ │ │ │ │ │ └── key-nav.ts │ │ │ │ │ │ ├── maximizable/ │ │ │ │ │ │ │ ├── maximizable.scss │ │ │ │ │ │ │ ├── maximizable.story.ts │ │ │ │ │ │ │ └── maximizable.ts │ │ │ │ │ │ ├── on-image-load/ │ │ │ │ │ │ │ └── on-image-load.ts │ │ │ │ │ │ ├── progress-gauge/ │ │ │ │ │ │ │ ├── progress-gauge.html │ │ │ │ │ │ │ ├── progress-gauge.scss │ │ │ │ │ │ │ ├── progress-gauge.story.ts │ │ │ │ │ │ │ └── progress-gauge.ts │ │ │ │ │ │ ├── progress-line/ │ │ │ │ │ │ │ ├── progress-line.html │ │ │ │ │ │ │ ├── progress-line.scss │ │ │ │ │ │ │ └── progress-line.ts │ │ │ │ │ │ ├── resizable/ │ │ │ │ │ │ │ └── resizable.ts │ │ │ │ │ │ ├── scroll/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── scroll-to.ts │ │ │ │ │ │ ├── search/ │ │ │ │ │ │ │ ├── search.html │ │ │ │ │ │ │ ├── search.scss │ │ │ │ │ │ │ ├── search.story.ts │ │ │ │ │ │ │ └── search.ts │ │ │ │ │ │ ├── simple-select/ │ │ │ │ │ │ │ ├── simple-select.html │ │ │ │ │ │ │ ├── simple-select.scss │ │ │ │ │ │ │ ├── simple-select.story.ts │ │ │ │ │ │ │ └── simple-select.ts │ │ │ │ │ │ ├── state-loader/ │ │ │ │ │ │ │ ├── state-loader.scss │ │ │ │ │ │ │ └── state-loader.ts │ │ │ │ │ │ ├── table/ │ │ │ │ │ │ │ ├── header/ │ │ │ │ │ │ │ │ ├── table-header.html │ │ │ │ │ │ │ │ ├── table-header.scss │ │ │ │ │ │ │ │ └── table-header.ts │ │ │ │ │ │ │ ├── row/ │ │ │ │ │ │ │ │ └── table-row.ts │ │ │ │ │ │ │ ├── table.html │ │ │ │ │ │ │ ├── table.scss │ │ │ │ │ │ │ ├── table.story.ts │ │ │ │ │ │ │ └── table.ts │ │ │ │ │ │ ├── tabs/ │ │ │ │ │ │ │ ├── tabs-router.html │ │ │ │ │ │ │ ├── tabs-router.ts │ │ │ │ │ │ │ ├── tabs.html │ │ │ │ │ │ │ ├── tabs.scss │ │ │ │ │ │ │ ├── tabs.story.ts │ │ │ │ │ │ │ └── tabs.ts │ │ │ │ │ │ ├── tags/ │ │ │ │ │ │ │ ├── tags.html │ │ │ │ │ │ │ ├── tags.scss │ │ │ │ │ │ │ ├── tags.story.ts │ │ │ │ │ │ │ └── tags.ts │ │ │ │ │ │ └── tooltip/ │ │ │ │ │ │ ├── tooltip.html │ │ │ │ │ │ ├── tooltip.scss │ │ │ │ │ │ ├── tooltip.story.ts │ │ │ │ │ │ └── tooltip.ts │ │ │ │ │ ├── filters/ │ │ │ │ │ │ ├── absolute-date.ts │ │ │ │ │ │ ├── date-utc.ts │ │ │ │ │ │ ├── date.ts │ │ │ │ │ │ ├── highlight.story.ts │ │ │ │ │ │ ├── highlight.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── relative-date.ts │ │ │ │ │ │ └── to-human-case.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── confirm.story.ts │ │ │ │ │ │ ├── confirm.ts │ │ │ │ │ │ ├── date.ts │ │ │ │ │ │ ├── dialog-testkit.ts │ │ │ │ │ │ ├── dialog.story.ts │ │ │ │ │ │ ├── dialog.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── toast.scss │ │ │ │ │ │ ├── toast.story.ts │ │ │ │ │ │ └── toast.ts │ │ │ │ │ ├── stories/ │ │ │ │ │ │ ├── action.story.ts │ │ │ │ │ │ ├── alert.story.ts │ │ │ │ │ │ ├── align.story.ts │ │ │ │ │ │ ├── badge.story.ts │ │ │ │ │ │ ├── border.story.ts │ │ │ │ │ │ ├── button.story.ts │ │ │ │ │ │ ├── colors.story.ts │ │ │ │ │ │ ├── empty-state.story.ts │ │ │ │ │ │ ├── flex.story.ts │ │ │ │ │ │ ├── form.story.ts │ │ │ │ │ │ ├── hint.story.ts │ │ │ │ │ │ ├── home-action.story.ts │ │ │ │ │ │ ├── input.story.ts │ │ │ │ │ │ ├── label.story.ts │ │ │ │ │ │ ├── media.story.ts │ │ │ │ │ │ ├── scroll.story.ts │ │ │ │ │ │ ├── space.story.ts │ │ │ │ │ │ ├── spinner.story.ts │ │ │ │ │ │ ├── tag.story.ts │ │ │ │ │ │ └── text.story.ts │ │ │ │ │ └── typings/ │ │ │ │ │ ├── globals.d.ts │ │ │ │ │ ├── turnerjs.d.ts │ │ │ │ │ └── types.d.ts │ │ │ │ ├── viz/ │ │ │ │ │ ├── bootstrap.ts │ │ │ │ │ ├── directives/ │ │ │ │ │ │ ├── chart/ │ │ │ │ │ │ │ ├── chart-renderer.ts │ │ │ │ │ │ │ ├── chart.html │ │ │ │ │ │ │ ├── chart.scss │ │ │ │ │ │ │ ├── chart.ts │ │ │ │ │ │ │ └── filter/ │ │ │ │ │ │ │ ├── chart-filter.html │ │ │ │ │ │ │ ├── chart-filter.scss │ │ │ │ │ │ │ └── chart-filter.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── picker/ │ │ │ │ │ │ │ ├── picker.html │ │ │ │ │ │ │ ├── picker.scss │ │ │ │ │ │ │ └── picker.ts │ │ │ │ │ │ ├── pie/ │ │ │ │ │ │ │ ├── filter/ │ │ │ │ │ │ │ │ ├── pie-filter.html │ │ │ │ │ │ │ │ ├── pie-filter.scss │ │ │ │ │ │ │ │ └── pie-filter.ts │ │ │ │ │ │ │ ├── pie-renderer.ts │ │ │ │ │ │ │ ├── pie.html │ │ │ │ │ │ │ ├── pie.scss │ │ │ │ │ │ │ └── pie.ts │ │ │ │ │ │ ├── table/ │ │ │ │ │ │ │ ├── table-renderer.ts │ │ │ │ │ │ │ ├── table.html │ │ │ │ │ │ │ ├── table.scss │ │ │ │ │ │ │ └── table.ts │ │ │ │ │ │ ├── viz.html │ │ │ │ │ │ ├── viz.scss │ │ │ │ │ │ └── viz.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── chart/ │ │ │ │ │ │ │ ├── chart-conf.ts │ │ │ │ │ │ │ ├── chart-data-service.ts │ │ │ │ │ │ │ ├── chart-filter-service.ts │ │ │ │ │ │ │ ├── chart-utils.ts │ │ │ │ │ │ │ └── chart-viz-service.ts │ │ │ │ │ │ ├── viz-conf.ts │ │ │ │ │ │ ├── viz-data-service.ts │ │ │ │ │ │ ├── viz-filter-service.ts │ │ │ │ │ │ └── viz-service.ts │ │ │ │ │ ├── transducers/ │ │ │ │ │ │ ├── chart/ │ │ │ │ │ │ │ ├── chart-input-filter-transducer.ts │ │ │ │ │ │ │ ├── chart-meta-transducer.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── parse-dates-transducer.ts │ │ │ │ │ │ ├── parse-floats-transducer.ts │ │ │ │ │ │ ├── sort-transducer.ts │ │ │ │ │ │ └── ungroup-transducer.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── web-worker-infra/ │ │ │ │ ├── types.ts │ │ │ │ ├── web-worker/ │ │ │ │ │ └── index.ts │ │ │ │ └── web-worker-manager/ │ │ │ │ └── index.ts │ │ │ ├── plugins/ │ │ │ │ ├── db/ │ │ │ │ │ ├── athena-db-plugin.ts │ │ │ │ │ ├── bigquery-db-plugin.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── jdbc-db-plugin.ts │ │ │ │ │ └── presto-db-plugin.ts │ │ │ │ ├── index.ts │ │ │ │ ├── note/ │ │ │ │ │ ├── athena-note-plugin.ts │ │ │ │ │ ├── bigquery-note-plugin.ts │ │ │ │ │ ├── default-note-plugin.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── jdbc-note-plugin.ts │ │ │ │ │ ├── presto-note-plugin.ts │ │ │ │ │ └── python-note-plugin.ts │ │ │ │ └── plugin-factory.ts │ │ │ ├── react-components/ │ │ │ │ ├── file-explorer/ │ │ │ │ │ ├── FileExplorerComponent.scss │ │ │ │ │ ├── FileExplorerComponent.tsx │ │ │ │ │ ├── TreeItem.tsx │ │ │ │ │ ├── TreeItemMenu.tsx │ │ │ │ │ ├── file-explorer-testkit.ts │ │ │ │ │ └── file-explorer.ts │ │ │ │ └── index.ts │ │ │ ├── services/ │ │ │ │ ├── db.ts │ │ │ │ ├── dialog.ts │ │ │ │ ├── files.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── use-view-state.ts │ │ │ │ │ └── with-outside-click.ts │ │ │ │ ├── index.ts │ │ │ │ ├── notebook.ts │ │ │ │ ├── notifications.ts │ │ │ │ ├── permissions.ts │ │ │ │ ├── plugins/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── plugin-manager.ts │ │ │ │ │ └── plugin-types.ts │ │ │ │ ├── popup.ts │ │ │ │ ├── resources.ts │ │ │ │ ├── runners.ts │ │ │ │ ├── scope.ts │ │ │ │ ├── search.ts │ │ │ │ ├── state.ts │ │ │ │ └── subscription.ts │ │ │ ├── state-components/ │ │ │ │ ├── base/ │ │ │ │ │ ├── base.html │ │ │ │ │ └── base.ts │ │ │ │ ├── embed/ │ │ │ │ │ ├── embed.ts │ │ │ │ │ └── note/ │ │ │ │ │ ├── embed-note-events.ts │ │ │ │ │ ├── embed-note-reactions.ts │ │ │ │ │ ├── embed-note-scope.ts │ │ │ │ │ ├── embed-note-url.ts │ │ │ │ │ ├── embed-note-vm.ts │ │ │ │ │ ├── embed-note.html │ │ │ │ │ ├── embed-note.scss │ │ │ │ │ └── embed-note.ts │ │ │ │ ├── favorites/ │ │ │ │ │ ├── FavoritesComponent.tsx │ │ │ │ │ ├── favorites-events.ts │ │ │ │ │ ├── favorites-table-fields.tsx │ │ │ │ │ ├── favorites-testkit.ts │ │ │ │ │ ├── favorites.scss │ │ │ │ │ └── favorites.ts │ │ │ │ ├── files/ │ │ │ │ │ ├── files-events.ts │ │ │ │ │ ├── files-reactions.ts │ │ │ │ │ ├── files-scope.ts │ │ │ │ │ ├── files-table-fields.ts │ │ │ │ │ ├── files-testkit.ts │ │ │ │ │ ├── files-types.ts │ │ │ │ │ ├── files-url.ts │ │ │ │ │ ├── files-vm.ts │ │ │ │ │ ├── files.html │ │ │ │ │ ├── files.scss │ │ │ │ │ └── files.ts │ │ │ │ ├── history/ │ │ │ │ │ ├── HistoryComponent.scss │ │ │ │ │ ├── HistoryComponent.tsx │ │ │ │ │ ├── history-events.ts │ │ │ │ │ ├── history-table-fields.tsx │ │ │ │ │ ├── history-testkit.ts │ │ │ │ │ └── history.ts │ │ │ │ ├── home/ │ │ │ │ │ ├── HomeComponent.tsx │ │ │ │ │ ├── home-testkit.ts │ │ │ │ │ ├── home.scss │ │ │ │ │ └── home.ts │ │ │ │ ├── import/ │ │ │ │ │ ├── import.html │ │ │ │ │ └── import.ts │ │ │ │ ├── index.ts │ │ │ │ ├── notebook/ │ │ │ │ │ ├── notebook-events.ts │ │ │ │ │ ├── notebook-reactions.ts │ │ │ │ │ ├── notebook-scope.ts │ │ │ │ │ ├── notebook-testkit.ts │ │ │ │ │ ├── notebook-types.ts │ │ │ │ │ ├── notebook-url.ts │ │ │ │ │ ├── notebook-vm.ts │ │ │ │ │ ├── notebook.html │ │ │ │ │ ├── notebook.scss │ │ │ │ │ └── notebook.ts │ │ │ │ ├── trash-bin/ │ │ │ │ │ ├── TrashBinComponent.tsx │ │ │ │ │ ├── trash-bin-events.ts │ │ │ │ │ ├── trash-bin-table-fields.tsx │ │ │ │ │ └── trash-bin.ts │ │ │ │ └── users/ │ │ │ │ ├── UsersComponent.tsx │ │ │ │ ├── users-events.ts │ │ │ │ ├── users-table-fields.tsx │ │ │ │ ├── users-testkit.ts │ │ │ │ ├── users.scss │ │ │ │ └── users.ts │ │ │ ├── store/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app-actions.ts │ │ │ │ │ └── app-branch.ts │ │ │ │ ├── db/ │ │ │ │ │ ├── db-actions.ts │ │ │ │ │ ├── db-branch.ts │ │ │ │ │ └── db-cache.ts │ │ │ │ ├── deleted-notebook/ │ │ │ │ │ ├── deleted-notebook-actions.ts │ │ │ │ │ ├── deleted-notebook-branch.ts │ │ │ │ │ └── deleted-notebook-cache.ts │ │ │ │ ├── favorites/ │ │ │ │ │ ├── favorites-actions.ts │ │ │ │ │ ├── favorites-branch.ts │ │ │ │ │ └── favorites-cache.ts │ │ │ │ ├── files/ │ │ │ │ │ ├── files-actions.ts │ │ │ │ │ ├── files-branch.ts │ │ │ │ │ └── files-cache.ts │ │ │ │ ├── folder/ │ │ │ │ │ ├── folder-actions.ts │ │ │ │ │ ├── folder-branch.ts │ │ │ │ │ └── folder-cache.ts │ │ │ │ ├── history/ │ │ │ │ │ ├── history-actions.ts │ │ │ │ │ ├── history-branch.ts │ │ │ │ │ └── history-cache.ts │ │ │ │ ├── index.ts │ │ │ │ ├── notebook/ │ │ │ │ │ ├── notebook-actions.ts │ │ │ │ │ ├── notebook-branch.ts │ │ │ │ │ └── notebook-cache.ts │ │ │ │ └── users/ │ │ │ │ ├── users-actions.ts │ │ │ │ ├── users-branch.ts │ │ │ │ └── users-cache.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── test/ │ │ │ ├── dev/ │ │ │ │ ├── localhost.crt │ │ │ │ ├── localhost.key │ │ │ │ ├── server.ts │ │ │ │ ├── vm.ts │ │ │ │ └── websocket-mock.ts │ │ │ ├── e2e/ │ │ │ │ ├── dbExplorer.e2e.ts │ │ │ │ ├── driver.ts │ │ │ │ ├── e2e-common.ts │ │ │ │ ├── favorites.e2e.ts │ │ │ │ ├── files.e2e.ts │ │ │ │ ├── history.e2e.ts │ │ │ │ ├── home.e2e.ts │ │ │ │ ├── notebook.e2e.ts │ │ │ │ └── users.e2e.ts │ │ │ ├── mocha-setup.ts │ │ │ ├── mocks.ts │ │ │ └── test-common.ts │ │ ├── tsconfig.json │ │ ├── tslint.json │ │ ├── velocity.data.json │ │ ├── velocity.private.data.json │ │ └── wallaby.js │ ├── lerna.json │ ├── npm-deploy.sh │ ├── package.json │ ├── service/ │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── .nvmrc │ │ ├── .prettierrc │ │ ├── .quixroot │ │ ├── .testenv │ │ ├── .travis.yml │ │ ├── README.md │ │ ├── ecosystem.config.js │ │ ├── index.js │ │ ├── nest-cli.json │ │ ├── nodemon-debug.json │ │ ├── nodemon.json │ │ ├── ormconfig.json │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── create_migrations.sh │ │ │ ├── helpers/ │ │ │ │ └── copy-statics.ts │ │ │ ├── ormconfig.json.template │ │ │ ├── run_migrations.sh │ │ │ ├── start.ts │ │ │ └── update-statics.ts │ │ ├── src/ │ │ │ ├── app.controller.spec.ts │ │ │ ├── app.controller.ts │ │ │ ├── app.module.ts │ │ │ ├── base.module.ts │ │ │ ├── common/ │ │ │ │ ├── demo-mode-interceptor.ts │ │ │ │ ├── entity-type.enum.ts │ │ │ │ └── user-sanitizer.ts │ │ │ ├── config/ │ │ │ │ ├── config.module.ts │ │ │ │ ├── config.service.ts │ │ │ │ ├── db-conf.ts │ │ │ │ ├── db-connection.ts │ │ │ │ ├── env/ │ │ │ │ │ ├── computed-settings.ts │ │ │ │ │ ├── engine-settings.ts │ │ │ │ │ ├── env.spec.ts │ │ │ │ │ ├── env.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── static-settings.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ ├── consts.ts │ │ │ ├── entities/ │ │ │ │ ├── deleted-notebook/ │ │ │ │ │ ├── dbdeleted-notebook.entity.ts │ │ │ │ │ └── deleted-notebook.repository.ts │ │ │ │ ├── favorites/ │ │ │ │ │ └── favorites.entity.ts │ │ │ │ ├── filenode/ │ │ │ │ │ ├── filenode.entity.ts │ │ │ │ │ └── filenode.repository.ts │ │ │ │ ├── folder/ │ │ │ │ │ └── folder.entity.ts │ │ │ │ ├── index.ts │ │ │ │ ├── note/ │ │ │ │ │ ├── dbnote.entity.ts │ │ │ │ │ └── note.repository.ts │ │ │ │ ├── notebook/ │ │ │ │ │ ├── dbnotebook.entity.ts │ │ │ │ │ └── notebook.repository.ts │ │ │ │ ├── user/ │ │ │ │ │ └── user.entity.ts │ │ │ │ ├── utils.ts │ │ │ │ └── version-metadata.entity.ts │ │ │ ├── errors/ │ │ │ │ ├── exceptions.ts │ │ │ │ └── index.ts │ │ │ ├── main.ts │ │ │ ├── migrations/ │ │ │ │ ├── 1558528771647-v1.ts │ │ │ │ ├── 1558528771648-v1-metadata.ts │ │ │ │ ├── 1562174176877-v2.ts │ │ │ │ ├── 1614173960671-v3.ts │ │ │ │ ├── 1614712161318-v4.ts │ │ │ │ └── 1634023683491-v5.ts │ │ │ ├── modules/ │ │ │ │ ├── auth/ │ │ │ │ │ ├── auth.controller.ts │ │ │ │ │ ├── auth.module.ts │ │ │ │ │ ├── common-auth.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── login.service.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── user-decorator.ts │ │ │ │ │ └── users.service.ts │ │ │ │ ├── event-sourcing/ │ │ │ │ │ ├── base-action-validation.ts │ │ │ │ │ ├── event-sourcing.module.ts │ │ │ │ │ ├── events.service.ts │ │ │ │ │ ├── infrastructure/ │ │ │ │ │ │ ├── action-store/ │ │ │ │ │ │ │ ├── action-store.spec.ts │ │ │ │ │ │ │ ├── action-store.ts │ │ │ │ │ │ │ ├── entities/ │ │ │ │ │ │ │ │ └── db-action.entity.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── event-bus/ │ │ │ │ │ │ │ ├── api.ts │ │ │ │ │ │ │ ├── context.ts │ │ │ │ │ │ │ ├── event-bus-builder.ts │ │ │ │ │ │ │ ├── event-bus.drawio │ │ │ │ │ │ │ ├── event-bus.spec.ts │ │ │ │ │ │ │ ├── event-bus.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── plugins/ │ │ │ │ │ │ ├── deleted-notebook-plugin.ts │ │ │ │ │ │ ├── events-plugin.ts │ │ │ │ │ │ ├── favorites-plugin.ts │ │ │ │ │ │ ├── file-tree-plugin.ts │ │ │ │ │ │ ├── note-plugin.ts │ │ │ │ │ │ ├── notebook-plugin.ts │ │ │ │ │ │ ├── trash-bin-plugin.ts │ │ │ │ │ │ ├── user-plugin.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── quix-event-bus.driver.ts │ │ │ │ │ ├── quix-event-bus.spec.ts │ │ │ │ │ ├── quix-event-bus.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── logger/ │ │ │ │ │ ├── logger.module.ts │ │ │ │ │ └── logger.service.ts │ │ │ │ ├── proxy-backend/ │ │ │ │ │ └── proxy-backend.module.ts │ │ │ │ ├── search/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── parser.spec.ts │ │ │ │ │ ├── parser.ts │ │ │ │ │ ├── search.module.ts │ │ │ │ │ ├── search.spec.ts │ │ │ │ │ ├── search.ts │ │ │ │ │ └── types.ts │ │ │ │ └── web-api/ │ │ │ │ ├── autocomplete/ │ │ │ │ │ ├── autocomplete.controller.ts │ │ │ │ │ └── autocomplete.service.ts │ │ │ │ ├── deleted-notebooks/ │ │ │ │ │ ├── deleted-notebook.controller.ts │ │ │ │ │ └── deleted-notebook.service.ts │ │ │ │ ├── events.controller.ts │ │ │ │ ├── events.gateway.ts │ │ │ │ ├── favorites/ │ │ │ │ │ ├── favorites.controller.ts │ │ │ │ │ └── favorites.service.ts │ │ │ │ ├── folders/ │ │ │ │ │ ├── folders.controller.ts │ │ │ │ │ ├── folders.service.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── notebooks/ │ │ │ │ │ ├── notebooks.controller.ts │ │ │ │ │ └── notebooks.service.ts │ │ │ │ ├── search.controller.ts │ │ │ │ ├── user-list.controller.ts │ │ │ │ ├── web-api.driver.ts │ │ │ │ ├── web-api.module.ts │ │ │ │ └── web-api.spec.ts │ │ │ ├── template-engine/ │ │ │ │ └── velocity.ts │ │ │ ├── types/ │ │ │ │ ├── 3rd-party/ │ │ │ │ │ ├── uuid.d.ts │ │ │ │ │ └── velocity.d.ts │ │ │ │ └── index.ts │ │ │ └── utils/ │ │ │ ├── create-schema-helpers.ts │ │ │ ├── deferred-promise.ts │ │ │ └── retry-promise.ts │ │ ├── test/ │ │ │ ├── app.e2e-spec.ts │ │ │ ├── builder.ts │ │ │ ├── custom-matchers.ts │ │ │ ├── driver.ts │ │ │ └── jest-e2e.js │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── tslint.json │ └── shared/ │ ├── .gitignore │ ├── config-helper/ │ │ ├── config-helper.ts │ │ └── consts.ts │ ├── entities/ │ │ ├── common/ │ │ │ ├── actions.ts │ │ │ ├── common-types.ts │ │ │ ├── create-reducer.spec.ts │ │ │ └── create-reducer.ts │ │ ├── deleted-notebook/ │ │ │ ├── actions.ts │ │ │ ├── deleted-notebook.ts │ │ │ ├── index.ts │ │ │ ├── reducer.ts │ │ │ └── types.ts │ │ ├── file/ │ │ │ ├── actions.ts │ │ │ ├── file.ts │ │ │ ├── index.ts │ │ │ ├── reducer.ts │ │ │ └── types.ts │ │ ├── folder/ │ │ │ ├── folder.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── history/ │ │ │ ├── actions.ts │ │ │ ├── history.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── note/ │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── note.ts │ │ │ ├── reducer.ts │ │ │ └── types.ts │ │ ├── notebook/ │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ ├── notebook.ts │ │ │ ├── reducer.ts │ │ │ └── types.ts │ │ ├── trash-bin/ │ │ │ ├── actions.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── user/ │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── user.ts │ ├── index.ts │ ├── package.json │ ├── tsconfig.json │ ├── types/ │ │ └── search-types.ts │ └── utils/ │ └── utils.ts └── terraform/ ├── README.md ├── acme_certificate.tf ├── aws-tf-backend.tf ├── ecs.tf ├── iam.tf ├── initialize.tf ├── lb.tf ├── outputs.tf ├── parameter_store.tf ├── provider.tf ├── rds.tf ├── route_53.tf ├── security_groups.tf ├── variables.tf ├── versions.tf └── vpc.tf ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ */node_modules *.log ================================================ FILE: .github/workflows/quix-backend-build.yml ================================================ name: Quix Backend Build on: pull_request: paths: - 'quix-backend/**' push: paths: - 'quix-backend/**' workflow_dispatch: jobs: scala_tests: runs-on: ubuntu-20.04 strategy: matrix: scala_version: ['2.12.17', '2.13.9'] steps: - name: Checkout uses: actions/checkout@v1 - name: Setup Scala uses: olafurpg/setup-scala@v12 with: java-version: "adopt@1.8" - name: Coursier cache uses: coursier/cache-action@v5 - name: Build and Test working-directory: ./quix-backend run: | sbt ++${{matrix.scala_version}} -v -Dfile.encoding=UTF-8 test publishM2 if [[ ${{matrix.scala_version}} = '2.12.17' ]] then mvn --quiet -f quix-webapps/quix-web-spring/pom.xml test fi rm -rf "$HOME/.ivy2/local" || true find $HOME/Library/Caches/Coursier/v1 -name "ivydata-*.properties" -delete || true find $HOME/.ivy2/cache -name "ivydata-*.properties" -delete || true find $HOME/.cache/coursier/v1 -name "ivydata-*.properties" -delete || true find $HOME/.sbt -name "*.lock" -delete || true ================================================ FILE: .github/workflows/quix-documentation-publish.yml ================================================ # This Workflow will publish Documentation on any push to master branch into # the documentation folder. name: Quix Documentation Publish on: workflow_dispatch: inputs: comment: description: 'Comment' required: true default: 'Publish' push: branches: ['master'] paths: - 'documentation/**/*.*' jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '14.19.1' - run: npm install working-directory: 'documentation/website' - run: npm run build working-directory: 'documentation/website' - name: Deploy if: success() uses: crazy-max/ghaction-github-pages@v2 with: target_branch: gh-pages build_dir: documentation/website/build/quix env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/quix-frontend-publish.yml ================================================ # Build on each branch and Publish to NPM on master if version bumped name: Quix Frontend Build & Publish on: workflow_dispatch: inputs: comment: description: 'Comment' required: true default: 'Publish' push: paths: - 'quix-frontend/**' defaults: run: working-directory: quix-frontend jobs: build_and_test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '14.19.1' - uses: samin/mysql-action@v1.3 with: mysql database: 'quixtest' mysql version: '5.7' - run: npm ci - run: npm run build:ci - run: npm test - name: Prepare Publish To NPM if: github.ref == 'refs/heads/master' run: | echo "registry=http://registry.npmjs.org/" >> .npmrc echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Publish if: github.ref == 'refs/heads/master' run: npm run publish env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .github/workflows/quix-frontend-release.yml ================================================ name: Quix Frontend Release DockerHub on: workflow_dispatch: inputs: comment: description: 'Comment' required: true default: 'Release' tags: description: 'Tags' labels: description: 'Labels' release: types: [published] defaults: run: working-directory: quix-frontend jobs: push_to_registry: name: Push Docker image to Docker Hub runs-on: ubuntu-latest steps: - name: Check out the repo uses: actions/checkout@v2 - name: Log in to Docker Hub uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: images: wixquix/quix-frontend - name: Log run: | echo "${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.labels }}" \ && echo "${{github.event.inputs.tags}}" \ && echo "${{github.event.inputs.labels}}" - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: context: ./quix-frontend/ push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io/api/maven,scala,jetbrains ### Maven ### target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties ### Scala ### *.class *.log # sbt specific .cache .history .lib/ dist/* target/ lib_managed/ src_managed/ project/boot/ project/plugins/project/ # Scala-IDE specific .scala_dependencies .worksheet ### JetBrains ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio *.iml ## Directory-based project format: .idea/ # if you remove the above rule, at least ignore the following: # User-specific stuff: # .idea/workspace.xml # .idea/tasks.xml # .idea/dictionaries # Sensitive or high-churn files: # .idea/dataSources.ids # .idea/dataSources.xml # .idea/sqlDataSources.xml # .idea/dynamic.xml # .idea/uiDesigner.xml # Gradle: # .idea/gradle.xml # .idea/libraries # Mongo Explorer plugin: # .idea/mongoSettings.xml ## File-based project format: *.ipr *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties .DS_Store .vscode node_modules .env ## Terraform *.tfstate *.tfstate.backup .terraform vpc.plan terraform.tfvars quix-frontend/.npmrc documentation/website/build/ ================================================ FILE: .travis.yml ================================================ jobs: include: - stage: test name: "Frontend" language: node_js dist: bionic node_js: 14 cache: npm env: PROJECT=frontend services: - mysql before_install: - mysql -e 'CREATE DATABASE IF NOT EXISTS quixtest;' install: - $TRAVIS_BUILD_DIR/build-selector.sh $TRAVIS_COMMIT_RANGE $PROJECT || exit 0 - cd ./quix-frontend - npm install script: - $TRAVIS_BUILD_DIR/build-selector.sh $TRAVIS_COMMIT_RANGE $PROJECT || exit 0 - npm run build:ci - npm run test deploy: provider: script script: bash npm-deploy.sh edge: true on: branch: master ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 Wix Incubator Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Quix ![Support](https://img.shields.io/npm/l/@wix/quix-client) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.wix/quix-api_2.13/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.wix/quix-api_2.13) [![Quix Backend Build](https://github.com/wix-incubator/quix/actions/workflows/quix-backend-build.yml/badge.svg?branch=master)](https://github.com/wix-incubator/quix/actions/workflows/quix-backend-build.yml) [![Quix Frontend Build & Publish](https://github.com/wix-incubator/quix/actions/workflows/quix-frontend-publish.yml/badge.svg)](https://github.com/wix-incubator/quix/actions/workflows/quix-frontend-publish.yml) [![Quix Documentation Publish](https://github.com/wix-incubator/quix/actions/workflows/quix-documentation-publish.yml/badge.svg)](https://github.com/wix-incubator/quix/actions/workflows/quix-documentation-publish.yml) Quix is an easy-to-use notebook manager with support for [Presto](https://wix-incubator.github.io/quix/docs/presto), [Athena](https://wix-incubator.github.io/quix/docs/athena), [BigQuery](https://wix-incubator.github.io/quix/docs/bigquery), [MySQL](https://wix-incubator.github.io/quix/docs/mysql), [PostgreSQL](https://wix-incubator.github.io/quix/docs/postgresql), [ClickHouse](https://wix-incubator.github.io/quix/docs/clickhouse) and more. * [Installation](https://wix-incubator.github.io/quix/docs/installation) ## Intro Check out these blog posts introducing Quix on Wix Engineering Blog : * [Introducing Quix: Presto-based Notebook Manager for Fast and Easy Data Exploration ](https://www.wix.engineering/post/introducing-quix-presto-based-notebook-manager-for-fast-and-easy-data-exploration) * [Quix Version 1: Now also Supporting Amazon Athena, Google BigQuery and Generic JDBC](https://www.wix.engineering/post/quix-version-1-now-also-supporting-amazon-athena-google-bigquery-and-generic-jdbc) ## Quick start Using `docker-compose`, this will run Quix with a MySQL container and an example Presto installation. Quix will run in a single-user mode without authentication. ```bash mkdir quix && cd quix curl https://raw.githubusercontent.com/wix/quix/master/docker-compose.prebuilt.yml -o docker-compose.yml curl https://raw.githubusercontent.com/wix/quix/master/env-example -o .env docker-compose up ``` Be sure to check the [full installation notes](https://wix-incubator.github.io/quix/docs/installation) on how to edit the `.env` file to add more data sources, turn on multi-user mode and customize your deployment. For support please contact us via [oss@wix.com](mailto:oss@wix.com). ## Main features - [Query management](#Management) - organize your notebooks in folders for easy access and sharing - [Visualizations](#Visualizations) - quickly plot time and bar series (more visualizations to follow) - [DB Explorer](#Explorer) - explore your data sources - Search - search notes of all users #### Management ![](documentation/docs/assets/management.gif) #### Visualizations ![](documentation/docs/assets/chart.gif) #### Explorer ![](documentation/docs/assets/db.gif) ## License MIT ================================================ FILE: build-selector.sh ================================================ #!/usr/bin/env bash if [ -z $2 ]; then GIT_RANGE="HEAD^1" BUILD_TYPE=$1 else GIT_RANGE="$1" BUILD_TYPE="$2" fi echo GIT RANGE=$GIT_RANGE echo BUILD_TYPE=$BUILD_TYPE declare -A PATTERN_MAP PATTERN_MAP[frontend]='^((quix-frontend/)|\.travis\.yml)' PATTERN_MAP[backend]='^(quix-backend/|\.travis\.yml)' git diff --name-only $GIT_RANGE | grep -qE ${PATTERN_MAP[$BUILD_TYPE]} ================================================ FILE: docker-compose.prebuilt.yml ================================================ version: '3' services: backend: image: wixquix/quix-backend:latest ports: - "8081:8081" depends_on: - presto env_file: - .env environment: - MODULES - AUTH_COOKIE - AUTH_SECRET - AUTH_TYPE frontend: image: wixquix/quix-frontend:latest ports: - "3000:3000" depends_on: - backend - db env_file: - .env environment: - DB_NAME - DB_USER - DB_PASS - DB_HOST - DB_PORT - BACKEND_INTERNAL_URL - BACKEND_PUBLIC_URL - GOOGLE_SSO_CLIENT_ID - GOOGLE_SSO_SECRET - AUTH_COOKIE - AUTH_SECRET - AUTH_TYPE - APPMETRICS_PORT - ENABLE_APPMETRICS - MODULES db: image: "mysql:5.7" restart: always environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "quix" volumes: - "db_volume:/var/lib/mysql" presto: image: "starburstdata/presto:340-e" ports: - "8181:8080" volumes: db_volume: ================================================ FILE: docker-compose.yml ================================================ version: "3" services: backend: build: ./quix-backend/ ports: - "8081:8081" depends_on: - presto - postgres env_file: - .env environment: - MODULES - AUTH_COOKIE - AUTH_SECRET - AUTH_TYPE frontend: build: ./quix-frontend/ ports: - "3000:3000" depends_on: - backend - db env_file: - .env environment: - DB_NAME - DB_USER - DB_PASS - DB_HOST - DB_PORT - BACKEND_INTERNAL_URL - BACKEND_PUBLIC_URL - GOOGLE_SSO_CLIENT_ID - GOOGLE_SSO_SECRET - AUTH_COOKIE - AUTH_SECRET - AUTH_TYPE - APPMETRICS_PORT - ENABLE_APPMETRICS - MODULES db: image: "mysql:5.7" restart: always environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "quix" volumes: - "db_volume:/var/lib/mysql" presto: image: "starburstdata/presto:340-e" ports: - "8181:8080" postgres: image: "aa8y/postgres-dataset:dellstore" ports: - "5432:5432" volumes: db_volume: ================================================ FILE: documentation/docs/about.md ================================================ --- id: about title: About sidebar_label: About --- Quix is an easy-to-use notebook manager with support for [Presto](/quix/docs/presto), [Athena](/quix/docs/athena), [BigQuery](/quix/docs/bigquery), [MySQL](/quix/docs/mysql), [PostgreSQL](/quix/docs/postgresql), [ClickHouse](/quix/docs/clickhouse), [Amazon Redshift](/quix/docs/redshift) and more. * [Demo](https://quix-demo.io/) * [Installation](/quix/docs/installation) ## Quick start Using docker-compose, this will run Quix with a MySQL container and an example Presto installation. Quix will run in a single-user mode without authentication. ```bash mkdir quix && cd quix curl https://raw.githubusercontent.com/wix/quix/master/docker-compose.prebuilt.yml -o docker-compose.yml curl https://raw.githubusercontent.com/wix/quix/master/env-example -o .env docker-compose up ``` Be sure to check the [full installation notes](/quix/docs/installation) on how to edit the `.env` file to add more data sources, turn on multi-user mode and customize your deployment. For support please conatct us via [oss@wix.com](mailto:oss@wix.com). ## Main features - [Query management](#management) - organize your notebooks in folders for easy access and sharing - [Visualizations](#visualizations) - quickly plot time and bar series (more visualizations to follow) - [DB Explorer](#explorer) - explore your data sources - Search - search notes of all users #### Management ![](assets/management.gif) #### Visualizations ![](assets/chart.gif) #### Explorer ![](assets/db.gif) ================================================ FILE: documentation/docs/architecture.md ================================================ --- id: architecture title: Architecture sidebar_label: Architecture --- ![](assets/architecture.png) Quix consists of three main elements: * Frontend to serve UI and manage notebooks * Backend to communicate with Presto * DB for storing notebooks Each component is run in a separate Docker container, and all of them are managed by a single Docker Compose configuration. There's also a fourth Docker container provided with this repository running Presto inside Docker Compose, but it's for demonstration purposes only. ================================================ FILE: documentation/docs/athena.md ================================================ --- id: athena title: Amazon Athena sidebar_label: Athena --- ## Features Work with Amazon Athena tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup ### 1. Create a new IAM Policy Create a new IAM policy to allow access to your bucket ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::your-bucket-name/*" ] }, { "Effect": "Allow", "Action": [ "s3:GetBucketLocation", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::your-bucket-name" ] } ] } ``` ### 2. Create a new IAM user Create a new user with `Programmatic Access`. Attach security policy `AmazonAthenaFullAccess` along with policy created in step 1. ### 3. Pick a new name for your athena note and update .env Add/update following properties to .env file to configure your new note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo` | | `MODULES_FOO_ENGINE` | note type | `athena` | | `MODULES_FOO_OUTPUT` | s3 bucket for results | `s3://some-bucket-id/` | | `MODULES_FOO_REGION` | aws region | `us-east-1` | | `MODULES_FOO_DATABASE` | default database | `default` | | `MODULES_FOO_AWS_ACCESS_KEY_ID` | aws access key | | | `MODULES_FOO_AWS_SECRET_KEY` | awe secret key | | Example of possible configuration that will create note type named foo : ```properties MODULES_FOO_ENGINE=athena MODULES_FOO_OUTPUT=s3://some-bucket-id/ MODULES_FOO_REGION=us-east-1 MODULES_FOO_DATABASE=default MODULES_FOO_AWS_ACCESS_KEY_ID=123 MODULES_FOO_AWS_SECRET_KEY=abc ``` ## Troubleshooting ================================================ FILE: documentation/docs/bigquery.md ================================================ --- id: bigquery title: Google BigQuery sidebar_label: BigQuery --- ## Features Work with Google bigquery tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup ### 1. Create a new service account Go to `Api & Services` -> `Credentials` and click `Create credentials` with `Service Account key`. Choose new service account in the dropdown, enter quix-bigquery-user as username, `BigQuery Admin` as role, and `Json` as key type. Store resulting json in a secure location and use `base64` command line tool to calculate the base64 string of the file contents. Alternatively use some online tool like https://www.base64encode.org/ to process the contents of json with credentials. ### 2. Pick a new name for your bigquery note and update .env Add/update following properties in .env file to configure your new note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo` | | `MODULES_FOO_ENGINE` | note type | `bigquery` | | `MODULES_FOO_CREDENTIALS_BASE64` | base64 value of your credentials.json | `AABB111222` | Example of possible configuration that will create new bigquery note named foo : ```properties MODULES_BQ_ENGINE=bigquery MODULES_BQ_SYNTAX=ansi_sql MODULES_BQ_CREDENTIALS_BASE64=AAABBBCCCDDDEEEFFFF ``` ## Troubleshooting ================================================ FILE: documentation/docs/clickhouse.md ================================================ --- id: clickhouse title: ClickHouse sidebar_label: ClickHouse --- ## Features Using jdbc note you can use quix to query ClickHouse. You will be able to execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup [ClickHouse](https://clickhouse.tech/) note you have to perform the following : ### 1. Pick new name and update .env Add/update following properties to .env file to configure your new note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `ru.yandex.clickhouse.ClickHouseDriver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:clickhouse://localhost:8123/test` | | `MODULES_FOO_USER` | db username | `user` | | `MODULES_FOO_PASS` | db password | `pass` | | `MODULES_FOO_SYNTAX` | syntax marker | `ansi_sql` | example of clickhouse jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=ru.yandex.clickhouse.ClickHouseDriver MODULES_FOO_URL=jdbc:clickhouse://localhost:8123/test MODULES_FOO_USER=your-user MODULES_FOO_PASS=your-password MODULES_FOO_SYNTAX=ansi_sql ``` ## Troubleshooting ================================================ FILE: documentation/docs/installation.md ================================================ --- id: installation title: Installation sidebar_label: Installation --- ## Requirements * [Docker](https://www.docker.com/products) * [Docker Compose](https://docs.docker.com/compose/install/) ## Running Run Docker Compose: ``` docker-compose up ``` The initial run of the `docker-compose up` command will take care of all the dependencies, like MySQL, Presto, Maven, etc, will install all necessary Quix components and create a web-accessible Quix instance. You will need an `.env` file to run it. We will configure it in the next step. To access Quix, navigate to: `http://localhost:3000` ## Clone repository ``` git clone https://github.com/wix-incubator/quix.git ``` ## Configuration Most of the configuration you'll need is done through environment variables. docker-compose can load environment-variables easily through a `.env` file. You should rename our [env-example](https://github.com/wix-incubator/quix/blob/master/env-example) file to `.env`, and modify it's values as needed. #### Presto By default, Quix works with demo Presto instance that runs inside Docker Compose. To work with your real Presto DB, change `PRESTO_API` environment variable. Note that you need to specify full URL, including protocol, port and API version: * MODULES_PRESTO_API - `http://presto.my.domain:8181/v1` If you're running Presto locally, use the following instead of `localhost`: * Your internal IP * Or `host.docker.internal` (macOS only) #### DB Quix also uses MySQL to store notebooks and other application data. The default docker-compose uses a mysql container, so no further setup is needed. As an alternative, you can also use an external MySQL database, by specifying some of the following variables: * DB_NAME - defaults to `quix`, must exist * DB_USER - defaults to `root` * DB_PASS - defaults to empty password * DB_HOST - defaults to `db` * DB_PORT - defaults to `3306` * DB_AUTO_MIGRATE - this sets the [TypeORM](https://typeorm.io/#/connection-options) `synchronize` flag. Defaults to `false`. You probably only want to set this when running locally for development or if you don't care at all about your data. #### User authentication Quix can work in two modes: multi-user mode, authenticated with [Google OAuth](https://console.developers.google.com/apis/credentials), or in a single-user mode. This is controlled by the following variables: * AUTH_TYPE - can be `fake` or `google`. Defaults to `fake` (single-user mode). If you use Google OAuth, you must supply the clientId and the secret: * GOOGLE_SSO_CLIENT_ID * GOOGLE_SSO_SECRET Other variables related to authentication: * AUTH_COOKIE - defaults to `__quix`. When using `google` auth, must be provided. * AUTH_SECRET - the encryption key for the cookie. Must be provided. * COOKIE_MAX_AGE - should be in seconds, default is 30 days. #### Configuration for custom deployment Running quix with `docker-compose` should "just work", but when deploying quix, there are a couple more variables you might want to change: * BACKEND_INTERNAL_URL - An address + port number (no protocol) where you have the backend service deployed and accessible to the frontend service. * BACKEND_PUBLIC_URL - An address + port number (no protocol) to the backend service, made accessible to user's browser. In most scenarios, it's value is the same as `BACKEND_INTERNAL_URL`. * ENABLE_APPMETRICS - Set this variable if you want to enable [appmetrics-dash](https://github.com/RuntimeTools/appmetrics-dash). * APPMETRICS_PORT - The port where appmetrics dashboard will be exposed. ## Upgrading Quix This takes into account a `docker-compose` setup. Extrapolate as needed if you have some other custom deployment. 1. Backup your data, if possible. 2. Download an updated `docker-compose.yml` or `docker-compose.prebuilt.yml`. If you are not using the prebuilt images, you need to run `docker-compose build`. 3. Stop the frontend and backend services - `docker-compose stop backend frontend`. 4. Make sure all your environment variables are exported correctly in your current shell, specifically all the `DB_*` variables. 5. Run DB migrations: `docker-compose run --no-deps --rm frontend scripts/run_migrations.sh`. 6. Start services again `docker-compose up -d`. ================================================ FILE: documentation/docs/jdbc.md ================================================ --- id: jdbc title: Jdbc sidebar_label: Jdbc --- ## Features Using jdbc note you can use quix to query [MySQL](mysql.md), [ClickHouse](clickhouse.md), [PostgreSQL](postgresql.md), Microsoft SQL Server, [MariaDB](mariadb.md), [Oracle](oracle.md), SQLite, [Redshift](redshift.md), Firebird, H2, HSQLDB, Apache Derby, IBM DB2, Teradata and more. You will be able to execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup jdbc note you have to perform the following two steps : ### 1. Add new jdbc dependency to [Dockerfile](https://github.com/wix-incubator/quix/blob/master/quix-backend/Dockerfile) Right now quix is pre-bundled with several populat jdbc drivers. If your driver is missing from the list, you should edit the [Dockerfile](https://github.com/wix-incubator/quix/blob/master/quix-backend/Dockerfile) and add a line that will download the driver and another line to push it into `quix.jar` file Examples of pre-bundled jdbc drivers : ``` RUN wget -q -P BOOT-INF/lib/ \ https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc/0.2.4/clickhouse-jdbc-0.2.4.jar \ https://repo1.maven.org/maven2/org/postgresql/postgresql/42.2.10/postgresql-42.2.10.jar \ https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.19/mysql-connector-java-8.0.19.jar \ https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.30.1/sqlite-jdbc-3.30.1.jar \ https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.5.4/mariadb-java-client-2.5.4.jar \ https://repo1.maven.org/maven2/org/hsqldb/hsqldb/2.5.0/hsqldb-2.5.0.jar \ https://maven.ceon.pl/artifactory/repo/com/oracle/ojdbc/ojdbc10/19.3.0.0/ojdbc10-19.3.0.0.jar \ https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/8.2.1.jre11/mssql-jdbc-8.2.1.jre11.jar RUN jar uf0 quix.jar \ BOOT-INF/lib/clickhouse-jdbc-0.2.4.jar \ BOOT-INF/lib/postgresql-42.2.10.jar \ BOOT-INF/lib/mysql-connector-java-8.0.19.jar \ BOOT-INF/lib/sqlite-jdbc-3.30.1.jar \ BOOT-INF/lib/mariadb-java-client-2.5.4.jar \ BOOT-INF/lib/hsqldb-2.5.0.jar \ BOOT-INF/lib/ojdbc10-19.3.0.0.jar \ BOOT-INF/lib/mssql-jdbc-8.2.1.jre11.jar ``` ### 2. Pick new name and update .env Add/update following properties to .env file to configure your new note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `org.postgresql.Driver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:postgresql:postgres` | | `MODULES_FOO_USER` | db username | `user` | | `MODULES_FOO_PASS` | db password | `pass` | | `MODULES_FOO_SYNTAX` | syntax marker | `mysql` or `ansi_sql` | example of postgres jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=org.postgresql.Driver MODULES_FOO_URL=jdbc:postgresql:postgres MODULES_FOO_USER=your-user MODULES_FOO_PASS=your-password MODULES_FOO_SYNTAX=ansi_sql ``` ## Troubleshooting ================================================ FILE: documentation/docs/mariadb.md ================================================ --- id: mariadb title: MariaDB sidebar_label: MariaDB --- ## Features Work with MariaDB tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup MariaDB note you have to perform the following two steps : ### 1. Pick new name and update .env Add/update following properties to .env file to configure your new note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `org.mariadb.jdbc.Driver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:mariadb://localhost:3306/DB` | | `MODULES_FOO_USER` | db username | `user` | | `MODULES_FOO_PASS` | db password | `pass` | | `MODULES_FOO_SYNTAX` | syntax marker | `mysql`| example of mariadb jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=org.mariadb.jdbc.Driver MODULES_FOO_URL=jdbc:mariadb://localhost:3306/DB MODULES_FOO_USER=your-username MODULES_FOO_PASS=your-password MODULES_FOO_SYNTAX=mysql ``` ## Troubleshooting ================================================ FILE: documentation/docs/mysql.md ================================================ --- id: mysql title: MySQL sidebar_label: MySQL --- ## Features Work with MySQL tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup MySQL note you have to perform the following two steps : ### 1. Pick new name and update .env Add/update following properties to .env file to configure your new note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `com.mysql.jdbc.Driver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:mysql://localhost/test` | | `MODULES_FOO_USER` | db username | `user` | | `MODULES_FOO_PASS` | db password | `pass` | | `MODULES_FOO_SYNTAX` | syntax marker | `mysql`| example of mysql jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=com.mysql.jdbc.Driver MODULES_FOO_URL=jdbc:mysql://localhost/test MODULES_FOO_USER=your-username MODULES_FOO_PASS=your-password MODULES_FOO_SYNTAX=mysql ``` ## Troubleshooting ================================================ FILE: documentation/docs/oracle.md ================================================ --- id: oracle title: Oracle sidebar_label: Oracle --- ## Features Work with Oracle straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup Oracle note you have to perform the following two steps : ### 1. Pick new name and update .env Add/update following properties to .env file to configure your new oracle note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `oracle.jdbc.driver.OracleDriver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:oracle:thin:@localhost:1521:db` | | `MODULES_FOO_USER` | db username | `user` | | `MODULES_FOO_PASS` | db password | `pass` | | `MODULES_FOO_SYNTAX` | syntax marker | `ansi_sql` | example of oracle jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=oracle.jdbc.driver.OracleDriver MODULES_FOO_URL=jdbc:oracle:thin:@localhost:1521:db MODULES_FOO_USER=your-user MODULES_FOO_PASS=your-password MODULES_FOO_SYNTAX=ansi_sql ``` ## Troubleshooting ================================================ FILE: documentation/docs/postgresql.md ================================================ --- id: postgresql title: PostgreSQL sidebar_label: PostgreSQL --- ## Features Work with PostgreSQL straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup PostgreSQL note you have to perform the following two steps : ### 1. Pick new name and update .env Add/update following properties to .env file to configure your new postgresql note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `org.postgresql.Driver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:postgresql:postgres` | | `MODULES_FOO_USER` | db username | `user` | | `MODULES_FOO_PASS` | db password | `pass` | | `MODULES_FOO_SYNTAX` | syntax marker | `ansi_sql` | example of postgresql jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=org.postgresql.Driver MODULES_FOO_URL=jdbc:postgresql:postgres MODULES_FOO_USER=your-user MODULES_FOO_PASS=your-password MODULES_FOO_SYNTAX=ansi_sql ``` ## Troubleshooting ================================================ FILE: documentation/docs/presto.md ================================================ --- id: presto title: Presto sidebar_label: Presto --- ## Features Quix is a great tool for querying Presto. You can execute multiple queries in parallel, stream results straight to your browser, download them as csv, build visualizations, share your notes with other people in your organization and more. ## Setup ### 1. Pick a new name for your presto note and update .env Add the following properties to the .env file to configure your new presto note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo` | | `MODULES_FOO_ENGINE` | note type | `presto` | | `MODULES_FOO_API` | presto url | `http://presto.your-domain.com:8080/v1` | | `MODULES_FOO_CATALOG` | default catalog | `system` | | `MODULES_FOO_SCHEMA` | default schema | `runtime` | | `MODULES_FOO_SOURCE` | default source | `quix` | Example of possible configuration that will create Presto note named foo : ```properties MODULES_FOO_ENGINE=presto MODULES_FOO_API=http://presto:8080/v1 MODULES_FOO_CATALOG=system MODULES_FOO_SCHEMA=runtime MODULES_FOO_SOURCE=quix ``` ## Troubleshooting ================================================ FILE: documentation/docs/python.md ================================================ --- id: python title: Python sidebar_label: Python --- ## Features * Execute lightweight Python scripts straight from Quix * Manage pip packages on user-level * Render and visualize results in Quix ## Ideas for using python in Quix 1) Python notes can be used to orchestrate more complex processes that are hard to achieve in simple sql note, so it's a perfect tool for simple prototyping and ETLS. 2) You can query much more data sources in addition to out-of-the-box Quix notes. For example, PyMongo can be used to query MongoDB, hbase-python for HBase, boto3 for s3, python-firebase for firebase and many more. ## Setup ### 1. Pick a new name for your python note and update .env Add the following properties to the .env file to configure your new python note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo` | | `MODULES_FOO_ENGINE` | note type | `python` | | `MODULES_FOO_SYNTAX` | note syntax | `python` | | `MODULES_FOO_PIP_INDEX` | custom pip index url | `https://your-own-pypi-mirror.org/simple` | | `MODULES_FOO_PIP_EXTRA_INDEX` | extra pip index url | `https://pypi.python.org/simple` | | `MODULES_FOO_PIP_PACKAGES` | list of mandatory pip packages | `ujson,pyhive` | | `MODULES_FOO_SCRIPTS_DIR` | dir that will be used to store each user temp files | `/tmp/quix-python` | | `MODULES_FOO_ADDITIONAL_CODE_FILE` | additional code that would be prepended to each python note | `/tmp/quix-python/init.py` | Example : ```properties MODULES=foo MODULES_FOO_ENGINE=python MODULES_FOO_SYNTAX=python MODULES_FOO_PIP_INDEX=https://pypi.your-domain.com/simple MODULES_FOO_PIP_EXTRA_INDEX=https://pypi.python.org/simple MODULES_FOO_PIP_PACKAGES=ujson,requests MODULES_FOO_SCRIPTS_DIR=/tmp/quix-python MODULES_FOO_ADDITIONAL_CODE_FILE=/tmp/quix-python/init.py ``` ## Troubleshooting ================================================ FILE: documentation/docs/redshift.md ================================================ --- id: redshift title: Amazon Redshift sidebar_label: Redshift --- ## Features Query Amazon Redshift data warehouse straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv. ## Setup To setup Amazon Redshift note you have to perform the following steps : ### 1. Obtain link to redshift jdbc driver Go to https://docs.aws.amazon.com/redshift/latest/mgmt/configure-jdbc-connection.html#download-jdbc-driver and choose the jar file that you need. For example, ``` https://s3.amazonaws.com/redshift-downloads/drivers/jdbc/1.2.41.1065/RedshiftJDBC42-no-awssdk-1.2.41.1065.jar ``` ### 2. Update [Dockerfile](https://github.com/wix-incubator/quix/blob/master/quix-backend/Dockerfile) You need to update the Dockerfile that prepares image of quix-backend to include the missing jar. Edit it and add a line that will download the driver and another line to push it into `quix.jar` file ``` RUN wget -q -P BOOT-INF/lib/ \ https://s3.amazonaws.com/redshift-downloads/drivers/jdbc/1.2.41.1065/https://s3.amazonaws.com/redshift-downloads/drivers/jdbc/1.2.41.1065/RedshiftJDBC42-no-awssdk-1.2.41.1065.jar RUN jar uf0 quix.jar \ BOOT-INF/lib/RedshiftJDBC42-no-awssdk-1.2.41.1065.jar ``` ### 3. Build the quix-backend image Execute the following command to prepare a new docker image of quix-backend ``` docker-compose build backend ``` ### 4. Pick new name and update .env Add/update following properties to .env file to configure your new Amazon Redshift note | Variables | Meaning | Example | | ------------- |:-------------:| -----:| | `MODULES` | list of registered notes | `foo,boo,prod,qa` | | `MODULES_FOO_ENGINE` | note type | `jdbc` | | `MODULES_FOO_DRIVER` | jdbc driver class | `com.amazon.redshift.jdbc.Driver` | | `MODULES_FOO_URL` | jdbc url | `jdbc:redshift://examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com:5439/dev` | | `MODULES_FOO_SYNTAX` | syntax marker | `ansi_sql` | example of redshift jdbc note that will be named `foo` in the UI ```properties MODULES=,foo MODULES_FOO_ENGINE=jdbc MODULES_FOO_DRIVER=com.amazon.redshift.jdbc.Driver MODULES_FOO_URL=jdbc:redshift://examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com:5439/dev MODULES_FOO_SYNTAX=ansi_sql ``` ## Troubleshooting ================================================ FILE: documentation/website/README.md ================================================ This website was created with [Docusaurus](https://docusaurus.io/). # What's In This Document * [Get Started in 5 Minutes](#get-started-in-5-minutes) * [Directory Structure](#directory-structure) * [Editing Content](#editing-content) * [Adding Content](#adding-content) * [Full Documentation](#full-documentation) # Get Started in 5 Minutes 1. Make sure all the dependencies for the website are installed: ```sh # Install dependencies $ yarn ``` 2. Run your dev server: ```sh # Start the site $ yarn start ``` ## Directory Structure Your project file structure should look something like this ``` my-docusaurus/ docs/ doc-1.md doc-2.md doc-3.md website/ blog/ 2016-3-11-oldest-post.md 2017-10-24-newest-post.md core/ node_modules/ pages/ static/ css/ img/ package.json sidebar.json siteConfig.js ``` # Editing Content ## Editing an existing docs page Edit docs by navigating to `docs/` and editing the corresponding document: `docs/doc-to-be-edited.md` ```markdown --- id: page-needs-edit title: This Doc Needs To Be Edited --- Edit me... ``` For more information about docs, click [here](https://docusaurus.io/docs/en/navigation) ## Editing an existing blog post Edit blog posts by navigating to `website/blog` and editing the corresponding post: `website/blog/post-to-be-edited.md` ```markdown --- id: post-needs-edit title: This Blog Post Needs To Be Edited --- Edit me... ``` For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) # Adding Content ## Adding a new docs page to an existing sidebar 1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`: ```md --- id: newly-created-doc title: This Doc Needs To Be Edited --- My new content here.. ``` 1. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`: ```javascript // Add newly-created-doc to the Getting Started category of docs { "docs": { "Getting Started": [ "quick-start", "newly-created-doc" // new doc here ], ... }, ... } ``` For more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation) ## Adding a new blog post 1. Make sure there is a header link to your blog in `website/siteConfig.js`: `website/siteConfig.js` ```javascript headerLinks: [ ... { blog: true, label: 'Blog' }, ... ] ``` 2. Create the blog post with the format `YYYY-MM-DD-My-Blog-Post-Title.md` in `website/blog`: `website/blog/2018-05-21-New-Blog-Post.md` ```markdown --- author: Frank Li authorURL: https://twitter.com/foobarbaz authorFBID: 503283835 title: New Blog Post --- Lorem Ipsum... ``` For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) ## Adding items to your site's top navigation bar 1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`: `website/siteConfig.js` ```javascript { headerLinks: [ ... /* you can add docs */ { doc: 'my-examples', label: 'Examples' }, /* you can add custom pages */ { page: 'help', label: 'Help' }, /* you can add external links */ { href: 'https://github.com/facebook/Docusaurus', label: 'GitHub' }, ... ], ... } ``` For more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation) ## Adding custom pages 1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`: 1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: `website/siteConfig.js` ```javascript { headerLinks: [ ... { page: 'my-new-custom-page', label: 'My New Custom Page' }, ... ], ... } ``` For more information about custom pages, click [here](https://docusaurus.io/docs/en/custom-pages). # Full Documentation Full documentation can be found on the [website](https://docusaurus.io/). ================================================ FILE: documentation/website/blog/2019-11-25-first-release.md ================================================ --- title: First release author: Quix Team --- Quix is a notebook manager that focuses on ease of use and shareability. It aims to be a shared space for your company's BI insights and know-how. Since the official announcement this summer and following the requests from our first users we added support for more data sources (Athena, BigQuery, JDBC), tweaked the visualizations, fixed bugs and improved the documentation. If you're in the market for an intuitive and fast tool to query and share your data, give Quix a try: * [Online demo](https://quix-demo.io/) * Quick start ```bash mkdir quix && cd quix curl https://raw.githubusercontent.com/wix/quix/master/docker-compose.prebuilt.yml -o docker-compose.yml curl https://raw.githubusercontent.com/wix/quix/master/env-example -o .env docker-compose up ``` * [Full installation](https://wix.github.io/quix/docs/installation) ### Here's what's available in our first release: #### Notebook/note management with multi-user support * Shareable folders/notebooks/notes * Favorite notebooks * Full-text note search across all users * Readonly access to the notebooks of all users #### Query editor * Multiple statements * Syntax highlighting * Live syntax validation and autocompletion (currently for Presto only) * Keyboard shortcuts * Typed parameters (String, Boolean, Number, Date, Option, List) * Export results as CSV #### One-click visualizations * Timeline chart * Bar chart * Pie chart #### DB types you can query * Presto (supports live syntax validation and basic autocompletion) * Amazon Athena * Google BigQuery * Generic JDBC (MySQL, PostgreSQL, SQL Server, ClickHouse, etc...) #### DB Explorer * Navigate, search and preview your catalogs and tables #### What's in the pipeline? * Python note * More SSO options (OpenID) * More visualizations * Note embedding * Scheduled queries * Public queries * SDK for extending the base functionality of Quix #### Contributors @frolovv, @sthuck, @antonpod, @ittaym, @yaarams, @stas-slu, @shl3vi, @amitmarx, @kgshv, @erezr ================================================ FILE: documentation/website/core/Footer.js ================================================ /** * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const React = require('react'); class Footer extends React.Component { docUrl(doc, language) { const baseUrl = this.props.config.baseUrl; const docsUrl = this.props.config.docsUrl; const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; const langPart = `${language ? `${language}/` : ''}`; return `${baseUrl}${docsPart}${langPart}${doc}`; } pageUrl(doc, language) { const baseUrl = this.props.config.baseUrl; return baseUrl + (language ? `${language}/` : '') + doc; } render() { return ( ); } } module.exports = Footer; ================================================ FILE: documentation/website/i18n/en.json ================================================ { "_comment": "This file is auto-generated by write-translations.js", "localized-strings": { "next": "Next", "previous": "Previous", "tagline": "An easy-to-use notebook manager", "docs": { "about": { "title": "About", "sidebar_label": "About" }, "architecture": { "title": "Architecture", "sidebar_label": "Architecture" }, "athena": { "title": "Amazon Athena", "sidebar_label": "Athena" }, "bigquery": { "title": "Google BigQuery", "sidebar_label": "BigQuery" }, "clickhouse": { "title": "ClickHouse", "sidebar_label": "ClickHouse" }, "installation": { "title": "Installation", "sidebar_label": "Installation" }, "jdbc": { "title": "Jdbc", "sidebar_label": "Jdbc" }, "mariadb": { "title": "MariaDB", "sidebar_label": "MariaDB" }, "mysql": { "title": "MySQL", "sidebar_label": "MySQL" }, "oracle": { "title": "Oracle", "sidebar_label": "Oracle" }, "postgresql": { "title": "PostgreSQL", "sidebar_label": "PostgreSQL" }, "presto": { "title": "Presto", "sidebar_label": "Presto" }, "python": { "title": "Python", "sidebar_label": "Python" }, "redshift": { "title": "Amazon Redshift", "sidebar_label": "Redshift" } }, "links": { "Docs": "Docs", "Blog": "Blog", "GitHub": "GitHub" }, "categories": { "Introduction": "Introduction", "Getting Started": "Getting Started", "Supported datasources": "Supported datasources" } }, "pages-strings": { "Help Translate|recruit community translators for your project": "Help Translate", "Edit this Doc|recruitment message asking to edit the doc source": "Edit", "Translate this Doc|recruitment message asking to translate the docs": "Translate" } } ================================================ FILE: documentation/website/package.json ================================================ { "scripts": { "examples": "docusaurus-examples", "start": "docusaurus-start", "build": "docusaurus-build", "publish-gh-pages": "docusaurus-publish", "write-translations": "docusaurus-write-translations", "version": "docusaurus-version", "rename-version": "docusaurus-rename-version" }, "devDependencies": { "docusaurus": "^1.14.6" } } ================================================ FILE: documentation/website/pages/en/help.js ================================================ /** * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const React = require('react'); const CompLibrary = require('../../core/CompLibrary.js'); const Container = CompLibrary.Container; const GridBlock = CompLibrary.GridBlock; function Help(props) { const {config: siteConfig, language = ''} = props; const {baseUrl, docsUrl} = siteConfig; const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; const langPart = `${language ? `${language}/` : ''}`; const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`; const supportLinks = [ { content: `Learn more using the [documentation on this site.](${docUrl( 'doc1.html', )})`, title: 'Browse Docs', }, { content: 'Ask questions about the documentation and project', title: 'Join the community', }, { content: "Find out what's new with this project", title: 'Stay up to date', }, ]; return (

Need help?

This project is maintained by a dedicated group of people.

); } module.exports = Help; ================================================ FILE: documentation/website/pages/en/index.js ================================================ /** * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const React = require('react'); const CompLibrary = require('../../core/CompLibrary.js'); const Container = CompLibrary.Container; const GridBlock = CompLibrary.GridBlock; class HomeSplash extends React.Component { render() { const {siteConfig, language = ''} = this.props; const {baseUrl, docsUrl} = siteConfig; const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; const langPart = `${language ? `${language}/` : ''}`; const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`; const SplashContainer = props => (
{props.children}
); const Logo = props => (
Project Logo
); const ProjectTitle = () => (

{siteConfig.title} {siteConfig.tagline}

); const PromoSection = props => (
{props.children}
); const Button = props => ( ); return (
); } } class Index extends React.Component { render() { const {config: siteConfig, language = ''} = this.props; const {baseUrl, docsUrl} = siteConfig; const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`; const langPart = `${language ? `${language}/` : ''}`; const docUrl = (doc, hash) => `${baseUrl}${docsPart}${langPart}${doc}${hash ? `#${hash}` : ''}`; const Block = props => ( ); const MainFeatures = () => ( {[ { content: 'You can run Quix in single-user or
multi-user mode via Google OAuth', title: 'Multi-user web-app', }, { content: 'Quix uses notes to edit and run queries.
Notes live inside notebooks, which
can be organized in folders.', title: 'Notebook manager', }, { content: 'The DB explorer lets you navigate,
search and preview your tables', title: 'DB explorer', }, ]}
); const MoreFeatures = () => ( {[ { content: 'Quix features smart charts which help
you quickly visualize your data', title: 'One-click visualizations', }, { content: 'Search queries across all users', title: 'Search', }, { content: 'Easily share your folders, notebooks and notes', title: 'Shareability', }, ]}
{[ { content: 'View the history of queries executed by you
or other users', title: 'History', }, {}, {}, ]}
); const Showcase = () => { if ((siteConfig.users || []).length === 0) { return null; } const showcase = siteConfig.users .filter(user => user.pinned) .map(user => ( {user.caption} )); const pageUrl = page => baseUrl + (language ? `${language}/` : '') + page; return (

Who is Using This?

This project is used by all these people

{showcase}
); }; return (
); } } module.exports = Index; ================================================ FILE: documentation/website/pages/en/users.js ================================================ /** * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const React = require('react'); const CompLibrary = require('../../core/CompLibrary.js'); const Container = CompLibrary.Container; class Users extends React.Component { render() { const {config: siteConfig} = this.props; if ((siteConfig.users || []).length === 0) { return null; } const editUrl = `${siteConfig.repoUrl}/edit/master/website/siteConfig.js`; const showcase = siteConfig.users.map(user => ( {user.caption} )); return (

Who is Using This?

This project is used by many folks

{showcase}

Are you using this project?

Add your company
); } } module.exports = Users; ================================================ FILE: documentation/website/sidebars.json ================================================ { "docs": { "Introduction": ["about", "architecture"], "Getting Started": ["installation"], "Supported datasources": ["athena", "bigquery", "clickhouse", "jdbc", "mariadb", "mysql", "oracle", "postgresql", "presto", "python", "redshift"] } } ================================================ FILE: documentation/website/siteConfig.js ================================================ /** * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ // See https://docusaurus.io/docs/site-config for all the possible // site configuration options. // List of projects/orgs using your project for the users page. const users = [ { caption: 'User1', // You will need to prepend the image path with your baseUrl // if it is not '/', like: '/test-site/img/image.jpg'. image: '/img/undraw_open_source.svg', infoLink: 'https://www.facebook.com', pinned: true, }, ]; const siteConfig = { algolia: { apiKey: '706ea6606dcf22ab4091945383d0cff9', indexName: 'quix', }, title: 'Quix', // Title for your website. tagline: 'An easy-to-use notebook manager', // url: 'https://your-docusaurus-test-site.com', // Your website URL baseUrl: '/quix/', // Base URL for your project */ // For github.io type URLs, you would set the url and baseUrl like: url: 'https://wix.github.io', baseUrl: '/quix/', // Used for publishing and more projectName: 'quix', organizationName: 'wix', // For top-level user or org sites, the organization is still the same. // e.g., for the https://JoelMarcey.github.io site, it would be set like... // organizationName: 'JoelMarcey' // For no header links in the top nav bar -> headerLinks: [], headerLinks: [ {doc: 'installation', label: 'Docs'}, {blog: true, label: 'Blog'}, {href: 'https://github.com/wix-incubator/quix', label: 'GitHub'}, ], // If you have users set above, you add it here: users, /* path to images for header/footer */ headerIcon: 'img/favicon.ico', footerIcon: 'img/favicon.ico', favicon: 'img/favicon.ico', /* Colors for website */ colors: { primaryColor: '#fc4a6a', secondaryColor: '#00a9f4', }, /* Custom fonts for website */ /* fonts: { myFont: [ "Times New Roman", "Serif" ], myOtherFont: [ "-apple-system", "system-ui" ] }, */ // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds. copyright: `© ${new Date().getFullYear()} Wix.com, Inc`, highlight: { // Highlight.js theme to use for syntax highlighting in code blocks. theme: 'default', }, // Add custom scripts here that would be placed in ================================================ FILE: quix-frontend/client/src/lib/app/bootstrap.ts ================================================ import jQuery from 'jquery'; window.jQuery = jQuery; window.$ = jQuery; import angular from 'angular'; import 'angular-resource'; import 'angular-ui-router'; import '../core'; import '../ui'; export const ngApp = angular.module('bi.app', [ 'ngResource', 'bi.core', 'bi.ui', 'ui.router' ]); ================================================ FILE: quix-frontend/client/src/lib/app/constants.ts ================================================ export const Apps = []; ================================================ FILE: quix-frontend/client/src/lib/app/directives/app/app.html ================================================
{{::app.getTitle()}}
apps
  • lens {{::menuApp.title}}
{{::user.getName()}}
{{vm.menu.current.name}}
keyboard_arrow_left
Signing in...
================================================ FILE: quix-frontend/client/src/lib/app/directives/app/app.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; bi-app { display: flex; flex-direction: column; flex-grow: 1; overflow: hidden; .bi-app-header { [ng-transclude="header"] { header { display: block; height: 54px; } } bi-dropdown { bi-toggle { height: 53px; } } } .bi-app-menu { .bi-app-menu-separator { width: 100%; border-top: 1px solid darken($darker-bg, 7); border-bottom: 1px solid lighten($darker-bg, 7); } } .bi-app-sidebar { width: 300px; .bi-app-sidebar-toggle { margin-right: -6px; } .bi-section-content { padding: 0; } } } ================================================ FILE: quix-frontend/client/src/lib/app/directives/app/app.ts ================================================ import template from './app.html'; import './app.scss'; import { assign, find, without } from 'lodash'; import { initNgScope, inject } from '../../../core'; import { IMenuItem } from '../../services/app'; import { App } from '../..'; import { Apps } from '../../constants'; import { Store } from '../../../store'; export interface IScope extends ng.IScope { app: App; store: Store; } function setCurrentMenuItem(scope: IScope, item: IMenuItem) { return (scope.vm.menu.current = item); } export default () => { return { restrict: 'E', template, transclude: { header: '?header', }, scope: { app: '=', store: '=', }, link: { pre(scope: IScope) { scope.user = scope.app.getUser(); initNgScope(scope) .withVM({ apps: without(Apps, find(Apps, { id: scope.app.getId() } as any)), header: {}, menu: { current: null, content: {}, }, loginHint: {}, }) .withEvents({ onMenuItemToggle(item: IMenuItem) { const { current, content } = scope.vm.menu; if (!item.template) { item.onToggle && item.onToggle(scope.app, item); return; } if (typeof item.onToggle === 'function') { item.onToggle(scope.app, item); setCurrentMenuItem(scope, item); } else { setCurrentMenuItem(scope, current === item ? null : item); } if (scope.vm.menu.current) { content.reload(); } else { content.toggle(false); } if (current && current.scope) { current.scope.$destroy(); delete current.scope; } }, onAppClick({ href }) { window.open(href, '_blank'); }, onTitleClick() { scope.app.getNavigator().goHome(); }, }); scope.compileMenuItem = (item: IMenuItem) => { (item as any).scope = scope.$new(true); return { html: item.compiled || inject('$compile')(item.template)((item as any).scope), }; }; scope.app .getNavigator() .listen( scope.app .getMenuItems() .map((item) => item.state) .filter((state) => state), 'start', (params, stateName) => { scope.app.getMenuItems().some((item) => { if (!item.state) { return false; } return ( stateName.indexOf(item.state) >= 0 && !!(setCurrentMenuItem(scope, item) || true) ); }); }, scope ) .otherwise( () => scope.vm.menu.current && scope.vm.menu.current.state && setCurrentMenuItem(scope, null) ); scope.app.getStore().subscribe( 'app', ({ header, menu }) => { scope.vm.header.toggle(header); scope.vm.menu.toggle(menu); }, scope ); scope.renderMenuItem = (_scope: any, menuItem: IMenuItem) => { let html; if ( typeof menuItem.icon === 'string' || menuItem.name === 'separator' ) { html = inject('$compile')( menuItem.name === 'separator' ? `
` : `{{::item.icon}}` )(assign(_scope.$new(true), { item: menuItem })); } else { html = menuItem.icon(_scope.app, _scope.store, _scope); } return { html }; }; inject('$timeout')(() => scope.vm.loginHint.toggle(true), 5000); }, }, }; }; ================================================ FILE: quix-frontend/client/src/lib/app/directives/index.ts ================================================ export {default as biApp} from './app/app'; export {default as biAppLogin} from './login/login'; ================================================ FILE: quix-frontend/client/src/lib/app/directives/login/login.html ================================================
================================================ FILE: quix-frontend/client/src/lib/app/directives/login/login.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; bi-app-login { img { width: 100px; margin-bottom: 43px; } .bi-panel { width: 400px; button { height: 40px; } } } ================================================ FILE: quix-frontend/client/src/lib/app/directives/login/login.ts ================================================ import template from './login.html'; import './login.scss'; import {initNgScope, utils} from '../../../core'; import {App} from '../..'; export interface IScope extends ng.IScope { app: App; } export default () => { return { restrict: 'E', template, scope: { app: '=' }, link: { pre(scope: IScope) { initNgScope(scope) .withVM({ pending: {} }) .withEvents({ onLoginClick() { scope.vm.pending.toggle(true); scope.app.login() .catch(() => utils.scope.safeDigest(scope, () => scope.vm.pending.toggle(false))); } }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/app/index.ts ================================================ import './typings/window'; import {forEach} from 'lodash'; import {ngApp} from './bootstrap'; import {Builder} from './services/builder'; import * as directives from './directives'; import {Options} from './types'; export {App} from './services/app'; export {PluginBuilder} from './services/plugin-builder'; forEach(directives, (fn, name) => ngApp.directive(name, fn as any)); export default function app(id: string | { id: string; title: string; }, options: Options = {}, modules = []): Builder { return new Builder(id, ngApp, options, modules); } ================================================ FILE: quix-frontend/client/src/lib/app/services/app.ts ================================================ import {createStore, Store} from '../../store'; import angular from 'angular'; import Navigator from './navigator'; import {User} from './user'; import {login} from './sso'; import {Options} from '../types'; import { hooks } from '../../../hooks'; export interface IMenuItem { name: string; icon?: string | Function; state?: string; template?: string; compiled?: string; onToggle?(app?: App, item?: IMenuItem): any; } export class App { private ngModule: angular.IModule; private readonly store: Store; constructor( private readonly id: string, private readonly title: string, private readonly options: Options, private readonly plugins, private readonly user: User, private readonly navigator: Navigator, private readonly menuItems: IMenuItem[], private readonly config: Config, ) { this.store = createStore({ app: register => register((state = { header: true, menu: true, }, action) => { switch (action.type) { case 'toggle.header': return {...state, header: action.header}; case 'toggle.menu': return {...state, menu: action.menu}; default: } return state; }) }); } init(modules: string[] = []) { this.ngModule = angular.module(this.id, ['bi.app'].concat(modules)); this.navigator.on('stateChangeSuccess', (name, params, fromState) => { hooks.app.stateChange.call(this, name, params, fromState); }); return this; } login() { return login(this.options.auth.googleClientId, this.options.apiBasePath) .then(data => this.navigator.finishLogin(data)); } getId() { return this.id; } getTitle() { return this.title; } getLogoUrl() { return this.options.logoUrl; } getUser(): User { return this.user; } getModule(): angular.IModule { return this.ngModule; } getNavigator(): Navigator { return this.navigator; } getPlugin(id: string) { return this.plugins[id]; } getMenuItems() { return this.menuItems; } getStore() { return this.store; } getConfig() { return this.config; } toggleHeader(state: boolean) { this.store.dispatch({type: 'toggle.header', header: state}); } toggleMenu(state: boolean) { this.store.dispatch({type: 'toggle.menu', menu: state}); } go(state: string, params?: Object, options?) { this.navigator.go(state, params, options); } } ================================================ FILE: quix-frontend/client/src/lib/app/services/appStoreProvider.tsx ================================================ import React from 'react'; import { Subtract } from 'utility-types'; import {Store} from '../../store'; import {App} from '../../app'; const AppStoreContext = React.createContext({ app: null, store: null }); export interface InjectedAppStoreProps { app:App, store: Store } export const withAppStoreProvider =

(app: App, store: Store, ComponentToWrap: React.ComponentType

):React.FC

=> (props) => export const withAppStore =

( ComponentToWrap: React.ComponentType

, ): React.ComponentType> => props => ( {({ app, store }) => { const injectedProps = { ...props, app, store } as P; return ; }} ); ================================================ FILE: quix-frontend/client/src/lib/app/services/builder.ts ================================================ import {mapValues, last} from 'lodash'; import {paramCase, camelCase, headerCase} from 'change-case'; import {srv, inject, utils} from '../../core'; import {createStore, Store} from '../../../lib/store'; import Navigator from './navigator'; import {App, IMenuItem} from './app'; import { PluginBuilder, IPluginComponent, IStateFactory, IPluginBranches, IStateComponentFactory, IUrlParamListener, IReactStateComponentConfig, IAngularStateComponentConfig, IStateComponentConfig, IPluginReactComponent } from './plugin-builder'; import {initScopeListeners} from '../utils/scope-utils'; import {User} from './user'; import {LocalStorage} from '../../core/srv/local-storage'; import {Options} from '../types'; import {react2angular} from 'react2angular'; import { withAppStoreProvider } from './appStoreProvider'; export type PluginFactory = (app: PluginBuilder) => any; const userActionToUrlParam = {}; const urlMiddleware = str => next => action => { next(action); if (action.origin !== 'user' || !userActionToUrlParam[action.type]) { return; } const location = inject('$location'); const {param, listener} = userActionToUrlParam[action.type]; location.search({...location.search(), [param]: listener.to(action)}); }; /** * Application instance builder * * Allows to: * - register application plugins * - register application states * - register menu items */ export class Builder extends srv.eventEmitter.EventEmitter { private readonly plugins: {[key: string]: PluginBuilder} = {}; private readonly navigator: Navigator; private readonly user: User; private readonly menuItems: IMenuItem[] = []; private readonly title: string; private conf: Config; constructor( private readonly id: string | { id: string; title: string; }, private readonly ngApp: angular.IModule, private readonly options: Options, private ngmodules = [] ) { super(); this.user = new User(); if (typeof id === 'object') { this.id = id.id; this.title = id.title; } else { this.title = id; } this.navigator = new Navigator({ ...options, statePrefix: typeof options.statePrefix === 'undefined' ? 'auth.content.' : options.statePrefix, defaultUrl: options.defaultUrl || '/', }).init(this.user, ngApp); } /** * Registers an application plugin * * @param id plugin id * @param factory plugin factory */ plugin(id: string, factory: (pluginBuilder: PluginBuilder) => any): Builder { this.plugins[id] = new PluginBuilder(id, this); factory(this.plugins[id]); return this; } /** * Registers a ui-router state * * @param options ui-router state options */ state(options: any): Builder { const {name} = options; delete options.name; this.navigator.state(name, options); return this; } /** * Registers an angular directive * * @param name component name * @param factory component factory */ component(name: string, factory: angular.IDirectiveFactory): Builder { this.ngApp.directive(name, factory); return this; } reactComponent(name: string, factory: angular.IComponentOptions): Builder { this.ngApp.component(name, factory); return this; } /** * Registers a state component * * @param config state component config */ stateComponent(config: IStateComponentConfig, app: App, store: Store): Builder { function fromUrl(scope, url: {[key: string]: IUrlParamListener}, params: object) { const actions = Object.keys(url).map(param => (url as any)[param].from(params[param])); utils.scope.safeDigest(scope, () => store.dispatch(actions)); } const [fullStateName, paramName] = config.name.split(':'); const stateParts = fullStateName.split('.'); const stateName = last(stateParts); const componentName = [app.getId(), paramCase(stateParts.join('_'))].filter(x => !!x).join('-'); const stateUrl = config.abstract ? '' : `/${fullStateName.replace(/\./g, '/')}${paramName ? `/:${paramName}` : ''}?${Object.keys(config.url)}`; this.state({ name: fullStateName, abstract: config.abstract || false, url: stateUrl, reloadOnSearch: false, template: ` <${componentName} class="bi-c-h bi-grow" ${Object.keys(config.scope).map(prop => `${paramCase(prop)}="${prop}"`).join(' ')} $state-options="$stateOptions" > `, params: config.options || {}, onEnter: config.onEnter, onExit: config.onExit, controller: ['$scope', '$stateParams', 'user', (scope, params) => { config.controller(scope, params, { syncUrl(getArgs = () => []) { let {url} = config; url = mapValues(url, (listener: IUrlParamListener, param) => { let normalizedListener = listener; if (typeof listener === 'function') { normalizedListener = {from: listener, to: action => listener(action[param])[param]}; } const enrichedListener = mapValues(normalizedListener, (l, key) => value => normalizedListener[key](typeof value === 'undefined' ? null : value, ...getArgs())); userActionToUrlParam[(enrichedListener as any).from().type] = {param, listener: enrichedListener}; return enrichedListener; }) as {[key: string]: IUrlParamListener}; fromUrl(scope, url, inject('$location').search()); inject('$timeout')(() => { const cleaner = scope.$on('$locationChangeSuccess', () => fromUrl(scope, url, inject('$location').search())); scope.$on('$destroy', () => cleaner()); }); }, setTitle(getTitle = () => [app.getTitle(), headerCase(stateName)]) { document.title = getTitle({ appTitle: app.getTitle(), stateName: headerCase(stateName) }).join(' · '); } }); scope.$stateOptions = Object.keys(config.options || {}) .reduce((res, key) => { res[key] = params[key]; return res; }, {}); }] }); const isAngularConfig = (unknownConfig: IStateComponentConfig): unknownConfig is IAngularStateComponentConfig => { return typeof (unknownConfig as IAngularStateComponentConfig).template === 'string'; }; const createAngularFactory = (angularConfig: IAngularStateComponentConfig) => () => ({ restrict: 'E', template: angularConfig.template, scope: mapValues({...angularConfig.scope, $stateOptions: true}, () => '<'), link: { pre(scope, ...args) { initScopeListeners(scope, store, angularConfig.scope); (angularConfig.link as any)(scope, ...args); } } }); const createReactFactory = (reactConfig: IReactStateComponentConfig) => react2angular(withAppStoreProvider(app, store, reactConfig.template), Object.keys(reactConfig.scope)); isAngularConfig(config) ? this.component(camelCase(componentName), createAngularFactory(config)): this.reactComponent(camelCase(componentName), createReactFactory(config)); return this; } modules(modules: string[]) { this.ngmodules = this.ngmodules.concat(modules); } menuItem(item: IMenuItem) { this.menuItems.push(item); return this; } config(config: Config) { this.conf = config; return this; } getUser() { return this.user; } /** * Creates an application instance */ build(): App { const app = new App( this.id as string, this.title, this.options, this.plugins, this.user, this.navigator, this.menuItems, this.conf, ) .init(this.ngmodules); Object.keys(this.plugins).forEach(name => { const plugin = this.plugins[name]; const {branches, logUrl, server} = plugin.store() as IPluginBranches; const intializedBranches = mapValues({ ...branches, _global: () => next => next(x => null, urlMiddleware) } as any, branch => branch(app)) const store = createStore(intializedBranches, {logUrl, server}); (plugin.states() as IStateFactory[]).forEach(factory => this.state(factory(app, store))); (plugin.components() as IPluginComponent[]).forEach(({name: componentName, factory}) => this.component(componentName, factory(app, store))); (plugin.stateComponents() as IStateComponentFactory[]).forEach(factory => this.stateComponent(factory(app, store), app, store)); (plugin.reactComponents() as IPluginReactComponent[]).forEach( ({name: componentName, factory}) => this.reactComponent( camelCase(componentName), react2angular( factory().template, factory().scope ) ) ); this.fire(`ready|${plugin.getId()}`, app, store); }); LocalStorage.setPrefix(`${this.id}-`); this.fire('ready', app); return app; } } ================================================ FILE: quix-frontend/client/src/lib/app/services/navigator.ts ================================================ import { IModule } from 'angular'; import { inject, srv } from '../../core'; import { User } from './user'; import { Options } from '../types'; const EVENT_MAP = { start: 'stateChangeStart', success: 'stateChangeSuccess', visible: 'viewLoaded', }; export type TEventType = 'start' | 'success' | 'visible'; export type INavigatorCallback = (params: any, stateName: string) => any; export default class Navigator extends srv.eventEmitter.EventEmitter { private readonly states = []; private prefix; private resolveLogin: (data: any) => any; constructor(private readonly options: Options) { super(); } init(user: User, ngApp: IModule) { this.prefix = this.options.statePrefix; if (this.options.auth) { const self = this; this.states.push({ name: 'auth', options: { abstract: true, template: '

', resolve: { user() { return user .fetch(self.options.apiBasePath) .catch(() => { user.toggleLoggedIn(false); return new Promise( (resolve) => (self.resolveLogin = resolve) ); }) .then((data: any) => { user.toggleLoggedIn(true); self.trigger('ready', user); }); }, }, }, }); this.prefix = `auth.${this.prefix}`; } ngApp.config([ '$stateProvider', '$locationProvider', '$urlRouterProvider', ($stateProvider, $locationProvider, $urlRouterProvider) => { $locationProvider.hashPrefix(''); $urlRouterProvider.otherwise(this.options.defaultUrl); this.states.forEach(({ name, options }) => { try { $stateProvider.state(name, options); } catch (e) { console.warn(e); } }); }, ]); ngApp.run([ '$rootScope', (scope) => { scope.$on('$stateChangeStart', (e, state, params, fromState) => { this.trigger('stateChangeStart', state.name, params, fromState.name); }); scope.$on('$stateChangeSuccess', (e, state, params, fromState) => { this.trigger( 'stateChangeSuccess', state.name, params, fromState.name ); }); scope.$on('$viewContentLoaded', (e, viewConfig) => this.trigger('viewLoaded') ); }, ]); return this; } finishLogin(data: any) { if (this.resolveLogin) { this.resolveLogin(data); } } getStatePrefix() { return this.prefix; } state(name, options) { this.states.push({ name: `${this.prefix}${name ? `.${name}` : ''}`, options, }); } go( state: string, params?: Object, options: { reload: boolean | string } = { reload: false } ): PromiseLike { if (typeof options.reload === 'string') { options.reload = `${this.prefix}.${options.reload}`; } return inject('$state').go(`${this.prefix}.${state}`, params, options); } getUrl(state?: string, params?: Object): string { state = state || inject('$state').current.name; return `${document.location.protocol}//${document.location.host}${ document.location.pathname }${inject('$state').href(state, params, { relative: true, inherit: false, })}`; } goHome() { return inject('$state').go(`${this.prefix}.${this.options.homeState}`); } listen( state: string | string[], type: TEventType, fn: INavigatorCallback, scope? ) { const states = typeof state === 'string' ? [state] : state || []; const eventName = EVENT_MAP[type]; let otherwise: INavigatorCallback = null; this.on( eventName, (stateName = '', params = {}) => { stateName = stateName.replace(`${this.getStatePrefix()}.`, ''); if (states.some((s) => stateName.indexOf(s) >= 0)) { fn(params, stateName); } else if (otherwise) { otherwise(params, stateName); } }, true, scope ); return { otherwise(f: INavigatorCallback) { otherwise = f; }, }; } listenFrom( state: string | string[], type: TEventType, fn: Function, invoke = false, scope? ) { const states = typeof state === 'string' ? [state] : state || []; const eventName = EVENT_MAP[type]; let otherwise = null; this.on( eventName, (_, __, stateName) => { if (states.some((s) => stateName.indexOf(s) >= 0)) { fn(); } else if (otherwise) { otherwise(); } }, invoke, scope ); return { otherwise(f: Function) { otherwise = f; }, }; } reload(state?: string) { inject('$state').reload(state); } } ================================================ FILE: quix-frontend/client/src/lib/app/services/plugin-builder.ts ================================================ import {forEach} from 'lodash'; import {IDirectiveFactory, IDirectiveLinkFn} from 'angular'; import {Store, IBranch} from '../../store'; import {Builder} from './builder'; import {App, IMenuItem} from './app'; import {ServerFrameworkType} from '../../store/services/store-logger'; import * as React from 'react'; export type IComponentFactory = (app: App, store: Store) => IDirectiveFactory; export type IReactComponentFactory = () => IReactComponentConfig; export type IStateComponentFactory = (app: App, store: Store) => IStateComponentConfig; export type IStateFactory = (app: App, store: Store) => object; export type IBranchFactory = (app: App) => IBranch; export interface IPluginComponent { name: string; factory: IComponentFactory; } export interface IPluginReactComponent { name: string; factory: IReactComponentFactory; } export interface IPluginBranches { branches: {[key: string]: IBranchFactory}; logUrl: string; server?: ServerFrameworkType; } export type IUrlParamListener = Function | {from: Function; to: Function}; export type IScopeListener = (scope, current: any, previous: any, store: Store) => any interface IScopeListeners extends Record {} export interface IStateComponentConfigBase { name: string; abstract?: boolean; url: {[key: string]: IUrlParamListener}; scope: IScopeListeners; options?: Record, controller(scope: any, params: {[key: string]: any}, api: { syncUrl(getArgs?: () => any): any; setTitle(getTitle?: (args: { appTitle?: string; stateName?: string; }) => string[]): any; }): any; onEnter?(): any; onExit?(): any; } export interface IAngularStateComponentConfig extends IStateComponentConfigBase{ template: string; link: IDirectiveLinkFn; } export interface IReactStateComponentConfig extends IStateComponentConfigBase{ template: React.ComponentType; } export type IStateComponentConfig = IAngularStateComponentConfig | IReactStateComponentConfig; export interface IReactComponentConfig{ name: string; scope: string[]; template: React.ComponentType; } /** * A subset of Builder which is exposed to plugin factories */ export class PluginBuilder { private readonly pluginStates = []; private readonly pluginComponents: IPluginComponent[] = []; private readonly pluginReactComponents: IPluginReactComponent[] = []; private readonly pluginStateComponents: IStateComponentFactory[] = []; private pluginBranches: IPluginBranches = {logUrl: '', server: null, branches: {}}; constructor(private readonly id: string, private readonly builder: Builder) { } /** * Registers a ui-router state * * @param options ui-router state options */ state(options: Object): PluginBuilder { this.builder.state(options); return this; } /** * Registers ui-router states * * @param states ui-router states */ states(states?: {[name: string]: IStateFactory}) { if (states) { forEach(states, factory => this.pluginStates.push(factory)); return this; } return this.pluginStates; } /** * Registers a react component * * @param name component name * @param factory component factory */ reactComponent(name: string, factory: IReactComponentFactory): PluginBuilder { this.pluginReactComponents.push({name, factory}); return this; } /** * Registers react components * * @param components components */ reactComponents(components?: {[name: string]: IReactComponentFactory}) { if (components) { forEach(components, (factory, name) => this.reactComponent(name, factory)); return this; } return this.pluginReactComponents; } /** * Registers an angular directive * * @param name component name * @param factory component factory */ component(name: string, factory: IComponentFactory): PluginBuilder { this.pluginComponents.push({name, factory}); return this; } /** * Registers angular directives * * @param components directives */ components(components?: {[name: string]: IComponentFactory}) { if (components) { forEach(components, (factory, name) => this.component(name, factory)); return this; } return this.pluginComponents; } /** * Registers a react state component * * @param factory component factory */ stateComponent(factory?: IStateComponentFactory) { this.pluginStateComponents.push(factory); return this; } /** * Registers a react state components * * @param stateComponents components */ stateComponents(stateComponents?: {[name: string]: IStateComponentFactory}) { if (stateComponents) { forEach(stateComponents, (factory, name) => this.stateComponent(factory)); return this; } return this.pluginStateComponents; } /** * Registers store branches * * @param branches store branches * @param logUrl log url * @param server */ store(branches?: Record , logUrl?: string, server?: ServerFrameworkType) { if (branches) { this.pluginBranches = {branches, logUrl, server}; return this; } return this.pluginBranches; } modules(modules) { this.builder.modules(modules); return this; } menuItem(item: IMenuItem) { this.builder.menuItem(item); return this; } getUser() { return this.builder.getUser(); } getId() { return this.id; } /** * Subscribes to application ready event * * @param fn will be called with app's instance after app.build() was called */ ready(fn: (app: App) => any) { this.builder.on('ready', fn); } /** * Subscribes to application ready event per plugin * * @param fn will be called with app's instance after app.build() was called */ onPluginReady(fn: (app: App, store: Store) => any) { this.builder.on(`ready|${this.id}`, fn); } } ================================================ FILE: quix-frontend/client/src/lib/app/services/sso.ts ================================================ import {inject} from '../../core'; declare const gapi; const insertScript = file => { const deferred = inject('$q').defer(); const po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = file; po.onload = () => deferred.resolve(); const s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); return deferred.promise; }; const insertGoogleSdk = () => { return insertScript('https://apis.google.com/js/platform.js'); }; const authenticate = (apiBasePath: string, code?: string) => { const url = (apiBasePath ? apiBasePath : '') + '/api/authenticate' + (code ? `?code=${code}` : ''); return inject('$resource')(url).get().$promise; }; export const init = () => { return insertGoogleSdk(); }; export const login = async (clientId, apiBasePath?: string): Promise => { await init(); const deferred = inject('$q').defer(); $(() => gapi.load('auth2', () => { try { const auth2 = gapi.auth2.init({ client_id: clientId, scope: 'email profile', }); auth2.grantOfflineAccess().then(res => authenticate(apiBasePath, res.code) .then(deferred.resolve) .catch(deferred.reject)); } catch(e) { console.error(e); deferred.reject(e); } })); return deferred.promise; }; export const logout = () => { (window as any).gapi.auth.signOut(); }; ================================================ FILE: quix-frontend/client/src/lib/app/services/user.ts ================================================ import { inject } from '../../core'; export class Permission { private timeout; private password: string; elevate(password) { this.password = password; } deelevate() { this.password = null; } isElevated() { return !!this.password; } getPassword() { return this.password; } renew() { if (!this.isElevated()) { return; } const timeout = inject('$timeout'); timeout.cancel(this.timeout); this.timeout = timeout(() => this.deelevate(), 30 * 60 * 10000); // 30 minutes } } const addPrefixSlash = (s: string) => (s[0] === '/' ? s : '/' + s); export class User { private email: string; private name: string; private avatar: string; private loggedIn; private role: string; private id: string; private stats: { trashBinCount: number }; private readonly permission = new Permission(); fetch(apiBasePath?: string) { return inject('$resource')( `${apiBasePath ? addPrefixSlash(apiBasePath) : ''}/api/user` ) .get() .$promise.then((data) => this.set(data.payload || data)); } set({ email, name, avatar, role, id, stats }: Record) { this.email = email; this.name = name; this.avatar = avatar; this.role = role || 'user'; this.loggedIn = null; this.id = id; this.stats = stats as any; return this; } getStats() { return this.stats; } getEmail() { return this.email; } getName() { return this.name; } getAvatar() { return this.avatar; } getRole() { return this.role; } getId() { return this.id; } getPermission() { return this.permission; } isLoggedIn() { return this.loggedIn; } toggleLoggedIn(loggedIn) { return (this.loggedIn = loggedIn); } } ================================================ FILE: quix-frontend/client/src/lib/app/types.ts ================================================ export interface Options { statePrefix?: string; defaultUrl?: string; homeState?: string; logoUrl?: string; apiBasePath?: string; auth?: { googleClientId: string; }; } ================================================ FILE: quix-frontend/client/src/lib/app/typings/story-builder.ts ================================================ import {PluginBuilder} from '../services/plugin-builder'; export interface StoryBuilder extends PluginBuilder { story(folder: string, name: string): any; } export type StoryDefiniton = (sb: StoryBuilder) => any; ================================================ FILE: quix-frontend/client/src/lib/app/typings/types.d.ts ================================================ declare module '*.scss'; declare module '*.html'; ================================================ FILE: quix-frontend/client/src/lib/app/typings/window.ts ================================================ import * as angular from 'angular'; import {StoryDefiniton} from './story-builder'; declare global { interface Window { angular: angular.IAngularStatic; $: JQueryStatic; jQuery: JQueryStatic; } var biStorybook: { create(stories: StoryDefiniton | StoryDefiniton[], moduleDependencies: string[]): any; } } ================================================ FILE: quix-frontend/client/src/lib/app/utils/scope-utils.ts ================================================ import {isPlainObject} from 'lodash'; import {Store} from '../../../lib/store'; export const initScopeListeners = (scope, store: Store, listeners) => { Object.keys(listeners).forEach(key => { const listener = listeners[key]; const watched = {}; scope.$watch(key, (current, prev) => { if (isPlainObject(listener)) { const {self, ...props} = listener; Object.keys(props).forEach(prop => { if (!current || (prev && current[prop] === prev[prop] && watched[key + prop])) { return; } listener[prop](scope, current[prop], prev && prev[prop], store); watched[key + prop] = true; }); if (self) { self(scope, current, prev, store); } } else { listener(scope, current, prev, store); } }); }); }; ================================================ FILE: quix-frontend/client/src/lib/code-editor/ace-extensions/index.ts ================================================ import {setupLanguageTools} from './language-tools'; import {setupPrestoMode} from './presto.mode'; import {setupSnippets} from './presto-snippets'; import {setupSearchbox} from './searchbox'; import 'brace/mode/json'; import 'brace/mode/python'; export const setupAce = (ace) => { setupLanguageTools(ace); setupPrestoMode(ace); setupSnippets(ace); setupSearchbox(ace); }; ================================================ FILE: quix-frontend/client/src/lib/code-editor/ace-extensions/language-tools.ts ================================================ /* tslint:disable */ export const setupLanguageTools = (ace) => { ace.define("ace/snippets", ["require", "exports", "module", "ace/lib/oop", "ace/lib/event_emitter", "ace/lib/lang", "ace/range", "ace/anchor", "ace/keyboard/hash_handler", "ace/tokenizer", "ace/lib/dom", "ace/editor"], function (require, exports, module) { var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var lang = require("./lib/lang"); var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; var HashHandler = require("./keyboard/hash_handler").HashHandler; var Tokenizer = require("./tokenizer").Tokenizer; var comparePoints = Range.comparePoints; var SnippetManager: any = function () { this.snippetMap = {}; this.snippetNameMap = {}; }; (function () { oop.implement(this, EventEmitter); this.getTokenizer = function () { function TabstopToken(str, _, stack) { str = str.substr(1); if (/^\d+$/.test(str) && !stack.inFormatString) return [{tabstopId: parseInt(str, 10)}]; return [{text: str}]; } function escape(ch) { return "(?:[^\\\\" + ch + "]|\\\\.)"; } SnippetManager.$tokenizer = new Tokenizer({ start: [ { regex: /:/, onMatch: function (val, state, stack) { if (stack.length && stack[0].expectIf) { stack[0].expectIf = false; stack[0].elseBranch = stack[0]; return [stack[0]]; } return ":"; } }, { regex: /\\./, onMatch: function (val, state, stack) { var ch = val[1]; if (ch == "}" && stack.length) { val = ch; } else if ("`$\\".indexOf(ch) != -1) { val = ch; } else if (stack.inFormatString) { if (ch == "n") val = "\n"; else if (ch == "t") val = "\n"; else if ("ulULE".indexOf(ch) != -1) { val = {changeCase: ch, local: ch > "a"}; } } return [val]; } }, { regex: /}/, onMatch: function (val, state, stack) { return [stack.length ? stack.shift() : val]; } }, {regex: /\$(?:\d+|\w+)/, onMatch: TabstopToken}, { regex: /\$\{[\dA-Z_a-z]+/, onMatch: function (str, state, stack) { var t = TabstopToken(str.substr(1), state, stack); stack.unshift(t[0]); return t; }, next: "snippetVar" }, {regex: /\n/, token: "newline", merge: false} ], snippetVar: [ { regex: "\\|" + escape("\\|") + "*\\|", onMatch: function (val, state, stack) { stack[0].choices = val.slice(1, -1).split(","); }, next: "start" }, { regex: "/(" + escape("/") + "+)/(?:(" + escape("/") + "*)/)(\\w*):?", onMatch: function (val, state, stack) { var ts = stack[0]; ts.fmtString = val; val = this.splitRegex.exec(val); ts.guard = val[1]; ts.fmt = val[2]; ts.flag = val[3]; return ""; }, next: "start" }, { regex: "`" + escape("`") + "*`", onMatch: function (val, state, stack) { stack[0].code = val.splice(1, -1); return ""; }, next: "start" }, { regex: "\\?", onMatch: function (val, state, stack) { if (stack[0]) stack[0].expectIf = true; }, next: "start" }, {regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "start"} ], formatString: [ {regex: "/(" + escape("/") + "+)/", token: "regex"}, { regex: "", onMatch: function (val, state, stack) { stack.inFormatString = true; }, next: "start" } ] }); SnippetManager.prototype.getTokenizer = function () { return SnippetManager.$tokenizer; }; return SnippetManager.$tokenizer; }; this.tokenizeTmSnippet = function (str, startState) { return this.getTokenizer().getLineTokens(str, startState).tokens.map(function (x) { return x.value || x; }); }; this.$getDefaultValue = function (editor, name) { if (/^[A-Z]\d+$/.test(name)) { var i = name.substr(1); return (this.variables[name[0] + "__"] || {})[i]; } if (/^\d+$/.test(name)) { return (this.variables.__ || {})[name]; } name = name.replace(/^TM_/, ""); if (!editor) return; var s = editor.session; switch (name) { case "CURRENT_WORD": var r = s.getWordRange(); case "SELECTION": case "SELECTED_TEXT": return s.getTextRange(r); case "CURRENT_LINE": return s.getLine(editor.getCursorPosition().row); case "PREV_LINE": // not possible in textmate return s.getLine(editor.getCursorPosition().row - 1); case "LINE_INDEX": return editor.getCursorPosition().column; case "LINE_NUMBER": return editor.getCursorPosition().row + 1; case "SOFT_TABS": return s.getUseSoftTabs() ? "YES" : "NO"; case "TAB_SIZE": return s.getTabSize(); case "FILENAME": case "FILEPATH": return ""; case "FULLNAME": return "Ace"; } }; this.variables = {}; this.getVariableValue = function (editor, varName) { if (this.variables.hasOwnProperty(varName)) return this.variables[varName](editor, varName) || ""; return this.$getDefaultValue(editor, varName) || ""; }; this.tmStrFormat = function (str, ch, editor) { var flag = ch.flag || ""; var re = ch.guard; re = new RegExp(re, flag.replace(/[^gi]/, "")); var fmtTokens = this.tokenizeTmSnippet(ch.fmt, "formatString"); var _self = this; var formatted = str.replace(re, function () { _self.variables.__ = arguments; var fmtParts = _self.resolveVariables(fmtTokens, editor); var gChangeCase = "E"; for (var i = 0; i < fmtParts.length; i++) { var ch = fmtParts[i]; if (typeof ch == "object") { fmtParts[i] = ""; if (ch.changeCase && ch.local) { var next = fmtParts[i + 1]; if (next && typeof next == "string") { if (ch.changeCase == "u") fmtParts[i] = next[0].toUpperCase(); else fmtParts[i] = next[0].toLowerCase(); fmtParts[i + 1] = next.substr(1); } } else if (ch.changeCase) { gChangeCase = ch.changeCase; } } else if (gChangeCase == "U") { fmtParts[i] = ch.toUpperCase(); } else if (gChangeCase == "L") { fmtParts[i] = ch.toLowerCase(); } } return fmtParts.join(""); }); this.variables.__ = null; return formatted; }; this.resolveVariables = function (snippet, editor) { var result = []; for (var i = 0; i < snippet.length; i++) { var ch = snippet[i]; if (typeof ch == "string") { result.push(ch); } else if (typeof ch != "object") { continue; } else if (ch.skip) { gotoNext(ch); } else if (ch.processed < i) { continue; } else if (ch.text) { var value = this.getVariableValue(editor, ch.text); if (value && ch.fmtString) value = this.tmStrFormat(value, ch); ch.processed = i; if (ch.expectIf == null) { if (value) { result.push(value); gotoNext(ch); } } else { if (value) { ch.skip = ch.elseBranch; } else gotoNext(ch); } } else if (ch.tabstopId != null) { result.push(ch); } else if (ch.changeCase != null) { result.push(ch); } } function gotoNext(ch) { var i1 = snippet.indexOf(ch, i + 1); if (i1 != -1) i = i1; } return result; }; this.insertSnippetForSelection = function (editor, snippetText) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); var tabString = editor.session.getTabString(); var indentString = line.match(/^\s*/)[0]; if (cursor.column < indentString.length) indentString = indentString.slice(0, cursor.column); snippetText = snippetText.replace(/\r/g, ""); var tokens = this.tokenizeTmSnippet(snippetText); tokens = this.resolveVariables(tokens, editor); tokens = tokens.map(function (x) { if (x == "\n") return x + indentString; if (typeof x == "string") return x.replace(/\t/g, tabString); return x; }); var tabstops = []; tokens.forEach(function (p, i) { if (typeof p != "object") return; var id = p.tabstopId; var ts = tabstops[id]; if (!ts) { ts = tabstops[id] = []; ts.index = id; ts.value = ""; } if (ts.indexOf(p) !== -1) return; ts.push(p); var i1 = tokens.indexOf(p, i + 1); if (i1 === -1) return; var value = tokens.slice(i + 1, i1); var isNested = value.some(function (t) {return typeof t === "object"}); if (isNested && !ts.value) { ts.value = value; } else if (value.length && (!ts.value || typeof ts.value !== "string")) { ts.value = value.join(""); } }); tabstops.forEach(function (ts) {ts.length = 0}); var expanding = {}; function copyValue(val) { var copy = []; for (var i = 0; i < val.length; i++) { var p = val[i]; if (typeof p == "object") { if (expanding[p.tabstopId]) continue; var j = val.lastIndexOf(p, i - 1); p = copy[j] || {tabstopId: p.tabstopId}; } copy[i] = p; } return copy; } for (var i = 0; i < tokens.length; i++) { var p = tokens[i]; if (typeof p != "object") continue; var id = p.tabstopId; var i1 = tokens.indexOf(p, i + 1); if (expanding[id]) { if (expanding[id] === p) expanding[id] = null; continue; } var ts = tabstops[id]; var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); arg.unshift(i + 1, Math.max(0, i1 - i)); arg.push(p); expanding[id] = p; tokens.splice.apply(tokens, arg); if (ts.indexOf(p) === -1) ts.push(p); } var row = 0, column = 0; var text = ""; tokens.forEach(function (t) { if (typeof t === "string") { var lines = t.split("\n"); if (lines.length > 1) { column = lines[lines.length - 1].length; row += lines.length - 1; } else column += t.length; text += t; } else { if (!t.start) t.start = {row: row, column: column}; else t.end = {row: row, column: column}; } }); var range = editor.getSelectionRange(); var end = editor.session.replace(range, text); var tabstopManager = new TabstopManager(editor); var selectionId = editor.inVirtualSelectionMode && editor.selection.index; tabstopManager.addTabstops(tabstops, range.start, end, selectionId); }; this.insertSnippet = function (editor, snippetText) { var self = this; if (editor.inVirtualSelectionMode) return self.insertSnippetForSelection(editor, snippetText); editor.forEachSelection(function () { self.insertSnippetForSelection(editor, snippetText); }, null, {keepOrder: true}); if (editor.tabstopManager) editor.tabstopManager.tabNext(); }; this.$getScope = function (editor) { var scope = editor.session.$mode.$id || ""; scope = scope.split("/").pop(); if (scope === "html" || scope === "php") { if (scope === "php" && !editor.session.$mode.inlinePhp) scope = "html"; var c = editor.getCursorPosition(); var state = editor.session.getState(c.row); if (typeof state === "object") { state = state[0]; } if (state.substring) { if (state.substring(0, 3) == "js-") scope = "javascript"; else if (state.substring(0, 4) == "css-") scope = "css"; else if (state.substring(0, 4) == "php-") scope = "php"; } } return scope; }; this.getActiveScopes = function (editor) { var scope = this.$getScope(editor); var scopes = [scope]; var snippetMap = this.snippetMap; if (snippetMap[scope] && snippetMap[scope].includeScopes) { scopes.push.apply(scopes, snippetMap[scope].includeScopes); } scopes.push("_"); return scopes; }; this.expandWithTab = function (editor, options) { var self = this; var result = editor.forEachSelection(function () { return self.expandSnippetForSelection(editor, options); }, null, {keepOrder: true}); if (result && editor.tabstopManager) editor.tabstopManager.tabNext(); return result; }; this.expandSnippetForSelection = function (editor, options) { var cursor = editor.getCursorPosition(); var line = editor.session.getLine(cursor.row); var before = line.substring(0, cursor.column); var after = line.substr(cursor.column); var snippetMap = this.snippetMap; var snippet; this.getActiveScopes(editor).some(function (scope) { var snippets = snippetMap[scope]; if (snippets) snippet = this.findMatchingSnippet(snippets, before, after); return !!snippet; }, this); if (!snippet) return false; if (options && options.dryRun) return true; editor.session.doc.removeInLine(cursor.row, cursor.column - snippet.replaceBefore.length, cursor.column + snippet.replaceAfter.length ); this.variables.M__ = snippet.matchBefore; this.variables.T__ = snippet.matchAfter; this.insertSnippetForSelection(editor, snippet.content); this.variables.M__ = this.variables.T__ = null; return true; }; this.findMatchingSnippet = function (snippetList, before, after) { for (var i = snippetList.length; i--;) { var s = snippetList[i]; if (s.startRe && !s.startRe.test(before)) continue; if (s.endRe && !s.endRe.test(after)) continue; if (!s.startRe && !s.endRe) continue; s.matchBefore = s.startRe ? s.startRe.exec(before) : [""]; s.matchAfter = s.endRe ? s.endRe.exec(after) : [""]; s.replaceBefore = s.triggerRe ? s.triggerRe.exec(before)[0] : ""; s.replaceAfter = s.endTriggerRe ? s.endTriggerRe.exec(after)[0] : ""; return s; } }; this.snippetMap = {}; this.snippetNameMap = {}; this.register = function (snippets, scope) { var snippetMap = this.snippetMap; var snippetNameMap = this.snippetNameMap; var self = this; if (!snippets) snippets = []; function wrapRegexp(src) { if (src && !/^\^?\(.*\)\$?$|^\\b$/.test(src)) src = "(?:" + src + ")"; return src || ""; } function guardedRegexp(re, guard, opening) { re = wrapRegexp(re); guard = wrapRegexp(guard); if (opening) { re = guard + re; if (re && re[re.length - 1] != "$") re = re + "$"; } else { re = re + guard; if (re && re[0] != "^") re = "^" + re; } return new RegExp(re); } function addSnippet(s) { if (!s.scope) s.scope = scope || "_"; scope = s.scope; if (!snippetMap[scope]) { snippetMap[scope] = []; snippetNameMap[scope] = {}; } var map = snippetNameMap[scope]; if (s.name) { var old = map[s.name]; if (old) self.unregister(old); map[s.name] = s; } snippetMap[scope].push(s); if (s.tabTrigger && !s.trigger) { if (!s.guard && /^\w/.test(s.tabTrigger)) s.guard = "\\b"; s.trigger = lang.escapeRegExp(s.tabTrigger); } if (!s.trigger && !s.guard && !s.endTrigger && !s.endGuard) return; s.startRe = guardedRegexp(s.trigger, s.guard, true); s.triggerRe = new (RegExp as any)(s.trigger, "", true); s.endRe = guardedRegexp(s.endTrigger, s.endGuard, true); s.endTriggerRe = new (RegExp as any)(s.endTrigger, "", true); } if (snippets && snippets.content) addSnippet(snippets); else if (Array.isArray(snippets)) snippets.forEach(addSnippet); this._signal("registerSnippets", {scope: scope}); }; this.unregister = function (snippets, scope) { var snippetMap = this.snippetMap; var snippetNameMap = this.snippetNameMap; function removeSnippet(s) { var nameMap = snippetNameMap[s.scope || scope]; if (nameMap && nameMap[s.name]) { delete nameMap[s.name]; var map = snippetMap[s.scope || scope]; var i = map && map.indexOf(s); if (i >= 0) map.splice(i, 1); } } if (snippets.content) removeSnippet(snippets); else if (Array.isArray(snippets)) snippets.forEach(removeSnippet); }; this.parseSnippetFile = function (str) { str = str.replace(/\r/g, ""); var list = [], snippet: any = {}; var re = /^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm; var m; while (m = re.exec(str)) { if (m[1]) { try { snippet = JSON.parse(m[1]); list.push(snippet); } catch (e) {} } if (m[4]) { snippet.content = m[4].replace(/^\t/gm, ""); list.push(snippet); snippet = {}; } else { var key = m[2], val = m[3]; if (key == "regex") { var guardRe = /\/((?:[^\/\\]|\\.)*)|$/g; snippet.guard = guardRe.exec(val)[1]; snippet.trigger = guardRe.exec(val)[1]; snippet.endTrigger = guardRe.exec(val)[1]; snippet.endGuard = guardRe.exec(val)[1]; } else if (key == "snippet") { snippet.tabTrigger = val.match(/^\S*/)[0]; if (!snippet.name) snippet.name = val; } else { snippet[key] = val; } } } return list; }; this.getSnippetByName = function (name, editor) { var snippetMap = this.snippetNameMap; var snippet; this.getActiveScopes(editor).some(function (scope) { var snippets = snippetMap[scope]; if (snippets) snippet = snippets[name]; return !!snippet; }, this); return snippet; }; }).call(SnippetManager.prototype); var TabstopManager: any = function (editor) { if (editor.tabstopManager) return editor.tabstopManager; editor.tabstopManager = this; this.$onChange = this.onChange.bind(this); this.$onChangeSelection = lang.delayedCall(this.onChangeSelection.bind(this)).schedule; this.$onChangeSession = this.onChangeSession.bind(this); this.$onAfterExec = this.onAfterExec.bind(this); this.attach(editor); }; (function () { this.attach = function (editor) { this.index = 0; this.ranges = []; this.tabstops = []; this.$openTabstops = null; this.selectedTabstop = null; this.editor = editor; this.editor.on("change", this.$onChange); this.editor.on("changeSelection", this.$onChangeSelection); this.editor.on("changeSession", this.$onChangeSession); this.editor.commands.on("afterExec", this.$onAfterExec); this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); }; this.detach = function () { this.tabstops.forEach(this.removeTabstopMarkers, this); this.ranges = null; this.tabstops = null; this.selectedTabstop = null; this.editor.removeListener("change", this.$onChange); this.editor.removeListener("changeSelection", this.$onChangeSelection); this.editor.removeListener("changeSession", this.$onChangeSession); this.editor.commands.removeListener("afterExec", this.$onAfterExec); this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); this.editor.tabstopManager = null; this.editor = null; }; this.onChange = function (delta) { // var changeRange = delta; var isRemove = delta.action[0] == "r"; var start = delta.start; var end = delta.end; var startRow = start.row; var endRow = end.row; var lineDif = endRow - startRow; var colDiff = end.column - start.column; if (isRemove) { lineDif = -lineDif; colDiff = -colDiff; } if (!this.$inChange && isRemove) { var ts = this.selectedTabstop; var changedOutside = ts && !ts.some(function (r) { return comparePoints(r.start, start) <= 0 && comparePoints(r.end, end) >= 0; }); if (changedOutside) return this.detach(); } var ranges = this.ranges; for (var i = 0; i < ranges.length; i++) { var r = ranges[i]; if (r.end.row < start.row) continue; if (isRemove && comparePoints(start, r.start) < 0 && comparePoints(end, r.end) > 0) { this.removeRange(r); i--; continue; } if (r.start.row == startRow && r.start.column > start.column) r.start.column += colDiff; if (r.end.row == startRow && r.end.column >= start.column) r.end.column += colDiff; if (r.start.row >= startRow) r.start.row += lineDif; if (r.end.row >= startRow) r.end.row += lineDif; if (comparePoints(r.start, r.end) > 0) this.removeRange(r); } if (!ranges.length) this.detach(); }; this.updateLinkedFields = function () { var ts = this.selectedTabstop; if (!ts || !ts.hasLinkedRanges) return; this.$inChange = true; var session = this.editor.session; var text = session.getTextRange(ts.firstNonLinked); for (var i = ts.length; i--;) { var range = ts[i]; if (!range.linked) continue; var fmt = exports.snippetManager.tmStrFormat(text, range.original); session.replace(range, fmt); } this.$inChange = false; }; this.onAfterExec = function (e) { if (e.command && !e.command.readOnly) this.updateLinkedFields(); }; this.onChangeSelection = function () { if (!this.editor) return; var lead = this.editor.selection.lead; var anchor = this.editor.selection.anchor; var isEmpty = this.editor.selection.isEmpty(); for (var i = this.ranges.length; i--;) { if (this.ranges[i].linked) continue; var containsLead = this.ranges[i].contains(lead.row, lead.column); var containsAnchor = isEmpty || this.ranges[i].contains(anchor.row, anchor.column); if (containsLead && containsAnchor) return; } this.detach(); }; this.onChangeSession = function () { this.detach(); }; this.tabNext = function (dir) { var max = this.tabstops.length; var index = this.index + (dir || 1); index = Math.min(Math.max(index, 1), max); if (index == max) index = 0; this.selectTabstop(index); if (index === 0) this.detach(); }; this.selectTabstop = function (index) { this.$openTabstops = null; var ts = this.tabstops[this.index]; if (ts) this.addTabstopMarkers(ts); this.index = index; ts = this.tabstops[this.index]; if (!ts || !ts.length) return; this.selectedTabstop = ts; if (!this.editor.inVirtualSelectionMode) { var sel = this.editor.multiSelect; sel.toSingleRange(ts.firstNonLinked.clone()); for (var i = ts.length; i--;) { if (ts.hasLinkedRanges && ts[i].linked) continue; sel.addRange(ts[i].clone(), true); } if (sel.ranges[0]) sel.addRange(sel.ranges[0].clone()); } else { this.editor.selection.setRange(ts.firstNonLinked); } this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); }; this.addTabstops = function (tabstops, start, end) { if (!this.$openTabstops) this.$openTabstops = []; if (!tabstops[0]) { var p = Range.fromPoints(end, end); moveRelative(p.start, start); moveRelative(p.end, start); tabstops[0] = [p]; tabstops[0].index = 0; } var i = this.index; var arg = [i + 1, 0]; var ranges = this.ranges; tabstops.forEach(function (ts, index) { var dest = this.$openTabstops[index] || ts; for (var i = ts.length; i--;) { var p = ts[i]; var range = Range.fromPoints(p.start, p.end || p.start); movePoint(range.start, start); movePoint(range.end, start); range.original = p; range.tabstop = dest; ranges.push(range); if (dest != ts) dest.unshift(range); else dest[i] = range; if (p.fmtString) { range.linked = true; dest.hasLinkedRanges = true; } else if (!dest.firstNonLinked) dest.firstNonLinked = range; } if (!dest.firstNonLinked) dest.hasLinkedRanges = false; if (dest === ts) { arg.push(dest); this.$openTabstops[index] = dest; } this.addTabstopMarkers(dest); }, this); if (arg.length > 2) { if (this.tabstops.length) arg.push(arg.splice(2, 1)[0]); this.tabstops.splice.apply(this.tabstops, arg); } }; this.addTabstopMarkers = function (ts) { var session = this.editor.session; ts.forEach(function (range) { if (!range.markerId) range.markerId = session.addMarker(range, "ace_snippet-marker", "text"); }); }; this.removeTabstopMarkers = function (ts) { var session = this.editor.session; ts.forEach(function (range) { session.removeMarker(range.markerId); range.markerId = null; }); }; this.removeRange = function (range) { var i = range.tabstop.indexOf(range); range.tabstop.splice(i, 1); i = this.ranges.indexOf(range); this.ranges.splice(i, 1); this.editor.session.removeMarker(range.markerId); if (!range.tabstop.length) { i = this.tabstops.indexOf(range.tabstop); if (i != -1) this.tabstops.splice(i, 1); if (!this.tabstops.length) this.detach(); } }; this.keyboardHandler = new HashHandler(); this.keyboardHandler.bindKeys({ "Tab": function (ed) { if (exports.snippetManager && exports.snippetManager.expandWithTab(ed)) { return; } ed.tabstopManager.tabNext(1); }, "Shift-Tab": function (ed) { ed.tabstopManager.tabNext(-1); }, "Esc": function (ed) { ed.tabstopManager.detach(); }, "Return": function (ed) { return false; } }); }).call(TabstopManager.prototype); var changeTracker: any = {}; changeTracker.onChange = Anchor.prototype.onChange; changeTracker.setPosition = function (row, column) { this.pos.row = row; this.pos.column = column; }; changeTracker.update = function (pos, delta, $insertRight) { this.$insertRight = $insertRight; this.pos = pos; this.onChange(delta); }; var movePoint = function (point, diff) { if (point.row == 0) point.column += diff.column; point.row += diff.row; }; var moveRelative = function (point, start) { if (point.row == start.row) point.column -= start.column; point.row -= start.row; }; require("./lib/dom").importCssString("\ .ace_snippet-marker {\ -moz-box-sizing: border-box;\ box-sizing: border-box;\ background: rgba(194, 193, 208, 0.09);\ border: 1px dotted rgba(211, 208, 235, 0.62);\ position: absolute;\ }"); exports.snippetManager = new SnippetManager(); var Editor = require("./editor").Editor; (function () { this.insertSnippet = function (content, options) { return exports.snippetManager.insertSnippet(this, content, options); }; this.expandSnippet = function (options) { return exports.snippetManager.expandWithTab(this, options); }; }).call(Editor.prototype); }); ace.define("ace/autocomplete/popup", ["require", "exports", "module", "ace/virtual_renderer", "ace/editor", "ace/range", "ace/lib/event", "ace/lib/lang", "ace/lib/dom"], function (require, exports, module) { "use strict"; var Renderer = require("../virtual_renderer").VirtualRenderer; var Editor = require("../editor").Editor; var Range = require("../range").Range; var event = require("../lib/event"); var lang = require("../lib/lang"); var dom = require("../lib/dom"); var $singleLineEditor: any = function (el) { var renderer = new Renderer(el); renderer.$maxLines = 4; var editor = new Editor(renderer); editor.setHighlightActiveLine(false); editor.setShowPrintMargin(false); editor.renderer.setShowGutter(false); editor.renderer.setHighlightGutterLine(false); editor.$mouseHandler.$focusWaitTimout = 0; editor.$highlightTagPending = true; return editor; }; var AcePopup = function (parentNode) { var el = dom.createElement("div"); var popup = new $singleLineEditor(el); if (parentNode) parentNode.appendChild(el); el.style.display = "none"; popup.renderer.content.style.cursor = "default"; popup.renderer.setStyle("ace_autocomplete"); popup.setOption("displayIndentGuides", false); popup.setOption("dragDelay", 150); var noop = function () {}; popup.focus = noop; popup.$isFocused = true; popup.renderer.$cursorLayer.restartTimer = noop; popup.renderer.$cursorLayer.element.style.opacity = 0; popup.renderer.$maxLines = 8; popup.renderer.$keepTextAreaAtCursor = false; popup.setHighlightActiveLine(false); popup.session.highlight(""); popup.session.$searchHighlight.clazz = "ace_highlight-marker"; popup.on("mousedown", function (e) { var pos = e.getDocumentPosition(); popup.selection.moveToPosition(pos); selectionMarker.start.row = selectionMarker.end.row = pos.row; e.stop(); }); var lastMouseEvent; var hoverMarker = new Range(-1, 0, -1, Infinity); var selectionMarker = new Range(-1, 0, -1, Infinity); selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine"); popup.setSelectOnHover = function (val) { if (!val) { hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine"); } else if (hoverMarker.id) { popup.session.removeMarker(hoverMarker.id); hoverMarker.id = null; } }; popup.setSelectOnHover(false); popup.on("mousemove", function (e) { if (!lastMouseEvent) { lastMouseEvent = e; return; } if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) { return; } lastMouseEvent = e; lastMouseEvent.scrollTop = popup.renderer.scrollTop; var row = lastMouseEvent.getDocumentPosition().row; if (hoverMarker.start.row != row) { if (!hoverMarker.id) popup.setRow(row); setHoverMarker(row, false); } }); popup.renderer.on("beforeRender", function () { if (lastMouseEvent && hoverMarker.start.row != -1) { lastMouseEvent.$pos = null; var row = lastMouseEvent.getDocumentPosition().row; if (!hoverMarker.id) popup.setRow(row); setHoverMarker(row, true); } }); popup.renderer.on("afterRender", function () { var row = popup.getRow(); var t = popup.renderer.$textLayer; var selected = t.element.childNodes[row - t.config.firstRow]; if (selected == t.selectedNode) return; if (t.selectedNode) dom.removeCssClass(t.selectedNode, "ace_selected"); t.selectedNode = selected; if (selected) dom.addCssClass(selected, "ace_selected"); }); var hideHoverMarker = function () {setHoverMarker(-1, false)}; var setHoverMarker = function (row, suppressRedraw) { if (row !== hoverMarker.start.row) { hoverMarker.start.row = hoverMarker.end.row = row; if (!suppressRedraw) popup.session._emit("changeBackMarker"); popup._emit("changeHoverMarker"); } }; popup.getHoveredRow = function () { return hoverMarker.start.row; }; event.addListener(popup.container, "mouseout", hideHoverMarker); popup.on("hide", hideHoverMarker); popup.on("changeSelection", hideHoverMarker); popup.session.doc.getLength = function () { return popup.data.length; }; popup.session.doc.getLine = function (i) { var data = popup.data[i]; if (typeof data == "string") return data; return (data && data.value) || ""; }; var bgTokenizer = popup.session.bgTokenizer; bgTokenizer.$tokenizeRow = function (row) { var data = popup.data[row]; var tokens = []; if (!data) return tokens; if (typeof data == "string") data = {value: data}; if (!data.caption) data.caption = data.value || data.name; var last = -1; var flag, c; for (var i = 0; i < data.caption.length; i++) { c = data.caption[i]; var matchMask = data.matchMask ? data.matchMask[i % 31] : 0; flag = matchMask & (1 << (i - (i % 31) * 31)) ? 1 : 0; if (last !== flag) { tokens.push({type: data.className || "" + (flag ? "completion-highlight" : ""), value: c}); last = flag; } else { tokens[tokens.length - 1].value += c; } } if (data.meta) { var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth; var metaData = data.meta; if (metaData.length + data.caption.length > maxW - 2) { metaData = metaData.substr(0, maxW - data.caption.length - 3) + "\u2026" } tokens.push({type: "rightAlignedText", value: metaData}); } return tokens; }; bgTokenizer.$updateOnChange = noop; bgTokenizer.start = noop; popup.session.$computeWidth = function () { return this.screenWidth = 0; }; popup.$blockScrolling = Infinity; popup.isOpen = false; popup.isTopdown = false; popup.autoSelect = true; popup.data = []; popup.setData = function (list) { popup.setValue(lang.stringRepeat("\n", list.length), -1); popup.data = list || []; popup.setRow(0); }; popup.getData = function (row) { return popup.data[row]; }; popup.getRow = function () { return selectionMarker.start.row; }; popup.setRow = function (line) { line = Math.max(this.autoSelect ? 0 : -1, Math.min(this.data.length, line)); if (selectionMarker.start.row != line) { popup.selection.clearSelection(); selectionMarker.start.row = selectionMarker.end.row = line || 0; popup.session._emit("changeBackMarker"); popup.moveCursorTo(line || 0, 0); if (popup.isOpen) popup._signal("select"); } }; popup.on("changeSelection", function () { if (popup.isOpen) popup.setRow(popup.selection.lead.row); popup.renderer.scrollCursorIntoView(); }); popup.hide = function () { this.container.style.display = "none"; this._signal("hide"); popup.isOpen = false; }; popup.show = function (pos, lineHeight, topdownOnly) { var el = this.container; var screenHeight = window.innerHeight; var screenWidth = window.innerWidth; var renderer = this.renderer; var maxH = renderer.$maxLines * lineHeight * 1.4; var top = pos.top + this.$borderSize; var allowTopdown = top > screenHeight / 2 && !topdownOnly; if (allowTopdown && top + lineHeight + maxH > screenHeight) { renderer.$maxPixelHeight = top - 2 * this.$borderSize; el.style.top = ""; el.style.bottom = screenHeight - top + "px"; popup.isTopdown = false; } else { top += lineHeight; renderer.$maxPixelHeight = screenHeight - top - 0.2 * lineHeight; el.style.top = top + "px"; el.style.bottom = ""; popup.isTopdown = true; } el.style.display = ""; this.renderer.$textLayer.checkForSizeChanges(); var left = pos.left; if (left + el.offsetWidth > screenWidth) left = screenWidth - el.offsetWidth; el.style.left = left + "px"; this._signal("show"); lastMouseEvent = null; popup.isOpen = true; }; popup.getTextLeftOffset = function () { return this.$borderSize + this.renderer.$padding + this.$imageSize; }; popup.$imageSize = 0; popup.$borderSize = 1; return popup; }; dom.importCssString("\ .ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {\ background-color: #CAD6FA;\ z-index: 1;\ }\ .ace_editor.ace_autocomplete .ace_line-hover {\ border: 1px solid #abbffe;\ margin-top: -1px;\ background: rgba(233,233,253,0.4);\ }\ .ace_editor.ace_autocomplete .ace_line-hover {\ position: absolute;\ z-index: 2;\ }\ .ace_editor.ace_autocomplete .ace_scroller {\ background: none;\ border: none;\ box-shadow: none;\ }\ .ace_rightAlignedText {\ color: gray;\ display: inline-block;\ position: absolute;\ right: 4px;\ text-align: right;\ z-index: -1;\ }\ .ace_editor.ace_autocomplete .ace_completion-highlight{\ color: #000;\ text-shadow: 0 0 0.01em;\ }\ .ace_editor.ace_autocomplete {\ width: 280px;\ z-index: 200000;\ background: #fbfbfb;\ color: #444;\ border: 1px lightgray solid;\ position: fixed;\ box-shadow: 2px 3px 5px rgba(0,0,0,.2);\ line-height: 1.4;\ }"); exports.AcePopup = AcePopup; }); ace.define("ace/autocomplete/util", ["require", "exports", "module"], function (require, exports, module) { "use strict"; exports.parForEach = function (array, fn, callback) { var completed = 0; var arLength = array.length; if (arLength === 0) callback(); for (var i = 0; i < arLength; i++) { fn(array[i], function (result, err) { completed++; if (completed === arLength) callback(result, err); }); } }; var ID_REGEX = /[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/; exports.retrievePrecedingIdentifier = function (text, pos, regex) { regex = regex || ID_REGEX; var buf = []; for (var i = pos - 1; i >= 0; i--) { if (regex.test(text[i])) buf.push(text[i]); else break; } return buf.reverse().join(""); }; exports.retrieveFollowingIdentifier = function (text, pos, regex) { regex = regex || ID_REGEX; var buf = []; for (var i = pos; i < text.length; i++) { if (regex.test(text[i])) buf.push(text[i]); else break; } return buf; }; //not used anymore exports.getCompletionPrefix = function (editor) { const pos = editor.getCursorPosition(); const line = editor.session.getLine(pos.row); let prefix; editor.completers.forEach(function (completer) { if (completer.identifierRegexps) { completer.identifierRegexps.forEach(function (identifierRegex) { if (!prefix && identifierRegex) prefix = this.retrievePrecedingIdentifier(line, pos.column, identifierRegex); }.bind(this)); } }.bind(this)); return prefix || this.retrievePrecedingIdentifier(line, pos.column); }; const getCompletionPrefixByRegex = function (editor, regexArr) { const pos = editor.getCursorPosition(); const line = editor.session.getLine(pos.row); let prefix; if (regexArr) { regexArr.forEach((identifierRegex) => { if (!prefix && identifierRegex) { prefix = exports.retrievePrecedingIdentifier(line, pos.column, identifierRegex); } }); } return prefix; }; exports.getCompletionPrefixByCompleter = function (editor, completer) { if (completer.linePredicate) { const pos = editor.getCursorPosition(); const line = editor.session.getLine(pos.row); const str = line.substr(0, pos.column); const shouldUseCompleter = completer.linePredicate(str); if (!shouldUseCompleter) { return; } } const prefix = getCompletionPrefixByRegex(editor, completer.identifierRegexps); if (prefix === '' && !completer.acceptEmptyString) { return; } return prefix; } }); ace.define("ace/autocomplete", ["require", "exports", "module", "ace/keyboard/hash_handler", "ace/autocomplete/popup", "ace/autocomplete/util", "ace/lib/event", "ace/lib/lang", "ace/lib/dom", "ace/snippets"], function (require, exports, module) { "use strict"; var HashHandler = require("./keyboard/hash_handler").HashHandler; var AcePopup = require("./autocomplete/popup").AcePopup; var util = require("./autocomplete/util"); // var event = require("./lib/event"); var lang = require("./lib/lang"); var dom = require("./lib/dom"); var snippetManager = require("./snippets").snippetManager; var Autocomplete: any = function () { this.autoInsert = false; this.autoSelect = true; this.exactMatch = false; this.gatherCompletionsId = 0; this.keyboardHandler = new HashHandler(); this.keyboardHandler.bindKeys(this.commands); this.blurListener = this.blurListener.bind(this); this.changeListener = this.changeListener.bind(this); this.mousedownListener = this.mousedownListener.bind(this); this.mousewheelListener = this.mousewheelListener.bind(this); this.changeTimer = lang.delayedCall(function () { this.updateCompletions(true); }.bind(this)); this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50); }; (function () { this.$init = function () { this.popup = new AcePopup(document.body || document.documentElement); this.popup.on("click", function (e) { this.insertMatch(); e.stop(); }.bind(this)); this.popup.focus = this.editor.focus.bind(this.editor); this.popup.on("show", this.tooltipTimer.bind(null, null)); this.popup.on("select", this.tooltipTimer.bind(null, null)); this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null)); return this.popup; }; this.getPopup = function () { return this.popup || this.$init(); }; this.openPopup = function (editor, prefix, keepPopupPosition) { if (!this.popup) this.$init(); this.popup.autoSelect = this.autoSelect; this.popup.setData(this.completions.filtered); editor.keyBinding.addKeyboardHandler(this.keyboardHandler); var renderer = editor.renderer; this.popup.setRow(this.autoSelect ? 0 : -1); if (!keepPopupPosition) { this.popup.setTheme(editor.getTheme()); this.popup.setFontSize(editor.getFontSize()); var lineHeight = renderer.layerConfig.lineHeight; var pos = renderer.$cursorLayer.getPixelPosition(this.base, true); pos.left -= this.popup.getTextLeftOffset(); var rect = editor.container.getBoundingClientRect(); pos.top += rect.top - renderer.layerConfig.offset; pos.left += rect.left - editor.renderer.scrollLeft; pos.left += renderer.gutterWidth; this.popup.show(pos, lineHeight); } else if (keepPopupPosition && !prefix) { this.detach(); } }; this.detach = function () { this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); this.editor.off("changeSelection", this.changeListener); this.editor.off("blur", this.blurListener); this.editor.off("mousedown", this.mousedownListener); this.editor.off("mousewheel", this.mousewheelListener); this.changeTimer.cancel(); this.hideDocTooltip(); this.gatherCompletionsId += 1; if (this.popup && this.popup.isOpen) this.popup.hide(); if (this.base) this.base.detach(); this.activated = false; this.completions = this.base = null; }; this.changeListener = function (e) { var cursor = this.editor.selection.lead; if (cursor.row != this.base.row || cursor.column < this.base.column) { this.detach(); } if (this.activated) this.changeTimer.schedule(); else this.detach(); }; this.blurListener = function (e) { var el = document.activeElement; var text = this.editor.textInput.getElement(); var fromTooltip = e.relatedTarget && this.tooltipNode && this.tooltipNode.contains(e.relatedTarget); var container = this.popup && this.popup.container; if (el != text && el.parentNode != container && !fromTooltip && el != this.tooltipNode && e.relatedTarget != text ) { this.detach(); } }; this.mousedownListener = function (e) { this.detach(); }; this.mousewheelListener = function (e) { this.detach(); }; this.goTo = function (where) { var row = this.popup.getRow(); var max = this.popup.session.getLength() - 1; switch (where) { case "up": row = row <= 0 ? max : row - 1; break; case "down": row = row >= max ? -1 : row + 1; break; case "start": row = 0; break; case "end": row = max; break; } this.popup.setRow(row); }; this.insertMatch = function (data, options) { if (!data) data = this.popup.getData(this.popup.getRow()); if (!data) return false; if (data.completer && data.completer.insertMatch) { data.completer.insertMatch(this.editor, data); } else { if (this.completions.filterText) { var ranges = this.editor.selection.getAllRanges(); for (var i = 0, range; range = ranges[i]; i++) { range.start.column -= this.completions.filterText.length; this.editor.session.remove(range); } } if (data.snippet) snippetManager.insertSnippet(this.editor, data.snippet); else this.editor.execCommand("insertstring", data.value || data); } this.detach(); }; this.commands = { "Up": function (editor) {editor.completer.goTo("up");}, "Down": function (editor) {editor.completer.goTo("down");}, "Ctrl-Up|Ctrl-Home": function (editor) {editor.completer.goTo("start");}, "Ctrl-Down|Ctrl-End": function (editor) {editor.completer.goTo("end");}, "Esc": function (editor) {editor.completer.detach();}, // "Return": function (editor) {return editor.completer.insertMatch();}, "Shift-Return": function (editor) {editor.completer.insertMatch(null, {deleteSuffix: true});}, "Tab": function (editor) { var result = editor.completer.insertMatch(); if (!result && !editor.tabstopManager) editor.completer.goTo("down"); else return result; }, "PageUp": function (editor) {editor.completer.popup.gotoPageUp();}, "PageDown": function (editor) {editor.completer.popup.gotoPageDown();} }; this.gatherCompletions = function (editor, callback) { const session = editor.getSession(); const pos = editor.getCursorPosition(); // const prefix = util.getCompletionPrefix(editor); let matches = []; // let total = editor.completers.length; const success = editor.completers.some((completer, i) => { const prefix = util.getCompletionPrefixByCompleter(editor, completer); if (typeof prefix !== 'undefined') { this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length); this.base.$insertRight = true; completer.getCompletions(editor, session, pos, prefix, function (err, results) { if (!err && results) matches = matches.concat(results); callback(null, { prefix, matches: matches, finished: true }); }); return true; } return false; }); if (!success) { callback(null, {prefix: null, matches: [], finished: true}); } }; this.showPopup = function (editor) { if (this.editor) this.detach(); this.activated = true; this.editor = editor; if (editor.completer != this) { if (editor.completer) editor.completer.detach(); editor.completer = this; } editor.on("changeSelection", this.changeListener); editor.on("blur", this.blurListener); editor.on("mousedown", this.mousedownListener); editor.on("mousewheel", this.mousewheelListener); this.updateCompletions(); }; this.updateCompletions = function (keepPopupPosition) { if (keepPopupPosition && this.base && this.completions) { /* if updating an existing popup */ var pos = this.editor.getCursorPosition(); var prefix = this.editor.session.getTextRange({start: this.base, end: pos}); if (prefix === this.completions.filterText) return; if (prefix === '') return; // this.completions.setFilter(prefix); this.gatherCompletions(this.editor, (err, results) => { this.latestPrefix = results.prefix; const matches = results && results.matches; this.completions = new FilteredList(matches); this.completions.setFilter(this.latestPrefix); if (!this.completions.filtered.length) return this.detach(); if (this.completions.filtered.length == 1 && this.completions.filtered[0].value == prefix && !this.completions.filtered[0].snippet) return this.detach(); this.openPopup(this.editor, prefix, keepPopupPosition); }); return; } /* new popup */ var _id = this.gatherCompletionsId; this.gatherCompletions(this.editor, function (err, results) { var detachIfFinished = function () { if (!results.finished) return; return this.detach(); }.bind(this); var prefix = this.latestPrefix = results.prefix; var matches = results && results.matches; if (!matches || !matches.length) return detachIfFinished(); if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId) return; this.completions = new FilteredList(matches); if (this.exactMatch) this.completions.exactMatch = true; this.completions.setFilter(prefix); var filtered = this.completions.filtered; if (!filtered.length) return detachIfFinished(); if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet) return detachIfFinished(); if (this.autoInsert && filtered.length == 1 && results.finished) return this.insertMatch(filtered[0]); this.openPopup(this.editor, prefix, keepPopupPosition); }.bind(this)); }; this.cancelContextMenu = function () { this.editor.$mouseHandler.cancelContextMenu(); }; this.updateDocTooltip = function () { var popup = this.popup; var all = popup.data; var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]); var doc = null; if (!selected || !this.editor || !this.popup.isOpen) return this.hideDocTooltip(); this.editor.completers.some(function (completer) { if (completer.getDocTooltip) doc = completer.getDocTooltip(selected); return doc; }); if (!doc) doc = selected; if (typeof doc == "string") doc = {docText: doc}; if (!doc || !(doc.docHTML || doc.docText)) return this.hideDocTooltip(); this.showDocTooltip(doc); }; this.showDocTooltip = function (item) { if (!this.tooltipNode) { this.tooltipNode = dom.createElement("div"); this.tooltipNode.className = "ace_tooltip ace_doc-tooltip"; this.tooltipNode.style.margin = 0; this.tooltipNode.style.pointerEvents = "auto"; this.tooltipNode.tabIndex = -1; this.tooltipNode.onblur = this.blurListener.bind(this); this.tooltipNode.onclick = this.onTooltipClick.bind(this); } var tooltipNode = this.tooltipNode; if (item.docHTML) { tooltipNode.innerHTML = item.docHTML; } else if (item.docText) { tooltipNode.textContent = item.docText; } if (!tooltipNode.parentNode) document.body.appendChild(tooltipNode); var popup = this.popup; var rect = popup.container.getBoundingClientRect(); tooltipNode.style.top = popup.container.style.top; tooltipNode.style.bottom = popup.container.style.bottom; if (window.innerWidth - rect.right < 320) { tooltipNode.style.right = window.innerWidth - rect.left + "px"; tooltipNode.style.left = ""; } else { tooltipNode.style.left = (rect.right + 1) + "px"; tooltipNode.style.right = ""; } tooltipNode.style.display = "block"; }; this.hideDocTooltip = function () { this.tooltipTimer.cancel(); if (!this.tooltipNode) return; var el = this.tooltipNode; if (!this.editor.isFocused() && document.activeElement == el) this.editor.focus(); this.tooltipNode = null; if (el.parentNode) el.parentNode.removeChild(el); }; this.onTooltipClick = function (e) { var a = e.target; while (a && a != this.tooltipNode) { if (a.nodeName == "A" && a.href) { a.rel = "noreferrer"; a.target = "_blank"; break; } a = a.parentNode; } } }).call(Autocomplete.prototype); Autocomplete.startCommand = { name: "startAutocomplete", exec: function (editor) { if (!editor.completer) editor.completer = new Autocomplete(); editor.completer.autoInsert = false; editor.completer.autoSelect = true; editor.completer.showPopup(editor); editor.completer.cancelContextMenu(); }, bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" }; var FilteredList = function (array, filterText?) { this.all = array; this.filtered = array; this.filterText = filterText || ""; this.exactMatch = false; }; (function () { this.setFilter = function (str) { if (str && str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0) var matches = this.filtered; else var matches = this.all; this.filterText = str; // matches = this.filterCompletions(matches, this.filterText); matches = matches.sort(function(a, b) { return b.exactMatch - a.exactMatch || b.score - a.score; }); var prev = null; matches = matches.filter(function (item) { var caption = item.snippet || item.caption || item.value; if (caption === prev) return false; prev = caption; return true; }); this.filtered = matches; }; this.filterCompletions = function (items, needle) { var results = []; var upper = needle.toUpperCase(); var lower = needle.toLowerCase(); loop: for (var i = 0, item; item = items[i]; i++) { var caption = item.value || item.caption || item.snippet; if (!caption) continue; var lastIndex = -1; var matchMask = 0; var penalty = 0; var index, distance; if (this.exactMatch) { if (needle !== caption.substr(0, needle.length)) continue loop; } else { for (var j = 0; j < needle.length; j++) { var i1 = caption.indexOf(lower[j], lastIndex + 1); var i2 = caption.indexOf(upper[j], lastIndex + 1); index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2; if (index < 0) continue loop; distance = index - lastIndex - 1; if (distance > 0) { if (lastIndex === -1) penalty += 10; penalty += distance; } matchMask = matchMask | (1 << index); lastIndex = index; } } item.matchMask = matchMask; item.exactMatch = penalty ? 0 : 1; item.score = (item.score || 0) - penalty; results.push(item); } return results; }; }).call(FilteredList.prototype); exports.Autocomplete = Autocomplete; exports.FilteredList = FilteredList; }); ace.define("ace/autocomplete/text_completer", ["require", "exports", "module", "ace/range"], function (require, exports, module) { var Range = require("../range").Range; var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/; function getWordIndex(doc, pos) { var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column: 0}, pos)); return textBefore.split(splitRegex).length - 1; } function wordDistance(doc, pos, _) { var prefixPos = getWordIndex(doc, pos); var words = doc.getValue().split(splitRegex); var wordScores = Object.create(null); var currentWord = words[prefixPos]; words.forEach(function (word, idx) { if (!word || word === currentWord) return; var distance = Math.abs(prefixPos - idx); var score = words.length - distance; if (wordScores[word]) { wordScores[word] = Math.max(score, wordScores[word]); } else { wordScores[word] = score; } }); return wordScores; } exports.getCompletions = function (editor, session, pos, prefix, callback) { var wordScore = wordDistance(session, pos, prefix); var wordList = Object.keys(wordScore); callback(null, wordList.map(function (word) { return { caption: word, value: word, score: wordScore[word], meta: "local" }; })); }; }); ace.define("ace/ext/language_tools-bi", ["require", "exports", "module", "ace/snippets", "ace/autocomplete", "ace/config", "ace/lib/lang", "ace/autocomplete/util", "ace/autocomplete/text_completer", "ace/editor", "ace/config"], function (require, exports, module) { "use strict"; var snippetManager = require("../snippets").snippetManager; var Autocomplete = require("../autocomplete").Autocomplete; var config = require("../config"); var lang = require("../lib/lang"); var util = require("../autocomplete/util"); var textCompleter = require("../autocomplete/text_completer"); var keyWordCompleter = { getCompletions: function (editor, session, pos, prefix, callback) { if (session.$mode.completer) { return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback); } var state = editor.session.getState(pos.row); var completions = session.$mode.getCompletions(state, session, pos, prefix); callback(null, completions); } }; var snippetCompleter = { getCompletions: function (editor, session, pos, prefix, callback) { var snippetMap = snippetManager.snippetMap; var completions = []; snippetManager.getActiveScopes(editor).forEach(function (scope) { var snippets = snippetMap[scope] || []; for (var i = snippets.length; i--;) { var s = snippets[i]; var caption = s.name || s.tabTrigger; if (!caption) continue; completions.push({ caption: caption, snippet: s.content, meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet", type: "snippet" }); } }, this); callback(null, completions); }, getDocTooltip: function (item) { if (item.type == "snippet" && !item.docHTML) { item.docHTML = [ "", lang.escapeHTML(item.caption), "", "
", lang.escapeHTML(item.snippet) ].join(""); } } }; var completers = [snippetCompleter, textCompleter, keyWordCompleter]; exports.setCompleters = function (val) { completers.length = 0; if (val) completers.push.apply(completers, val); }; exports.addCompleter = function (completer) { completers.push(completer); }; exports.textCompleter = textCompleter; exports.keyWordCompleter = keyWordCompleter; exports.snippetCompleter = snippetCompleter; var expandSnippet = { name: "expandSnippet", exec: function (editor) { return snippetManager.expandWithTab(editor); }, bindKey: "Tab" }; var onChangeMode = function (e, editor) { loadSnippetsForMode(editor.session.$mode); }; var loadSnippetsForMode = function (mode) { var id = mode.$id; if (!snippetManager.files) snippetManager.files = {}; loadSnippetFile(id); if (mode.modes) mode.modes.forEach(loadSnippetsForMode); }; var loadSnippetFile = function (id) { if (!id || snippetManager.files[id]) return; var snippetFilePath = id.replace("mode", "snippets"); snippetManager.files[id] = {}; config.loadModule(snippetFilePath, function (m) { if (m) { snippetManager.files[id] = m; if (!m.snippets && m.snippetText) m.snippets = snippetManager.parseSnippetFile(m.snippetText); snippetManager.register(m.snippets || [], m.scope); if (m.includeScopes) { snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes; m.includeScopes.forEach(function (x) { loadSnippetFile("ace/mode/" + x); }); } } }); }; var doLiveAutocomplete = function (e) { var editor = e.editor; var hasCompleter = editor.completer && editor.completer.activated; if (e.command.name === "backspace") { if (hasCompleter && !util.getCompletionPrefix(editor)) editor.completer.detach(); } else if (e.command.name === "insertstring") { var prefix = util.getCompletionPrefix(editor); if (prefix && !hasCompleter) { if (!editor.completer) { editor.completer = new Autocomplete(); } editor.completer.autoInsert = false; editor.completer.showPopup(editor); } } }; var Editor = require("../editor").Editor; require("../config").defineOptions(Editor.prototype, "editor", { enableBasicAutocompletion: { set: function (val) { if (val) { if (!this.completers) this.completers = Array.isArray(val) ? val : completers; this.commands.addCommand(Autocomplete.startCommand); } else { this.commands.removeCommand(Autocomplete.startCommand); } }, value: false }, enableLiveAutocompletion: { set: function (val) { if (val) { if (!this.completers) this.completers = Array.isArray(val) ? val : completers; this.commands.on('afterExec', doLiveAutocomplete); } else { this.commands.removeListener('afterExec', doLiveAutocomplete); } }, value: false }, enableSnippets: { set: function (val) { if (val) { this.commands.addCommand(expandSnippet); this.on("changeMode", onChangeMode); onChangeMode(null, this); } else { this.commands.removeCommand(expandSnippet); this.off("changeMode", onChangeMode); } }, value: false } }); }); (function () { ace.acequire(["ace/ext/language_tools-bi"], function () {}); })(); } ================================================ FILE: quix-frontend/client/src/lib/code-editor/ace-extensions/presto-snippets.ts ================================================ /* tslint:disable */ export const setupSnippets = (ace) => { ace.define("ace/snippets/presto", ["require", "exports", "module"], function (e, t, n) { "use strict"; t.snippetText = "snippet tbl\n create table ${1:table} (\n ${2:columns}\n );\nsnippet col\n ${1:name} ${2:type} ${3:default ''} ${4:not null}\nsnippet ccol\n ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\nsnippet ncol\n ${1:name} number ${3:default 0} ${4:not null}\nsnippet dcol\n ${1:name} date ${3:default sysdate} ${4:not null}\nsnippet ind\n create index ${3:$1_$2} on ${1:table}(${2:column});\nsnippet uind\n create unique index ${1:name} on ${2:table}(${3:column});\nsnippet tblcom\n comment on table ${1:table} is '${2:comment}';\nsnippet colcom\n comment on column ${1:table}.${2:column} is '${3:comment}';\nsnippet addcol\n alter table ${1:table} add (${2:column} ${3:type});\nsnippet seq\n create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\nsnippet s*\n select * from ${1:table}\n", t.scope = "sql"}) } ================================================ FILE: quix-frontend/client/src/lib/code-editor/ace-extensions/presto.mode.ts ================================================ /* tslint:disable */ export const setupPrestoMode = (ace) => { ace.define("ace/mode/presto_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function (require, exports, module) { "use strict"; var oop = require("../lib/oop"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var SqlHighlightRules = function () { var keywords = ( "select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|" + "when|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|" + "foreign|not|references|default|null|inner|cross|natural|database|drop|grant" ); var prestoKeywords = ( "|ALL|ALL PRIVILEGES|ALTER TABLE|ADD COLUMN|RENAME COLUMN TO|RENAME TO|AS|ASC|CALL|COMMIT|CREATE|CREATE TABLE" + "|CROSS JOIN|CUBE|DATA|DELETE FROM|DESC|DESCRIBE|DISTINCT|DISTRIBUTED|DROP TABLE|DROP VIEW|EXPLAIN" + "|EXPLAIN ANALYZE|FORMAT|FROM|FULL|GRANT|GRANT OPTION FOR|GRAPHVIZ|GROUP BY|GROUPING SETS|HAVING|IF EXISTS" + "|IF NOT EXISTS|INNER|INSERT INTO|ISOLATION LEVEL|JOIN|LEFT|LIKE|LIMIT|LOGICAL|NO|ON|ONLY|OR REPLACE|ORDER BY" + "|OUTER|PUBLIC|READ|READ COMMITTED|READ UNCOMMITTED|REPEATABLE READ|RESET SESSION|REVOKE|RIGHT|ROLLBACK|ROLLUP" + "|SELECT|SERIALIZABLE|SET SESSION|SHOW CATALOGS|SHOW COLUMNS FROM|SHOW CREATE TABLE|SHOW CREATE VIEW" + "|SHOW FUNCTIONS|SHOW PARTITIONS FROM|SHOW SCHEMAS|SHOW SESSION|SHOW TABLES|START TRANSACTION|TABLE" + "|TEXT|TO|TYPE|UNION|USE|USING|VALUES|VIEW AS|WHERE|WITH|WITH GRANT OPTION|WORK|WRITE" ); var builtinConstants = ( "true|false" ); var builtinFunctions = ( "avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|" + "coalesce|ifnull|isnull|nvl" ); var prestoFunctions = ( "|abs|acos|approx_distinct|approx_percentile|arbitrary|array_agg|array_distinct|array_intersect|array_join|" + "array_max|array_min|array_position|array_remove|array_sort|asin|atan|atan2|avg|bar|bit_count|bitwise_and|" + "bitwise_not|bitwise_or|bitwise_xor|bool_and|bool_or|cardinality|cardinality|cast|cbrt|ceil|ceiling|" + "char2hexint|checksum|chr|color|concat|concat|contains|corr|cos|cosh|cosine_similarity|count|count_if|" + "covar_pop|covar_samp|cume_dist|current_timezone|date_add|date_diff|date_format|date_parse|date_trunc|day|" + "day_of_month|day_of_week|day_of_year|degrees|dense_rank|dow|doy|e|element_at|element_at|every|exp|extract|" + "first_value|flatten|floor|format_datetime|from_base|from_base64|from_base64url|from_hex|from_iso8601_date|" + "from_iso8601_timestamp|from_unixtime|from_utf8|geometric_mean|greatest|histogram|hour|index|infinity|is_finite|" + "is_infinite|is_nan|json_array_contains|json_array_get|json_array_length|json_extract|json_extract_scalar|" + "json_format|json_parse|json_size|lag|last_value|lead|least|length|length|ln|log|log10|log2|lower|lpad|ltrim|" + "map|map_agg|map_concat|map_keys|map_union|map_values|max|max_by|md5|min|min_by|minute|mod|month|multimap_agg|" + "nan|normalize|now|nth_value|ntile|numeric_histogram|parse_datetime|percent_rank|pi|position|pow|power|quarter|" + "radians|rand|random|rank|regexp_extract|regexp_extract_all|regexp_like|regexp_replace|regexp_split|" + "regr_intercept|regr_slope|render|replace|reverse|rgb|round|row_number|rpad|rtrim|second|sequence|" + "sha1|sha256|sha512|sign|sin|slice|split|split_part|split_to_map|sqrt|stddev|stddev_pop|stddev_samp|strpos|" + "substr|substring|sum|tan|tanh|timezone_hour|timezone_minute|to_base|to_base64|to_base64url|to_char|to_date|" + "to_hex|to_iso8601|to_timestamp|to_unixtime|to_utf8|trim|truncate|try_cast|upper|url_decode|url_encode|" + "url_extract_fragment|url_extract_host|url_extract_parameter|url_extract_path|url_extract_port|" + "url_extract_protocol|url_extract_query|var_pop|var_samp|variance|week|week_of_year|width_bucket|" + "year|year_of_week|yow|zip" ); var dataTypes = ( "int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|" + "money|real|number|integer" ); var prestoDataTypes = "|varbinary|json|time|interval|array|map"; var keywordMapper = this.createKeywordMapper({ "support.function": builtinFunctions + prestoFunctions, "keyword": keywords + prestoKeywords, "constant.language": builtinConstants, "storage.type": dataTypes + prestoDataTypes }, "identifier", true); this.$rules = { "start": [{ token: "comment", regex: "--.*$" }, { token: "comment", start: "/\\*", end: "\\*/" }, { token: "string", // " string start: '"', end: '"' }, { token: "string", // ' string start: "'", end: "'" }, { token: "constant.numeric", // float regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" }, { token: keywordMapper, regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" }, { token: "keyword.operator", regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=" }, { token: "paren.lparen", regex: "[\\(]" }, { token: "paren.rparen", regex: "[\\)]" }, { token: "text", regex: "\\s+" }, { token: "custom-keyword--reference", regex: "@[^\\s@]+" }] }; this.normalizeRules(); }; oop.inherits(SqlHighlightRules, TextHighlightRules); exports.SqlHighlightRules = SqlHighlightRules; }); ace.define("ace/mode/folding/presto", ["require", "exports", "module", "ace/lib/oop", "ace/mode/folding/fold_mode", "ace/range"], function (require, exports, module) { "use strict"; // function escapeRegExp(str) { // return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); // } var oop = require("../../lib/oop"); var Range = require("../../range").Range; var BaseFoldMode = require("./fold_mode").FoldMode; var TokenIterator = require("../../token_iterator").TokenIterator; var FoldMode = exports.FoldMode = function () {}; oop.inherits(FoldMode, BaseFoldMode); (function () { this.foldingStartMarker = /(\()[^)]*$|^\s*(\/\*)/; this.foldingStopMarker = /^[^(]*(\))|^.*(\*\/)/; this.singleLineBlockCommentRe = /^.*(\/\*).*\*\/.*$/; this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/; this.startRegionRe = /^\s*--#?region\b/; this.sqlCommentRe = /^--.*/; this._getFoldWidgetBase = this.getFoldWidget; this.getFoldWidget = function (session, foldStyle, row) { var line = session.getLine(row); // if (this.sqlCommentRe.test(line)) { // return this.sqlCommentFoldWidget(session, foldStyle, row); // } if (this.singleLineBlockCommentRe.test(line)) { if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line)) return ""; } var fw = this._getFoldWidgetBase(session, foldStyle, row); if (!fw && this.startRegionRe.test(line)) return "start"; // lineCommentRegionStart if (!fw && this.isStartIndentationBlock(session, line, row)) { return "start"; } return fw; }; this.getFoldWidgetRange = function (session, foldStyle, row, forceMultiline) { var line = session.getLine(row); if (this.startRegionRe.test(line)) return this.getCommentRegionBlock(session, line, row); // if (this.sqlCommentRe.test(line)) { // var type = this.sqlCommentFoldWidget(session, foldStyle, row); // if (type === "start") { // return this.getCommentFoldRange(session, row, 0, 1); // } else if (type === "end") { // return this.getCommentFoldRange(session, row, line.length - 1, -1); // } else { // return; // } // } var match = line.match(this.foldingStartMarker); if (match) { var i = match.index; if (match[1]) return this.openingBracketBlock(session, match[1], row, i); var range = this.getCommentFoldRange(session, row, i + match[0].length, 1); if (range && !range.isMultiLine()) { if (forceMultiline) { range = this.getSectionRange(session, row); } else if (foldStyle != "all") range = null; } return range; } if (foldStyle === "markbegin") return; var match = line.match(this.foldingStopMarker); if (match) { var i = match.index + match[0].length; if (match[1]) return this.closingBracketBlock(session, match[1], row, i); return this.getCommentFoldRange(session, row, i, -1); } if (this.isStartIndentationBlock(session, line, row)) { return this.indentationBlock(session, row); } }; this.isStartIndentationBlock = function (session, line, row) { if (session.getLength() - 1 === row) { return; } var re = /\S/; var nextLineRow = row + 1; var firstCharPosNextLine; var firstCharPos = line.search(re); if (firstCharPos !== -1) { do { firstCharPosNextLine = session.getLine(nextLineRow).search(re); } while (firstCharPosNextLine === -1 && session.getLength() > ++nextLineRow); if (firstCharPosNextLine !== -1 && firstCharPos < firstCharPosNextLine) { return 'start'; } } }; // this.sqlCommentFoldWidget = function (session, foldStyle, row) { // var nextLine = session.getLine(row + 1); // var prevLine = session.getLine(row - 1); // var nextLineIsComment = this.sqlCommentRe.test(nextLine); // var prevLineIsComment = this.sqlCommentRe.test(prevLine); // if (nextLineIsComment && !prevLineIsComment) { // return 'start'; // } else if (foldStyle === 'markbeginend' && !nextLineIsComment && prevLineIsComment) { // return 'end'; // } else { // return ''; // } // }; this.getCommentFoldRange = function (session, row, column, dir) { var iterator = new TokenIterator(session, row, column); var token = iterator.getCurrentToken(); if (token && /^comment|string/.test(token.type)) { var range = new Range(); var re = new RegExp(token.type.replace(/\..*/, "")); if (dir != 1) { do { token = iterator.stepBackward(); } while (token && re.test(token.type)); iterator.stepForward(); } range.start.row = iterator.getCurrentTokenRow(); // range.start.row = iterator.getCurrentTokenRow() + 1; // range.start.column = iterator.getCurrentTokenColumn() + 2; range.start.column = session.getLine(iterator.getCurrentTokenRow()).length; iterator = new TokenIterator(session, row, column); if (dir != -1) { do { token = iterator.stepForward(); } while (token && re.test(token.type)); token = iterator.stepBackward(); } else token = iterator.getCurrentToken(); range.end.row = iterator.getCurrentTokenRow(); range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2; return range; } }; this.getSectionRange = function (session, row) { var line = session.getLine(row); var startIndent = line.search(/\S/); var startRow = row; var startColumn = line.length; row = row + 1; var endRow = row; var maxRow = session.getLength(); while (++row < maxRow) { line = session.getLine(row); var indent = line.search(/\S/); if (indent === -1) continue; if (startIndent > indent) break; var subRange = this.getFoldWidgetRange(session, "all", row); if (subRange) { if (subRange.start.row <= startRow) { break; } else if (subRange.isMultiLine()) { row = subRange.end.row; } else if (startIndent == indent) { break; } } endRow = row; } return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); }; this.getCommentRegionBlock = function (session, line, row) { var startColumn = line.search(/\s*$/); var maxRow = session.getLength(); var startRow = row; var re = /^\s*--#?(end)?region\b/; var depth = 1; while (++row < maxRow) { line = session.getLine(row); var m = re.exec(line); if (!m) continue; if (m[1]) depth--; else depth++; if (!depth) break; } var endRow = row; if (endRow > startRow) { return new Range(startRow, startColumn, endRow, line.length); } }; }).call(FoldMode.prototype); }); ace.define("ace/mode/presto", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/presto_highlight_rules", "ace/range"], function (require, exports, module) { "use strict"; var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var SqlHighlightRules = require("./presto_highlight_rules").SqlHighlightRules; // var Range = require("../range").Range; var SqlFoldMode = require("./folding/presto").FoldMode; var Mode = function () { this.HighlightRules = SqlHighlightRules; this.foldingRules = new SqlFoldMode(); }; oop.inherits(Mode, TextMode); (function () { this.lineCommentStart = "--"; this.$id = "ace/mode/presto"; // syntax validation worker // var WorkerClient = require("ace/worker/worker_client").WorkerClient; // this.createWorker = function(session) { // var document = session.getDocument(); // this.$worker = new WorkerClient(["ace"], "ace/worker/sql-worker", "SqlWorker", "3rd-party/ace/modes/sql-worker.js"); // this.$worker.attachToDocument(document); // this.$worker.on('annotate', function(e) { // session.setAnnotations(e.data); // }); // this.$worker.on('terminate', function() { // session.clearAnnotations(); // }); // return this.$worker; // }; }).call(Mode.prototype); exports.Mode = Mode; }); } ================================================ FILE: quix-frontend/client/src/lib/code-editor/ace-extensions/searchbox.ts ================================================ /* This is searchbox from ace 1.2.9, if we upgrade, this can be removed */ /* tslint:disable */ export const setupSearchbox = (ace) => { ace.define("ace/ext/searchbox", ["require", "exports", "module", "ace/lib/dom", "ace/lib/lang", "ace/lib/event", "ace/keyboard/hash_handler", "ace/lib/keys"], function (require, exports, module) { "use strict"; var dom = require("../lib/dom"); var lang = require("../lib/lang"); var event = require("../lib/event"); var searchboxCss = "\ .ace_search {\ background-color: #ddd;\ color: #666;\ border: 1px solid #cbcbcb;\ border-top: 0 none;\ overflow: hidden;\ margin: 0;\ padding: 4px 6px 0 4px;\ position: absolute;\ top: 0;\ z-index: 99;\ white-space: normal;\ }\ .ace_search.left {\ border-left: 0 none;\ border-radius: 0px 0px 5px 0px;\ left: 0;\ }\ .ace_search.right {\ border-radius: 0px 0px 0px 5px;\ border-right: 0 none;\ right: 0;\ }\ .ace_search_form, .ace_replace_form {\ margin: 0 20px 4px 0;\ overflow: hidden;\ line-height: 1.9;\ }\ .ace_replace_form {\ margin-right: 0;\ }\ .ace_search_form.ace_nomatch {\ outline: 1px solid red;\ }\ .ace_search_field {\ border-radius: 3px 0 0 3px;\ background-color: white;\ color: black;\ border: 1px solid #cbcbcb;\ border-right: 0 none;\ box-sizing: border-box!important;\ outline: 0;\ padding: 0;\ font-size: inherit;\ margin: 0;\ line-height: inherit;\ padding: 0 6px;\ min-width: 17em;\ vertical-align: top;\ }\ .ace_searchbtn {\ border: 1px solid #cbcbcb;\ line-height: inherit;\ display: inline-block;\ padding: 0 6px;\ background: #fff;\ border-right: 0 none;\ border-left: 1px solid #dcdcdc;\ cursor: pointer;\ margin: 0;\ position: relative;\ box-sizing: content-box!important;\ color: #666;\ }\ .ace_searchbtn:last-child {\ border-radius: 0 3px 3px 0;\ border-right: 1px solid #cbcbcb;\ }\ .ace_searchbtn:disabled {\ background: none;\ cursor: default;\ }\ .ace_searchbtn:hover {\ background-color: #eef1f6;\ }\ .ace_searchbtn.prev, .ace_searchbtn.next {\ padding: 0px 0.7em\ }\ .ace_searchbtn.prev:after, .ace_searchbtn.next:after {\ content: \"\";\ border: solid 2px #888;\ width: 0.5em;\ height: 0.5em;\ border-width: 2px 0 0 2px;\ display:inline-block;\ transform: rotate(-45deg);\ }\ .ace_searchbtn.next:after {\ border-width: 0 2px 2px 0 ;\ }\ .ace_searchbtn_close {\ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;\ border-radius: 50%;\ border: 0 none;\ color: #656565;\ cursor: pointer;\ font: 16px/16px Arial;\ padding: 0;\ height: 14px;\ width: 14px;\ top: 9px;\ right: 7px;\ position: absolute;\ }\ .ace_searchbtn_close:hover {\ background-color: #656565;\ background-position: 50% 100%;\ color: white;\ }\ .ace_button {\ margin-left: 2px;\ cursor: pointer;\ -webkit-user-select: none;\ -moz-user-select: none;\ -o-user-select: none;\ -ms-user-select: none;\ user-select: none;\ overflow: hidden;\ opacity: 0.7;\ border: 1px solid rgba(100,100,100,0.23);\ padding: 1px;\ box-sizing: border-box!important;\ color: black;\ }\ .ace_button:hover {\ background-color: #eee;\ opacity:1;\ }\ .ace_button:active {\ background-color: #ddd;\ }\ .ace_button.checked {\ border-color: #3399ff;\ opacity:1;\ }\ .ace_search_options{\ margin-bottom: 3px;\ text-align: right;\ -webkit-user-select: none;\ -moz-user-select: none;\ -o-user-select: none;\ -ms-user-select: none;\ user-select: none;\ clear: both;\ }\ .ace_search_counter {\ float: left;\ font-family: arial;\ padding: 0 8px;\ }"; var HashHandler = require("../keyboard/hash_handler").HashHandler; var keyUtil = require("../lib/keys"); var MAX_COUNT = 999; dom.importCssString(searchboxCss, "ace_searchbox"); var html = ''.replace(/> +/g, ">"); var SearchBox = function (editor, range?, showReplaceForm?) { var div = dom.createElement("div"); div.innerHTML = html; this.element = div.firstChild; this.setSession = this.setSession.bind(this); this.$init(); this.setEditor(editor); }; (function () { this.setEditor = function (editor) { editor.searchBox = this; editor.renderer.scroller.appendChild(this.element); this.editor = editor; }; this.setSession = function (e) { this.searchRange = null; this.$syncOptions(true); }; this.$initElements = function (sb) { this.searchBox = sb.querySelector(".ace_search_form"); this.replaceBox = sb.querySelector(".ace_replace_form"); this.searchOption = sb.querySelector("[action=searchInSelection]"); this.replaceOption = sb.querySelector("[action=toggleReplace]"); this.regExpOption = sb.querySelector("[action=toggleRegexpMode]"); this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]"); this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]"); this.searchInput = this.searchBox.querySelector(".ace_search_field"); this.replaceInput = this.replaceBox.querySelector(".ace_search_field"); this.searchCounter = sb.querySelector(".ace_search_counter"); }; this.$init = function () { var sb = this.element; this.$initElements(sb); var _this = this; event.addListener(sb, "mousedown", function (e) { setTimeout(function () { _this.activeInput.focus(); }, 0); event.stopPropagation(e); }); event.addListener(sb, "click", function (e) { var t = e.target || e.srcElement; var action = t.getAttribute("action"); if (action && _this[action]) _this[action](); else if (_this.$searchBarKb.commands[action]) _this.$searchBarKb.commands[action].exec(_this); event.stopPropagation(e); }); event.addCommandKeyListener(sb, function (e, hashId, keyCode) { var keyString = keyUtil.keyCodeToString(keyCode); var command = _this.$searchBarKb.findKeyCommand(hashId, keyString); if (command && command.exec) { command.exec(_this); event.stopEvent(e); } }); this.$onChange = lang.delayedCall(function () { _this.find(false, false); }); event.addListener(this.searchInput, "input", function () { _this.$onChange.schedule(20); }); event.addListener(this.searchInput, "focus", function () { _this.activeInput = _this.searchInput; _this.searchInput.value && _this.highlight(); }); event.addListener(this.replaceInput, "focus", function () { _this.activeInput = _this.replaceInput; _this.searchInput.value && _this.highlight(); }); }; this.$closeSearchBarKb = new HashHandler([{ bindKey: "Esc", name: "closeSearchBar", exec: function (editor) { editor.searchBox.hide(); } }]); this.$searchBarKb = new HashHandler(); this.$searchBarKb.bindKeys({ "Ctrl-f|Command-f": function (sb) { var isReplace = sb.isReplace = !sb.isReplace; sb.replaceBox.style.display = isReplace ? "" : "none"; sb.replaceOption.checked = isReplace; sb.$syncOptions(); sb.searchInput.focus(); }, "Ctrl-H|Command-Option-F": function (sb) { sb.replaceOption.checked = true; sb.$syncOptions(); sb.replaceInput.focus(); }, "Ctrl-G|Command-G": function (sb) { sb.findNext(); }, "Ctrl-Shift-G|Command-Shift-G": function (sb) { sb.findPrev(); }, "esc": function (sb) { setTimeout(function () {sb.hide();}); }, "Return": function (sb) { if (sb.activeInput == sb.replaceInput) sb.replace(); sb.findNext(); }, "Shift-Return": function (sb) { if (sb.activeInput == sb.replaceInput) sb.replace(); sb.findPrev(); }, "Alt-Return": function (sb) { if (sb.activeInput == sb.replaceInput) sb.replaceAll(); sb.findAll(); }, "Tab": function (sb) { (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus(); } }); this.$searchBarKb.addCommands([{ name: "toggleRegexpMode", bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"}, exec: function (sb) { sb.regExpOption.checked = !sb.regExpOption.checked; sb.$syncOptions(); } }, { name: "toggleCaseSensitive", bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"}, exec: function (sb) { sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked; sb.$syncOptions(); } }, { name: "toggleWholeWords", bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"}, exec: function (sb) { sb.wholeWordOption.checked = !sb.wholeWordOption.checked; sb.$syncOptions(); } }, { name: "toggleReplace", exec: function (sb) { sb.replaceOption.checked = !sb.replaceOption.checked; sb.$syncOptions(); } }, { name: "searchInSelection", exec: function (sb) { sb.searchOption.checked = !sb.searchRange; sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange()); sb.$syncOptions(); } }]); this.setSearchRange = function (range) { this.searchRange = range; if (range) { this.searchRangeMarker = this.editor.session.addMarker(range, "ace_active-line"); } else if (this.searchRangeMarker) { this.editor.session.removeMarker(this.searchRangeMarker); this.searchRangeMarker = null; } }; this.$syncOptions = function (preventScroll) { // dom.setCssClass(this.replaceOption, "checked", this.searchRange); dom.setCssClass(this.searchOption, "checked", this.searchOption.checked); this.replaceOption.textContent = this.replaceOption.checked ? "-" : "+"; dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked); dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked); dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked); this.replaceBox.style.display = this.replaceOption.checked ? "" : "none"; this.find(false, false, preventScroll); }; this.highlight = function (re) { this.editor.session.highlight(re || this.editor.$search.$options.re); this.editor.renderer.updateBackMarkers(); }; this.find = function (skipCurrent, backwards, preventScroll) { var range = this.editor.find(this.searchInput.value, { skipCurrent: skipCurrent, backwards: backwards, wrap: true, regExp: this.regExpOption.checked, caseSensitive: this.caseSensitiveOption.checked, wholeWord: this.wholeWordOption.checked, preventScroll: preventScroll, range: this.searchRange }); var noMatch = !range && this.searchInput.value; dom.setCssClass(this.searchBox, "ace_nomatch", noMatch); this.editor._emit("findSearchBox", {match: !noMatch}); this.highlight(); this.updateCounter(); }; this.updateCounter = function () { var editor = this.editor; var regex = editor.$search.$options.re; var all = 0; var before = 0; if (regex) { var value = this.searchRange ? editor.session.getTextRange(this.searchRange) : editor.getValue(); var offset = editor.session.doc.positionToIndex(editor.selection.anchor); if (this.searchRange) offset -= editor.session.doc.positionToIndex(this.searchRange.start); var last = regex.lastIndex = 0; var m; while ((m = regex.exec(value))) { all++; last = m.index; if (last <= offset) before++; if (all > MAX_COUNT) break; if (!m[0]) { regex.lastIndex = last += 1; if (last >= value.length) break; } } } this.searchCounter.textContent = before + " of " + (all > MAX_COUNT ? MAX_COUNT + "+" : all); }; this.findNext = function () { this.find(true, false); }; this.findPrev = function () { this.find(true, true); }; this.findAll = function () { var range = this.editor.findAll(this.searchInput.value, { regExp: this.regExpOption.checked, caseSensitive: this.caseSensitiveOption.checked, wholeWord: this.wholeWordOption.checked }); var noMatch = !range && this.searchInput.value; dom.setCssClass(this.searchBox, "ace_nomatch", noMatch); this.editor._emit("findSearchBox", {match: !noMatch}); this.highlight(); this.hide(); }; this.replace = function () { if (!this.editor.getReadOnly()) this.editor.replace(this.replaceInput.value); }; this.replaceAndFindNext = function () { if (!this.editor.getReadOnly()) { this.editor.replace(this.replaceInput.value); this.findNext(); } }; this.replaceAll = function () { if (!this.editor.getReadOnly()) this.editor.replaceAll(this.replaceInput.value); }; this.hide = function () { this.isReplace = false; this.active = false; this.setSearchRange(null); this.editor.off("changeSession", this.setSession); this.element.style.display = "none"; this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb); this.editor.focus(); }; this.show = function (value, isReplace) { this.active = true; this.editor.on("changeSession", this.setSession); this.element.style.display = ""; this.replaceOption.checked = isReplace; if (value) this.searchInput.value = value; this.searchInput.focus(); this.searchInput.select(); this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb); this.$syncOptions(true); }; this.isFocused = function () { var el = document.activeElement; return el == this.searchInput || el == this.replaceInput; }; }).call(SearchBox.prototype); exports.SearchBox = SearchBox; exports.Search = function (editor, isReplace) { var sb = editor.searchBox || new SearchBox(editor); sb.show(editor.session.getTextRange(), isReplace); }; }); (function () { ace.acequire(["ace/ext/searchbox"], function () {}); })(); } ================================================ FILE: quix-frontend/client/src/lib/code-editor/bootstrap.ts ================================================ import angular from 'angular'; import 'jquery-ui/ui/widgets/sortable'; import 'angular-ui-sortable'; import ace from 'brace'; import {setupAce} from './ace-extensions'; setupAce(ace); import 'brace/theme/tomorrow'; import '../core'; import '../ui'; export default angular.module('bi.codeEditor', ['bi.core', 'bi.ui', 'ui.sortable']); ================================================ FILE: quix-frontend/client/src/lib/code-editor/directives/code-editor.html ================================================
menu
share
Name
Type
Options
Select an auto param
  • {{::param}}
drag_indicator
{{::param.key}} {{::param.type}}
close
menu
================================================ FILE: quix-frontend/client/src/lib/code-editor/directives/code-editor.scss ================================================ @import '../../ui/assets/css/def/defaults.def'; @import '../../ui/assets/css/def/colors.def'; @import '../../ui/assets/css/def/flex.def'; @import '../../ui/assets/css/def/space.def'; bi-code-editor { display: flex; .bce-params-list { padding-bottom: 60px; .bce-params-list-inner { &.bi-form--vertical { .bi-form-row { .bi-form-input { margin-top: 3px; } .bce-param-handle, .bce-param-remove { padding: 0; &:hover { background: none; } } .bce-param-handle { margin: 19px 1px 0 -5px; } .bce-param-remove { margin: 20px 1px 0 4px; } } } } } .bce-params { position: relative; min-width: 300px; max-width: 300px; .bce-params-inner { margin-right: 15px; } .bce-auto-param-list { .bi-dropdown-menu { box-shadow: none; } } &.bce-params--closed { min-width: 0; } } &.bce-narrow { .bce-container { @include flex(column); @include space-v__inner(); .bce-params { padding-bottom: $default-space; border-right: 0; border-bottom: 1px solid $grey--300; .bce-params-inner { @include flex(column); @include space-v__inner(); max-height: 300px; padding-left: 0; } } } } .bce-container { .bce-editor-wrapper { transition: border-color, .3s; border-left: 3px solid $grey--200; &.bce-valid { border-color: lighten($success, 12); } &.bce-invalid { border-color: lighten($danger, 12); } } .bce-editor-container { height: 400px; &.bce-readonly { background-color: $grey--50; .ace_cursor { display: none; } } .ace_gutter { background-color: transparent !important; .ace_gutter-layer { width: auto; min-width: 26px; } .ace_gutter-cell { padding: 0 13px 0 5px; color: lighten($muted, 5); } .ace_gutter-active-line { background-color: transparent !important; } } .ace_marker-layer { .ace_active-line { background-color: $grey--100 !important; } } } } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/directives/code-editor.ts ================================================ import template from './code-editor.html'; import './code-editor.scss'; import {uniq} from 'lodash'; import jquery from 'jquery'; import {IScope} from 'angular'; import {utils, createNgModel, initNgScope, inject} from '../../core'; import CodeEditor from '../services/code-editor-service'; import Instance from '../services/code-editor-instance'; import {IParam, ParamParser} from '../services/param-parser'; import {renderParam} from '../services/param-parser/param-renderers'; const {safeApply} = utils.scope; function initEditor(scope, element, container, text) { const editor = new CodeEditor(scope, container, text, scope.options); editor .on('change', value => !scope.readonly && safeApply(scope, () => scope.model = value)) .on('validToggle', valid => { container.parent().removeClass('bce-valid bce-invalid'); container.parent().addClass({true: 'bce-valid', false: 'bce-invalid'}[valid]); }) .on('resize', () => element.toggleClass('bce-narrow', element.width() < 1000)); scope.$watch('readonly', (readonly = false) => { editor.setReadonly(readonly); container.toggleClass('bce-readonly', readonly); }); editor.getShortcuts().addShortcut('Ctrl-S', 'Command-S', () => scope.onSave(), scope); return editor; } function exportParams(editor: CodeEditor) { const params = editor.getParams(); const serializer = params.getParser().getSerializer(); return params.getParams().reduce((res, {key, value}) => { res[`var_${key}`] = serializer.toString(value); return res; }, {}); } function importParams(editor: CodeEditor, urlImports) { const params = editor.getParams(); const serializer = params.getParser().getSerializer(); params.getParams().forEach(({key, value, type}) => { const urlParam = urlImports[`var_${key}`]; if (typeof urlParam === 'undefined') { return; } params.overrideParam(key, {value: serializer.toJs(urlParam, type) || null}); }); } function render(scope, element, text, editor: CodeEditor, urlImports): CodeEditor { if (!editor) { editor = initEditor(scope, element, element.find('.bce-editor-container'), text); if (editor.getParams().hasParams()) { importParams(editor, urlImports); } else { scope.vm.params.toggleVisible(false); } scope.vm.param.types = ParamParser.TYPES; scope.vm.param.autoParams = ParamParser.AUTO_PARAMS; } else { editor.setValue(text); } return editor; } export default () => { return { restrict: 'E', template, require: 'ngModel', scope: { onSave: '&', onLoad: '&', onParamsShare: '&', readonly: '=', bceOptions: '<' }, link: { pre (scope: IScope & {model: string}, element, attrs, ngModel) { let editor: CodeEditor; let urlImports = {}; createNgModel(scope, ngModel) .renderWith(text => editor = render(scope, element, text, editor, urlImports)) .then(() => { scope.onLoad({instance: new Instance(editor, scope)}); }); initNgScope(scope) .withOptions('bceOptions', { ace: {}, focus: false, params: false, customParams: true, fitContent: false, shareParams: false, dateFormat: null, }) .withVM({ param: { types: [], kinds: ['auto', 'custom'], current: null, $init() { this.init(); }, init() { this.model = { key: '', type: (this.model && this.model.type) || 'string', options: undefined }; } }, params: { visible: true, $init() { Object.defineProperty(this, 'all', { get() { return editor && editor.getParams().getParams(); } }); }, $export(provider) { if (provider === 'url') { return exportParams(editor); } return {paramsOpen: this.visible}; }, $import(obj) { urlImports = obj; if (typeof obj.paramsOpen === 'boolean') { this.toggleVisible(obj.paramsOpen); } } } }) .withEvents({ onParamChange() { inject('$timeout')(() => editor.getParams().syncParams()); }, onParamsToggle() { scope.vm.params.toggleVisible(); scope.state.save(); }, onParamAdd() { const {key, type, options} = scope.vm.param.model; editor.getParams().addParam(key, type, undefined, uniq(options)); scope.vm.param.init(); }, onParamRemove({key}) { editor.getParams().removeParam(key); }, onShareClick() { scope.onParamsShare({params: scope.state.state.exportAsURL('url')}); } }) .withState('bce', 'bce', {}); scope.renderParam = (param: IParam) => ({ html: renderParam(scope, param, {dateFormat: scope.options.dateFormat}, editor.getParams().getParamOverrides(param.key)) }); if (!scope.options.customParams) { inject('$timeout')(() => element.find('.bce-custom-param-toggle').remove()); } // this is needed because angular directives dont work inside be-controls element.on('mousedown', '.bce-custom-param-toggle, .bce-auto-param-toggle', (e) => { const target = jquery(e.currentTarget); utils.scope.safeApply(scope, () => { scope.vm.param.current = target.is('.bce-custom-param-toggle') ? 'custom' : 'auto'; }); }); scope.$on('$destroy', () => editor.destroy()); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/code-editor/directives/index.ts ================================================ export {default as codeEditor} from './code-editor'; ================================================ FILE: quix-frontend/client/src/lib/code-editor/index.ts ================================================ import ngApp from './bootstrap'; import init from './init'; export {default as CodeEditorInstance} from './services/code-editor-instance'; export {paramParserFactory} from './services/param-parser'; export {paramSerializerFactory} from './services/param-parser/param-serializers'; init(ngApp); ================================================ FILE: quix-frontend/client/src/lib/code-editor/init.ts ================================================ import {forEach} from 'lodash'; import * as directives from './directives'; function toDirectiveName(name: string) { return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`; } export default function init(ngApp: angular.IModule) { forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any)); } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-annotator.ts ================================================ export default class CodeEditorAnnotator { constructor (private readonly ace) { } showError(row: number, message: string) { this.ace.getSession().setAnnotations([{ row: row - 1, column: 0, text: message, type: 'error' }]); } hideAll() { this.ace.getSession().clearAnnotations(); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-completer.ts ================================================ import { find, isFunction, escapeRegExp } from 'lodash'; import { Editor, IEditSession } from 'brace'; export type ICompleterFn = (prefix: string, session?: IEditSession) => ng.IPromise | ICompleterItem[]; const isPromise = (maybePromise: T | ng.IPromise): maybePromise is ng.IPromise => (maybePromise as any).then && isFunction(((maybePromise as any).then)); export interface ICompleterItem { value: string; meta: string; caption?: string; matchMask?: number[]; score?: number } export interface IAceCompleter { identifierRegexps: RegExp[]; getCompletions(editor, session: IEditSession, pos, prefix: string, callback): void; linePredicate?(line: string): boolean; /* do another check on the line that isn't (necessarily) regex based */ acceptEmptyString?: boolean; prefix?: string; /* for live completion */ } function createCompleter(fn: ICompleterFn, prefixRegex: RegExp, options: {prefix?: string; acceptEmptyString?: boolean; linePredicate?: any } = {}): IAceCompleter { return { identifierRegexps: [prefixRegex], getCompletions(editor, session: IEditSession, pos, prefix: string, callback) { const completions = fn(prefix, session); if (!completions) { return; } if (isPromise(completions)) { completions.then(c => callback(null, c)); } else { callback(null, completions); } }, ...options }; } function createLiveCompleter(prefix: string, fn: ICompleterFn) { const regex = new RegExp(escapeRegExp(prefix)); const completer = createCompleter(_prefix => _prefix === prefix && fn(prefix), regex, {prefix}); return completer; } export default class CodeEditorCompleter { private readonly completers = []; constructor(ace: Editor) { ace.setOptions({ enableBasicAutocompletion: this.completers, enableSnippets: false, enableLiveAutocompletion: false }); ace.getSession().on('change', e => { if (e.action === 'insert' && find(this.completers, {prefix: e.lines[0]})) { setTimeout(() => ace.commands.byName.startAutocomplete.exec(ace), 0); } }); } addLiveCompleter(prefix: string, fn: ICompleterFn) { this.completers.push(createLiveCompleter(prefix, fn)); } addOnDemandCompleter(identifierRegex: RegExp, fn: ICompleterFn, options?) { this.completers.push(createCompleter(fn, identifierRegex, options)); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-instance.ts ================================================ import {utils, srv} from '../../core'; import CodeEditor from './code-editor-service'; import {ICompleterFn} from './code-editor-completer'; import {default as Annotator} from './code-editor-annotator'; import {default as Selection} from './code-editor-selection'; import {default as Params} from './code-editor-params'; const {safeApply} = utils.scope; export default class CodeEditorInstance extends srv.eventEmitter.EventEmitter { constructor(private readonly editor: CodeEditor, scope) { super(); editor.getSelection() .on('select', text => safeApply(scope, () => this.fire('select', text))) .on('deselect', () => safeApply(scope, () => this.fire('deselect'))); } setValid(valid: boolean): CodeEditorInstance { this.editor.setValid(valid); return this; } addLiveCompleter(prefix: string, fn: ICompleterFn): CodeEditorInstance { this.editor.getCompleter().addLiveCompleter(prefix, fn); return this; } addOnDemandCompleter(identifierRegex: RegExp, fn: ICompleterFn, options?: {prefix?: string; acceptEmptyString?: boolean; linePredicate?: any }): CodeEditorInstance { this.editor.getCompleter().addOnDemandCompleter(identifierRegex, fn, options); return this; } setLiveAutocompletion(value: boolean) { this.editor.setLiveAutocompletion(value); return this; } addShortcut(winShortcut: string, macShortcut: string, fn: Function, scope): CodeEditorInstance { this.editor.getShortcuts().addShortcut(winShortcut, macShortcut, fn, scope); return this; } getAnnotator(): Annotator { return this.editor.getAnnotator(); } getSelection(): Selection { return this.editor.getSelection(); } getParams(): Params { return this.editor.getParams(); } getLockedRange() { return this.editor.getLockedRange(); } resize(): CodeEditorInstance { this.editor.resize(); return this; } focus(): CodeEditorInstance { this.editor.focus(); return this; } getValue() { return this.editor.getValue(); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-params.ts ================================================ import {debounce, pull, find, clone, flatten, last} from 'lodash'; import {utils} from '../../core'; import {UndoManager} from 'brace'; import {ParamParser, TType, IParam} from './param-parser'; import {paramSerializerFactory} from './param-parser/param-serializers'; import CodeEditor from './code-editor-service'; import { AUTO_PARAM_TYPES, AUTO_PARAM_DEFAULTS } from './param-parser/param-types'; export default class CodeEditorParams { private params: IParam[] = []; private readonly parser: ParamParser; private mute = false; private folded = false; private readonly paramOverrides: {[key: string]: Partial} = {}; private readonly parserOptions: {customParamsEnabled: boolean}; constructor(private readonly editor: CodeEditor, private readonly ace, private readonly options, private readonly scope) { const type = last(`${options.ace.mode}`.split('/')); this.parser = new ParamParser(paramSerializerFactory(type)); if (!options.params) { return; } this.parserOptions = {customParamsEnabled: this.options.customParams}; this.init(scope); } private init(scope) { this.params = this.parser.params(this.editor.getValue(), this.parserOptions); this.syncParams(); this.ace.getSession().setUndoManager(new UndoManager()); // reset undo stack this.mute = false; this.editor.on('change', debounce((value, {isInLockRange, isMultilineInsert}) => { if (this.mute) { this.mute = false; return; } if (isInLockRange || isMultilineInsert) { utils.scope.safeApply(scope, () => { this.params = this.parser.params(value, this.parserOptions, this.getParams()); this.setLock(this.getParser().getSerializer().getLockRange(value)); }); } }, 100)); } private replace(text, needle, replacement): string { if (needle === replacement) { return text; } this.mute = true; if (text === '') { this.editor.setValue(replacement); } else { this.ace.replaceAll(replacement, {needle}); } return this.editor.getValue(); } private setLock(ranges: [number, number][]) { this.editor.unlockLines(); if (this.hasParams()) { this.editor.lockLines(ranges); } } private setFold(ranges: [number, number][]) { if (!this.hasParams()) { return; } let foldRange = flatten(ranges); foldRange = [foldRange[0], foldRange[foldRange.length - 1]]; if (!this.folded) { this.folded = true; setTimeout(() => this.ace.getSession().foldAll(...foldRange)); } else { this.ace.getSession().foldAll(...foldRange); } } getParser(): ParamParser { return this.parser; } getParams(): IParam[] { return this.params; } hasParams(): boolean { return !!this.getParams().length; } addParam(key: string, type: TType, value, options?: string[]): CodeEditorParams { if (!find(this.getParams(), {key})) { this.getParams().push(this.parser.createParam(key, type, value, options)); this.syncParams(); } return this; } addAutoParam(key: string): CodeEditorParams { this.addParam(key, AUTO_PARAM_TYPES[key], AUTO_PARAM_DEFAULTS[key]); return this; } removeParam(key: string): CodeEditorParams { pull(this.getParams(), find(this.getParams(), {key})); this.syncParams(); return this; } removeAllParams(): CodeEditorParams { this.params = []; this.syncParams(); return this; } getParamOverrides(key: string) { return this.paramOverrides[key]; } overrideParam(key: string, param: Partial): CodeEditorParams { this.paramOverrides[key] = param; if (typeof param.value !== 'undefined') { const p = find(this.params, {key}); p.value = param.value; } // trigger watchers utils.scope.safeApply(this.scope, () => { this.params = this.params.map((p: any) => { delete p.$$hashKey; return clone(p); }); }); return this; } /** * Sync params array to editor */ syncParams() { const ranges = this.parser.sync(this.editor.getValue(), this.getParams(), this.parserOptions, (text, needle, replacement) => { return this.replace(text, needle, replacement); }); this.setLock(ranges); this.setFold(ranges); return ranges; } /** * Replaces params in text with their respective values */ format(text?: string): string { return this.parser.format(typeof text !== 'undefined' ? text : this.editor.getValue(), this.getParams(), { customParamsEnabled: this.options.customParams, keepEmbed: false }); } formatEmbed(options?): string { const embed = this.getParser().getSerializer().extract(this.editor.getValue(), options); return this.parser.format(embed, this.getParams(), { customParamsEnabled: this.options.customParams, keepEmbed: true }); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-selection.ts ================================================ import {throttle} from 'lodash'; import {srv, utils} from '../../core'; export default class CodeEditorSelection extends srv.eventEmitter.EventEmitter { private range; constructor (private readonly ace, scope) { super(); const self = this; const selectionEvents = { onSelection: throttle(text => utils.scope.safeApply(scope, () => self.fire('select', text)), 200), onDeselection: () => utils.scope.safeApply(scope, () => self.fire('deselect')) }; ace.getSession().getSelection().on('changeSelection', (e, selection) => { const range = selection.getRange(); const selectedText = ace.getSession().getDocument().getTextRange(selection.getRange()).trim(); if (selectedText && selectedText.split(/\s|\n/, 2).length >= 2) { selectionEvents.onSelection(selectedText); this.range = range; } else { selectionEvents.onDeselection(); this.range = null; } }); } getRange() { return this.range; } clearSelection() { this.ace.getSelection().clearSelection(); this.fire('deselect'); } getOffset() { return (this.range && this.range.start.row) || 0; } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-service.ts ================================================ import { flatten, last } from 'lodash'; import ace from 'brace'; import { srv, inject } from '../../core'; import { default as Completer } from './code-editor-completer'; import { default as Annotator } from './code-editor-annotator'; import { default as Selection } from './code-editor-selection'; import { default as Shortcuts } from './code-editor-shortcuts'; import { default as Params } from './code-editor-params'; declare const ResizeObserver; export interface AceEditorOptions { mode?: string; theme?: string; enableMultiselect?: boolean; showGutter?: boolean; highlightActiveLine?: boolean; focus?: boolean; } export interface CodeEditorOptions { ace?: AceEditorOptions; focus?: boolean; fitContent?: boolean; } const aceDefaults = { mode: 'ace/mode/presto', theme: 'ace/theme/tomorrow', enableMultiselect: false, highlightActiveLine: true, showGutter: true }; function getHeight(_ace) { // tslint:disable-next-line: restrict-plus-operands return _ace.getSession().getScreenLength() * 16 + _ace.renderer.scrollBar.getWidth(); } function setHeight(_ace, element) { // tslint:disable-next-line: restrict-plus-operands element.css('height', Math.min(getHeight(_ace), 400) + 'px'); } export default class CodeEditor extends srv.eventEmitter.EventEmitter { private readonly ace; private valid: boolean = null; private locked: [number, number][] = null; private readonly completer: Completer = null; private readonly annotator: Annotator = null; private readonly selection: Selection = null; private readonly shortcuts: Shortcuts = null; private readonly params: Params = null; constructor(scope, private readonly element, text, options?: CodeEditorOptions) { super(); this.ace = ace.edit(element.text(text).get(0)); this.completer = new Completer(this.ace); this.annotator = new Annotator(this.ace); this.selection = new Selection(this.ace, scope); this.shortcuts = new Shortcuts(this.ace); this.params = new Params(this, this.ace, scope.options, scope); this.init(options); } private init(options: CodeEditorOptions = {}): CodeEditor { this.ace.setOptions({...aceDefaults, ...options.ace}); this.ace.$blockScrolling = Infinity; this.ace.session.setFoldStyle('markbeginend'); this.ace.getSession().on('change', ({start, lines}) => { this.setValid(null); this.fire('change', this.ace.getValue(), { isInLockRange: this.locked && start.row < last(flatten(this.locked)), isMultilineInsert: lines.length > 1 }); }); const lockExceptions = ['golinedown', 'golineup', 'gotoright', 'gotoleft']; this.ace.commands.on('exec', e => { const range = this.getSelection().getRange(); if (!this.locked || (range && ['paste', 'del', 'backspace'].indexOf(e.command.name) !== -1 && range.start.row === 0 && range.end.row >= 1)) { return; } const {row, column} = this.ace.selection.getCursor(); const lock = this.locked.some(([start, end]) => { return (row >= start && row <= end && lockExceptions.indexOf(e.command.name) === -1) || (e.command.name === 'backspace' && row === end + 1 && column === 0); }); if (lock) { e.preventDefault(); e.stopPropagation(); } }); if (options.focus) { this.ace.focus(); } if (options.fitContent) { setHeight(this.ace, this.element); this.ace.getSession().on('change', () => { setHeight(this.ace, this.element); this.resize(); }); } if (typeof ResizeObserver !== 'undefined') { // listen to element resize natively new ResizeObserver(() => this.resize()).observe(this.element.get(0)); } else { // resize the editor corectly inside a hidden container inject('$timeout')(() => this.resize()); } return this; } isValid(): boolean { return this.valid; } getCompleter(): Completer { return this.completer; } getAnnotator(): Annotator { return this.annotator; } getSelection(): Selection { return this.selection; } getShortcuts(): Shortcuts { return this.shortcuts; } getParams(): Params { return this.params; } getValue(): string { return this.ace.getValue(); } getLockedRange(): [number, number][] { return this.locked; } setReadonly(readonly: boolean): CodeEditor { this.ace.setReadOnly(readonly); this.ace.setOption('highlightActiveLine', !readonly); this.ace.setOption('highlightGutterLine', !readonly); return this; } setLiveAutocompletion(value: boolean) { this.ace.setOption('enableLiveAutocompletion', value); return this; } setValid(valid: boolean): CodeEditor { this.valid = valid; this.fire('validToggle', valid); return this; } setValue(value): CodeEditor { this.ace.setValue(value, -1); this.getSelection().clearSelection(); return this; } lockLines(range: [number, number][]): CodeEditor { this.locked = range; return this; } unlockLines(): CodeEditor { this.locked = null; return this; } resize(): CodeEditor { this.ace.resize(); this.fire('resize', this.element.width()); return this; } focus(): CodeEditor { this.ace.focus(); return this; } destroy(): CodeEditor { this.ace.session.setUseWorker(false); this.ace.destroy(); return this; } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/code-editor-shortcuts.ts ================================================ import {utils} from '../../core'; export default class CodeEditorShortcuts { constructor (private readonly ace) { } addShortcut(winShortcut: string, macShortcut: string, fn, scope) { this.ace.commands.addCommand({ name: macShortcut, bindKey: {win: winShortcut, mac: macShortcut}, exec: () => utils.scope.safeApply(scope, fn) }); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/index.ts ================================================ import {ParamParser} from './params-parser'; import {paramSerializerFactory} from './param-serializers'; export {IParam, TType} from './param-types'; export {ParamParser} from './params-parser'; export const paramParserFactory = type => { return new ParamParser(paramSerializerFactory(type)); }; ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/boolean-param-renderer.ts ================================================ export default function () { return ` `; } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/index.ts ================================================ import {isArray} from 'lodash'; import {inject} from '../../../../core'; import {IParam} from '../param-types'; import {default as renderInput} from './input-param-renderer'; import {default as renderBoolean} from './boolean-param-renderer'; import {default as renderDatetime} from './datetime-param-renderer'; import {default as renderOption} from './option-param-renderer'; import {default as renderList} from './list-param-renderer'; import {default as renderTextarea} from './textarea-param-renderer'; function compile(scope, param, html, overrides: Partial = {}) { const childScope = scope.$new(); childScope.param = param; childScope.options = overrides.options || param.options; childScope.getOptionTitle = option => { return isArray(option) ? option[1] : option; }; return inject('$compile')(html)(childScope); } function getHtml(param: IParam, options: {dateFormat?: string} = {}) { switch (param.type) { case 'string': return renderInput('text'); case 'number': return renderInput('number'); case 'boolean': return renderBoolean(); case 'datetime': (param as any).widgetValue = param.value; return renderDatetime(options.dateFormat); case 'option': return renderOption(); case 'list': return renderList(); case 'text': return renderTextarea(); default: return renderInput('text'); } } export function renderParam(scope, param: IParam, options, overrides?: Partial) { return compile(scope, param, getHtml(param, options), overrides); } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/input-param-renderer.ts ================================================ export default function (type: 'text' | 'number' = 'text') { return ` `; } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/list-param-renderer.ts ================================================ export default function () { return ` `; } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/option-param-renderer.ts ================================================ export default function () { return ` `; } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/textarea-param-renderer.ts ================================================ export default function () { return ` `; } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/default-param-serializer.ts ================================================ import {IParam, AUTO_PARAMS, TType} from '../param-types'; import {ParamSerializer, ITokenizedParam} from './param-serializer'; const EMBED_PREFIX = 'AUTOGENERATED'; const EMBED_SUFFIX = 'AUTOGENERATED END'; export class DefaultParamSerializer extends ParamSerializer { public *parse(text: string): Iterable { const regex = new RegExp('\\$([a-z0-9_]+)(?:\\:([a-z_]+))?(?:\\:([^=]+))?=\\[([^\\[\\]]*)]|(\\$([a-z0-9_]+))|' + '(\\$((' + AUTO_PARAMS.join(')|(') + ')))', 'g'); let param = null; // tslint:disable-next-line: no-conditional-assignment while ((param = regex.exec(text))) { yield param; } } public stringify(param: any[]): string { let pair = param; if (param.length > 1) { const value = param.pop(); pair = [param.join(':'), `[${value}]`]; } return pair.join('='); } public convert([match, key, type, options, value, keyOnlyParamMatch, keyOnlyParam, autoParamMatch, autoParamKey]: string[]): any[] { value = this.toJs(value, type as TType); options = (options && this.toJs(options, 'list')) || []; return [match, key, type, options, value, keyOnlyParamMatch, keyOnlyParam, autoParamMatch, autoParamKey]; } public unconvert(param: any[]): string[] { return param; } public transform(param: ITokenizedParam): ITokenizedParam { return param; } public untransform(param: ITokenizedParam): ITokenizedParam { return param; } public tokenize([match, key, type, options, value, keyOnlyParamMatch, keyOnlyParam, autoParamMatch, autoParamKey]: any[]): ITokenizedParam { let isAutoParam = false; let isKeyOnlyParam = false; if (autoParamMatch) { match = autoParamMatch; key = autoParamKey; isAutoParam = true; } else if (keyOnlyParamMatch) { match = keyOnlyParamMatch; key = keyOnlyParam; isKeyOnlyParam = true; } return {match, key, value, type, isAutoParam, isKeyOnlyParam, options}; } public detokenize({key, type, value, isAutoParam, isKeyOnlyParam, options}: ITokenizedParam, serializationType: 'serialize' | 'value'): string[] { const res = []; switch (serializationType) { case 'serialize': res.push(`$${key}`); if (!isAutoParam && !isKeyOnlyParam) { res.push(type); if (options && options.length) { res.push(options); } res.push(value); } break; case 'value': res.push(value); break; default: } return res; } public embed(text: string, params: IParam[]): string { const paramsText = params.map(param => this.serialize(param as ITokenizedParam)).join(' '); return `/* ${EMBED_PREFIX}\n${paramsText}\n${EMBED_SUFFIX} */\n`; } public extract(text: string): string { const match = new RegExp(`^\\/\\*[\\s\\S]+${EMBED_PREFIX}[\\s\\S]+${EMBED_SUFFIX}[\\s\\S]+?\\*\\/\\n?`).exec(text); return (match && match[0]) || ''; } public getLockRange(text: string): [number, number][] { return [[0, this.extract(text).split('\n').length - 2]]; } public toJs(value: string, type: TType = 'string'): any { if (typeof value === 'undefined') { return null; } if (type === 'boolean') { return value === 'true' ? true : false; } if (type === 'number') { return parseInt(value, 10); } if (type === 'list') { return value.split(','); } return value; } public toString(value: any, type: TType = 'string'): any { // tslint:disable-next-line: restrict-plus-operands return '' + value; } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/index.ts ================================================ import {DefaultParamSerializer} from './default-param-serializer'; import {PythonParamSerializer} from './python-param-serializer'; export {ParamSerializer, ITokenizedParam} from './param-serializer'; export function paramSerializerFactory(type) { switch (type) { case 'python': return new PythonParamSerializer(); default: return new DefaultParamSerializer(); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/param-serializer.ts ================================================ import {TType, IParam} from '../param-types'; export interface ITokenizedParam { match: string; key: string; type: TType; value: any; isAutoParam: boolean; isKeyOnlyParam: boolean; options: string[]; } export abstract class ParamSerializer { // serialization pipileine public abstract untransform(param: ITokenizedParam): ITokenizedParam; public abstract detokenize(param: ITokenizedParam, serializationType: 'serialize' | 'value'): any[]; public abstract unconvert(param: any[], type: TType): string[]; public abstract stringify(param: any[]): string; // parsing pipeline public abstract parse(text: string): Iterable; public abstract convert(param: string[]): any[]; public abstract tokenize(param: any[]): ITokenizedParam; public abstract transform(param: ITokenizedParam): ITokenizedParam; /** * Generates an embed string */ public abstract embed(text: string, params: IParam[]): string; /** * Extracts the embed string */ public abstract extract(text: string, options?: {[key: string]: any}): string; /** * Converts value to js */ public abstract toJs(value: string, type: TType): any; /** * Converts value to string */ public abstract toString(value: any, type?: TType): any; /** * Ranges of rows to lock */ public abstract getLockRange(text: string): [number, number][]; /** * Returns a serialized param */ public serialize(param: ITokenizedParam, serializationType: 'serialize' | 'value' = 'serialize'): string { return this.stringify(this.unconvert(this.detokenize(this.untransform(param), serializationType), param.type)); } /** * Params iterator */ public params(text: string): Iterable { return Array.from(this.parse(text)).map(param => this.transform(this.tokenize(this.convert(param)))); } /** * Params iterator */ public removeEmbed(text: string): string { return text.replace(this.extract(text), ''); } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/python-param-serializer.ts ================================================ import {isArray, isPlainObject, assign} from 'lodash'; import {IParam, AUTO_PARAMS, TType} from '../param-types'; import {ParamSerializer, ITokenizedParam} from './param-serializer'; const EMBED_PREFIX = '# AUTOGENERATED {'; const EMBED_SUFFIX = '# AUTOGENERATED END }'; const CUSTOM_FN_DEF = 'def __custom__():'; const CUSTOM_FN_CALL = '__custom__()'; const INIT_FN_DEF = 'def __init__(c):'; const INIT_FN_CALL = '__init__(False)'; const CUSTOM_REGEX = `(${CUSTOM_FN_DEF.replace(/(\(|\))/g, '\\$1')})([\\s\\S]+)(${INIT_FN_DEF.replace(/(\(|\))/g, '\\$1')})`; const EMBED_REGEX = `^${EMBED_PREFIX}[\\s\\S]+${EMBED_SUFFIX}\\n`; const PARAM_REGEX = `\\((?:"([a-zA-Z0-9_]+)","([a-z]+)",(.+?),(\\[.*?\\]))\\)|(\\("(${AUTO_PARAMS.join('|')})",None,(?:(?:"\\$[a-zA-Z_]+")|None),\\[[^\\[\\]]*\\]\\))`; const PARAMS_VAR = 'p'; const PYTHON_TO_JS = { None: null, True: true, False: false }; const PYTHON_TO_JS_BY_TYPE = { list: { '\\(': '[', '\\)': ']' } }; const JS_TO_PYTHON = { null: 'None', true: 'True', false: 'False' }; const JS_TO_PYTHON_BY_TYPE = { list: { '\\[': '(', '\\]': ')' } }; function transform(value, transformations) { return Object.keys(transformations).reduce((res, k) => res.replace(new RegExp(`(${k})`, 'g'), transformations[k]), value); } function getSerializedParamsText(serializedParams: string[]) { return `${PARAMS_VAR} = [${serializedParams}]`; } function getEmbedText(params: IParam[], serializedParams: any[]): string { return `${EMBED_PREFIX} def __param__(key, options, value = None): _fields('k', 'o', 'v') _row(key, options, value) ${CUSTOM_FN_DEF} pass ${INIT_FN_DEF} ${getSerializedParamsText(serializedParams)} if c: ${CUSTOM_FN_CALL} return {t[0]: t[2] for t in ${PARAMS_VAR}} q = ${INIT_FN_CALL} ${EMBED_SUFFIX} `; } export class PythonParamSerializer extends ParamSerializer { public *parse(text: string): Iterable { const regex = new RegExp(PARAM_REGEX, 'g'); let param = null; // tslint:disable-next-line: no-conditional-assignment while ((param = regex.exec(this.extract(text)))) { yield param; } } public stringify(param: any[]): string { return `(${param})`; } public convert([match, key, type, value, options, autoParamMatch, autoParamKey]: string[]): any[] { value = this.toJs(value, type as TType); options = (options && this.toJs(options, 'list')) || []; return [match, key, type, value, options, autoParamMatch, autoParamKey]; } public unconvert(param: any[], type: TType): string[] { return param.map(p => this.toString(p, type)); } public tokenize([match, key, type, value, options, autoParamMatch, autoParamKey]: any[]): ITokenizedParam { let isAutoParam = false; const isKeyOnlyParam = false; if (autoParamMatch) { match = autoParamMatch; key = autoParamKey; isAutoParam = true; } return {match, key, value, type, isAutoParam, isKeyOnlyParam, options}; } public detokenize({key, type, value, isAutoParam, options}: ITokenizedParam, serializationType: 'serialize' | 'value' = 'serialize'): any[] { let res; switch (serializationType) { case 'serialize': if (isAutoParam) { res = [key, null, `$${key}`, []]; } else { res = [key, type, value, options]; } break; case 'value': res = [key, null, value, null]; break; default: } return res; } public transform(param: ITokenizedParam): ITokenizedParam { return param; } public untransform(param: ITokenizedParam): ITokenizedParam { return param; } public embed(text: string, params: IParam[]): string { let res = getEmbedText(params, params.map(param => this.serialize(param as ITokenizedParam))); const custom = new RegExp(CUSTOM_REGEX).exec(text); if (custom) { res = res.replace(new RegExp(CUSTOM_REGEX), `$1${custom[2]}$3`); } return res; } public extract(text: string, options = {runCustom: false}): string { const match = new RegExp(EMBED_REGEX).exec(text); let res = ''; if (!match) { return res; } res = match[0]; if (options.runCustom) { res = res.replace(INIT_FN_CALL, INIT_FN_CALL.replace(this.toString(false), this.toString(true))); } return res; } public getLockRange(text: string): [number, number][] { const range = []; const rows = this.extract(text).split('\n'); for (let i = 0; i < rows.length; i++) { const row = rows[i]; if (row.includes(CUSTOM_FN_DEF)) { range.push([0, i]); } else if (row.includes(INIT_FN_DEF)) { range.push([i, rows.length - 2]); break; } } return range; } public toJs(value: string, type: TType): any { if (!value) { return value; } value = transform(value, assign({}, PYTHON_TO_JS, PYTHON_TO_JS_BY_TYPE[type])); return type === 'string' ? value.replace(/^"/, '').replace(/"$/, '') : JSON.parse(value); } public toString(value: any, type: TType = 'string'): string { if ((typeof value === 'boolean' || value === null) && typeof JS_TO_PYTHON[value] !== 'undefined') { return JS_TO_PYTHON[value]; } if (isArray(value)) { return `[${value.map(v => transform(this.toString(v), JS_TO_PYTHON_BY_TYPE.list))}]`; } if (isPlainObject(value)) { return `{${Object.keys(value).map(k => `"${k}":${this.toString(value[k])}`).join(',')}}`; } if (typeof value === 'string' && value.length) { if (JS_TO_PYTHON_BY_TYPE[type]) { value = transform(value, JS_TO_PYTHON_BY_TYPE[type]); } return JSON.stringify(value); } if (typeof value === 'number') { // tslint:disable-next-line: restrict-plus-operands return '' + value; } return 'None'; } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/param-types.ts ================================================ import BiDate from '../../../../lib/ui/services/date'; import {TPredefindListsTypes} from './params-predefined-types'; export const DATE_FORMAT = BiDate.DATE_FORMAT.replace(/\//g, '-'); export type TType = 'string' | 'number' | 'boolean' | 'option' | 'list' | 'datetime' | 'text'; export const TYPES: TType[] = ['string', 'number', 'boolean', 'option', 'list', 'datetime', 'text']; export type TUserSelectableTypes = TPredefindListsTypes | TType; export const TYPE_DEFAULTS = { string: null, number: null, boolean: null, option: null, list: [], datetime: null, text: null }; export const AUTO_PARAMS = [ 'START_TIME', 'STOP_TIME', ]; export const AUTO_PARAM_TYPES = { START_TIME: 'datetime', STOP_TIME: 'datetime', }; export const AUTO_PARAM_DEFAULTS = { get START_TIME() { return new BiDate(new BiDate().asMoment().utc().subtract(2, 'days').startOf('day').valueOf()).fromUTC().format(DATE_FORMAT); }, get STOP_TIME() { return new BiDate(new BiDate().asMoment().utc().startOf('day').valueOf()).fromUTC().format(DATE_FORMAT); } }; export interface IParam { key: string; type: TType; value: any; isAutoParam: boolean; options?: string[]; } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/params-parser.ts ================================================ import { IParam, TType, TYPES, AUTO_PARAMS, TYPE_DEFAULTS, AUTO_PARAM_TYPES, AUTO_PARAM_DEFAULTS, TUserSelectableTypes } from './param-types'; import {TPredefindListsTypes, PREDEFINED_LISTS, PREDEFINED_LISTS_DATA} from './params-predefined-types'; import {ParamSerializer, ITokenizedParam} from './param-serializers'; export type IParamTransformer = (param: ITokenizedParam) => string; export type IParamReplacer = (text: string, oldParam: string, newParam: string) => string; function defaultReplacer(text: string, oldParam: string, newParam: string) { return text.replace(oldParam, newParam); } const isPredefinedListType = (type: TUserSelectableTypes): type is TPredefindListsTypes => PREDEFINED_LISTS.some(value => value === type); export class ParamParser { constructor(private readonly serializer: ParamSerializer) { } static TYPES: TUserSelectableTypes[] = [...TYPES, ...PREDEFINED_LISTS]; static AUTO_PARAMS = AUTO_PARAMS; /** * Iterates over params in text * By default, doesn't interate over more than one instance of param */ public *each(text: string, all: boolean = false): Iterable { const processed = {}; for (const param of this.serializer.params(text)) { if (!all && (param.isKeyOnlyParam || processed[param.key])) { continue; } processed[param.key] = true; yield param; } } /** * Iterates over all params in text */ private all(text: string): Iterable { return this.each(text, true); } /** * Iterates over params in text and replaces them */ private replace(text: string, transformer: IParamTransformer, replacer: IParamReplacer = defaultReplacer): string { return Array.from(this.all(text)).reduce((res, param) => replacer(res, param.match, transformer(param)), text); } /** * Indexes params by key */ private paramsByKey(params: IParam[]): {[key: string]: IParam} { return params.reduce((res, param: IParam) => { res[param.key] = param; return res; }, {}); } /********************************************** * PUBLIC **********************************************/ public getSerializer(): ParamSerializer { return this.serializer; } /** * Checks for differences between the params encoded in the text and the array of params */ public isSynced(params: IParam[], text: string): boolean { let res = true; const paramsByKey = this.paramsByKey(params); for (const {key, value, isAutoParam} of this.all(text)) { if (!isAutoParam && (!paramsByKey[key] || paramsByKey[key].value !== value)) { res = false; break; } } return res; } /** * Embeds params into text */ public embed(text, params: IParam[], replacer: IParamReplacer = defaultReplacer): string { const embeded = this.serializer.extract(text); if (!embeded) { return params.length ? replacer(text, text, `${this.serializer.embed(text, params)}${text}`) : text; } return replacer(text, embeded, params.length ? this.serializer.embed(text, params) : ''); } /** * Creates an array of params encoded in the text */ public params(text: string, {customParamsEnabled} = {customParamsEnabled: true}, params: IParam[] = []): IParam[] { const paramsByKey = this.paramsByKey(params); return Array.from(this.each(text)).reduce((res, {key, value, type, isAutoParam, options}) => { if (!isAutoParam && !customParamsEnabled) { return res; } res.push(this.createParam(key, type, isAutoParam && paramsByKey[key] ? paramsByKey[key].value : value, options)); return res; }, []); } /** * Updates params encoded in the text with values in the params array * Returns lock ranges */ public sync(text: string, params: IParam[], {customParamsEnabled} = {customParamsEnabled: true}, replacer: IParamReplacer = defaultReplacer): [number, number][] { let res = this.embed(text, params, replacer); const paramsByKey = this.paramsByKey(params); res = this.replace(res, param => { if (!paramsByKey[param.key] || (!param.isAutoParam && !customParamsEnabled)) { return param.match; } return this.serializer.serialize({...param, ...paramsByKey[param.key] || {}}); }, replacer); return this.serializer.getLockRange(res); } /** * Replaces params in text with their respective values */ public format(text: string, params: IParam[], options = {customParamsEnabled: true, keepEmbed: false}): string { if (!text) { return text; } const res = options.keepEmbed ? text : this.embed(text, []); const paramsByKey = this.paramsByKey(params); return this.replace(res, param => { if (!paramsByKey[param.key] || (!param.isAutoParam && !options.customParamsEnabled)) { return param.match; } return this.serializer.serialize({...param, ...paramsByKey[param.key] || {}}, 'value'); }); } public createParam(key: string, type: TUserSelectableTypes = 'string', value: any, options?: string[]): IParam { const isAutoParam = AUTO_PARAMS.indexOf(key) !== -1; type = isAutoParam ? AUTO_PARAM_TYPES[key] : type || 'string'; if (isAutoParam) { type = AUTO_PARAM_TYPES[key]; value = value || AUTO_PARAM_DEFAULTS[key]; } const actualType: TType = isPredefinedListType(type) ? 'list' : type; if (isPredefinedListType(type)) { options = PREDEFINED_LISTS_DATA[type]; } if (typeof value === 'undefined') { value = TYPE_DEFAULTS[type]; } return { key, type: actualType, value, isAutoParam, options }; } } ================================================ FILE: quix-frontend/client/src/lib/code-editor/services/param-parser/params-predefined-types.ts ================================================ export const PREDEFINED_LISTS_DATA = { browser_family: ['Chrome', 'Edge', 'Epiphany', 'Firefox', 'Internet Explorer', 'Maxthon', 'Mozilla', 'NativeMobile', 'Opera', 'Playstation Browser', 'Puffin Mobile', 'Safari', 'YaBrowser'], country_code: ['AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IQ', 'IR', 'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KM', 'KN', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NG', 'NI', 'NL', 'NO', 'NP', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TG', 'TH', 'TJ', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TW', 'TZ', 'UA', 'UG', 'US', 'UY', 'UZ', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'XK', 'YE', 'YT', 'ZA', 'ZM', 'ZW'], device_type: [ 'Mobile', 'Tablet', 'Unknown', 'Computer' ] }; export const PREDEFINED_LISTS: TPredefindListsTypes[] = []; export type TPredefindListsTypes = keyof typeof PREDEFINED_LISTS_DATA; ================================================ FILE: quix-frontend/client/src/lib/core/ang/drv/bi-options.drv.ts ================================================ 'use strict'; import {lodash as _} from '../../utils'; import {get as inject} from '../../srv/injector'; export function biOptions() { const $parse: ng.IParseService = inject('$parse'); const $interpolate: ng.IInterpolateService = inject('$interpolate'); const NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+order\s+by\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?$/; // 1: value expression (valueFn) // 2: label expression (displayFn) // 3: group by expression (groupByFn) // 4: disable when expression (disableWhenFn) // 5: array item variable name // 6: object item key variable name // 7: object item value variable name // 8: collection expression // 9: track by expression function parseExpression(str: string) { const match = str.match(NG_OPTIONS_REGEXP); if (!(match)) { throw new Error('biOptions: bad expression "' + str + '"'); } // The variable name for the value of the item in the collection const valueName = match[5] || match[7]; // The variable name for the key of the item in the collection const keyName = match[6]; // An expression that generates the viewValue for an option if there is a label expression const selectAs = / as /.test(match[0]) && match[1]; // An expression that is used to track the id of each object in the options collection const trackBy = match[10]; // An expression that generates the viewValue for an option if there is no label expression const valueFn = $parse(match[2] ? match[1] : valueName); const selectAsFn = selectAs && $parse(selectAs); const viewValueFn = selectAsFn || valueFn; const trackByFn = trackBy && $parse(trackBy); const orderBy = match[9]; const orderByFn = orderBy && $parse(orderBy); const displayFn = $parse(match[2] || match[1]); const groupBy = match[3] || ''; const groupByFn = $parse(match[3] || ''); const disableWhen = match[4] || ''; const disableWhenFn = $parse(disableWhen); const values = match[8]; const valuesFn = $parse(values); return {valueName, keyName, selectAs, trackBy, valueFn, selectAsFn, viewValueFn, orderBy, orderByFn, trackByFn, displayFn, groupBy, groupByFn, disableWhen, disableWhenFn, valuesFn, values}; } function getLocals(options: {valueName: string}, value) { const locals = {}; locals[options.valueName] = value; return locals; } return { restrict: 'A', require: ['biOptions', 'ngModel'], scope: false, controller: ['$scope', '$attrs', function ($scope, $attrs) { const options = parseExpression($interpolate($attrs.biOptions)($scope)); let watcher = null; $scope.$watch(options.values, values => _.isFunction(watcher) && watcher(values)); this.hasGroupBy = function () { return !!options.groupBy; }; this.hasOrderBy = function () { return !!options.orderBy; }; this.hasTrackBy = function () { return !!options.trackBy; }; this.hasDisabledWhen = function () { return !!options.disableWhen; }; this.getKey = function () { return options.keyName; }; this.getItemName = function () { return options.valueName; }; this.getCollection = function () { return options.valuesFn($scope); }; this.groupBy = function (value) { return options.groupByFn($scope, getLocals(options, value)); }; this.isDisabled = function (value) { return options.disableWhenFn($scope, getLocals(options, value)); }; this.orderBy = function (value) { return options.orderByFn($scope, getLocals(options, value)); }; this.trackBy = function (value) { return options.trackByFn($scope, getLocals(options, value)); }; this.render = function (value) { return options.displayFn($scope, getLocals(options, value)); }; this.format = function (value) { if (!options.selectAsFn) { return value; } const collection = this.getCollection(); return (_.isArray(collection) && _.find(collection, item => { return options.selectAsFn($scope, getLocals(options, item)) === value; })) || value; }; this.parse = function (value) { if (!options.selectAsFn) { return value; } return options.selectAsFn($scope, getLocals(options, value)); }; this.eval = function (str, value) { return $parse(str)($scope, getLocals(options, value)); }; this.watch = function (fn) { watcher = fn; }; }] }; } ================================================ FILE: quix-frontend/client/src/lib/core/ang/drv/bi-validator.drv.ts ================================================ import {forEach} from 'lodash'; import {inject} from '../../'; import {IDirective, IQService, IParseService} from 'angular'; export default (): IDirective => { const $q: IQService = inject('$q'); const $parse: IParseService = inject('$parse'); return { restrict: 'A', require: 'ngModel', link(scope: ng.IScope, element, attrs, ngCtrl) { const ngModel = ngCtrl as ng.INgModelController; const validators = $parse(attrs.validators)(scope); const asyncValidators = $parse(attrs.asyncValidators)(scope); const validatorsPromise = $q.when(validators || {}); const asyncValidatorsPromise = $q.when(asyncValidators || {}); ngModel.$validators = ngModel.$validators || {}; ngModel.$asyncValidators = ngModel.$asyncValidators || {}; asyncValidatorsPromise.then(vals => { forEach(vals, (validator, name: string) => ngModel.$asyncValidators[name] = validator); }); validatorsPromise.then(vals => { forEach(vals, (validator, name: string) => ngModel.$validators[name] = validator); }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/core/ang/srv/ng-model/ng-model-test.drv.ts ================================================ 'use strict'; import {create as createNgModel} from './ng-model'; /* @ngInject */ export function ngModelTest() { return { template: 'create-model-test', restrict: 'E', require: 'ngModel', scope: { template: '=', formatter: '&', parser: '&', validator: '&', asyncValidator: '&', renderer: '&', watcher: '&', then: '&', keepReference: '=', watchDeep: '=' }, link: function postLink(scope, element, attrs, ngModel) { createNgModel(scope, ngModel) .fromTemplate(scope.template) .formatWith(scope.formatter()) .parseWith(scope.parser()) .validateWith(scope.validator()) .validateAsyncWith(scope.asyncValidator()) .renderWith(scope.renderer()) .watchWith(scope.watcher()) .keepReference(scope.keepReference) .watchDeep(scope.watchDeep) .then(scope.then()); scope.ngModel = ngModel; } }; } ================================================ FILE: quix-frontend/client/src/lib/core/ang/srv/ng-model/ng-model.test.ts ================================================ 'use strict'; import * as angular from 'angular'; import {ngModelTest} from './ng-model-test.drv'; describe('bi.core.drv.createModel()', function () { let scope, $rootScope, $compile, $timeout, $q: angular.IQService; function createModel(params) { let {data, template, formatter, parser, validator, asyncValidator, renderer, watcher, keepReference, watchDeep, then} = (params || {}); let scope = $rootScope.$new(); let directiveScope; scope.data = data; scope.template = template; scope.formatter = formatter; scope.parser = parser; scope.asyncValidator = asyncValidator; scope.validator = validator; scope.renderer = renderer; scope.watcher = watcher; scope.keepReference = keepReference; scope.watchDeep = watchDeep; scope.then = then; const element = angular.element(''); $compile(element)(scope); directiveScope = element.isolateScope(); $rootScope.$digest(); $timeout.flush(); return { get data() { return scope.data; }, set data(_data) { scope.data = _data; }, get directiveData() { return directiveScope.model; }, set directiveData(data) { directiveScope.model = data; }, get ngModel() { return directiveScope.ngModel; } }; } beforeAll(() => { angular .module('bi.core') .directive('createModelTest', ngModelTest); }); beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$rootScope_, _$compile_, _$timeout_, _$q_) { scope = _$rootScope_.$new(); $compile = _$compile_; $rootScope = _$rootScope_; $timeout = _$timeout_; $q = _$q_; })); describe('createModel', function () { describe('creation', function () { it('should be undefined if no data and template were set', function () { const model = createModel({}); expect(model.data).toEqual(undefined); expect(model.directiveData).toEqual(undefined); }); it('should use the data object as is if template is undefined', function () { const data = {a: 1}; const model = createModel({data}); expect(model.data).toEqual(data); expect(model.directiveData).toEqual(data); }); it('should create a model with the provided data and null template', function () { const data = {a: 1}; const model = createModel({data}); expect(model.data).toEqual(data); expect(model.directiveData).toEqual(data); }); it('should populate undefined model with template values', function () { const template = {a: 1}; const model = createModel({template}); expect(model.data).toEqual(template); expect(model.directiveData).toEqual(template); }); it('should populate null model with template values', function () { const template = {a: 1}; const model = createModel({template, data: null}); expect(model.data).toEqual(template); expect(model.directiveData).toEqual(template); }); it('should populate empty model with template values', function () { const data = {}; const template = {a: 1}; const model = createModel({data, template}); expect(model.data).toEqual(template); expect(model.directiveData).toEqual(template); }); it('should fill model with default template values', function () { const data = {a: 0}; const template = {a: 1, b: []}; const model = createModel({data, template}); expect(model.data).toEqual({a: 0, b: []}); expect(model.directiveData).toEqual({a: 0, b: []}); }); it('should support nesting', function () { let data = {a: 0, b: {d: 4}}; const template = {a: 1, b: {c: 3, d: 4}}; let model = createModel({data, template}); expect(model.data).toEqual({a: 0, b: {c: 3, d: 4}}); expect(model.directiveData).toEqual({a: 0, b: {c: 3, d: 4}}); data = {a: 0, b: {d: 4}}; model = createModel({data, template: {a: 1, b: null}}); expect(model.data).toEqual({a: 0, b: {d: 4}}); expect(model.directiveData).toEqual({a: 0, b: {d: 4}}); }); }); describe('original model reference', function () { it('should not keep the reference by default', function () { const data = {a: 1}; const model = createModel({data}); expect(model.data).not.toBe(data); expect(model.data).toEqual(data); expect(model.directiveData).not.toBe(data); expect(model.directiveData).toEqual(data); }); it('should not keep the reference', function () { const data = {a: 1}; const model = createModel({data, keepReference: false}); expect(model.data).not.toBe(data); expect(model.data).toEqual(data); expect(model.directiveData).not.toBe(data); expect(model.directiveData).toEqual(data); }); it('should keep the reference (with data)', function () { const data = {a: 1}; const model = createModel({data, keepReference: true}); expect(model.directiveData).toBe(data); expect(model.directiveData).toBe(model.data); }); it('should keep the reference (with template)', function () { const template = {a: 1}; const model = createModel({template, keepReference: true}); expect(model.directiveData).toBe(model.data); }); it('should keep the reference (with parser)', function () { const data = {a: 1}; const model = createModel({ data, parser(model) { return {a: 2}; }, keepReference: true }); expect(model.data).toBe(data); expect(model.data).toEqual({a: 2}); }); it('should keep the reference (with formatter)', function () { const data = {a: 1}; const model = createModel({ data, formatter(model) { return {a: 2}; }, keepReference: true }); expect(model.data).toBe(data); expect(model.data).toEqual({a: 2}); }); it('should not override primitive values', function () { const data = 1; const model = createModel(data); model.directiveData = 2; $rootScope.$digest(); expect(model.data).toBe(2); expect(model.directiveData).toBe(2); }); }); describe('changing directive model reference', function () { it('should change the model accordingly', function () { const data = {a: 1}; const model = createModel({data}); model.directiveData = {a: 2}; $rootScope.$digest(); expect(model.data).toEqual({a: 2}); expect(model.directiveData).toEqual({a: 2}); }); it('should call model.$clone method if it is defined', function () { const clonedData = {a: 2}; const data = {a: 1}; const model = createModel({data}); model.directiveData = { $clone: function () { return clonedData; } }; $rootScope.$digest(); expect(model.data).toBe(clonedData); }); }); describe('changing directive model property', function () { it('should not change the model', function () { const data = {a: 1}; const model = createModel({data}); model.directiveData.a = 2; $rootScope.$digest(); expect(model.data).toEqual({a: 1}); expect(model.directiveData).toEqual({a: 2}); }); }); describe('changing model reference', function () { it('should change the directive model accordingly', function () { const data = {a: 1}; const model = createModel({data, template: {a: null}}); model.data = {a: 2}; $rootScope.$digest(); expect(model.data).toEqual({a: 2}); expect(model.directiveData).toEqual({a: 2}); }); }); describe('formatter', function () { it('should format the data with provided formatter', function () { const data = {a: 1}; const formatter = jasmine.createSpy('formatter').and.returnValue({a: 2}); const model = createModel({data, formatter}); expect(model.data).toEqual({a: 2}); expect(model.directiveData).toEqual({a: 2}); }); it('should keep class structure when formatting the data with provided formatter', function () { const data = {a: 1}; class DemoClass { private a; constructor(data) { this.a = data.a + 1; } foobar() { return this.a; } } const formatter = { formatter: (model) => new DemoClass(model) }; spyOn(formatter, 'formatter').and.callThrough(); const model = createModel({data, formatter: formatter.formatter}); expect(formatter.formatter).toHaveBeenCalled(); expect(model.data).toEqual({a: 2}); expect(model.directiveData.foobar()).toEqual(2); }); }); describe('parser', function () { it('should parse the model with provided parser', function () { const data = {a: 1}; const parser = jasmine.createSpy('parser').and.returnValue({a: 2}); const model = createModel({data, parser}); expect(model.data).toEqual({a: 2}); expect(model.directiveData).toEqual({a: 1}); }); }); describe('formatter + parser', function () { it('should format and parse the model', function () { const data = {a: 1}; const formatter = jasmine.createSpy('formatter').and.returnValue({a: 2}); const parser = jasmine.createSpy('parser').and.returnValue({a: 3}); const model = createModel({data, formatter, parser}); expect(model.data).toEqual({a: 3}); expect(model.directiveData).toEqual({a: 2}); }); }); describe('validator', function () { it('should validate the data with provided validator', function () { const data = {a: 1}; const testValidator = jasmine.createSpy('testValidator'); const validator = function () { return { testValidator: testValidator }; }; createModel({data, validator}); expect(testValidator).toHaveBeenCalled(); }); it('should set model to be "undefined" if validation fails', function () { const data = {a: 1}; const testValidator = jasmine.createSpy('testValidator').and.returnValue(false); const validator = function () { return { testValidator: testValidator }; }; const model = createModel({data, validator}); expect(model.data).toBeUndefined(); expect(model.directiveData).toEqual(data); }); it('should preserve the model if validation succeeds', function () { const data = {a: 1}; const testValidator = jasmine.createSpy('testValidator').and.returnValue(true); const validator = function () { return { testValidator: testValidator }; }; const model = createModel({data, validator}); expect(model.data).toEqual(data); expect(model.directiveData).toEqual(data); }); it('should trigger validation after model reference change', function () { const data = {a: 1}; const testValidator = jasmine.createSpy('testValidator').and.callFake(function (model) { return model.valid; }); const validator = function () { return { testValidator: testValidator }; }; const model = createModel({data, validator}); model.directiveData = {a: 1}; $rootScope.$digest(); expect(model.data).toBeUndefined(); expect(model.directiveData).toEqual({a: 1}); }); }); describe('asyncValidator', function () { it('should validate the data with provided validator', function (done) { const data = {a: 1}; const deferred = $q.defer(); const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise); const asyncValidator = () => ({testValidator}); createModel({data, asyncValidator}); deferred.resolve(true); deferred.promise.finally(() => { expect(testValidator).toHaveBeenCalled(); done(); }); $rootScope.$apply(); }); it('should set model to be "undefined" if validation fails', function (done) { const data = {a: 1}; const deferred = $q.defer(); const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise); const asyncValidator = () => ({testValidator}); const model = createModel({data, asyncValidator}); deferred.reject(); $rootScope.$digest(); deferred.promise.finally(() => { expect(model.data).toBeUndefined(); expect(model.directiveData).toEqual(data); done(); }); $rootScope.$digest(); }); it('should preserve the model if validation succeeds', function (done) { const data = {a: 1}; const deferred = $q.defer(); const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise); const asyncValidator = () => ({testValidator}); const model = createModel({data, asyncValidator}); deferred.resolve(); $rootScope.$digest(); deferred.promise.finally(() => { expect(model.data).toEqual(data); expect(model.directiveData).toEqual(data); done(); }); $rootScope.$digest(); }); it('should trigger validation after model reference change', function (done) { const data = {a: 1}; const deferred = $q.defer(); const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise); const asyncValidator = () => ({testValidator}); const model = createModel({data, asyncValidator}); deferred.reject(); $rootScope.$digest(); model.directiveData = {a: 1}; $rootScope.$digest(); deferred.promise.finally(() => { expect(testValidator.calls.count()).toEqual(3); expect(model.data).toBeUndefined(); expect(model.directiveData).toEqual({a: 1}); done(); }); $rootScope.$digest(); }); }); describe('watcher', function () { it('should run when the model is created', function () { const data = {a: 1}; const watcher = jasmine.createSpy('testWatcher'); createModel({data, watcher}); expect(watcher).toHaveBeenCalledWith(data, data); }); it('should run the watcher every time the model reference changes', function () { const data = {a: 1}; const watcher = jasmine.createSpy('testWatcher'); const model = createModel({data, watcher}); model.directiveData = {a: 1}; $rootScope.$digest(); expect(watcher).toHaveBeenCalledWith({a: 1}, {a: 1}); }); }); describe('renderer', function () { it('should run when the model is created', function () { const data = {a: 1}; const renderer = jasmine.createSpy('testRenderer'); createModel({data, renderer}); expect(renderer).toHaveBeenCalledWith(data); }); }); describe('unique id', function () { it('should assign unique id to array items (no template)', function () { const data = {a: [{}]}; const model = createModel({data}); expect(model.data.a[0].$id).toBeDefined(); }); it('should assign unique id to the model (with template)', function () { const data = {a: [{}]}; const template = {a: []}; const model = createModel({data, template}); expect(model.data.a[0].$id).toBeDefined(); }); it('should ingore primitive values', function () { const data = {a: [1]}; const model = createModel({data}); expect(model.data.a[0]).toBe(1); }); it('should ingore null values', function () { const data = {a: [null]}; const model = createModel({data}); expect(model.data.a[0]).toBe(null); }); it('should preserve the original id and reference', function () { const data = {$id: 1}; const model = createModel({data}); model.directiveData = {a: 2}; $rootScope.$digest(); expect(model.data).toBe(data); expect(model.data).toEqual({$id: 1, a: 2}); }); it('should not preserve the original reference (no id)', function () { const data = {}; const model = createModel({data}); model.directiveData = {a: 2}; $rootScope.$digest(); expect(model.data).not.toBe(data); expect(model.data).toEqual({a: 2}); }); it('should not preserve the original reference (id + keepReference === false)', function () { const data = {$id: 1}; const model = createModel({data, keepReference: false}); model.directiveData = {a: 2}; $rootScope.$digest(); expect(model.data).not.toBe(data); expect(model.data).toEqual({a: 2}); }); }); describe('watchDeep', function () { it('should deep watch the model', function () { const data = {a: 1}; const model = createModel({data, watchDeep: true}); model.directiveData.a = 2; $rootScope.$digest(); expect(model.data).toEqual({a: 2}); }); it('should not deep watch the model', function () { const data = {a: 1}; const model = createModel({data}); model.directiveData.a = 2; $rootScope.$digest(); expect(data).toEqual({a: 1}); }); }); describe('call then function', function () { it('should call function in an async manner', function (done) { const then = function () { done(); }; const data = {a: 1}; createModel({data, then}); $rootScope.$digest(); }); }); describe('pristine state', function () { it('should leave ngModel in pristine state on initial change', function () { const data = {a: 1}; const model = createModel({data}); $rootScope.$digest(); expect(model.ngModel.$dirty).toBe(false); }); it('should not set ngModel to pristine state after making changes', function () { const data = {a: 1}; const model = createModel({data}); $rootScope.$digest(); model.directiveData = {a: 2}; $rootScope.$digest(); expect(model.ngModel.$dirty).toBe(true); }); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/ang/srv/ng-model/ng-model.ts ================================================ 'use strict'; /** * Core directive tools * * @author Our One Creator Which Flies and is Spaghetti and a Monster */ import {lodash as _} from '../../../utils'; export interface OptionalCloneable { $clone?(): T; } export interface IScope extends angular.IScope { model: T; } const tools = { createItem(item: any = {}) { if (!_.isPlainObject(item)) { return item; } item.$id = item.$id || _.uniqueId('model'); return item; }, defaultsDeep(data, defaults) { let res; if (typeof defaults === 'undefined') { return data; } if (_.isArray(defaults) || _.isArray(data)) { res = _.isArray(data) ? data : defaults; res = res.map(item => this.createItem(_.cloneDeep(item))); } else if (_.isPlainObject(defaults)) { res = _.defaults({}, data, defaults); _.forOwn(res, (value, key) => { res[key] = this.defaultsDeep(value, defaults[key]); }); } else { res = typeof data !== 'undefined' ? data : defaults; } return res; } }; export class ModelConf { public template; public formatter; public parser; public validator; public validatorAsync; public renderer; public watcher; public doThen; public opts = { watchDeep: false, log: false, feedBack: true }; fromTemplate(template): ModelConf { this.template = template; return this; } formatWith(formatter: (model) => any): ModelConf { this.formatter = formatter; return this; } parseWith(parser: (model) => any): ModelConf { this.parser = parser; return this; } validateWith(validator: () => Object): ModelConf { this.validator = validator; return this; } validateAsyncWith(validator: () => Object): ModelConf { this.validatorAsync = validator; return this; } renderWith(renderer: (model) => void): ModelConf { this.renderer = renderer; return this; } watchWith(watcher: (model, prevModel) => void): ModelConf { this.watcher = watcher; return this; } watchDeep(val: boolean): ModelConf { this.opts.watchDeep = val; return this; } feedBack(val: boolean): ModelConf { this.opts.feedBack = val; return this; } log(): ModelConf { this.opts.log = true; return this; } then(doThen: Function): ModelConf { this.doThen = doThen; return this; } } export class Model> { private feedBack = false; constructor(private readonly scope: IScope, private readonly ngModel: angular.INgModelController, private readonly conf: ModelConf) { this.initFormat(); this.initRender(_.once(() => { this.initWatch(); this.initParse(); this.initValidate(); if (_.isFunction(conf.doThen)) { conf.doThen(); } })); } private initFormat() { this.ngModel.$formatters.push(model => { if (this.conf.opts.log) { // tslint:disable-next-line: no-console console.log('Formatting from', model); } let res = tools.defaultsDeep(model, this.conf.template || model); res = this.conf.formatter ? this.conf.formatter(model) : model; if (this.conf.opts.log) { // tslint:disable-next-line: no-console console.log('Formatted to', res); } return res; }); } private initRender(then) { this.ngModel.$render = () => { this.scope.model = this.ngModel.$viewValue; if (this.conf.renderer) { this.conf.renderer(this.scope.model); } if (this.conf.opts.log) { // tslint:disable-next-line: no-console console.log('Rendering', this.scope.model); } this.feedBack = false; then(); }; } private initWatch() { let isFirst = true; this.scope.$watch('model', (model, prevModel) => { const data = this.scope.model && this.scope.model.$clone ? this.scope.model.$clone() : _.clone(this.scope.model); if (this.conf.opts.log) { // tslint:disable-next-line: no-console console.log('Watching', this.scope.model, data, {isFirst, feedBack: this.feedBack}); } if (this.feedBack || (isFirst && this.conf.opts.feedBack)) { this.ngModel.$setViewValue(data); } if (isFirst) { this.ngModel.$setPristine(); } if (this.conf.watcher) { this.conf.watcher(model, prevModel); } isFirst = false; this.feedBack = true; }, !!this.conf.opts.watchDeep); } private initParse() { this.ngModel.$parsers.push(model => { if (this.conf.opts.log) { // tslint:disable-next-line: no-console console.log('Parsing from', model); } const res = this.conf.parser ? this.conf.parser(model) : model; if (this.conf.opts.log) { // tslint:disable-next-line: no-console console.log('Parsed', res); } return res; }); } private initValidate() { if (this.conf.validator) { _.forOwn(this.conf.validator(), (fn, name) => { this.ngModel.$validators[name] = fn; }); } if (this.conf.validatorAsync) { _.forOwn(this.conf.validatorAsync(), (fn, name) => { this.ngModel.$asyncValidators[name] = fn; }); } } } export function create(scope: IScope, ngModel: angular.INgModelController): ModelConf { const conf = new ModelConf(); // tslint:disable-next-line: no-unused-expression-chai new Model(scope, ngModel, conf); return conf; } export const createItem = tools.createItem; ================================================ FILE: quix-frontend/client/src/lib/core/ang/srv/scope/index.ts ================================================ export {init, ScopeHelper} from './scope'; ================================================ FILE: quix-frontend/client/src/lib/core/ang/srv/scope/scope.test.ts ================================================ 'use strict'; import {ViewModel} from '../../../srv/view-model/view-model'; import {init as initScope} from './scope'; import * as angular from 'angular'; describe('Scope: scopeHelper', function () { beforeEach(function () { angular.mock.module('bi.core.internal'); }); let $rootScope, $location, $browser, $q, $timeout; beforeEach(inject(function (_$rootScope_, _$location_, _$browser_, _$q_, _$timeout_) { $rootScope = _$rootScope_; $location = _$location_; $browser = _$browser_; $q = _$q_; $timeout = _$timeout_; })); describe('withEvents()', function () { it('should define actions on scope for read and edit modes', function () { const scope: any = {}; const events = {onClick: angular.noop}; initScope(scope).withEvents(events); expect(scope.events.onClick).toBe(events.onClick); }); }); describe('withEditableEvents()', function () { it('should define actions on scope for edit mode only', function () { const scope: any = {}; const events = {onClick: angular.noop}; initScope(scope).readonly(true).withEditableEvents(events); expect(scope.events.onClick).toBeUndefined(); }); }); describe('events', function () { it('should set both event types', function () { const scope: any = {}; initScope(scope) .withEvents({onSelect: angular.noop}) .withEditableEvents({onClick: angular.noop}); expect(scope.events.onSelect).toBeDefined(); expect(scope.events.onClick).toBeDefined(); }); }); describe('withActions()', function () { it('should define actions on scope for read and edit modes', function () { const scope: any = {}; const actions = {toggle: angular.noop}; initScope(scope).withActions(actions); expect(scope.actions.toggle).toBe(actions.toggle); }); }); describe('withEditableActions()', function () { it('should define actions for edit mode only', function () { const scope: any = {}; const actions = {toggle: angular.noop}; initScope(scope).readonly(true).withEditableActions(actions); expect(scope.actions.toggle).toBeUndefined(); }); }); describe('actions', function () { it('should set both action types', function () { const scope: any = {}; initScope(scope) .withActions({select: angular.noop}) .withEditableActions({click: angular.noop}); expect(scope.actions.select).toBeDefined(); expect(scope.actions.click).toBeDefined(); }); }); describe('withVM()', function () { it('should define vm object on scope', function () { const scope: any = {}; initScope(scope).withVM({test: true}); expect(scope.vm.test).toBe(true); }); it('should persist the vm by assigning it to the $vm scope variable', function () { const scope: any = {}; initScope(scope).withVM({test: true}); expect(scope.vm.test).toBe(true); expect(scope.$vm.test).toBe(true); }); it('should use and init the scope.$vm view model', function () { const scope: any = { $vm: { init: jasmine.createSpy('scope.$vm.init') } }; initScope(scope).withVM({}); expect(scope.vm).toBe(scope.$vm); expect(scope.$vm.init).toHaveBeenCalled(); }); it('should define model as custom VM param', function () { const scope: any = { model: {} }; initScope(scope).withVM({}); expect(scope.vm.$params.model).toBe(scope.model); }); it('should define ngModel.$modelValue and ngModel.$viewValue as custom VM param', function () { const scope: any = {}; const ngModel = { $modelValue: {}, $viewValue: {} }; initScope(scope, {ngModel}).withVM({}); expect(scope.vm.$params.modelValue).toBe(ngModel.$modelValue); expect(scope.vm.$params.viewValue).toBe(ngModel.$viewValue); }); it('should define custom VM params', function () { const scope: any = {}; const params = { foo: 1, goo: 2 }; initScope(scope).withVM({}, params); expect(scope.vm.$params.foo).toBe(1); expect(scope.vm.$params.goo).toBe(2); }); it('should throw errors when using ngModel.$modelValue and ngModel.$viewValue if ngModel controller was not passed', function () { const scope: any = {}; initScope(scope).withVM({}); expect(function () { return scope.vm.$params.modelValue; }).toThrow('scopeHelper: ngModel controller is required when accesing vm.$params.modelValue'); expect(function () { return scope.vm.$params.viewValue; }).toThrow('scopeHelper: ngModel controller is required when accesing vm.$params.viewValue'); }); }); describe('withErrors()', function () { it('should set messages on the errors controller', function () { const scope: any = {}; const errors = { setMessages: jasmine.createSpy('controllers.errors') }; const messages = [{ name: 'required', text: 'Value is required' }]; initScope(scope, {errors}).withErrors(messages); expect(errors.setMessages).toHaveBeenCalledWith(messages); }); }); describe('readonly()', function () { it('should not set events and actions in readonly mode', function () { const scope: any = {}; initScope(scope).readonly(true) .withEditableEvents({foo: angular.noop}) .withEditableActions({foo: angular.noop}); expect(scope.events.foo).toBeUndefined(); expect(scope.actions.foo).toBeUndefined(); }); }); describe('thenIfNotReadonly()', function () { it('should run when not readonly', function () { const scope: any = {}; const fn = jasmine.createSpy('not readonly'); initScope(scope) .thenIfNotReadonly(fn); expect(fn).toHaveBeenCalled(); }); it('should not run when readonly', function () { const scope: any = {}; const fn = jasmine.createSpy('not readonly'); initScope(scope) .readonly(true) .thenIfNotReadonly(fn); expect(fn).not.toHaveBeenCalled(); }); }); describe('withOptions()', function () { it('should set default options when no options where passed', function () { const scope: any = { testOptions: undefined }; initScope(scope) .withOptions(scope.testOptions, { opt1: true }); expect(scope.options).toEqual({ opt1: true }); }); it('should set default options when options where passed', function () { const scope: any = { testOptions: { opt1: true } }; initScope(scope) .withOptions(scope.testOptions, { opt2: true }); expect(scope.options).toEqual({ opt1: true, opt2: true }); }); it('should support string as object name', function () { const scope: any = { testOptions: { opt1: true } }; initScope(scope) .withOptions('testOptions', { opt2: true }); expect(scope.options).toEqual({ opt1: true, opt2: true }); }); it('should deep watch options and update scope.options', function () { const scope = $rootScope.$new(); scope.testOptions = { opt1: true }; initScope(scope) .withOptions('testOptions', { opt1: true }, true); scope.testOptions.opt1 = false; $rootScope.$digest(); expect(scope.options).toEqual({ opt1: false }); }); it('should deep watch options and call handler when no options where passed', function () { const scope = $rootScope.$new(); const handler = jasmine.createSpy('watch handler'); scope.testOptions = undefined; initScope(scope) .withOptions('testOptions', { opt1: true }, handler); $rootScope.$digest(); expect(handler).toHaveBeenCalledWith({ opt1: true }, undefined); }); it('should deep watch options and call handler', function () { const scope = $rootScope.$new(); const handler = jasmine.createSpy('watch handler'); scope.testOptions = { opt1: true }; initScope(scope) .withOptions('testOptions', { opt1: true }, handler); $rootScope.$digest(); scope.testOptions = { opt1: false }; $rootScope.$digest(); expect(handler).toHaveBeenCalledWith({ opt1: false }, { opt1: true }); }); }); describe('withState', function () { let scope; function updateURL(url) { $location.url(url); $browser.poll(); } beforeEach(() => { window.localStorage.clear(); }); beforeEach(function () { scope = $rootScope.$new(); scope.vm = new ViewModel({ a: '1', b: '2', c: '3', nestedObj: { d: '4', $export: function () { return {d: this.d}; }, $import: function (params) { this.d = params.d; } }, $export: function () { return {a: this.a, b: this.b}; }, $import: function (params) { this.a = params.a; this.b = params.b; } }); }); it('should save and load variables from localStorage', function () { const expectedData = { a: '1', b: '2', c: '100', nestedObj: jasmine.objectContaining({ d: '4' }) }; initScope(scope).withState('testState', 'testClient', {doClientLoad: false}); scope.state.save(); ['a', 'b', 'c'].forEach(field => scope.vm[field] = '100'); scope.vm.nestedObj.d = 100; scope.state.load(); expect(scope.vm).toEqual(jasmine.objectContaining(expectedData)); }); it('should load variables from URL', function () { updateURL('/loc1?testState-data=testClient-a:2;'); initScope(scope).withState('testState', 'testClient', {doClientLoad: true}); expect(scope.vm.a).toEqual('2'); }); it('should handle doClientLoad passed as a promise', function (done) { const deferred = $q.defer(); updateURL('/loc1?testState-data=testClient-a:2;'); initScope(scope).withState('testState', 'testClient', {doClientLoad: deferred.promise}); expect(scope.vm.a).toEqual('1'); deferred.resolve(true); scope.$apply(); setTimeout(() => { expect(scope.vm.a).toEqual('2'); done(); }); }); it('should accept state from parent scope', function () { const scope2 = scope.$new(); scope.vm = new ViewModel({ a: '1', $export: function() { return {a: this.a}; }, $import: function(params) { this.a = params.a; } }); scope2.vm = new ViewModel({ $export: function() { return {b: this.b}; }, $import: function(params) { this.b = params.b; }, b: '2' }); initScope(scope).withState('testState', 'testClient1', {doClientLoad: false}); initScope(scope2).withState(scope.state, 'testClient2', {doClientLoad: false}); scope.state.save('testClient2'); scope2.vm.b = '3'; scope2.state.load(); expect(scope2.vm.b).toEqual('2'); }); it('should unregister on scope destroy', function () { scope.vm = {a: '1'}; initScope(scope).withState('testState', 'testClient', {doClientLoad: false}); spyOn(scope.state, 'unregister'); scope.$destroy(); expect(scope.state.unregister).toHaveBeenCalled(); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/ang/srv/scope/scope.ts ================================================ 'use strict'; import {ViewModel} from '../../../srv/view-model/view-model'; import {StateWrapper, StateWrapperOptions} from '../../../srv/state/state-wrapper'; import {lodash as _} from '../../../utils'; export class ScopeHelper { private _readonly = false; constructor(private readonly scope, private readonly controllers = {ngModel: null, errors: null}) { scope.events = {}; scope.actions = {}; } readonly(readonly) { this._readonly = readonly; return this; } withEvents(events = {}) { _.assign(this.scope.events, events); return this; } withEditableEvents(events = {}) { if (!this._readonly) { _.assign(this.scope.events, events); } return this; } withPermissionEvents(events: T, permissions: (eventName: keyof T) => boolean) { events = _.reduce(events, (res, fn, name) => { if (permissions(name)) { res[name] = fn; } return res; }, {}); this.withEvents(events); return this; } withActions(actions = {}) { _.assign(this.scope.actions, actions); return this; } withEditableActions(actions = {}) { if (!this._readonly) { _.assign(this.scope.actions, actions); } return this; } withVM(vm, params = {}) { if (this.scope.$vm) { vm = this.scope.$vm; } else { vm = _.isFunction(vm) ? new vm() : new ViewModel(vm); } const {scope, controllers} = this; /* clousre var for getters on the VM */ Object.defineProperty(params, 'model', { get() { return scope.model; } }); Object.defineProperty(params, 'modelValue', { get() { if (!controllers.ngModel) { throw new Error('scopeHelper: ngModel controller is required when accesing vm.$params.modelValue'); } return controllers.ngModel.$modelValue; } }); Object.defineProperty(params, 'viewValue', { get() { if (!controllers.ngModel) { throw new Error('scopeHelper: ngModel controller is required when accesing vm.$params.viewValue'); } return controllers.ngModel.$viewValue; } }); vm.init(params); this.scope.vm = this.scope.$vm = vm; return this; } withErrors(messages: any[]) { if (this.controllers.errors) { this.controllers.errors.setMessages(messages); } return this; } withOptions(options, defaults, watch?: any) { this.scope.options = _.defaults({}, typeof options === 'string' ? this.scope[options] : options, defaults); if (watch && typeof options === 'string') { this.scope.$watch(options, (opts, prevOptions) => { this.scope.options = _.defaults({}, opts, defaults); if (typeof watch === 'function') { watch(this.scope.options, prevOptions); } }, true); } return this; } withState(state: StateWrapper | string, clientName, options: StateWrapperOptions) { if (!state || !this.scope.vm) { return this; } const builder = StateWrapper.build() .withOptions(options) .withCustomTraverse(function (vm: ViewModel, callback, args) { vm.forEach(function (model) { callback(model, args); }); }).setClientName(clientName) .useObject(this.scope.vm); if (typeof state === 'string') { builder.withNewState(state); } else { builder.withState(state); } this.scope.state = builder.end(); this.scope.$on('$destroy', () => { this.scope.state.unregister(); }); return this; } thenIfNotReadonly(fn) { if (!this._readonly) { fn(); } return this; } } export function init(scope, {ngModel = null, errors = null} = {}) { return new ScopeHelper(scope, {ngModel, errors}); } ================================================ FILE: quix-frontend/client/src/lib/core/config/index.ts ================================================ export class Config { private options: Partial = {}; get() { return this.options; } set(options: Partial) { this.options = {...this.options as any, ...options as any}; } } ================================================ FILE: quix-frontend/client/src/lib/core/index.ts ================================================ /* This file is the bundle entry point */ import {Socket} from './srv/socket/socket'; import {BufferedCollection, Collection, PartitionedCollection} from './srv/collections'; import {EventEmitter} from './srv/event-emitter'; import {injector} from './srv/injector'; import {init} from './ang/srv/scope'; import {create, IScope as IScope_, Model} from './ang/srv/ng-model/ng-model'; import {create as createVM, ViewModel as ViewModel_} from './srv/view-model/view-model'; import * as biUtils from './utils'; import './main.angular'; export const utils = biUtils; export const srv = { collections: {BufferedCollection, Collection, PartitionedCollection}, Model, Socket, eventEmitter: { EventEmitter }, viewModel: { ViewModel: ViewModel_ }, injector }; export const initNgScope = init; export const createNgModel = create; export const inject = injector.get; export const createViewModel = createVM; export type IScope = IScope_; export {Config} from './config'; ================================================ FILE: quix-frontend/client/src/lib/core/main.angular.ts ================================================ import * as angular from 'angular'; import {biOptions} from './ang/drv/bi-options.drv'; import {default as biValidator} from './ang/drv/bi-validator.drv'; import {LocalStorage} from './srv/local-storage/local-storage'; angular.module('bi.core', []) .run(['$injector', ($injector: angular.auto.IInjectorService) => { window.dispatchEvent(new CustomEvent('biCore.injector.ready', {detail: $injector})); }]) .provider('biLocalStorage', () => { return { setPrefix(name) { LocalStorage.setPrefix(name); }, $get() { return new LocalStorage(); } }; }); if ((window as any).__biCoreLoaded) { console.warn('warning: multiple bi-core instances.'); } else { (window as any).__biCoreLoaded = true; } angular.module('bi.core') .directive('biOptions', biOptions) .directive('biValidator', biValidator); ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/buffered-collection.test.ts ================================================ import {Model} from '../../ang/srv/ng-model/ng-model'; import {BufferedCollection} from './buffered-collection'; import * as angular from 'angular'; describe('Collection: BufferedCollection', function () { let $rootScope; beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$rootScope_) { $rootScope = _$rootScope_; })); function createCollection(chunkSize?) { const collection = new BufferedCollection(); collection.setChunkSize(chunkSize); return collection; } describe('Collection creation', function () { it('should create an empty collection', function () { const collection = createCollection(); expect(collection).toBeDefined(); expect(collection.models.length).toBe(0); }); }); describe('fetch()', function () { it('should resolve after the next chunk of models is received', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2]); $rootScope.$digest(); expect(collection.size()).toBe(2); expect(collection.models).toEqual([{data: 1}, {data: 2}]); }); it('should populate models with next chunk only', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2, 3, 4]); $rootScope.$digest(); expect(collection.size()).toBe(2); expect(collection.models).toEqual([{data: 1}, {data: 2}]); }); it('should reset the buffer and models', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2, 3, 4]); $rootScope.$digest(); collection.fetch(); collection.feed([10, 20]); $rootScope.$digest(); expect(collection.size()).toBe(2); expect(collection.models).toEqual([{data: 10}, {data: 20}]); }); it('should note be sealed', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2, 3, 4]); collection.seal(); $rootScope.$digest(); collection.fetch(); collection.feed([10, 20]); $rootScope.$digest(); expect(collection.isSealed()).toBe(false); }); it('should be resolved with self', function () { const collection = createCollection(2); const promise = collection.fetch(); const spy = jasmine.createSpy('then callback'); collection.feed([1, 2]); collection.promise.then(spy); promise.then(spy); $rootScope.$digest(); expect(spy.calls.allArgs()).toEqual([[collection], [collection]]); }); }); describe('feed()', function () { it('should support one-at-a-time feed', function () { const collection = createCollection(2); collection.fetch(); collection.feed(1); collection.feed(2); $rootScope.$digest(); expect(collection.size()).toBe(2); expect(collection.models).toEqual([{data: 1}, {data: 2}]); }); it('should not populate models with next chunk when called subsequently', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2]); $rootScope.$digest(); collection.feed([3, 4]); $rootScope.$digest(); expect(collection.size()).toBe(2); expect(collection.models).toEqual([{data: 1}, {data: 2}]); }); }); describe('more()', function () { it('should populate models with the next chunk if it is available', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2, 3, 4]); $rootScope.$digest(); collection.more(); $rootScope.$digest(); expect(collection.size()).toBe(4); expect(collection.models).toEqual([{data: 1}, {data: 2}, {data: 3}, {data: 4}]); }); it('should populate models with the next chunk after it is fed', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2]); $rootScope.$digest(); collection.more(); collection.feed([3, 4]); $rootScope.$digest(); expect(collection.size()).toBe(4); expect(collection.models).toEqual([{data: 1}, {data: 2}, {data: 3}, {data: 4}]); }); it('should note ignore consequent calls', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2]); $rootScope.$digest(); collection.feed([3, 4, 5, 6]); collection.more(); $rootScope.$digest(); collection.more(); $rootScope.$digest(); expect(collection.size()).toBe(6); expect(collection.models).toEqual([{data: 1}, {data: 2}, {data: 3}, {data: 4}, {data: 5}, {data: 6}]); }); it('should be resolved with self', function () { const collection = createCollection(2); const spy = jasmine.createSpy('then callback'); collection.fetch(); collection.feed([1, 2, 3, 4]); $rootScope.$digest(); const promise = collection.more(); collection.promise.then(spy); promise.then(spy); $rootScope.$digest(); expect(spy.calls.allArgs()).toEqual([[collection], [collection]]); }); }); describe('hasMore()', function () { it('should be false by default', function () { const collection = createCollection(2); expect(collection.hasMore()).toBe(false); }); it('should be true if buffered is bigger than the models', function () { const collection = createCollection(2); collection.feed(1); expect(collection.hasMore()).toBe(true); }); }); describe('seal()', function () { it('should populate models if there only one chunk', function () { const collection = createCollection(2); collection.fetch(); collection.feed(1); $rootScope.$digest(); collection.seal(); $rootScope.$digest(); expect(collection.size()).toBe(1); expect(collection.models).toEqual([{data: 1}]); }); }); describe('isSealed()', function () { it('should return false if the collection isnt sealed', function () { const collection = createCollection(2); expect(collection.isSealed()).toBe(false); }); it('should return true when the collection is sealed', function () { const collection = createCollection(2); collection.seal(); expect(collection.isSealed()).toBe(true); }); }); describe('bufferSize()', function () { it('should return the buffer array length', function () { const collection = createCollection(2); collection.feed([1, 2, 3]); expect(collection.bufferSize()).toBe(3); }); }); describe('buffer', function () { it('should return the buffer array', function () { const collection = createCollection(2); collection.feed([1, 2, 3]); expect(collection.buffer).toEqual([1, 2, 3]); }); }); describe('rewind()', function () { it('should reset the models array', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1, 2, 3]); $rootScope.$digest(); collection.rewind(); expect(collection.size()).toBe(0); }); }); describe('flush()', function () { it('should flush the buffer into the models array', function () { const collection = createCollection(2); collection.fetch(); collection.feed([1]); $rootScope.$digest(); collection.flush(); $rootScope.$digest(); expect(collection.models).toEqual([{data: 1}]); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/buffered-collection.ts ================================================ 'use strict'; import {PartitionedCollection} from './partitioned-collection'; import {injector} from '../injector'; import {IBaseModel, Model} from '../model/model'; import {ModelCtor} from './collection'; const inject = injector.get; export class BufferedCollection extends PartitionedCollection { _buffer: T[] | Model[] = []; _hasMore = true; _isSealed = false; _deferred; constructor(Mdl?: ModelCtor) { super(Mdl); } // PRIVATE _getAction() { return () => { const deferred = inject('$q').defer(); deferred.$promise = deferred.promise; return deferred; }; } _startRequestHook(deferred) { this._deferred = deferred; } _finishRequestHook(models) { this._deferred = null; return models; } _getNextChunk() { const offset = this.size(); return this._buffer.slice(offset, offset + this._chunkSize); } _resolveNextChunk() { this._deferred.resolve(this._getNextChunk()); } _isNextChunkReady() { return this.bufferSize() - this.size() >= this._chunkSize; } _isRequestPending() { return !!this._deferred; } // PUBLIC // getters get buffer() { return this._buffer; } // methods isSealed() { return this._isSealed; } hasMore() { return this._buffer.length - this.models.length > 0; } bufferSize() { return this._buffer.length; } fetch() { this._buffer = []; this._models = []; this._deferred = null; this._isSealed = false; return super.fetch(); } more() { if (this._isSealed && !this.hasMore()) { return this._resolveAsSelf(inject('$q').when()); } { const promise = this._more(); if (this.hasMore()) { this._resolveNextChunk(); } return this._resolveAsSelf(promise); } } feed(models: T | Model | T[] | Model[]) { this._buffer.push.apply(this._buffer, models instanceof Array ? models : [models]); if (this._isRequestPending() && this._isNextChunkReady()) { this._resolveNextChunk(); } return this; } seal() { this.flush(); this._isSealed = true; return this; } rewind() { this._models = []; return this; } flush() { if (this._isRequestPending()) { this._resolveNextChunk(); } } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/collection.test.ts ================================================ import {Model} from '../model/model'; import {Collection} from './collection'; import * as angular from 'angular'; describe('Collection: Collection', function () { let $httpBackend, $resource, TestModel; beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$httpBackend_, _$resource_) { $httpBackend = _$httpBackend_; $resource = _$resource_; TestModel = createModelClass(); })); function createModelClass() { const resource = $resource('/:action', {}, { query: { method: 'GET', isArray: true, params: { action: 'query' } } }); class TestModel extends Model { constructor(data) { super(data, { id: null }); this._Resource = resource; } static Resource = resource; } return TestModel; } function createCollection(Model?, action?) { return new Collection(Model, action); } function toDataArray(collection) { return (collection.models || collection).map(function (model) { return model.data; }); } describe('Collection creation', function () { it('should create an empty collection', function () { const collection = createCollection(); expect(collection).toBeDefined(); expect(collection.models.length).toBe(0); }); }); describe('fetch() (GET)', function () { it('should call resource.query and update the models array', function () { const collection = createCollection(TestModel); collection.fetch(); $httpBackend.expectGET('/query').respond(200, [{id: 1}, {id: 2}]); $httpBackend.flush(); expect(collection.models.length).toBe(2); }); it('should call resource.query with provided params', function () { const collection = createCollection(TestModel); collection.fetch({ myData: 1 }); $httpBackend.expectGET('/query?myData=1').respond(200, [{id: 1}, {id: 2}]); $httpBackend.flush(); expect(collection.models.length).toBe(2); }); it('should transform each item in array into a Model', function () { const collection = createCollection(TestModel); collection.fetch(); $httpBackend.expectGET('/query').respond(200, [{id: 1}, {id: 2}]); $httpBackend.flush(); expect(collection.models[0] instanceof TestModel).toBe(true); expect(collection.models[1] instanceof TestModel).toBe(true); expect(collection.models[0].data).toEqual({id: 1}); expect(collection.models[1].data).toEqual({id: 2}); }); it('should be resolved with self', function () { const collection = createCollection(TestModel); const promise = collection.fetch(); const spy = jasmine.createSpy('then callback'); promise.then(spy); $httpBackend.expectGET('/query').respond(200, []); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith(collection); }); it('should throw an exception if action is unsupported', function () { const collection = createCollection(TestModel, 'invalidaction'); expect(function () { collection.fetch(); }).toThrow('Collection: resource is missing definition for "invalidaction" action'); }); }); describe('resolved', function () { it('should not be resolved until theres a response from server', function () { const collection = createCollection(TestModel); collection.fetch(); $httpBackend.expectGET('/query').respond(200, []); expect(collection.resolved).toBe(false); }); it('should be resolved after a server response', function () { const collection = createCollection(TestModel); collection.fetch(); $httpBackend.expectGET('/query').respond(200, []); $httpBackend.flush(); expect(collection.resolved).toBe(true); }); }); describe('promise', function () { it('should be set to the latest resource.$promise', function () { const collection = createCollection(TestModel); collection.fetch(); $httpBackend.expectGET('/query').respond(200, []); $httpBackend.flush(); expect(collection.promise).toBeDefined(); }); it('should be resolved with self', function () { const collection = createCollection(TestModel); const spy = jasmine.createSpy('then callback'); collection.fetch(); collection.promise.then(spy); $httpBackend.expectGET('/query').respond(200, []); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith(collection); }); }); describe('add()', function () { it('should return the added item', function () { const collection = createCollection(TestModel); const item = collection.add({id: 1}); expect(toDataArray(collection)).toEqual([item.data]); expect(item).toBeDefined(); expect(item.id).toBe(1); }); it('should add multiple items', function () { const collection = createCollection(TestModel); collection.add([{id: 1}, {id: 2}]); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]); }); it('should return the added items', function () { const collection = createCollection(TestModel); const items = collection.add([{id: 1}, {id: 2}]); expect(items.length).toBe(2); expect(items[0].id).toBe(1); expect(items[1].id).toBe(2); }); it('should transform added item into Model', function () { const collection = createCollection(TestModel); collection.add({id: 1}); expect(collection.models[0] instanceof TestModel).toBe(true); expect(collection.models[0].data).toEqual({id: 1}); }); it('should wrap item in object with data property if Model was not provided', function () { const collection = createCollection(); collection.add({id: 1}); expect(collection.models[0]).toEqual({data: {id: 1}}); }); it('should not transform added item into Model if item is already a Model', function () { const collection = createCollection(TestModel); const model = new TestModel({id: 1}); collection.add(model); expect(collection.models[0]).toBe(model); }); it('should not transform added item into Model if Model was not provided', function () { const collection = createCollection(); const model = {id: 1}; collection.add(model); expect(collection.models[0].data).toBe(model); }); }); describe('remove()', function () { it('should remove a model and return it', function () { const collection = createCollection(TestModel); const modelToRemove = collection.add({id: 1}); const modelToRemain = collection.add({id: 2}); const removedModel = collection.remove(modelToRemove); expect(collection.models).toEqual([modelToRemain]); expect(removedModel).toBe(modelToRemove); }); }); describe('filter()', function () { it('should return all items matching the criteria', function () { const collection = createCollection(TestModel); collection.add({id: 1, status: 'a'}); collection.add({id: 2, status: 'a'}); collection.add({id: 3, status: 'b'}); const items = collection.filter('status', 'a'); expect(toDataArray(items)).toEqual([{id: 1, status: 'a'}, {id: 2, status: 'a'}]); }); }); describe('format()', function () { it('should call model.format() for each mdoel', function () { const collection = createCollection(TestModel); const model = collection.add({id: 1}); spyOn(model, 'format').and.callThrough(); const formatted = collection.format(); expect(model.format).toHaveBeenCalled(); expect(formatted).toEqual([{id: 1}]); }); }); describe('has()', function () { it('should return true if the collection has a mdoel with given id', function () { const collection = createCollection(TestModel); collection.add({id: 1}); expect(collection.has(1)).toBe(true); expect(collection.has(2)).toBe(false); }); }); describe('size()', function () { it('should return the length of the models array', function () { const collection = createCollection(TestModel); collection.add({id: 1}); expect(collection.size()).toBe(1); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/collection.ts ================================================ 'use strict'; import {lodash as _} from '../../utils'; import {Model, IBaseModel} from '../model/model'; export type ModelCtor = new (...args: any[]) => Model; export class Collection { _Resource; _Model; _action; _models: (Model | {data: T})[]; _resolved; _promise; static Model; constructor(Mdl?: ModelCtor, action = 'query') { this._Model = Mdl; this._action = action; this._models = []; } // PRIVATE // tslint:disable-next-line:no-empty _startRequestHook(deferred) { return deferred; } _finishRequestHook(models) { return models; } _getAction() { const action = (this._Resource || this._Model.Resource)[this._action]; if (!action) { // tslint:disable-next-line: restrict-plus-operands throw new Error('Collection: resource is missing definition for "' + this._action + '" action'); } return action; } _fetch(params) { const promise = this._startRequest(params); return this._finishRequest(promise); } _startRequest(params) { const action = this._getAction(); const deferred = action(params); this._startRequestHook(deferred); this._resolved = false; return deferred.$promise; } _finishRequest(promise) { return promise .then(models => this._finishRequestHook(models)) .finally(() => this._resolved = true); } _setModels(models: T | Model | Model[] | T[]) { this._models = []; this.add(models); } _resolveAsSelf(promise) { return (this._promise = promise.then(() => this)); } // PUBLIC // getters get models() { return this._models; } get promise() { return this._promise; } get resolved() { return this._resolved; } // methods setResource(resource) { this._Resource = resource; return this; } size() { return this.models.length; } fetch(params?) { return this._resolveAsSelf(this._fetch(params).then(models => this._setModels(models))); } add(model: T | Model | Model[] | T[]) { let modelArray: any = (model instanceof Array ? model : [model]); if (this._Model) { modelArray = modelArray.map(mdl => mdl instanceof this._Model ? mdl : new this._Model(mdl)); } else if (!(model instanceof Model)) { modelArray = modelArray.map(item => ({data: item})); } Array.prototype.push.apply(this._models, modelArray); return model instanceof Array ? modelArray : modelArray[0]; } remove(model) { return _.remove(this._models, _model_ => _model_ === model)[0]; } get(id) { return _.find(this.models, 'id', id); } has(id) { return !!this.get(id); } filter(what, value) { return _.filter(this.models, model => model.data[what] === value); } format() { return this.models.map(model => model instanceof Model ? model.format() : (model as any).data); } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/index.ts ================================================ export {PartitionedCollection} from './partitioned-collection'; export {BufferedCollection} from './buffered-collection'; export {Collection} from './collection'; ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/partitioned-collection.test.ts ================================================ 'use strict'; import {Model} from '../model/model'; import {PartitionedCollection} from './partitioned-collection'; import * as angular from 'angular'; describe('Collection: PartitionedCollection', function () { let $httpBackend, $resource, TestModel; beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$httpBackend_, _$resource_) { $httpBackend = _$httpBackend_; $resource = _$resource_; TestModel = createModelClass(); })); function createModelClass() { const resource = $resource('/:action', {}, { partitionedQuery: { method: 'GET', isArray: true, params: { action: 'query' } } }); class TestModel extends Model { constructor(data) { super(data, { id: null }); this._Resource = resource; } static Resource = resource; } return TestModel; } function createCollection(chunkSize?) { const collection = new PartitionedCollection(TestModel); collection.setChunkSize(chunkSize); return collection; } function toDataArray(collection) { return collection.models.map(function (model) { return model.data; }); } describe('Collection creation', function () { it('should create an empty collection', function () { const collection = createCollection(); expect(collection).toBeDefined(); expect(collection.models.length).toBe(0); }); }); describe('fetch() (GET)', function () { it('should request more items than was defined for chunkSize (chunkSize + 1)', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200); $httpBackend.flush(); }); it('should fetch the initial chunk', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]); }); it('should fetch with optional params', function () { const collection = createCollection(2); collection.fetch({ param1: 1 }); $httpBackend.expectGET('/query?offset=0¶m1=1&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]); }); it('should reset offset if called after more()', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=2&total=3').respond(200, [{id: 3}, {id: 4}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}, {id: 3}, {id: 4}]); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]); }); it('should reset optional params if called afer more()', function () { const collection = createCollection(2); collection.fetch({ param1: 1 }); $httpBackend.expectGET('/query?offset=0¶m1=1&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=2¶m1=1&total=3').respond(200, [{id: 3}, {id: 4}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}, {id: 3}, {id: 4}]); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]); }); it('should be resolved with self', function () { const collection = createCollection(2); const spy = jasmine.createSpy('then callback'); const promise = collection.fetch(); collection.promise.then(spy); promise.then(spy); $httpBackend.expectGET('/query?offset=0&total=3').respond(200); $httpBackend.flush(); expect(spy.calls.allArgs()).toEqual([[collection], [collection]]); }); }); describe('more() (GET)', function () { it('should fetch the next chunk if there are more items to fetch', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=2&total=3').respond(200); $httpBackend.flush(); }); it('should not fetch the next chunk if there are no more items to fetch', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}]); $httpBackend.flush(); collection.more(); $httpBackend.verifyNoOutstandingExpectation(); }); it('should fetch the next chunk with same optional params used with fetch()', function () { const collection = createCollection(2); collection.fetch({ param1: 1 }); $httpBackend.expectGET('/query?offset=0¶m1=1&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=2¶m1=1&total=3').respond(200); $httpBackend.flush(); }); it('should send the correct offset', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=2&total=3').respond(200, [{id: 3}, {id: 4}, {id: 5}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=4&total=3').respond(200, [{id: 6}]); $httpBackend.flush(); }); it('should fetch the next chunk and append it to current models', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); collection.more(); $httpBackend.expectGET('/query?offset=2&total=3').respond(200, [{id: 3}, {id: 4}]); $httpBackend.flush(); expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}, {id: 3}, {id: 4}]); }); it('should be resolved with self', function () { const collection = createCollection(2); const spy = jasmine.createSpy('then callback'); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); const promise = collection.more(); collection.promise.then(spy); promise.then(spy); $httpBackend.expectGET('/query?offset=2&total=3').respond(200); $httpBackend.flush(); expect(spy.calls.allArgs()).toEqual([[collection], [collection]]); }); }); describe('hasMore', function () { it('should return true initially', function () { const collection = createCollection(2); expect(collection.hasMore()).toBe(true); }); it('should return true if response length is equal to the total param', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]); $httpBackend.flush(); expect(collection.hasMore()).toBe(true); }); it('should return false if response length is less than the total param', function () { const collection = createCollection(2); collection.fetch(); $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}]); $httpBackend.flush(); expect(collection.hasMore()).toBe(false); }); }); describe('getChunkSize()', function () { it('should return the chunk size', function () { const collection = createCollection(2); expect(collection.getChunkSize()).toBe(2); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/collections/partitioned-collection.ts ================================================ import {Collection, ModelCtor} from './collection'; import {lodash as _} from '../../utils'; import {injector} from '../injector'; import {IBaseModel} from '../model/model'; const inject = injector.get; export class PartitionedCollection extends Collection { _chunkSize = 50; _offset = 0; _hasMore ; _optionalParams; private paramsTransformer = x => x; private requestStartHandler = x => x; private requestFinishHandler = x => x; static $q: ng.IQService; constructor(Model?: ModelCtor, action = 'partitionedQuery') { super(Model, action); this._hasMore = true; } // PRIVATE _getParams() { const params = _.defaults({}, { offset: this._offset, total: this._chunkSize + 1 }, this._optionalParams); return this.paramsTransformer(params); } _startRequestHook(deferred) { this.requestStartHandler(deferred); } _finishRequestHook(models) { this._hasMore = models.length > this._chunkSize; if (this._hasMore) { models.splice(-1, 1); } this._offset += models.length; this.requestFinishHandler(models); return models; } _more(params?) { return this._fetch(params).then(models => this.add(models)); } // PUBLIC // methods setChunkSize(chunkSize) { this._chunkSize = chunkSize; return this; } getChunkSize() { return this._chunkSize; } fetch(optionalParams?) { this._offset = 0; this._optionalParams = optionalParams; return super.fetch(this._getParams()); } more() { if (!this.hasMore()) { return this._resolveAsSelf(inject('$q').when()); } return this._resolveAsSelf(this._more(this._getParams())); } hasMore() { return this._hasMore; } transformRequestParams(transformer) { this.paramsTransformer = transformer; return this; } onRequestStart(handler: (x) => any) { this.requestStartHandler = handler; return this; } onRequestFinish(handler: (x) => any) { this.requestFinishHandler = handler; return this; } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/event-emitter/event-emitter.test.ts ================================================ 'use strict'; import {EventEmitter} from './event-emitter'; import * as angular from 'angular'; describe('bi.core.srv.EventeMitter', function () { let $rootScope: angular.IScope; beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$rootScope_) { $rootScope = _$rootScope_; })); class ChildEventEmitter extends EventEmitter { constructor(private scope?) { super(scope); } getScope(): angular.IScope { return this.scope; } } function createEventEmitter({withScope} = {withScope: false}): ChildEventEmitter { const scope = withScope ? $rootScope.$new() : undefined; return new ChildEventEmitter(scope); } describe('creation', function () { it('should create with a private state member', function () { const emitter = createEventEmitter(); expect(emitter['__state']).toBeDefined(); expect(emitter['__id']).toBeUndefined(); }); it('should create with a state id', function () { const emitter = createEventEmitter({withScope: true}); expect(emitter['__state']).toBeUndefined(); expect(emitter['__id']).toBeDefined(); }); }); describe('on()', function () { it('should reeturn self', function () { const emitter = createEventEmitter(); expect(emitter.on('someEvent', () => true)).toBe(emitter); }); it('should subscribe to event and call handler when triggered', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter .on('someEvent', spy) .trigger('someEvent'); expect(spy).toHaveBeenCalled(); }); it('should subscribe to event and call multiple handlers when triggered', function () { const emitter = createEventEmitter(); const spy1 = jasmine.createSpy('event handler 1'); const spy2 = jasmine.createSpy('event handler 2'); emitter .on('someEvent', spy1) .on('someEvent', spy2) .trigger('someEvent'); expect(spy1).toHaveBeenCalled(); expect(spy2).toHaveBeenCalled(); }); it('should subscribe to multiple events and call handlers when triggered', function () { const emitter = createEventEmitter(); const spy1 = jasmine.createSpy('event handler 1'); const spy2 = jasmine.createSpy('event handler 2'); emitter .on('someEvent', spy1) .on('someOtherEvent', spy2) .trigger('someEvent') .trigger('someOtherEvent'); expect(spy1).toHaveBeenCalled(); expect(spy2).toHaveBeenCalled(); }); it('should call handler with triggered args', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter .on('someEvent', spy) .trigger('someEvent', 1, 2); expect(spy).toHaveBeenCalledWith(1, 2); }); it('should not call handler when subscribing to already triggered event', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter.trigger('someEvent'); emitter.on('someEvent', spy); expect(spy).not.toHaveBeenCalled(); }); it('should call handler when subscribing to already triggered event', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter.trigger('someEvent'); emitter.on('someEvent', spy, true); expect(spy).toHaveBeenCalled(); }); it('should call handler with original arguments when subscribing to already triggered event', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter.trigger('someEvent', 1, 2); emitter.on('someEvent', spy, true); expect(spy).toHaveBeenCalledWith(1, 2); }); it('should call handler with arguments of last triggered event', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter.trigger('someEvent', 1, 2); emitter.trigger('someEvent', 3, 4); emitter.on('someEvent', spy, true); expect(spy.calls.count()).toBe(1); expect(spy).toHaveBeenCalledWith(3, 4); }); }); describe('scope', function () { it('should destroy state on scope destroy if created with scope', function () { const emitter = createEventEmitter({withScope: true}); emitter.getScope().$destroy(); expect(emitter['$state']()).toBeUndefined(); }); it('should remove handler on scope destroy if subscribed with scope', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); const scope = $rootScope.$new(); emitter .on('someEvent', spy, false, scope) .trigger('someEvent'); scope.$destroy(); emitter.trigger('someEvent'); expect(spy.calls.count()).toBe(1); }); }); describe('onOnce()', function () { it('should subscribe to event and call handler when triggered', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter .onOnce('someEvent', spy) .trigger('someEvent'); expect(spy).toHaveBeenCalled(); }); it('should not call the handler if triggered for a second time', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter .onOnce('someEvent', spy) .trigger('someEvent') .trigger('someEvent'); expect(spy.calls.count()).toBe(1); }); it('should call handler with original arguments when subscribing to already triggered event, but not more than once', function () { const emitter = createEventEmitter(); const spy = jasmine.createSpy('event handler'); emitter.trigger('someEvent', 1, 2); emitter.onOnce('someEvent', spy, true); emitter.trigger('someEvent', 1, 2); expect(spy).toHaveBeenCalledWith(1, 2); expect(spy.calls.count()).toBe(1); }); it('should not fuck up other event handlers', function () { const emitter = createEventEmitter(); const spyOnce = jasmine.createSpy('once handler'); const spy = jasmine.createSpy('event handler'); emitter.onOnce('someEvent', spyOnce, true); emitter.on('someEvent', spy, true); emitter.trigger('someEvent', 1, 2); expect(spyOnce.calls.count()).toBe(1); expect(spy.calls.count()).toBe(1); }); }); describe('triggerStream()', function () { it('should call handler on all previous events that were triggered', function () { const emitter = createEventEmitter(); const argsHistory = []; const spy = jasmine.createSpy('event handler').and.callFake((...args) => argsHistory.push(args)); emitter .triggerStream('someEvent', 'args1', 2) .triggerStream('someEvent', 'args3', 4) .on('someEvent', spy, true); expect(spy.calls.count()).toBe(2); expect(argsHistory).toEqual([['args1', 2], ['args3', 4]]); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/event-emitter/event-emitter.ts ================================================ 'use strict'; /** * Core services * * @author Our One Creator Which Flies and is Spaghetti and a Monster */ import {lodash as _} from '../../utils'; function cloneArray(arr: any[]) { return arr.slice(0); } const state = { state: {}, clear() { this.state = {}; }, init(id) { this.state[id] = this.state[id] || new State(); }, get(id) { return this.state[id]; }, destroy(id) { // tslint:disable-next-line: no-dynamic-delete delete this.state[id]; } }; class State { private readonly events = {}; private getEvent(eventName: string) { return this.events[eventName] = this.events[eventName] || { handlers: [], lastArgs: null }; } addHandler(eventName: string, handler: (...args) => any) { const event = this.getEvent(eventName); event.handlers.push(handler); return event; } removeHandler(eventName: string, handler: (...args) => any) { _.pull(this.getEvent(eventName).handlers, handler); } setArgs(eventName, ...args) { const event = this.getEvent(eventName); event.lastArgs = [[...args]]; return event; } setArgsKeepHistory(eventName, ...args) { const event = this.getEvent(eventName); if (!event.lastArgs) { event.lastArgs = []; } event.lastArgs.push([...args]); return event; } } /** * Adds event subscription ability to inheriting classes */ export class EventEmitter { private readonly __state; private readonly __id; /** * @param scope Pass scope when the inheriting object is deep watched. This will create the internal state outside of the object. */ constructor(scope?: angular.IScope) { if (scope) { this.__id = _.uniqueId(); state.init(this.__id); this.setScope(scope); } else { this.__state = new State(); } } private $state() { return this.__state ? this.__state : state.get(this.__id); } /** * Invokes all event subscribers */ protected fire(eventName: string, ...args): EventEmitter { const event = this.$state().setArgs(eventName, ...args); cloneArray(event.handlers).forEach(handler => handler(...args)); return this; } /** * Invokes all event subscribers, and also keep event in history list. */ protected stream(eventName: string, ...args): EventEmitter { const event = this.$state().setArgsKeepHistory(eventName, ...args); event.handlers.forEach(handler => handler(...args)); return this; } /** * Subscribes to event * * @param invoke Pass true to immediately invoke the handler if event was already triggered * @param scope Pass scope to automatically remove the handler when scope is destroyed */ public on(eventName: string, handler: (...args) => any, invoke: boolean = false, scope?: angular.IScope): EventEmitter { const event = this.$state().addHandler(eventName, handler); if (invoke && event.lastArgs) { event.lastArgs.forEach(args => handler(...args)); } if (scope) { scope.$on('$destroy', () => { this.$state().removeHandler(eventName, handler); }); } return this; } /** * Subscribes to event, but only for one occurrence of the event. * * @param invoke Pass true to immediately invoke the handler if event was already triggered */ onOnce(eventName: string, handler: (...args) => any, invoke: boolean = false): EventEmitter { const wrappedHandler = (...args) => { handler(...args); this.$state().removeHandler(eventName, wrappedHandler); }; const event = this.$state().addHandler(eventName, wrappedHandler); if (invoke && event.lastArgs) { wrappedHandler(...event.lastArgs[event.lastArgs.length - 1]); } return this; } /** * Invokes all event subscribers. This is a public version of {@link fire}. */ public trigger(eventName: string, ...args): EventEmitter { this.fire(eventName, ...args); return this; } /** * Invokes all event subscribers, but also keep it in history. This is a public version of {@link stream}. */ public triggerStream(eventName: string, ...args): EventEmitter { this.stream(eventName, ...args); return this; } /** * Use to update scope reference */ public setScope(scope: angular.IScope): EventEmitter { if (scope) { scope.$on('$destroy', () => state.destroy(this.__id)); } return this; } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/event-emitter/index.ts ================================================ export {EventEmitter} from './event-emitter'; ================================================ FILE: quix-frontend/client/src/lib/core/srv/injector/index.ts ================================================ import { EventEmitter } from '../event-emitter'; let _injector = null; const eventEmitter = new EventEmitter(); function use(realInjector): void { _injector = realInjector; eventEmitter.trigger('ready'); } export function get(dependencyName: string): any { return _injector.get(dependencyName); } function on(event: string, callback: (...args: any[]) => any) { eventEmitter.on(event, callback, true); } window.addEventListener('biCore.injector.ready', (e: any) => use(e.detail)); export const injector = { use, get, on }; ================================================ FILE: quix-frontend/client/src/lib/core/srv/local-storage/index.ts ================================================ export {LocalStorage} from './local-storage'; ================================================ FILE: quix-frontend/client/src/lib/core/srv/local-storage/local-storage.test.ts ================================================ 'use strict'; import {LocalStorage} from './local-storage'; import * as angular from 'angular'; describe('LocalStorage Wrapper', function () { let localStorage: LocalStorage; beforeEach(() => { localStorage = new LocalStorage(); localStorage.clear(); }); afterEach(() => { LocalStorage.setPrefix(''); }); it('should store values', function () { localStorage.setItem('setting', 'aaaa'); expect(window.localStorage.getItem('setting')).toEqual('aaaa'); }); it('should load values', function () { window.localStorage.setItem('setting', 'bbbb'); expect(localStorage.getItem('setting')).toEqual('bbbb'); }); it('should clear all values', function () { localStorage.setItem('setting', 'aaaa'); localStorage.clear(); expect(localStorage.getItem('setting')).toEqual(null); }); it('should add prefix to saved values when requested', () => { LocalStorage.setPrefix('test_'); localStorage.setItem('setting', 'aaaa'); expect(window.localStorage.getItem('test_setting')).toEqual('aaaa'); }); describe('Custom storage', function () { let customStorage = { data: {}, setItem(name, _data) { this.data[name] = _data; }, getItem(name) { return this.data[name]; }, clear() { this.data = {}; } }; beforeEach(() => { localStorage.setStorage(customStorage as any); customStorage.clear(); }); it('should store values', function () { localStorage.setItem('setting', 'aaaa'); expect(customStorage.data['setting']).toEqual('aaaa'); }); it('should load values', function () { customStorage.data['setting'] = 'bbbb'; expect(localStorage.getItem('setting')).toEqual('bbbb'); }); it('should clear all values', function () { localStorage.setItem('setting', 'aaaa'); localStorage.clear(); expect(customStorage.data['setting']).toEqual(undefined); }); }); }); describe('LocalStorageWrapper angular provider', () => { let lsProvider; beforeEach(() => { angular.mock.module('bi.core.internal'); }); beforeEach(function () { angular.mock.module(['biLocalStorageProvider', function (biLocalStorageProvider) { lsProvider = biLocalStorageProvider; }]); angular.mock.inject(); }); it('should call set prefix', function () { spyOn(LocalStorage, 'setPrefix'); lsProvider.setPrefix('bla'); expect(LocalStorage.setPrefix).toHaveBeenCalledWith('bla'); }); it('should create a LocalStorage instance', function () { // spyOn(bi.core.srv.localStorage, 'LocalStorage'); // lsProvider.$get(); // expect(bi.core.srv.localStorage.LocalStorage).toHaveBeenCalled(); // TODO TODO TODO : restore this test }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/local-storage/local-storage.ts ================================================ 'use strict'; export class LocalStorage { static prefix: string = ''; private storage: Storage; constructor(storage?: Storage) { this.storage = storage || window.localStorage; } static setPrefix(prefix: string) { LocalStorage.prefix = prefix; } setStorage(storage: Storage) { this.storage = storage; } setItem(name: string, data: string) { name = LocalStorage.prefix + name; this.storage.setItem(name, data); } getItem(name: string) { name = LocalStorage.prefix + name; return this.storage.getItem(name); } clear() { this.storage.clear(); } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/model/model.test.ts ================================================ import {Collection} from '../collections'; import {Model} from './model'; import * as angular from 'angular'; import * as Uuid from 'uuid'; describe('Model: Model', function () { let $rootScope, $httpBackend, $resource, mocks, v4Orig; beforeEach(function () { angular.mock.module('bi.core.internal'); v4Orig = Uuid.v4; Uuid.v4 = function () { return 'MOCK-UUID'; }; mocks = { user: { data: { email: 'mock-user@wix.com' } }, TestCollection: Collection, TestModel: Model }; angular.mock.module({ user: mocks.user, TestCollection: mocks.TestCollection, TestModel: mocks.TestModel }); }); beforeEach(inject(function (_$rootScope_, _$httpBackend_, _$resource_) { $rootScope = _$rootScope_; $httpBackend = _$httpBackend_; $resource = _$resource_; })); afterEach(() => { Uuid.v4 = v4Orig; }); function createModel(data?, template?, options?, responseHook?) { class TestModel extends Model { constructor(data) { super(data, template, options); this._Resource = $resource('/:action/:id', {}, { save: { method: 'POST', params: { action: 'save' } }, get: { method: 'GET', params: { action: 'get' } } }); this._responseHook = responseHook; } } let model = new TestModel(data); spyOn(model, 'parse').and.callThrough(); spyOn(model, 'format').and.callThrough(); return model; } describe('instantiation', function () { it('should create an empty new model', function () { const model = createModel(); expect(model).toBeDefined(); expect(model.data).toEqual({}); }); it('should create a model with provided data', function () { const data = {name: 'John'}; const model = createModel(data); expect(model.data).toEqual(data); }); it('should parse the provided data', function () { const data = {name: 'John'}; const model = createModel(data, data); expect(model.data).toEqual(data); }); }); describe('id', function () { it('should return a generatad id with a "new" prefix', function () { const model = createModel(); expect(model.id.indexOf('new')).toBe(0); }); it('should return the actual model id', function () { const model = createModel({id: 1}); expect(model.id).toBe(1); }); it('should set id', function () { const model = createModel(); model.id = 2; expect(model.id).toBe(2); }); }); describe('isNew()', function () { it('should be new', function () { const model = createModel(); expect(model.isNew()).toBe(true); }); it('should not be new', function () { const model = createModel({id: 1}); expect(model.isNew()).toBe(false); }); }); describe('save() (POST)', function () { it('should call resource.save and update the data', function () { const data = {name: 'John'}; const model = createModel(data, data); model.save(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1}); $httpBackend.flush(); expect(model.id).toEqual(1); }); it('should call resource.save, parse and update the data', function () { const data = {}; const model = createModel(data, data); model.save(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'John'}); $httpBackend.flush(); expect((model.parse as any).calls.mostRecent().args[0].id).toBe(1); expect((model.parse as any).calls.mostRecent().args[0].name).toBe('John'); expect(model.data.id).toBe(1); expect(model.data.name).toBe('John'); }); it('should not be new', function () { const model = createModel(); model.save(); $httpBackend.expectPOST('/save', {}).respond(200, {id: 1}); $httpBackend.flush(); expect(model.isNew()).toBe(false); }); it('should be resolved with self', function () { const model = createModel(); const promise = model.save(); const spy = jasmine.createSpy('then callback'); promise.then(spy); $httpBackend.expectPOST('/save', {}).respond(200, {id: 1}); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith(model); }); }); describe('fetch() (GET)', function () { it('should call resource.get and update the data', function () { const model = createModel(); model.fetch(1); $httpBackend.expectGET('/get/1').respond(200, {id: 1}); $httpBackend.flush(); expect(model.data.id).toBe(1); }); it('should call resource.get, parse and update the data', function () { const model = createModel({}, {}); model.fetch(1); $httpBackend.expectGET('/get/1').respond(200, {id: 1, name: 'John'}); $httpBackend.flush(); expect((model.parse as any).calls.mostRecent().args[0].id).toBe(1); expect((model.parse as any).calls.mostRecent().args[0].name).toBe('John'); expect(model.data.id).toBe(1); expect(model.data.name).toBe('John'); }); it('should not be new', function () { const model = createModel(); model.fetch(2); $httpBackend.expectGET('/get/2').respond(200, {id: 2}); $httpBackend.flush(); expect(model.isNew()).toBe(false); }); it('should be resolved with self', function () { const model = createModel(); const promise = model.fetch(2); const spy = jasmine.createSpy('then callback'); promise.then(spy); $httpBackend.expectGET('/get/2').respond(200, {id: 2}); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith(model); }); }); describe('destroy()', function () { it('should call resource.delete and update the data', function () { const data = {id: 2}; const model = createModel(data, data); model.destroy(); $httpBackend.expectDELETE('/2').respond(200, {id: 2}); $httpBackend.flush(); }); it('should not call resource.delete if the model is new', function () { const model = createModel(); model.destroy(); $httpBackend.verifyNoOutstandingExpectation(); }); }); describe('resolved', function () { it('should not be resolved until theres a response from server', function () { const model = createModel(); model.fetch(2); $httpBackend.expectGET('/get/2').respond(200, {id: 2}); expect(model.resolved).toBe(false); }); it('should be resolved after a server response', function () { const model = createModel(); model.fetch(2); $httpBackend.expectGET('/get/2').respond(200, {id: 2}); $httpBackend.flush(); expect(model.resolved).toBe(true); }); }); describe('promise', function () { it('should be set to the latest resource.$promise', function () { const model = createModel(); model.fetch(2); $httpBackend.expectGET('/get/2').respond(200, {id: 2}); $httpBackend.flush(); expect(model.promise).toBeDefined(); }); it('should be resolved with self', function () { const model = createModel(); const spy = jasmine.createSpy('then callback'); model.fetch(2); model.promise.then(spy); $httpBackend.expectGET('/get/2').respond(200, {id: 2}); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith(model); }); }); describe('parse()', function () { describe('defaults', function () { it('should assign defaults for properties with undefined values', function () { const data = {}; const template = {name: 'John'}; const model = createModel(data, template); expect(model.data).toEqual({ name: 'John' }); }); it('should not assign defaults for properties with defined values', function () { const data = {name: 'John'}; const template = {name: 'Sam'}; const model = createModel(data, template); expect(model.data).toEqual({ name: 'John' }); }); it('should support nesting', function () { const data = {nested: {}}; const template = {nested: {name: 'John'}}; const model = createModel(data, template); expect(model.data).toEqual({ nested: { name: 'John' } }); }); }); describe('@optional', function () { it('should assing null value to optional properties if they are undefined', function () { const data = {name: 'John'}; const template = {name: 'John', lastname: '@optional'}; const model = createModel(data, template); expect(model.data).toEqual({ name: 'John', lastname: null }); }); it('should not assign null value to optional properties if they are defined', function () { const data = {name: 'John', lastname: 'Doe'}; const template = {name: 'John', lastname: '@optional'}; const model = createModel(data, template); expect(model.data).toEqual({ name: 'John', lastname: 'Doe' }); }); }); describe('@flat', function () { it('should unflatten the keys', function () { const data = {value: {'a.b': 1, 'a.c': 2}}; const template = {value: '@flat'}; const model = createModel(data, template); expect(model.data).toEqual({ value: { a: { b: 1, c: 2 } } }); }); it('should unflatten the keys (more complex example)', function () { const data = {value: {'a.b': 1, 'a.c': 2, 'c.d.e': 3}}; const template = {value: '@flat'}; const model = createModel(data, template); expect(model.data).toEqual({ value: { a: { b: 1, c: 2 }, c: { d: { e: 3 } } } }); }); }); describe('@collection', function () { it('should convert array to collection', function () { const data = {name: 'John', lastnames: [1]}; const template = {name: 'John', lastnames: '@collection:TestCollection'}; const model = createModel(data, template); expect(model.data.lastnames instanceof mocks.TestCollection).toBe(true); }); it('should create empty collection if array is empty', function () { const data = {name: 'John', lastnames: []}; const template = {name: 'John', lastnames: '@collection:TestCollection'}; const model = createModel(data, template); expect(model.data.lastnames instanceof mocks.TestCollection).toBe(true); expect(model.data.lastnames.models.length).toBe(0); }); it('should create empty collection if array is undefined', function () { const data = {name: 'John', lastnames: undefined}; const template = {name: 'John', lastnames: '@collection:TestCollection'}; const model = createModel(data, template); expect(model.data.lastnames instanceof mocks.TestCollection).toBe(true); expect(model.data.lastnames.models.length).toBe(0); }); it('should support nesting', function () { const data = {name: 'John', nested: {lastnames: []}}; const template = {name: 'John', nested: {lastnames: '@collection:TestCollection'}}; const model = createModel(data, template); expect(model.data.nested.lastnames instanceof mocks.TestCollection).toBe(true); }); describe('keep model references in existing collections after fetching fresh data', function () { it('should copy new models into old models', function () { const data = {values: [{id: 1}, {id: 2}]}; const template = {values: '@collection:TestCollection'}; const model = createModel(data, template); const value1 = model.data.values.models[0]; const value2 = model.data.values.models[1]; model.save(); $httpBackend.expectPOST('/save', data).respond(200, {values: [{id: 10}, {id: 20}]}); $httpBackend.flush(); expect(model.data.values instanceof mocks.TestCollection).toBe(true); expect(model.data.values.models.length).toBe(2); expect(model.data.values.models[0].data).toEqual({id: 10}); expect(model.data.values.models[1].data).toEqual({id: 20}); expect(model.data.values.models[0]).toBe(value1); expect(model.data.values.models[1]).toBe(value2); }); it('should add new models to an empty collection', function () { const data = {values: []}; const template = {values: '@collection:TestCollection'}; const model = createModel(data, template); model.fetch(1); $httpBackend.expectGET('/get/1').respond(200, {values: [{id: 10}, {id: 20}]}); $httpBackend.flush(); expect(model.data.values instanceof mocks.TestCollection).toBe(true); expect(model.data.values.models.length).toBe(2); expect(model.data.values.models[0].data).toEqual({id: 10}); expect(model.data.values.models[1].data).toEqual({id: 20}); }); }); }); describe('@model', function () { it('should create a model object based on template', function () { const data = {name: 'John', lastnames: {lastname: 'Smith'}}; const template = {name: 'John', lastnames: '@model:TestModel'}; const model = createModel(data, template); expect(model.data.lastnames.data.lastname).toEqual('Smith'); expect(model.data.lastnames instanceof mocks.TestModel).toBe(true); }); }); }); describe('format()', function () { describe('defaults', function () { it('should remove properties not defined in the template', function () { const data = {prop1: true, prop2: true}; const model = createModel(data, {prop1: null}); const formatted = model.format(); expect(formatted).toEqual({ prop1: true }); }); it('should strip keys starting with $', function () { const data = {$prop: 1}; const model = createModel(data, {$prop: null}); const formatted = model.format(); expect(formatted).toEqual({}); }); it('should strip keys starting with $ (nested objects)', function () { const data = {prop: {$prop: 1}}; const model = createModel(data, {prop: null}); const formatted = model.format(); expect(formatted).toEqual({prop: {}}); }); it('should strip keys starting with $ (arrays)', function () { const data = {prop: [{$prop: 1}]}; const model = createModel(data, {prop: null}); const formatted = model.format(); expect(formatted).toEqual({prop: [{}]}); }); }); describe('@optional', function () { it('should remove optional properties that are null', function () { const data = {name: 'John', lastname: null}; const template = {name: null, lastname: '@optional'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({ name: 'John' }); }); it('should not remove optional properties that are primitive values', function () { const data = {name: 'John', lastname: 'Doe'}; const template = {name: null, lastname: '@optional'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({ name: 'John', lastname: 'Doe' }); }); it('should not remove optional properties that are objects', function () { const data = {name: {first: 'John', last: 'Doe'}}; const template = {name: '@optional'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({name: {first: 'John', last: 'Doe'}}); }); it('should send optional properties that are arrays', function () { const data = {prop: []}; const template = {prop: '@optional'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({prop: []}); }); }); describe('@collection', function () { it('should format the collection', function () { const data = {values: [1, 2]}; const template = {values: '@collection:TestCollection'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({values: [1, 2]}); }); }); describe('@flat', function () { it('should flatten the keys', function () { const data = { values: { a: { b: 1, c: 2 } } }; const template = {values: '@flat'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({values: {'a.b': 1, 'a.c': 2}}); }); it('should flatten the keys (more complex example)', function () { const data = { values: { a: { b: 1, c: 2 }, c: { d: { e: 3 } } } }; const template = {values: '@flat'}; const model = createModel(data, template); const formatted = model.format(); expect(formatted).toEqual({values: {'a.b': 1, 'a.c': 2, 'c.d.e': 3}}); }); // it('should remove keys starting with $', function () { // const data = { // values: { // a: { // $b: 1 // } // } // }; // const template = {values: '@flat'}; // const model = createModel(data, template); // const formatted = model.format(); // expect(formatted).toEqual({values: {'a.b': 1}}); // }); }); }); describe('clone()', function () { it('should fetch event by current id and return a new instance', function () { const model = createModel({id: 1}); const cloned = model.clone(true); $httpBackend.expectGET('/get/1').respond(200, {id: 1, name: 'test'}); $httpBackend.flush(); expect(cloned).not.toBe(model); expect(cloned.data.name).toBe('test'); }); it('should fetch event with provided params', function () { const model = createModel({id: 1}); const cloned = model.clone(true, {id: 2}); $httpBackend.expectGET('/get/2').respond(200, {id: 2, name: 'test'}); $httpBackend.flush(); expect(cloned).not.toBe(model); expect(cloned.data.name).toBe('test'); }); it('should fetch event by current id and return a new instance without id', function () { const data = {id: 1, name: 'test'}; const model = createModel(data, {id: '@optional'}); const cloned = model.clone(true); $httpBackend.expectGET('/get/1').respond(200, {id: 1}); $httpBackend.flush(); expect(cloned.data.id).toBe(null); expect(cloned.isNew()).toBe(true); }); it('should copy the data and return a new instance', function () { const data = {name: 'test'}; const model = createModel(data, {name: ''}); const cloned = model.clone(); $rootScope.$digest(); expect(cloned).not.toBe(model); expect(cloned.data.name).toBe('test'); expect(cloned.isNew()).toBe(true); }); it('should copy the data and return a new instance without id', function () { const data = {id: 1}; const model = createModel(data, {id: '@optional'}); const cloned = model.clone(); $rootScope.$digest(); expect(cloned.data.id).toBe(null); expect(cloned.isNew()).toBe(true); }); it('should set a promise that resolves to self', function () { const data = {a: 1}; const model = createModel(data, data); const cloned = model.clone(); const spy = jasmine.createSpy('cloned.promise'); cloned.promise.then(spy); $rootScope.$digest(); expect(spy).toHaveBeenCalledWith(cloned); }); }); describe('meta()', function () { it('should set and get a meta property', function () { const model = createModel(); model.meta('test', 1); expect(model.meta('test')).toBe(1); }); it('should return undefined for unset values', function () { const model = createModel(); expect(model.meta('test')).toBeUndefined(); }); it('should set a value that exists only until first read ', function () { const model = createModel(); model.meta('test', 1, true); expect(model.meta('test')).toBe(1); expect(model.meta('test')).toBeUndefined(); }); }); describe('isValid()', function () { it('should be valid by default', function () { const model = createModel(); expect(model.isValid()).toBe(true); }); it('should set the validity status', function () { const model = createModel(); model.setValidity(false); expect(model.isValid()).toBe(false); }); }); describe('promise.noSync()', function () { it('should not update model with next server response if called', function () { const data = {name: 'John'}; const model = createModel(data, data); model.save().noSync(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'}); $httpBackend.flush(); expect(model.data.name).toEqual('John'); }); it('should return a promise resolved with self', function () { const data = {name: 'John'}; const model = createModel(data, data); const promise = model.save().noSync(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'}); $httpBackend.flush(); const spy = jasmine.createSpy('promise'); promise.then(spy); $rootScope.$digest(); expect(spy).toHaveBeenCalledWith(model); }); it('should apply only once per call', function () { const data = {name: 'John'}; const model = createModel(data, data); model.save().noSync(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'}); $httpBackend.flush(); model.save(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'}); $httpBackend.flush(); expect(model.data.name).toEqual('Jack'); }); }); describe('responseHook', function () { it('should call hook with "get" action and processed model', function () { const spy = jasmine.createSpy('responseHook'); const model = createModel(undefined, undefined, {}, spy); model.fetch(1); $httpBackend.expectGET('/get/1').respond(200, {id: 1}); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith({id: 1}, 'get', {noSync: false}); }); it('should call hook with "save" action and processed model', function () { const spy = jasmine.createSpy('responseHook'); const data = {name: 'John'}; const model = createModel(data, data, {}, spy); model.save(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1}); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith({id: 1, name: 'John'}, 'save', {noSync: false}); }); it('should call hook with "clone" action and processed model', function () { const spy = jasmine.createSpy('responseHook'); const data = {name: 'John'}; const model = createModel(data, {name: ''}, {}, spy); model.clone(); $rootScope.$digest(); expect(spy).toHaveBeenCalledWith({id: null, name: 'John'}, 'clone', {noSync: false}); }); it('should call hook with "save" action and noSync=true', function () { const spy = jasmine.createSpy('responseHook'); const data = {name: 'John'}; const model = createModel(data, data, {}, spy); model.save().noSync(); $httpBackend.expectPOST('/save', data).respond(200, {id: 1}); $httpBackend.flush(); expect(spy).toHaveBeenCalledWith({id: 1, name: 'John'}, 'save', {noSync: true}); }); }); describe('options', function () { describe('autoId', function () { it('should generate id when data has no id param', function () { const model = createModel(undefined, undefined, {autoId: true}); expect(model.id).toBe('MOCK-UUID'); }); it('should not generate id when data has id param', function () { const model = createModel({id: 1}, undefined, {autoId: true}); expect(model.id).not.toBe('MOCK-UUID'); }); it('should be considered new', function () { const model = createModel(undefined, undefined, {autoId: true}); expect(model.isNew()).toBe(true); }); it('should not be considered new after fetching a model', function () { const model = createModel(undefined, undefined, {autoId: true}); model.fetch('MOCK-UUID'); $httpBackend.expectGET('/get/MOCK-UUID').respond(200, {id: 'MOCK-UUID'}); $httpBackend.flush(); expect(model.id).toBe('MOCK-UUID'); expect(model.isNew()).toBe(false); }); it('should not be considered new after saving a new model', function () { const data = {}; const model = createModel(data, data, {autoId: true}); model.save(); $httpBackend.expectPOST('/save', data).respond(200, {id: 'MOCK-UUID'}); $httpBackend.flush(); expect(model.id).toBe('MOCK-UUID'); expect(model.isNew()).toBe(false); }); it('should generate id for cloned model', function () { const data = {id: 1}; const model = createModel(data, data, {autoId: true}); const clonedModel = model.clone(); $rootScope.$digest(); expect(clonedModel.id).toBe('MOCK-UUID'); }); it('should consider cloned model new', function () { const data = {id: 1}; const model = createModel(data, data, {autoId: true}); const clonedModel = model.clone(); $rootScope.$digest(); expect(clonedModel.isNew()).toBe(true); }); }); describe('autoOwner', function () { it('should assign current user as owner', function () { const model = createModel(undefined, undefined, {autoOwner: true}); expect(model.data.owner).toEqual(mocks.user.data); }); it('should duplicate the user object', function () { const model = createModel(undefined, undefined, {autoOwner: true}); expect(model.data.owner).toEqual(mocks.user.data); expect(model.data.owner).not.toBe(mocks.user.data); }); it('should assign current user if owner object is defined without email', function () { const model = createModel({owner: {}}, {owner: {}}, {autoOwner: true}); expect(model.data.owner).toEqual(mocks.user.data); }); it('should not assign current user if owner email is defined', function () { const owner = {email: 'some-user@wix.com'}; const model = createModel({owner: owner}, {owner: {}}, {autoOwner: true}); expect(model.data.owner).toEqual(owner); }); it('should assign id for cloned model', function () { const data = {id: 1}; const model = createModel(data, data, {autoOwner: true}); const clonedModel = model.clone(); $rootScope.$digest(); expect(clonedModel.data.owner).toEqual(mocks.user.data); }); }); }); describe('data', function () { it('data property should be assignable', function () { const model = createModel(); model.data = {test: true}; expect(model.data).toEqual({test: true}); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/model/model.ts ================================================ 'use strict'; import {Collection} from '../collections/collection'; import {lodash as _, uuid} from '../../utils'; import {injector} from '../injector'; const inject = injector.get; function flatten(data, keys = [], res = {}) { _.forEach(data, (value, key) => { keys.push(key); if (_.isObject(value)) { flatten(value, keys, res); } else { res[keys.join('.')] = value; } keys.pop(); }); return res; } function unflatten(data, keys = []) { const res = {}; _.forEach(data, (value, key) => { unflattenKey(key.split('.'), value, res); }); return res; } function unflattenKey(keys, value, res = {}) { const key = keys.shift(); if (!keys.length) { res[key] = value; } else { res[key] = res[key] || {}; unflattenKey(keys, value, res[key]); } } export interface IBaseModel { id?: string; owner?: { email: string; }; } export class Model { _template; _resolved; _valid; _meta; _options; _cid; _data: T; _promise; _permission; _Resource; constructor(model?, template?, options = {autoId: false, autoOwner: null}) { this._template = template || {}; this._resolved = !!model; this._valid = true; this._meta = {}; this._options = options; this._data = this.parse(model); this._promise = inject('$q').when(this); if (options.autoId && !this.data.id) { this._assignId(); } else { this._cid = _.uniqueId('new'); } if (options.autoOwner && !(this.data.owner && this.data.owner.email)) { this._assignAutoOwner(); } } // PRIVATE _responseHook(data, action, options) { return data; } _assignId() { this._cid = this.data.id = uuid(); return this; } _doRequest(action, data) { this._resolved = false; return this._Resource[action](data).$promise; } _processResponse(promise, action) { return (this._promise = promise.then((data) => { if (!this._promise._noSync) { data = this._smartMerge(this._data, this.parse(data)); data = typeof this._responseHook === 'function' ? this._responseHook(data, action, {noSync: false}) : data; this._data = data; if (action === 'clone') { if (this._options.autoId) { this._assignId(); } if (this._options.autoOwner) { this._assignAutoOwner(); } } } else if (typeof this._responseHook === 'function') { this._responseHook(this.parse(data), action, {noSync: true}); } if ((action === 'get' || action === 'save') && this._options.autoId) { this._cid = _.uniqueId('new'); } return this; }).finally(() => { this._resolved = true; })); } _action(action, data?) { if (!data) { data = this.format(); } const promise = this._processResponse(this._doRequest(action, data), action); this._initPromise(promise); return promise; } _initPromise(promise) { promise.noSync = () => { promise._noSync = true; return promise; }; return promise; } _assignAutoOwner() { const user = inject('user'); this._data.owner = _.clone(user.data); } _stripDollars(data: any) { if (_.isPlainObject(data)) { // tslint:disable-next-line: restrict-plus-operands data = _.omit(data, (value, key) => ('' + key).charAt(0) === '$'); data = _.mapValues(data, value => this._stripDollars(value)); } if (_.isArray(data)) { data = data.map(item => this._stripDollars(item)); } return data; } _parseCollection(collectionString, data) { const collectionClassName = collectionString.replace('@collection:', ''); const CollectionClass = inject(collectionClassName); const collection = new CollectionClass(); if (data instanceof Array && data.length) { collection.add(data); } return collection; } _parseModel(modelString, data) { const modelClassName = modelString.replace('@model:', ''); const ModelClass = inject(modelClassName); return new ModelClass(data); } /** * Merges current with source while preserving collection item references * * @param current * @param source * @returns {object} * @private */ _smartMerge(current, source) { return _.merge(current, source, function (currentValue, sourceValue) { if (currentValue instanceof Collection) { sourceValue.models.forEach((sourceModel, index) => { if (currentValue.models[index]) { _.assign(currentValue.models[index], sourceModel); } else { currentValue.models[index] = sourceModel; } }); return currentValue; } if (_.isPlainObject(sourceValue)) { return; // let _.merge do the recursion } return sourceValue; }); } /** * Parses the data according to defaults definition. * Removes properties starting with "$" * * The parsed data is used for internal model representation. * * @param data * @param defaults * @returns {object} * @private */ _parse(data, defaults) { data = _.cloneDeep(data || {}); data = this._stripDollars(data); return _.merge(data, defaults, (dataValue, defaultValue) => { if (defaultValue === '@optional') { return typeof dataValue === 'undefined' ? null : dataValue; } if (defaultValue === '@flat') { return unflatten(dataValue); } if (/^@collection:/.test(defaultValue)) { return this._parseCollection(defaultValue, dataValue); } if (/^@model:/.test(defaultValue)) { return this._parseModel(defaultValue, dataValue); } if (_.isPlainObject(defaultValue)) { return; // let _.merge do the recursion } return typeof dataValue === 'undefined' ? _.cloneDeep(defaultValue) : dataValue; }); } /** * Formats the data according to filter definition. * The formatted data is used for server request payloads. * * @param data * @param filter * @returns {object} * @private */ _format(data, filter) { if (typeof filter === 'undefined') { return; } if (filter === '@optional') { return data === null ? undefined : data; } if (filter === '@flat') { return flatten(data); } if (/^@collection:/.test(filter)) { return data.format(); } if (filter === null || data === null || typeof data === 'undefined' || typeof data !== 'object' || data instanceof Array) { return data; } const res = {}; _.forOwn(data, (value, key) => { value = this._format(value, filter[key]); if (!_.isUndefined(value)) { res[key] = value; } }); return res; } // PUBLIC // static static Resource; // getters/setters get id() { return this.data.id || this._cid; } set id(value) { this.data.id = value; } get data() { return this._data; } set data(data) { this._data = data; } get promise() { return this._promise; } get resolved() { return this._resolved; } get permission() { return this._permission; } // methods isNew() { return this.id === this._cid; } isValid() { return this._valid; } setPermission(Permission) { this._permission = new Permission(this); return this; } setValidity(valid) { this._valid = valid; } format() { return this._stripDollars(this._format(this.data, this._template)); } parse(data) { return this._parse(data, this._template); } fetch(id, ...rest) { return this._action('get', {id}); } /** * Clones current model and returns a new instance. * New model will be considered new (isNew() === true). * * @params fetch {boolean} - if true will fetch model data from server before cloning * @returns {Model} - new model */ clone(fetch = false, params?) { let model, promise; if (fetch) { promise = this._Resource.get(params || {id: this.id}).$promise; } else { promise = inject('$q').when(this.format()); } promise = promise.then(data => { data.id = null; return data; }); model = new (this.constructor as any); model._processResponse(promise, 'clone'); return model; } save() { return this._action('save'); } /** * Deletes the model on server. * Does nothing for new models. * * @returns {Promise} - promise resolved with self */ destroy() { if (!this.isNew()) { return this._action('delete', {id: this.data.id}); } return this._initPromise(inject('$q').when(this)); } meta(key, value?, once = false) { if (typeof value === 'undefined') { return typeof this._meta[key] === 'function' ? this._meta[key]() : this._meta[key]; } this._meta[key] = once ? () => { this._meta[key] = undefined; return value; } : value; return this; } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/socket/socket.ts ================================================ 'use strict'; import {EventEmitter} from '../event-emitter/event-emitter'; function createSocket(self: Socket, url: string): any { const socket = new WebSocket(url); socket.onmessage = (message) => { const data = JSON.parse(message.data || '{}'); self.trigger('event', self, data.event, data); }; socket.onopen = () => { self.trigger('open', self); }; socket.onclose = () => { self.trigger('close', self); }; return socket; } export class Socket extends EventEmitter { private readonly socket: any; constructor (private readonly url: string) { super(); this.socket = createSocket(this, url); } send(payload): Socket { this.socket.send(JSON.stringify(payload)); return this; } close(): Socket { this.socket.close(); return this; } getUrl() { return this.url; } getWebSocket() { return this.socket; } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/localstorage-state-provider.test.ts ================================================ 'use strict'; import * as angular from 'angular'; import {localStorageStateProvider} from './localstorage-state-provider'; describe('LocalStorageStateProvider', function () { const demoData = { param1: 'aaa', param2: 4 }; beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(function () { window.localStorage.clear(); }); // beforeEach(inject(function () { // localStorageStateProvider = bi.core.srv.state.localStorageStateProvider; // })); describe('Save', () => { it('should correctly save data', function () { let data = JSON.stringify(demoData); localStorageStateProvider.setStateData('test', data); expect(window.localStorage['test']).toEqual(data); }); }); describe('Load', () => { it('should correctly load data', function () { window.localStorage['test'] = JSON.stringify(demoData); expect(localStorageStateProvider.getStateData('test')).toEqual(JSON.stringify(demoData)); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/localstorage-state-provider.ts ================================================ import {LocalStorage} from '../local-storage'; import {IStateProvider} from './types'; export const localStorageStateProvider: IStateProvider = new class LocalStorageStateProvider implements IStateProvider { private readonly storage = new LocalStorage(); getStateData(stateName: string): string { return this.storage.getItem(stateName); } setStateData(stateName: string, data: string): void { this.storage.setItem(stateName, data); } }; ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/state-wrapper.test.ts ================================================ import * as angular from 'angular'; import {StateWrapper} from './state-wrapper'; import {ViewModel, create as createViewModel} from '../view-model/view-model'; type Dictionary = _.Dictionary; function createDefaultExportImport(obj, paramList: string[]) { obj.$export = function(stateName) { const res = {}; paramList.forEach(paramName => { res[paramName] = obj[paramName]; }); return res; }; obj.$import = function(data: Dictionary) { paramList.forEach(paramName => { obj[paramName] = data[paramName]; }); }; } describe('LocalStorageStateProvider', function () { let $location, $browser, $q: ng.IQService, $rootScope: ng.IRootScopeService; beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$location_, _$browser_, _$q_, _$rootScope_) { $location = _$location_; $browser = _$browser_; $q = _$q_; $rootScope = _$rootScope_; })); beforeEach(() => { window.localStorage.clear(); }); function updateURL(url) { $location.url(url); $browser.poll(); } describe('check mandatory parameters', function () { const demoObject = {}; it('should throw error when no Object is passed', function () { expect(() => StateWrapper.build().end()).toThrow(new Error('StateWrapperBuilder::build: You must provide an object')); expect(() => { StateWrapper.build() .useObject(demoObject) .end(); }).toThrow(new Error('StateWrapperBuilder::build: You must provide a clientName')); expect(() => { StateWrapper.build() .useObject(demoObject) .setClientName('test') .end(); }).toThrow(new Error('StateWrapperBuilder::build: You must provide a state')); }); }); describe('Basic Load\\Save', function () { let demoObject; beforeEach(function () { demoObject = { a: 'aaa', b: {bb: 'bbb'} }; createDefaultExportImport(demoObject, ['a']); createDefaultExportImport(demoObject.b, ['bb']); }); it('should save values local storage', function () { const stateWrapper = StateWrapper.build() .useObject(demoObject) .withNewState('demoState') .setClientName('test') .end(); stateWrapper.save(); expect(window.localStorage.getItem('demoState')).toBe('{"test":{"a":"aaa","bb":"bbb"}}'); }); it('should load values local storage', function () { window.localStorage['demoState'] = '{"test":{"a":"bbb","bb":"ccc"}}'; StateWrapper.build() .useObject(demoObject) .withNewState('demoState') .setClientName('test') .end(); expect(demoObject.a).toBe('bbb'); expect(demoObject.b.bb).toBe('ccc'); }); it('should load values from local storage and then by url', function () { window.localStorage['demoState'] = '{"test":{"a":"bbb"}}'; updateURL('/loc1?demoState-data=test-a:ccc'); StateWrapper.build() .useObject(demoObject) .withNewState('demoState') .setClientName('test') .end(); expect(demoObject.a).toBe('ccc'); }); it('should load values ONLY from local storage if requested', function () { window.localStorage['demoState'] = '{"test":{"a":"bbb"}}'; updateURL('/loc1?demoState-data=test-a:ccc'); StateWrapper.build() .useObject(demoObject) .withNewState('demoState') .setClientName('test') .withProviders(['localStorage']) .end(); expect(demoObject.a).toBe('bbb'); }); }); describe('use custom traverse', function () { let vm; beforeEach(function () { vm = createViewModel({ a: 'aaa', b: { bb: 'bbb' } }); createDefaultExportImport(vm, ['a']); createDefaultExportImport(vm.b, ['bb']); }); it('should save values local storage', function () { const stateWrapper = StateWrapper.build() .useObject(vm) .withNewState('demoState') .setClientName('test') .withCustomTraverse(function (vm: ViewModel, callback, args) { vm.forEach(function (vm) { callback(vm, args); }); }) .end(); stateWrapper.save(); expect(window.localStorage.getItem('demoState')).toBe('{"test":{"a":"aaa","bb":"bbb"}}'); }); it('should load values local storage', function () { window.localStorage['demoState'] = '{"test":{"a":"bbb"}}'; StateWrapper.build() .useObject(vm) .withNewState('demoState') .setClientName('test') .withCustomTraverse(function (vm: ViewModel, callback, args) { vm.forEach(function (vm) { callback(vm, args); }); }) .end(); expect(vm.a).toBe('bbb'); }); }); describe('various options', function () { let demoObject1, demoObject2, deepObject; beforeEach(function () { demoObject1 = { a: 'aaa', b: 'bbb' }; demoObject2 = { c: 'ccc', d: 'ddd' }; deepObject = { a: 'aaa', b: {bb: 'bbb'} }; createDefaultExportImport(demoObject1, ['a', 'b']); createDefaultExportImport(demoObject2, ['c', 'd']); createDefaultExportImport(deepObject, ['a']); createDefaultExportImport(deepObject.b, ['bb']); }); it('should load only once when oneTimeLoad = true', function () { window.localStorage['demoState'] = '{"test1":{"a":"bbb"},"test2":{"c":"ddd"}}'; const stateWrapper1 = StateWrapper.build() .useObject(demoObject1) .withNewState('demoState') .setClientName('test1') .withOptions({oneTimeLoad: true}) .end(); StateWrapper.build() .useObject(demoObject2) .withState(stateWrapper1) .setClientName('test2') .end(); expect(demoObject1.a).toBe('bbb'); expect(demoObject2.c).toBe('ddd'); demoObject1.a = 'aaa'; demoObject2.c = 'ccc'; stateWrapper1.loadAll(); /* loading again, demoObject2 should load again, demoObject1 should not */ expect(demoObject1.a).toBe('aaa'); expect(demoObject2.c).toBe('ddd'); }); it('should load\\save only one level of Object when deep = false ', function () { window.localStorage['demoState'] = '{"test":{"a":"bbb","b":"ccc"}}'; const stateWrapper = StateWrapper.build() .useObject(deepObject) .withNewState('demoState') .setClientName('test') .withOptions({deep: false}) .end(); stateWrapper.load(); expect(deepObject.a).toBe('bbb'); expect(deepObject.b.bb).toBe('bbb'); window.localStorage['demoState'] = ''; stateWrapper.save(); expect(window.localStorage['demoState']).toBe('{"test":{"a":"bbb"}}'); }); it('should not load automatically when doClientLoad = false', function () { window.localStorage['demoState'] = '{"test1":{"a":"bbb"}}'; const stateWrapper1 = StateWrapper.build() .useObject(demoObject1) .withNewState('demoState') .setClientName('test1') .withOptions({doClientLoad: false}) .end(); expect(demoObject1.a).toBe('aaa'); stateWrapper1.load(); expect(demoObject1.a).toBe('bbb'); }); it('should not load automatically when doClientLoad = false, and load when promised is resolved', function (done) { window.localStorage['demoState'] = '{"test1":{"a":"bbb"}}'; const deferred = $q.defer(); StateWrapper.build() .useObject(demoObject1) .withNewState('demoState') .setClientName('test1') .withOptions({doClientLoad: deferred.promise}) .end(); expect(demoObject1.a).toBe('aaa'); deferred.resolve(true); deferred.promise.then(() => { setTimeout(() => { expect(demoObject1.a).toBe('bbb'); done(); }); }); $rootScope.$apply(); }); it('should not load automatically when doGlobalLoad = false', function () { window.localStorage['demoState'] = '{"test1":{"a":"bbb"}}'; const stateWrapper1 = StateWrapper.build() .useObject(demoObject1) .withNewState('demoState') .setClientName('test1') .withOptions({doGlobalLoad: false}) .end(); expect(demoObject1.a).toBe('aaa'); stateWrapper1.load(); /* even though we load, globalLoad is turned off */ expect(demoObject1.a).toBe('aaa'); }); it('should not load automatically when doGlobalLoad = false, and but should allow load when promised is resolved', function (done) { window.localStorage['demoState'] = '{"test1":{"a":"bbb"}}'; const deferred = $q.defer(); const stateWrapper1 = StateWrapper.build() .useObject(demoObject1) .withNewState('demoState') .setClientName('test1') .withOptions({doGlobalLoad: deferred.promise as any}) .end(); expect(demoObject1.a).toBe('aaa'); stateWrapper1.load(); expect(demoObject1.a).toBe('aaa'); deferred.resolve(true); deferred.promise.then(() => { setTimeout(() => { stateWrapper1.load(); expect(demoObject1.a).toBe('bbb'); done(); }); }); $rootScope.$apply(); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/state-wrapper.ts ================================================ 'use strict'; import {State} from './state'; import {IStateClient, IStateProvider} from './types'; import {urlStateProvider} from './url-state-provider'; import {localStorageStateProvider} from './localstorage-state-provider'; import {lodash as _, isPromise} from '../../utils'; /** * Core services * * @author Our One Creator Which Flies and is Spaghetti and a Monster */ const IOProviders = { localStorage: { provider: localStorageStateProvider, dataType: 'JSON' }, url: { provider: urlStateProvider, dataType: 'URL' } }; export type traverseFunction = (obj: any, callback: (obj: any, args: any[]) => void, args: any[], deep?: boolean) => void; function defaultTraverse(obj: any, callback, args: any[] = [], deep = true) { callback(obj, args); if (deep) { _.forOwn(obj, (child, childName) => { if (_.isObject(child) && child !== obj) { defaultTraverse(child, callback, args, deep); } }); } } function createLoadFunction(obj: any, deep = true, oneTimeLoad = false, customTraverse?) { const traverse = customTraverse ? customTraverse : defaultTraverse; const loadFunction = function (ob: any, args: any[] = []) { if (oneTimeLoad && ob.$stateLoaded) { return; } if (_.isFunction(ob.$import)) { ob.$import(...args); } if (oneTimeLoad) { ob.$stateLoaded = true; } }; return function (params) { traverse(obj, loadFunction, [params], deep); }; } function createSaveFunction(obj: Object, deep = true, customTraverse?): (providerName: string, stateName: any) => any { const traverse = customTraverse ? customTraverse : defaultTraverse; const saveFunction = function (providerName: string, accumulator, ob: any, args: any[] = []) { if (_.isFunction(ob.$export)) { _.assign(accumulator, ob.$export(providerName, ...args)); } }; return function (providerName: string, stateName) { const accumulator = {}; traverse(obj, saveFunction.bind(null, providerName, accumulator), [stateName], deep); return accumulator; }; } export interface StateWrapperOptions { doClientLoad?: PromiseLike | boolean; doGlobalLoad?: PromiseLike | boolean; deep?: boolean; oneTimeLoad?: boolean; } export class StateWrapperBuilder { private object: Object; private clientName: string; private state: StateWrapper; private options: StateWrapperOptions = { doClientLoad: true, doGlobalLoad: true, deep: true, oneTimeLoad: false }; private providers: string[]; private newStateName: string; private traverse: traverseFunction; useObject(object) { this.object = object; return this; } setClientName(name) { this.clientName = name; return this; } withOptions(options: StateWrapperOptions) { this.options = _.assign(this.options, options); return this; } withState(state: StateWrapper) { this.state = state; return this; } withNewState(name: string) { this.newStateName = name; return this; } withProviders(providers: string[]) { this.providers = providers; return this; } withCustomTraverse(traverseFunc: traverseFunction) { this.traverse = traverseFunc; return this; } private verifyMandatoryParametrs() { if (!this.object) { throw new Error('StateWrapperBuilder::build: You must provide an object'); } if (!this.clientName) { throw new Error('StateWrapperBuilder::build: You must provide a clientName'); } if (!this.state && !this.newStateName) { throw new Error('StateWrapperBuilder::build: You must provide a state'); } } public end() { this.verifyMandatoryParametrs(); const {doClientLoad, doGlobalLoad, deep, oneTimeLoad} = this.options; let baseState; if (!this.providers) { this.providers = ['localStorage', 'url']; } if (this.state) { baseState = this.state.getBaseState(); } else { baseState = new State(this.newStateName, doGlobalLoad); } const stateWrapper = new StateWrapper(baseState, this.clientName, this.providers); const stateClient: IStateClient = { name: this.clientName, importFunc: createLoadFunction(this.object, deep, oneTimeLoad, this.traverse), exportFunc: createSaveFunction(this.object, deep, this.traverse) }; baseState.register(stateClient); if (doClientLoad === true) { stateWrapper.load(); } else if (isPromise(doClientLoad)) { (doClientLoad as PromiseLike).then(() => { stateWrapper.load(); }); } return stateWrapper; } } export class StateWrapper { private readonly inputOutputProviders: {name: string; provider: IStateProvider; dataType: string}[] = []; static build() { return new StateWrapperBuilder(); } constructor(private readonly state: State, private readonly clientName, providers = ['localStorage', 'url']) { providers.forEach((providerName) => { if (IOProviders[providerName]) { this.inputOutputProviders.push({name: providerName, ...IOProviders[providerName]}); } }); } getBaseState() { return this.state; } private _load(clientList: string[] = []) { const stateName = this.state.getName(); this.inputOutputProviders.forEach(providerInfo => { const data = providerInfo.provider.getStateData(stateName); const functionName = 'importFrom' + providerInfo.dataType; this.state[functionName](data, ...clientList); }); } load(...clientList) { if (clientList.length === 0) { clientList = [this.clientName]; } this._load(clientList); } loadAll() { this._load([]); } private _save(clientList: string[] = []) { const stateName = this.state.getName(); this.inputOutputProviders.forEach(providerInfo => { const functionName = 'exportAs' + providerInfo.dataType; const data = this.state[functionName](providerInfo.name, ...clientList); providerInfo.provider.setStateData(stateName, data); }); } save(...clientList) { if (clientList.length === 0) { clientList = [this.clientName]; } this._save(clientList); } saveAll() { this._save([]); } unregister() { this.state.unregister(this.clientName); } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/state.test.ts ================================================ import {State} from './state'; import {IStateClient} from './types'; describe('State', function () { let state: State; beforeEach(() => { state = new State('test'); }); describe('State::register', () => { beforeEach(function() { spyOn(console, 'error'); }); const client1: IStateClient = { name: 'test1', exportFunc: () => ({original: true}), importFunc: (params) => ({}) }; const client1Again: IStateClient = { name: 'test1', exportFunc: () => ({redefined: true}), importFunc: (params) => ({}), }; it('should not override old client with new client with same name', () => { state.register(client1); state.register(client1Again); expect(console.error).toHaveBeenCalledWith('State:register:: trying to register same name twice - test1'); expect(state.exportAsJSON()).toEqual('{"test1":{"original":true}}'); }); it('should register waiting client when original client un-registers', () => { state.register(client1); state.register(client1Again); state.unregister('test1'); expect(console.error).toHaveBeenCalledWith('State:register:: trying to register same name twice - test1'); expect(state.exportAsJSON()).toEqual('{"test1":{"redefined":true}}'); }); }); describe('State::export', () => { let client1, client2: IStateClient; beforeEach(() => { client1 = { name: 'test1', exportFunc: () => ({param1: true, param2: 4}), importFunc: (params) => ({}) }; client2 = { name: 'test2', exportFunc: () => ({param2: 'aaaa', param1: 'bbbb'}), importFunc: (params) => ({}) }; }); it('should successfully call export function with the provider name and stateName', function () { spyOn(client1, 'exportFunc'); state.register(client1); state.exportAsJSON('testProvider'); expect(client1.exportFunc).toHaveBeenCalledWith('testProvider', 'test'); }); it('should successfully call export function with the provider name and stateName', function () { spyOn(client1, 'exportFunc'); state.register(client1); state.exportAsURL('testProvider'); expect(client1.exportFunc).toHaveBeenCalledWith('testProvider', 'test'); }); it('successfully export all clients to JSON\\URL', function () { state.register(client1); state.register(client2); expect(state.exportAsJSON()) .toBe('{"test1":{"param1":true,"param2":4},"test2":{"param2":"aaaa","param1":"bbbb"}}'); expect(state.exportAsURL()) .toBe('&test-data=test1-param1:true;test1-param2:4;test2-param2:aaaa;test2-param1:bbbb;'); }); it('successfully export specific client to JSON\\URL', function () { state.register(client1); state.register(client2); expect(state.exportAsURL('provider', 'test1')) .toBe('&test-data=test1-param1:true;test1-param2:4;'); expect(state.exportAsJSON('provider', 'test1')) .toBe('{"test1":{"param1":true,"param2":4}}'); }); }); describe('State::import', () => { let client1, client2: IStateClient; let results1, results2; beforeEach(() => { client1 = { name: 'test1', exportFunc: () => ({param1: true, param2: 4}), importFunc: (params: any) => { results1.param1 = params.param1; results1.param2 = params.param2; } }; client2 = { name: 'test2', exportFunc: () => ({param2: 'aaaa', param1: 'bbbb'}), importFunc: (params: any) => { results2.param2 = params.param2; results2.param1 = params.param1; } }; results1 = {}; results2 = {}; state.register(client1); state.register(client2); }); it('should successfully import all clients from JSON', function () { state.importFromJSON('{"test1":{"param1":true,"param2":4},"test2":{"param2":"aaaa","param1":"bbbb"}}'); expect(results1).toEqual({param1: true, param2: 4}); expect(results2).toEqual({param2: 'aaaa', param1: 'bbbb'}); }); it('should successfully import to all clients from URL', function () { state.importFromURL('test1-param1:true;test1-param2:4;test2-param2:aaaa;test2-param1:bbbb;'); expect(results1).toEqual({param1: 'true', param2: '4'}); expect(results2).toEqual({param2: 'aaaa', param1: 'bbbb'}); }); it('should correctly process values with colons', function () { state.importFromURL('test1-param1:a:b;'); expect(results1).toEqual({param1: 'a:b', param2: undefined}); }); }); describe('State::unregister', () => { let client1, client2: IStateClient; let results1, results2; beforeEach(() => { client1 = { name: 'test1', exportFunc: () => ({param1: true, param2: 4}), importFunc: (params: any) => { results1.param1 = params.param1; results1.param2 = params.param2; } }; client2 = { name: 'test2', exportFunc: () => ({param2: 'aaaa', param1: 'bbbb'}), importFunc: (params: any) => { results2.param2 = params.param2; results2.param1 = params.param1; } }; results1 = {}; results2 = {}; state.register(client1); state.register(client2); }); it('should not to do anything after client unregistered', function () { state.unregister('test2'); state.importFromJSON('{"test1":{"param1":true,"param2":4},"test2":{"param2":"aaaa","param1":"bbbb"}}'); expect(results1).toEqual({param1: true, param2: 4}); expect(results2).toEqual({}); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/state.ts ================================================ import {lodash as _, isPromise} from '../../utils'; type Dictionary = Record; import {IStateClient} from './types'; export class State { private readonly clients: {[key: string]: IStateClient} = {}; /* sometimes $destory is called only after another instance of a directive is loading so we save a queue of 1 "waiting" client */ private readonly clientsOnHold: {[key: string]: IStateClient} = {}; constructor (private readonly name: string, private doLoad: boolean | PromiseLike = true) { if (isPromise(doLoad)) { (doLoad as PromiseLike).then((value) => { this.doLoad = value; }); } } getName() { return this.name; } getClientByName(name: string) { return this.clients[name]; } /** * adds a new client to this state. * @param client * @returns {bi.core.srv.state.State} */ register (client: IStateClient): State { const {name} = client; if (this.clients[name]) { console.error('State:register:: trying to register same name twice - ' + name); this.clientsOnHold[name] = client; } else { this.clients[name] = client; } return this; } unregister(name: string): State { if (this.clients[name]) { // tslint:disable-next-line: no-dynamic-delete delete this.clients[name]; const waitingClient = this.clientsOnHold[name]; if (waitingClient) { this.clients[name] = waitingClient; // tslint:disable-next-line: no-dynamic-delete delete this.clientsOnHold[name]; } } return this; } private _export (providerName: string, clientList: string[]) { const res: Dictionary> = {}; if (clientList.length === 0) { clientList = Object.keys(this.clients); } _.forEach(clientList, (clientName: string) => { if (this.clients[clientName]) { const client = this.clients[clientName]; res[client.name] = {}; _.assign(res[client.name], client.exportFunc(providerName, this.name)); } }); return res; } exportAsJSON (providerName?: string, ...clientList: string[]) { return JSON.stringify(this._export(providerName, clientList)); } //TODO: handle objects? in paramData exportAsURL (providerName?: string, ...clientList: string[]) { const data = this._export(providerName, clientList); const params = _.reduce(data, (outerResult, clientData, clientName) => { // tslint:disable-next-line: restrict-plus-operands return outerResult + _.reduce(clientData, (innerResult, paramData, paramName) => { return innerResult + `${clientName}-${paramName}:${paramData};`; }, ''); }, ''); return encodeURI(`&${this.name}-data=${params}`); } private _import (data: Object, clientList: string[]) { if (clientList.length === 0) { clientList = Object.keys(this.clients); } _.forEach(clientList, (clientName: string) => { if (this.clients[clientName]) { const client = this.clients[clientName]; if (data[client.name]) { client.importFunc(data[client.name]); } } }); } importFromJSON(stringData: string, ...clientList: string[]) { if (this.doLoad !== true) { return; } if (stringData) { this._import(JSON.parse(stringData), clientList); } } importFromURL(stringData: string, ...clientList: string[]) { if (this.doLoad !== true) { return; } // let match = new RegExp(`&?${this.name}-data=(.*)&?`).exec(stringData); // if (match && match[1]) { // var stringDataStripStateName = match[1]; // } else { // throw new Error("State::importFromURL: Can't parse data!"); // } if (!stringData) { return; } const data = {}; const allParams = stringData.split(';'); allParams.forEach( singleParamStr => { const [paramFullName, ...paramData] = singleParamStr.split(':'); const path = paramFullName.replace('-', '.'); _.set(data, path, paramData.join(':')); }); this._import(data, clientList ); } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/types.ts ================================================ export interface IStateClient { name: string; importFunc(params: any): void; exportFunc(providerName: string, stateName: string): Object; } export interface IStateProvider { getStateData(stateName: string): string; setStateData(stateName: string, data: string): void; } ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/url-params.test.ts ================================================ 'use strict'; import * as angular from 'angular'; import {UrlParams} from './url-params'; describe('Service: UrlParams', function () { let urlParams, $location, $browser, decodeSpy, encodeSpy; function updateURL(url) { $location.url(url); $browser.poll(); } beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$location_, _$browser_) { urlParams = new UrlParams(); $location = _$location_; $browser = _$browser_; })); beforeEach(function () { decodeSpy = jasmine.createSpy('decode'); encodeSpy = jasmine.createSpy('encode'); }); it('should return expected interface, decode + generateURL', function () { updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3=true'); const urlObject = urlParams.register('fm', decodeSpy, encodeSpy); expect(typeof urlObject.decode).toBe('function'); expect(typeof urlObject.generateURL).toBe('function'); }); it('should call decode function', function () { updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3=true'); const urlObject = urlParams.register('fm', decodeSpy, encodeSpy); urlObject.decode(); expect(decodeSpy).toHaveBeenCalled(); }); it('should call decode function, with expected parameters', function () { updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3¬-param=5'); const expededObject = { param1: '1', param2: 'hello', param3: true }; const urlObject = urlParams.register('fm', decodeSpy, encodeSpy); urlObject.decode(); expect(decodeSpy).toHaveBeenCalledWith(expededObject); }); it('should call encode function', function () { updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3¬-param=5'); const urlObject = urlParams.register('fm', decodeSpy, encodeSpy); urlObject.generateURL(); expect(encodeSpy).toHaveBeenCalled(); }); it('should return correct url for all modules', function () { const encode = function () { return { param1: '1', param2: 'hello', param3: true }; }; const encodeSecond = function () { return { param1: '2' }; }; const decodeSpy = jasmine.createSpy('decode'); urlParams.register('fm', decodeSpy, encode); urlParams.register('second', decodeSpy, encodeSecond); const urlResult = urlParams.generateURL(); expect(urlResult).toBe('fm-param1=1&fm-param2=hello&fm-param3&second-param1=2'); }); it('should return correct url for specific module', function () { const encode = function () { return { param1: '1', param2: 'hello', param3: true }; }; const encodeSecond = function () { return { param1: '2' }; }; urlParams.register('fm', decodeSpy, encode); urlParams.register('second', decodeSpy, encodeSecond); let urlResult = urlParams.generateURL(['second']); expect(urlResult).toBe('second-param1=2'); urlResult = urlParams.generateURL(['fm']); expect(urlResult).toBe('fm-param1=1&fm-param2=hello&fm-param3'); }); it('should unregister a module', function () { const encodeSecondSpy = jasmine.createSpy('encode'); const urlObject = urlParams.register('fm', decodeSpy, encodeSpy); urlParams.register('second', decodeSpy, encodeSecondSpy); urlParams.generateURL(); expect(encodeSpy).toHaveBeenCalled(); expect(encodeSecondSpy).toHaveBeenCalled(); encodeSpy.calls.reset(); encodeSecondSpy.calls.reset(); urlObject.unregister(); urlParams.generateURL(); expect(encodeSpy).not.toHaveBeenCalled(); expect(encodeSecondSpy).toHaveBeenCalled(); }); it('should throw error when registering same prefix', function () { urlParams.register('fm', decodeSpy, encodeSpy); expect(function () { urlParams.register('fm', decodeSpy, encodeSpy); }).toThrow(new Error('urlParams: registered two modules with same prefix: fm')); }); it('should throw error when registering module with dash', function () { expect(function () { urlParams.register('fm-2', decodeSpy, encodeSpy); }).toThrow(new Error('urlParams: can\'t register module name with a dash: fm-2')); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/url-params.ts ================================================ 'use strict'; import {lodash as _} from '../../utils'; import {injector} from '../injector'; function processParam(moduleName: string, paramName: string, paramValue: string | boolean) { let paramNameWithPrefix = moduleName + '-' + paramName; if (paramValue === true) { return paramNameWithPrefix + '&'; } else if (paramValue === false) { return ''; } else { return paramNameWithPrefix + '=' + paramValue + '&'; } } export type decodeFunc = (input: {}) => any; export type encodeFunc = () => {[key: string]: string | boolean}; export interface ModuleCallbacks { encode: encodeFunc; decode: decodeFunc; } export class UrlParams { modules = {}; private $location: ng.ILocationService; constructor() { this.$location = injector.get('$location'); } register(moduleName: string, decode: decodeFunc, encode: encodeFunc) { if (moduleName.search('\-') !== -1) { throw new Error('urlParams: can\'t register module name with a dash: ' + moduleName); } if (this.modules[moduleName]) { throw new Error('urlParams: registered two modules with same prefix: ' + moduleName); } this.modules[moduleName] = {decode, encode}; return { decode: () => { return this.decode([moduleName]); }, generateURL: this.generateURL.bind(this, [moduleName]), unregister: () => { if (this.modules[moduleName]) { delete this.modules[moduleName]; } } }; } public generateURL(moduleList: Array = null) { let res = ''; _.forEach(this.modules, (cb: ModuleCallbacks, moduleName) => { if (moduleList && ! _.includes(moduleList, moduleName)) { return; } let moduleParams = cb.encode(); _.forEach(moduleParams, (paramValue, paramName) => { res += processParam(moduleName, paramName, paramValue); }); }); return res.slice(0, -1); } public decode(moduleList: Array = null) { let map = this._sperateParamsByModule(); _.forEach(this.modules, (cb: ModuleCallbacks, moduleName) => { if (moduleList && ! _.includes(moduleList, moduleName)) { return; } cb.decode(map[moduleName]); }); } private _sperateParamsByModule() { let res = {}; let urlMap = this.$location.search(); _.forEach(urlMap, (value, key: string) => { let [moduleName] = key.split('-', 1); if (this.modules[moduleName]) { let path = key.replace('-', '.'); _.set(res, path, value); } }); return res; } } ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/url-state-provider.test.ts ================================================ 'use strict'; import {urlStateProvider} from './url-state-provider'; import * as angular from 'angular'; describe('UrlStateProvider', function () { let $location, $browser; function updateURL(url) { $location.url(url); $browser.poll(); } beforeEach(function () { angular.mock.module('bi.core.internal'); }); beforeEach(inject(function (_$location_, _$browser_) { $location = _$location_; $browser = _$browser_; })); describe('Load', () => { it('should correctly load data', function () { updateURL('/loc1?test-data=param1:2;parma2=aaa'); expect(urlStateProvider.getStateData('test')).toEqual('param1:2;parma2=aaa'); }); it('should return null when no data in url', function () { updateURL('/loc1?test-data=param1:2;parma2=aaa'); expect(urlStateProvider.getStateData('test2')).toEqual(null); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/state/url-state-provider.ts ================================================ import {IStateProvider} from './types'; import {injector} from '../injector'; export const urlStateProvider: IStateProvider = new class UrlStateProvider implements IStateProvider { private location: ng.ILocationService; constructor() { injector.on('ready', () => { this.location = injector.get('$location'); }); } getStateData(stateName: string): string { const urlMap = this.location.search(); const result = urlMap[stateName + '-data']; return result ? result : null; } setStateData(stateName: string, data: string): void { //-- Nothing for now. maybe change url -- } }; ================================================ FILE: quix-frontend/client/src/lib/core/srv/view-model/view-model.test.ts ================================================ 'use strict'; import {ViewModel, create as createVM} from './view-model'; import * as angular from 'angular'; describe('bi.core.drv.createViewModel()', function () { beforeEach(function () { angular.mock.module('bi.core.internal'); }); describe('creation', function () { it('should create an empty view model', function () { const vm = createVM(); expect(vm).toBeDefined(); }); it('should create an view model from object', function () { const vm = createVM({ test: true }) as any; expect(vm.test).toBe(true); }); it('should not alter the template', function () { const template = { test: true }; const templateString = JSON.stringify(template); createVM(template); expect(templateString).toBe(JSON.stringify(template)); }); it('should use the existing vm', function () { const vm = (createVM() as any).vm; const vm2 = (createVM(null, vm) as any).vm; expect(vm2).toBe(vm); }); }); describe('flags', function () { it('should define basic flags with false values', function () { const vm = createVM(); expect(vm.enabled).toBe(false); expect(vm.visible).toBe(false); }); it('should not override template flag values', function () { const vm = createVM({ enabled: true }); expect(vm.enabled).toBe(true); }); it('should initialize nested values', function () { const vm = createVM({ nested: { enabled: true } }) as any; expect(vm.enabled).toBe(false); expect(vm.visible).toBe(false); expect(vm.nested.enabled).toBe(true); expect(vm.nested.visible).toBe(false); }); it('should toggle enabled and visible flags', function () { const vm = createVM() as any; vm.toggle(); expect(vm.enabled).toBe(true); expect(vm.visible).toBe(true); vm.toggle(false); expect(vm.enabled).toBe(false); expect(vm.visible).toBe(false); }); it('should set enabled and visible flags', function () { const vm = createVM(); vm.toggle(true); expect(vm.enabled).toBe(true); expect(vm.visible).toBe(true); vm.toggle(true); expect(vm.enabled).toBe(true); expect(vm.visible).toBe(true); }); it('should toggle enabled flag', function () { const vm = createVM() as any; vm.toggleEnabled(); expect(vm.enabled).toBe(true); expect(vm.visible).toBe(false); vm.toggleEnabled(true); expect(vm.enabled).toBe(true); expect(vm.visible).toBe(false); vm.toggleEnabled(false); expect(vm.enabled).toBe(false); expect(vm.visible).toBe(false); }); it('should toggle visible flag', function () { const vm = createVM() as any; vm.toggleVisible(); expect(vm.enabled).toBe(false); expect(vm.visible).toBe(true); vm.toggleVisible(true); expect(vm.enabled).toBe(false); expect(vm.visible).toBe(true); vm.toggleVisible(false); expect(vm.enabled).toBe(false); expect(vm.visible).toBe(false); }); }); describe('template cloning', function () { it('should deep clone the template (object)', function () { const obj = {}; const vm = createVM({ test: obj }) as any; expect(vm.test).not.toBe(obj); }); it('should deep clone the template (array)', function () { const arr = []; const vm = createVM({ test: arr }) as any; expect(vm.test).not.toBe(arr); }); }); describe('init', function () { it('should call $init function', function () { const vm = createVM({ $init: jasmine.createSpy('$init') }).init() as any; expect(vm.$init).toHaveBeenCalled(); }); it('should call $init function (nested values)', function () { const vm = createVM({ nested: { $init: jasmine.createSpy('$init') } }).init() as any; expect(vm.nested.$init).toHaveBeenCalled(); }); }); describe('$root', function () { it('should define a reference to the root', function () { const vm = createVM().init() as any; expect(vm.$root).toBe(vm); }); it('should define a reference to the root (nested)', function () { const vm = createVM({ test: {} }).init() as any; expect(vm.test.$root).toBe(vm); }); }); describe('$params', function () { it('should define custom params', function () { const vm = createVM().init({ foo: 1 }) as any; expect(vm.$params.foo).toBe(1); }); it('should define custom params (nested)', function () { const vm = createVM({ goo: {} }).init({ foo: 1 }) as any; expect(vm.goo.$params.foo).toBe(1); }); }); describe('createItemsVm()', function () { it('should create an items vm object', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm(); } }).init() as any; expect(vm.items).toBeDefined(); }); it('should create and return item vm by id', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm({ foo: 1 }); } }).init() as any; const itemVm = vm.items.get({id: 1}); expect(itemVm instanceof ViewModel).toBe(true); expect(itemVm.foo).toBe(1); }); it('should return same vm for items with same identifier', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm(); } }).init() as any; const item1Vm = vm.items.get({id: 1}); const item2Vm = vm.items.get({id: 1}); expect(item1Vm).toBe(item2Vm); }); it('should return different vm for items with different identifiers', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm(); } }).init() as any; const item1Vm = vm.items.get({id: 1}); const item2Vm = vm.items.get({id: 2}); expect(item1Vm).not.toBe(item2Vm); }); it('should return null if identifier is not defined', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm(); } }).init() as any; const item1Vm = vm.items.get({}); expect(item1Vm).toBe(null); }); it('should create and return vm by custom identifier', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm().identifyBy(function (item) { return item.index; }); } }).init() as any; const itemVm = vm.items.get({index: 1}); expect(itemVm instanceof ViewModel).toBe(true); }); it('should delete item vm', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm({ foo: 1 }); } }).init() as any; const item1Vm = vm.items.get({id: 1}); vm.items.delete({id: 1}); const item2Vm = vm.items.get({id: 1}); expect(item2Vm).not.toBe(item1Vm); }); it('should call $init for each new item vm', function () { const vm = createVM({ $init: function () { this.items = this.createItemsVm({ $init: jasmine.createSpy('$init') }); } }).init() as any; const item1Vm = vm.items.get({id: 1}); expect(item1Vm.$init.calls.count()).toBe(1); }); it('should call $init for each existing item vm', function () { const vm = createVM({ $init: function () { this.items = this.items || this.createItemsVm({ $init: jasmine.createSpy('$init') }); } }).init() as any; const item1Vm = vm.items.get({id: 1}); vm.items.get({id: 2}); vm.init(); expect(item1Vm.$init.calls.count()).toBe(4); }); }); describe('isHead()', function () { it('should return true', function () { const vm = createVM(); expect(vm.isHead()).toBe(true); }); it('should return false', function () { const vm = createVM({ child: {} }) as any; expect(vm.child.isHead()).toBe(false); }); }); describe('forEach()', function () { it('should apply the function to the root node', function () { const vm = createVM(); const fn = jasmine.createSpy('forEach'); vm.forEach(fn); expect(fn).toHaveBeenCalledWith(vm); }); it('should apply the function for all nodes recursively', function () { const vm = createVM({ child: {} }) as any; const fn = jasmine.createSpy('forEach'); vm.forEach(fn); expect(fn.calls.allArgs()).toEqual([[vm], [vm.child]]); }); it('should break on first iteration', function () { const vm = createVM({ child: {} }); const fn = jasmine.createSpy('forEach').and.returnValue(false); vm.forEach(fn); expect((fn).calls.allArgs()).toEqual([[vm]]); }); it('should not be called on a child head nodes', function () { const vm = createVM() as any; vm.childHead = createVM(); const fn = jasmine.createSpy('forEach'); vm.forEach(fn); expect(vm.childHead.isHead()).toBe(true); expect(fn.calls.allArgs()).toEqual([[vm]]); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/core/srv/view-model/view-model.ts ================================================ 'use strict'; import {lodash as _} from '../../utils'; import {injector} from '../injector'; /** * Core directive tools * * @author Our One Creator Which Flies and is Spaghetti and a Monster */ function createVM(template, root) { return _.cloneDeepWith(template, function (value) { if (_.isPlainObject(value)) { const vm = {}; _.forOwn(value, (val, key) => { if (_.isPlainObject(val)) { vm[key] = new ViewModel(val, root); } else { vm[key] = createVM(val, root); } }); return vm; } if (_.isArray(value)) { return; // let lodash clone the value } return value; }); } export class ItemsViewModel { private items: { [id: string]: ViewModel } = {}; private identifier = item => item.id; constructor(private readonly vm?) { } get(item: Object): ViewModel { const id = this.identifier(item); if (_.isUndefined(id)) { return null; } return this.items[id] = this.items[id] || new ViewModel(this.vm).init(); } all(): ViewModel[] { return _.values(this.items); } delete(item: Object): ItemsViewModel { // tslint:disable-next-line: no-dynamic-delete delete this.items[this.identifier(item)]; return this; } deleteAll(): ItemsViewModel { this.items = {}; return this; } identifyBy(identifier: (item: Object) => number): ItemsViewModel { this.identifier = identifier; return this; } forEach(fn) { let res; this.all().every(item => { res = item.forEach(fn); return res === false ? false : true; }); return res; } } export class ViewModel { enabled: boolean; visible: boolean; constructor(vm: Object = null, protected $root = null) { this.$root = this.$root || this; try { this.enabled = false; this.visible = false; } catch (e) { //empty } if (vm) { _.assign(this, createVM(vm, this.$root)); } } init(params?) { this.forEach(vm => { vm.$params = params; if (_.isFunction(vm.$init)) { vm.$init(); } }); return this; } isHead() { return this === this.$root; } /** * Toggle both "enabled" and "visible" flags */ toggle(enabled) { try { this.toggleEnabled(enabled); this.toggleVisible(enabled); } catch (e) { //empty } } /** * Toggle the "enabled" flag */ toggleEnabled(enabled) { try { this.enabled = typeof enabled !== 'undefined' ? enabled : !this.enabled; } catch (e) { //empty } return this.enabled; } /** * Toggle the "visible" flag */ toggleVisible(visible) { try { this.visible = typeof visible !== 'undefined' ? visible : !this.visible; } catch (e) { //empty } return this.visible; } reload() { this.toggleVisible(false); return injector.get('$timeout')(() => this.toggleEnabled(false)).then(() => injector.get('$timeout')(() => this.toggle(true))); } /** * Create a view model for items. Useful for managing view state of items in a list. */ createItemsVm(vm?) { return new ItemsViewModel(vm); } forEach(fn) { let res = fn(this); if (res !== false) { _.forOwn(this, (val, key) => { if (val instanceof ViewModel && val.isHead()) { return; } if (val instanceof ViewModel || val instanceof ItemsViewModel) { return (res = val.forEach(fn)); } }); } return res; } } /** * Create a view model object for use in the view layer * * @param vm Plain object representation of the view model. Nested objects will be also converted to ViewModel instances. */ export function create(vm: Object = null, root?): ViewModel { return new ViewModel(vm, root); } ================================================ FILE: quix-frontend/client/src/lib/core/types/angular-promise.d.ts ================================================ /// import * as angular from 'angular'; declare module 'angular' { export interface IPromise { then(successCallback: (promiseValue: T) => PromiseLike | TResult, errorCallback?: (reason: any) => TResult2, notifyCallback?: (state: any) => any): IPromise; catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; } } ================================================ FILE: quix-frontend/client/src/lib/core/utils/index.ts ================================================ 'use strict'; import * as _ from 'lodash'; import jquery from 'jquery'; import * as Uuid from 'uuid'; import escapeHtml from 'escape-html'; export function isPromise(obj: any): boolean { return (obj && typeof obj.then === 'function'); } export function uuid() { return Uuid.v4(); } export const scope = { safeApply(sc, fn: Function) { const phase = sc.$root.$$phase; if (phase === '$apply' || phase === '$digest') { fn(); } else { sc.$apply(fn); } }, safeDigest(sc, fn: Function) { const phase = sc.$root.$$phase; if (phase === '$apply' || phase === '$digest') { fn(); } else { fn(); sc.$digest(); } } } export const dom = { KEYS: { escape: 27 }, onBlur(element, fn, sc?): Function { const document = $(window.document); const eventName = _.uniqueId('click.utils.dom.onBlur'); function off() { document.off(eventName); } document.on(eventName, e => { const parent = element.parent(); const target = $(e.target); if (!target.closest(parent).length || target.closest(element).length) { const child = target.closest(element).length && target; let res; if (sc) { res = sc.$apply(() => fn(off, child)); } else { res = fn(off, child); } if (res !== false) { off(); } } }); if (sc) { sc.$on('$destroy', off); } return off; }, onKey(key, fn, s?): Function { const document = $(window.document); const eventName = _.uniqueId('keydown.utils.dom.onKey.' + key); const codes = (Array.isArray(key) ? key : [key]).map(k => dom.KEYS[k] || k); function off() { document.off(eventName); } document.on(eventName, e => { // tslint:disable-next-line: deprecation if (codes.indexOf(e.keyCode) !== -1) { e.preventDefault(); if (scope) { // tslint:disable-next-line: deprecation s.$apply(() => fn(off, e.keyCode)); } else { // tslint:disable-next-line: deprecation fn(off, e.keyCode); } } }); if (s) { s.$on('$destroy', off); } return off; }, escape(str) { return escapeHtml(str); }, scrollIntoView(element, animate = false, offset = 0) { const scrollParent = element.scrollParent(); // tslint:disable-next-line: restrict-plus-operands const scrollTop = element.position().top + scrollParent.scrollTop() + offset; scrollParent.animate({scrollTop}, animate ? 200 : 0); }, } export function stripDollars(data: T): Partial { if (_.isPlainObject(data)) { // tslint:disable-next-line: restrict-plus-operands data = _.omitBy(data, (value, key) => ('' + key).charAt(0) === '$') as T; data = _.mapValues(data, value => stripDollars(value as any)) as T; } if (_.isArray(data)) { data = data.map(item => stripDollars(item)) as any; } return data; } export function copyToClipboard(text: string) { const input = jquery('').val(text); input.appendTo(window.document.body); input.get(0).focus(); (input.get(0) as any).select(); // tslint:disable-next-line:deprecation document.execCommand('Copy'); input.remove(); } export const lodash: any = _; import './lodash4-polyfill'; ================================================ FILE: quix-frontend/client/src/lib/core/utils/lodash4-polyfill.ts ================================================ 'use strict'; import {lodash} from './'; if (!lodash.cloneDeepWith) { lodash.cloneDeepWith = function (value, customizerFunction) { return lodash.cloneDeep(value, customizerFunction); }; } ================================================ FILE: quix-frontend/client/src/lib/core/utils/lodash4-polyfill.types.ts ================================================ declare module _ { interface LoDashStatic { cloneDeepWith: ( value: any, customizer: CloneDeepCustomizer ) => TResult; } } ================================================ FILE: quix-frontend/client/src/lib/core/utils/utils.test-prepare.ts ================================================ 'use strict'; /* Don't include this file in index.vm' */ // window['_'] = null; ================================================ FILE: quix-frontend/client/src/lib/core/utils/utils.test.ts ================================================ import * as angular from 'angular'; import {scope, dom} from './'; describe('bi.core.utils', function () { beforeEach(function () { angular.mock.module('bi.core.internal'); }); let safeApply, $rootScope: ng.IRootScopeService; beforeEach(inject(function (_$rootScope_) { $rootScope = _$rootScope_; safeApply = scope.safeApply; })); describe('safeApply', () => { it('should call function', function () { const scope = $rootScope.$new(); const spy = jasmine.createSpy('scope spy'); safeApply(scope, spy); expect(spy).toHaveBeenCalled(); }); it('should call function, even if inside $apply', function () { const scope = $rootScope.$new(); const spy = jasmine.createSpy('scope spy'); expect(() => scope.$apply(() => scope.$apply(spy))).toThrow(); expect(spy).not.toHaveBeenCalled(); expect(() => scope.$apply(() => safeApply(scope, spy))).not.toThrow(); expect(spy).toHaveBeenCalled(); }); }); describe('escape', () => { it('should html-escape string', function () { expect(dom.escape('foo & bar')).toEqual('foo & bar'); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/file-explorer/bootstrap.ts ================================================ import angular from 'angular'; import 'jquery-ui/ui/widgets/draggable'; import 'jquery-ui/ui/widgets/droppable'; import 'angular-dragdrop'; import '../core'; import '../ui'; export default angular.module('bi.fileExplorer', ['bi.core', 'bi.ui', 'ngDragDrop']); ================================================ FILE: quix-frontend/client/src/lib/file-explorer/directives/file-explorer-dynamic.html ================================================
  • arrow_drop_down
    more_vert
  • Loading...
================================================ FILE: quix-frontend/client/src/lib/file-explorer/directives/file-explorer-static.html ================================================
  • arrow_drop_down
    more_vert
  • Loading...
================================================ FILE: quix-frontend/client/src/lib/file-explorer/directives/file-explorer-vm.ts ================================================ import {Item, File, Folder} from '../services/file-explorer-models'; export default { order: { field: 'name', setField(field: string, reversed = false) { this.field = reversed ? '-' + field : field; } }, dropped: { item: null as Item }, folder: { getPermissions(folder) { const vm = this.$root.folders.get(folder); return (vm.permissions = vm.permissions || this.$params.controller.getPermissions(folder)); }, canDelete(folder) { return this.getPermissions(folder).delete; }, canRename(folder) { return this.getPermissions(folder).rename; }, hasMenu(folder) { return this.getPermissions(folder).menu; }, toggleOpen(folder, value) { this.$root.folders.get(folder).open.toggle(value); }, toggleEdit(folder, value) { this.$root.folders.get(folder).edit.toggle(value); }, isOpen(folder) { return this.$root.folders.get(folder).open.enabled; }, setCurrent(folder: Folder) { this.$params.controller.setCurrentFolder(folder); }, getCurrent(): Folder { return this.$params.controller.getCurrentFolder(); }, isActive(folder: File): boolean { return folder.getId() === (this.getCurrent() && this.getCurrent().getId()); }, isEmpty(): boolean { return this.$params.item.isEmpty(); }, $init() { if (this.$params.item) { this.$params.item.on('openToggled', (model, folder, isOpen) => { this.$root.folder.toggleOpen(folder, isOpen); }, true); this.$params.item.on('editToggled', (model, folder, edit) => { this.$root.folder.toggleEdit(folder, edit); }, true); } } }, file: { setCurrent(file: File) { this.$params.controller.setCurrentFile(file); }, getCurrent(): File { return this.$params.controller.getCurrentFile(); }, isActive(file: File): boolean { return file.getId() === (this.getCurrent() && this.getCurrent().getId()); } }, $init() { if (!this.$params.controller) { return; } this.folders = this.folders || this.createItemsVm({ menu: {}, edit: {}, open: {}, permissions: null }); this.container = this.$params.controller.getContainer(); } }; ================================================ FILE: quix-frontend/client/src/lib/file-explorer/directives/file-explorer.scss ================================================ @import '../../ui/assets/css/def/colors.def'; $item-height: 35px; quix-file-explorer, bi-file-explorer, bi-file-explorer-static, bi-file-explorer-static, bi-file-explorer-inner-static { position: relative; display: block; bi-dropdown { bi-toggle { height: $item-height; } } > ul > li { user-select: none; cursor: default !important; .fe-item { padding-right: 5px; height: $item-height; > div { flex-grow: 1; overflow: hidden; text-overflow: ellipsis; } } .fe-item-name { height: $item-height; .fe-icon-container { line-height: 0; } .fe-icon { margin-right: 4px; font-size: 18px; vertical-align: text-bottom; } } } ul.fe-folders { > li { .fe-toggle { transition: transform .2s; transform: rotate(-90deg); font-size: 19px; &.fe-toggle--hidden { visibility: hidden; } } &.fe-folder--open { > div > div > .fe-toggle { transform: rotate(0); } } > .fe-item { @for $i from 0 through 3 { &.fe-item-depth-#{$i} { padding-left: $i * 12px + 4px; } } } } } &.fe-folder-mode-select { ul.fe-files > li, ul.fe-folders > li > .fe-item { transition: border-color .2s; border-left: 2px solid transparent; &:hover, &.bi-active { border-color: $primary; } } } ul.fe-files { .fe-item { @for $i from 0 through 3 { &.fe-item-depth-#{$i} { padding-left: $i * 12px + 29px; } } > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } } } ================================================ FILE: quix-frontend/client/src/lib/file-explorer/directives/file-explorer.ts ================================================ import { assign, isArray } from 'lodash'; import { createNgModel, initNgScope, inject } from '../../core'; import { toast } from '../../ui'; import { IItemDef } from '../services'; import { File, Folder } from '../services/file-explorer-models'; import { treeToDef, defToTree, addFile } from '../services/file-explorer-tools'; import Controller from '../services/file-explorer-controller'; import VM from './file-explorer-vm'; import templateDynamic from './file-explorer-dynamic.html'; import templateStatic from './file-explorer-static.html'; import './file-explorer.scss'; import { confirmAction } from '../../../services/dialog'; type Mode = 'static' | 'dynamic'; function directive(mode: Mode, params) { return assign( { template: mode === 'dynamic' ? templateDynamic : templateStatic, restrict: 'E', }, params ); } function initScope(scope, controller: Controller, depth: number, mode: Mode) { scope.depth = depth; scope.renderFolder = (s) => controller.renderFolder(s); scope.renderFile = (s) => controller.renderFile(s); scope.renderFolderIcon = (folder) => controller.renderFolderIcon(scope, folder); scope.renderFileIcon = (file) => controller.renderFileIcon(scope, file); scope.renderMenu = (s, folder) => controller.renderMenu(s, folder); const helper = initNgScope(scope) .readonly(scope.readonly) .withOptions( 'feOptions', { fileAlias: 'file', orderBy: 'name', // name|dateCreated|dateUpdated orderReversed: false, expandRootFolder: false, expandAllFolders: false, hideEmptyFolders: false, folderMode: 'expand', // expand|select draggable: false, }, ({ orderBy, orderReversed, fileAlias }) => { scope.options.fileAlias = isArray(fileAlias) ? fileAlias : [fileAlias]; scope.vm.order.setField(orderBy, orderReversed); } ) .withVM(VM) .withEditableEvents({ onFileCreate(type = scope.options.fileAlias[0], folder?: Folder) { const file = (folder || scope.model) .toggleOpen(true) .createFile(`New ${type}`, type); controller.syncItem(file, 'fileCreated', type); }, onFolderDelete(folder: Folder) { const after = () => { folder.destroy(); if (folder.getParent().isEmpty()) { folder.getParent().toggleOpen(false); } controller.syncItem(folder, 'folderDeleted'); toast.showToast( { text: `Deleted folder "${folder.getName()}"`, type: 'success', }, 3000 ); }; const action = folder.isEmpty() ? 'delete' : 'trash'; return confirmAction(action, 'folder', folder).then(after); }, onFolderRename(folder: Folder) { scope.vm.folder.toggleEdit(folder, true); }, onFolderRenamed(folder: Folder) { controller.syncItem(folder, 'folderRenamed'); }, }) .withEvents({ onItemDrop(_, __, folder: Folder) { const { item }: { item: File | Folder } = scope.vm.dropped; if (item instanceof File && !folder.getFileById(item.getId())) { item.moveTo(folder); controller.syncItem(item, 'fileMoved'); } else if ( item instanceof Folder && folder.getId() !== item.getId() && !folder.getFolderById(item.getId()) && !folder.getParentById(item.getId()) && folder.getDepth() + item.getLength() <= 3 ) { item.moveTo(folder); controller.syncItem(item, 'folderMoved'); } }, onDrag(item: Folder | File) { return item.getName(); }, onFolderBlur(folder: Folder) { scope.vm.folder.toggleEdit(folder, false); }, onFolderToggle(folder: Folder) { if (scope.vm.folders.get(folder).edit.enabled) { return; } scope.vm.folder.toggleOpen(folder); if (scope.vm.folder.isOpen(folder)) { folder.setLimit(20); if (folder.isLazy()) { controller.fetchLazyFolder(folder).then((items) => { items.forEach((item) => addFile(folder, item)); folder.setLazy(false); inject('$timeout')(() => folder.setLimit(null), 100); }); } else { inject('$timeout')(() => folder.setLimit(null), 100); } } }, onFolderClick(folder: Folder) { if (scope.options.folderMode === 'select') { scope.vm.folder.setCurrent(folder); scope.vm.file.setCurrent(null); controller.clickFolder(folder); } else { scope.events.onFolderToggle(folder); } }, onFileClick(file: File) { if (scope.options.folderMode === 'select') { scope.vm.file.setCurrent(file); scope.vm.folder.setCurrent(null); controller.clickFile(file); } }, }); if (depth < 2) { helper.withEditableEvents({ onFolderCreate(folder?: Folder) { folder = (folder || scope.model).toggleOpen(true); inject('$timeout')(() => { folder = folder.createFolder('New folder').toggleEdit(true); controller.syncItem(folder, 'folderCreated'); }); }, }); } } const fileExplorerInnerBuilder = (mode: Mode) => () => { return directive(mode, { require: `^biFileExplorer${mode === 'static' ? 'Static' : ''}`, scope: { model: '=', feOptions: '<', readonly: '=', }, link: { pre: (scope, element, attrs, controller) => { scope.$watch('model', (model) => scope.vm.init({ controller, item: scope.model, options: scope.options, }) ); initScope( scope, controller, (element.parents( `bi-file-explorer-inner${mode === 'static' ? '-static' : ''}` ).length as number) + 1, mode ); }, }, }); }; const fileExplorerBuilder = (mode: Mode) => () => { return directive(mode, { require: ['ngModel', `biFileExplorer${mode === 'static' ? 'Static' : ''}`], transclude: { folderIcon: '?folderIcon', fileIcon: '?fileIcon', menu: '?menu', }, controller: ['$scope', '$element', '$transclude', Controller], scope: { feOptions: '<', onLazyFolderFetch: '&', onFileClick: '&', onFolderClick: '&', onLoad: '&', permissions: '&', emptyText: '@', readonly: '=', }, link: { pre: ( scope, element, attrs, [ngModel, controller]: [ng.INgModelController, Controller] ) => { createNgModel(scope, ngModel) .formatWith((model: IItemDef[]) => defToTree(model, scope.options)) .parseWith((model: Folder) => treeToDef(model)) .renderWith((model: Folder) => { scope.vm.init({ controller, item: model, options: scope.options, isRoot: true, }); }) .then(() => { if ( scope.options.expandRootFolder && scope.model.getFolders().length === 1 ) { scope.model.getFolders()[0].toggleOpen(true); } scope.onLoad({ fileExplorer: controller.getInstance() }); }) .feedBack(false); initScope(scope, controller, 0, mode); element.addClass(`fe-folder-mode-${scope.options.folderMode}`); }, }, }); }; export const fileExplorer = fileExplorerBuilder('dynamic'); export const fileExplorerStatic = fileExplorerBuilder('static'); export const fileExplorerInner = fileExplorerInnerBuilder('dynamic'); export const fileExplorerInnerStatic = fileExplorerInnerBuilder('static'); ================================================ FILE: quix-frontend/client/src/lib/file-explorer/directives/index.ts ================================================ export { fileExplorer, fileExplorerStatic, fileExplorerInner, fileExplorerInnerStatic } from './file-explorer'; ================================================ FILE: quix-frontend/client/src/lib/file-explorer/index.ts ================================================ import ngApp from './bootstrap'; import init from './init'; init(ngApp); export * from './services'; ================================================ FILE: quix-frontend/client/src/lib/file-explorer/init.ts ================================================ import {forEach} from 'lodash'; import * as directives from './directives'; function toDirectiveName(name: string) { return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`; } export default function init(ngApp: angular.IModule) { forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any)); } ================================================ FILE: quix-frontend/client/src/lib/file-explorer/services/file-explorer-controller.ts ================================================ import {assign, defaults} from 'lodash'; import {inject} from '../../core'; import {Item, File, Folder} from './file-explorer-models'; import {itemToDef} from './file-explorer-tools'; import Instance from './file-explorer-instance'; interface Permissions { rename: boolean; delete: boolean; } export default class Controller { private readonly ngModel: ng.INgModelController; private readonly $compile: ng.ICompileService; private readonly instance: Instance; private currentFolder: Folder = null; private currentFile: File = null; constructor(private readonly $scope, private readonly $element, private readonly $transclude :ng.ITranscludeFunction) { this.instance = new Instance($scope); this.ngModel = $element.controller('ngModel'); this.$compile = inject('$compile'); } private render(html) { return scope => ({html: this.$compile(html)(scope)}); } getInstance(): Instance { return this.instance; } getPermissions(folder): Permissions { return defaults({}, this.$scope.permissions({folder: itemToDef(folder)}), { rename: !this.$scope.readonly, delete: !this.$scope.readonly, menu: !this.$scope.readonly }); } getContainer() { return this.$element; } setCurrentFolder(folder: Folder): Controller { this.currentFolder = folder; return this; } setCurrentFile(file: File): Controller { this.currentFile = file; return this; } getCurrentFolder(): Folder { return this.currentFolder; } getCurrentFile(): File { return this.currentFile; } fireEvent(item: Item, eventName: string, ...args): Controller { this.instance.trigger(eventName, itemToDef(item), ...args); return this; } syncItem(item: Item, eventName: string, ...args): Controller { this.ngModel.$setViewValue(this.$scope.model.$clone()); this.fireEvent(item, eventName, ...args); return this; } clickFile(file: File): Controller { this.$scope.onFileClick({file: itemToDef(file)}); return this; } clickFolder(folder: Folder): Controller { this.$scope.onFolderClick({folder: itemToDef(folder)}); return this; } fetchLazyFolder(folder: Folder) { return this.$scope.onLazyFolderFetch({folder: itemToDef(folder)}); } transclude(element, file) { this.$transclude((clone, scope) => { scope.bfe = {file}; element.append(clone); }); } renderFolder(scope) { return this.render(` {{folder.getName()}} {{folder.getName()}} `)(scope); } renderFile(scope) { return this.render(` {{file.getName()}} `)(scope); } renderFolderIcon(scope, folder: Folder) { let html; if (!this.$transclude.isSlotFilled('folderIcon')) { html = inject('$compile')(` folder `)(assign(scope.$new(true), {folder})); } else { html = this.$transclude((_, s) => s.folder = itemToDef(folder), null, 'folderIcon'); } return {html}; } renderFileIcon(scope, file: File) { let html; if (!this.$transclude.isSlotFilled('fileIcon')) { html = inject('$compile')(` insert_drive_file `)(assign(scope.$new(true), {file})); } else { html = this.$transclude((_, s) => s.file = itemToDef(file), null, 'fileIcon'); } return {html}; } renderMenu(scope, folder: Folder) { let html; if (!this.$transclude.isSlotFilled('menu')) { html = inject('$compile')(`
  • note_add New {{::type}}
  • create_new_folder New folder
  • edit Rename
  • delete Delete
`)(assign(scope)); } else { html = this.$transclude((_, s) => s.folder = itemToDef(folder), null, 'menu'); } return {html}; } } ================================================ FILE: quix-frontend/client/src/lib/file-explorer/services/file-explorer-instance.ts ================================================ import {srv} from '../../core'; import {IItemDef} from './'; import {File} from './file-explorer-models'; import {goToFile} from './file-explorer-tools'; /** * Will be propagated using on-load */ export default class Instance extends srv.eventEmitter.EventEmitter { constructor (private readonly scope) { super(); } createFolder() { this.scope.events.onFolderCreate(); } createFile(type?: string) { this.scope.events.onFileCreate(type); } setActive(fileDef: IItemDef) { const file: File = goToFile(fileDef, this.scope.model); this.scope.vm.folder.setCurrent(file); this.scope.vm.file.setCurrent(file); } clearActive() { this.scope.vm.folder.setCurrent(null); this.scope.vm.file.setCurrent(null); } } ================================================ FILE: quix-frontend/client/src/lib/file-explorer/services/file-explorer-models.ts ================================================ import {pull} from 'lodash'; import {utils, srv} from '../../core'; const {uuid} = utils; const {EventEmitter} = srv.eventEmitter; export class Item { private parent: Folder; private readonly eventEmitter; constructor( private readonly id: string, private readonly name: string, private readonly type: string, private readonly data = {} ) { this.eventEmitter = new EventEmitter(); } public getId(): string { return this.id; } public getName(): string { return this.name; } public getType(): string { return this.type; } public setParent(parent: Folder): Item { this.parent = parent; return this; } public getParent(): Folder { return this.parent; } public getDepth(): number { let res = 0; let parent: Item = this; // tslint:disable-next-line: no-conditional-assignment while (parent = parent.getParent()) { res++; } return res; } public getData(): any { return this.data; } public getParentById(id: string): Item { let res: Item; let parent: Item = this; // tslint:disable-next-line: no-conditional-assignment while (parent = parent.getParent()) { if (parent.getId() === id) { res = res || parent; break; } } return res; } public on(name, fn, invoke?, scope?) { this.eventEmitter.on(name, fn, invoke, scope); } public trigger(name, ...args) { this.eventEmitter.triggerStream(name, ...args); } } export class File extends Item { constructor(id: string, name: string, type: string = 'file', data = {}) { super(id, name, type, data); } public moveTo(folder: Folder): File { folder.addFile(this.getParent().removeFile(this)); return this; } } export class Folder extends Item { private pool: Record = {}; private folders: Folder[] = []; private files: File[] = []; private lazy: boolean = false; private limit: number = null; private readonly status = { open: false, edit: false, hasFileLeaf: false }; constructor(id: string, name: string, data = {}) { super(id, name, 'folder', data); } public setPool(pool: Record): Folder { this.pool = pool; return this; } public setFolders(folders: Folder[]): Folder { this.folders = folders; return this; } public setFiles(files: File[]): Folder { this.files = files; return this; } public setLazy(lazy: boolean = false): Folder { this.lazy = lazy; return this; } public isLazy(): boolean { return this.lazy; } public getFolderById(id: string): Folder { return this.pool[id] as Folder; } public getFileById(id: string): File { return this.pool[id] as File; } public getFolders(): Folder[] { return this.folders; } public getFiles(): File[] { return this.files; } public createFolder(name: string): Folder { return this.addFolder(uuid(), name); } public createFile(name: string, type?): File { return this.addFile(uuid(), name, type); } public addFolder(idOrFolder: string | Folder, name?: string, data = {}): Folder { const folder = idOrFolder instanceof Folder ? idOrFolder : new Folder(idOrFolder, name, data); folder.setParent(this); this.folders.push(folder); this.pool[folder.getId()] = folder; return folder; } public addFile(idOrFile: string | File, name?: string, type?: string, data = {}): File { const file = idOrFile instanceof File ? idOrFile : new File(idOrFile, name, type, data); file.setParent(this); this.files.push(file); this.pool[file.getId()] = file; return file; } public removeFile(file: File): File { pull(this.files, file); // tslint:disable-next-line: no-dynamic-delete delete this.pool[file.getId()]; return file; } public removeFolder(folder: Folder): Folder { pull(this.folders, folder); // tslint:disable-next-line: no-dynamic-delete delete this.pool[folder.getId()]; return folder; } public hasFiles(): boolean { return !!this.files.length; } public hasFolders(): boolean { return !!this.folders.length; } public isEmpty(): boolean { return !this.hasFolders() && !this.hasFiles() && !this.lazy; } public hasFileLeaf(): boolean { return this.status.hasFileLeaf; } public isOpen(): boolean { return this.status.open; } public toggleOpen(open?: boolean): Folder { this.status.open = typeof open === 'undefined' ? !this.status.open : open; if (this.getParent()) { this.getParent().trigger('openToggled', this.getParent(), this, this.isOpen()); } return this; } public toggleEdit(edit?: boolean): Folder { this.status.edit = typeof edit === 'undefined' ? !this.status.edit : edit; if (this.getParent()) { this.getParent().trigger('editToggled', this.getParent(), this, this.status.edit); } return this; } public toggleHasFileLeaf(hasFileLeaf: boolean): Folder { this.status.hasFileLeaf = hasFileLeaf; return this; } public moveTo(folder: Folder): Folder { folder.addFolder(this.getParent().removeFolder(this)); return this; } public getLength(res = 1): number { return Math.max(res, ...(this.folders.map(folder => folder.getLength(res + 1)))); } public setLimit(limit: number) { this.limit = limit; } public getLimit() { return this.limit; } public destroy() { this.getParent().removeFolder(this); } public $clone(): Folder { const folder = new Folder(this.getId(), this.getName(), this.getData()); return folder .setPool(this.pool) .setFolders(this.getFolders()) .setFiles(this.getFiles()) .setLazy(this.lazy); } } ================================================ FILE: quix-frontend/client/src/lib/file-explorer/services/file-explorer-tools.ts ================================================ import {IItemDef, IPathItemDef} from './'; import {Item, Folder, File} from './file-explorer-models'; function getId(parent) { return typeof parent === 'object' ? parent.id : parent; } /** * Opens all folders on the path to file */ export function goToFile(fileDef: IItemDef, folder: Folder): File { fileDef.path.forEach(parent => { folder = folder.getFolderById(getId(parent)).toggleOpen(true); }); return folder.getFileById(fileDef.id) || folder.getFolderById(fileDef.id); } export function addFolder(folder: Folder, {id, name, lazy, path, ...data}: IItemDef, options: any): Folder { const childFolder = folder.addFolder(id, name, data) .setLazy(lazy); if (options.expandAllFolders && !lazy) { childFolder.toggleOpen(true); } return childFolder; } export function addFile(folder: Folder, {id, name, type, path, ...data}: IItemDef): File { return folder.addFile(id, name, type, data); } /** * Creates a tree structure from a file definition array. */ export function defToTree(items: IItemDef[], options: any): Folder { const root = new Folder(null, null); const itemsMap = items.reduce((res, item: IItemDef) => { res[item.id] = item; return res; }, {}); items.forEach(item => { let folder = root; (item.path || []).forEach((parent) => { const id = getId(parent); folder = folder.getFolderById(id) || addFolder(folder, itemsMap[id], options); if (item.type !== 'folder') { folder.toggleHasFileLeaf(true); } }); if (item.type === 'folder') { if (!folder.getFolderById(item.id)) { addFolder(folder, item, options); } } else { addFile(folder, item); } }); return root; } /** * Creates a file definition array from a tree. */ export function treeToDef(item: Item, path = [], res: IItemDef[] = []): IItemDef[] { if (item.getId()) { if (item instanceof Folder) { res.push({ id: item.getId(), name: item.getName(), type: item.getType(), path, lazy: item.isLazy(), ...item.getData(), }); } else { res.push({ id: item.getId(), name: item.getName(), type: item.getType(), path, ...item.getData(), }); } } if (item instanceof Folder) { path = !item.getId() ? path : [ ...path, ...[{ id: item.getId(), name: item.getName() }] ]; (item as Folder).getFolders().forEach(folder => { treeToDef(folder, path, res); }); (item as Folder).getFiles().forEach(file => treeToDef(file, path, res)); } return res; } /** * Creates a file definition object from file */ export function itemToDef(item: Item): IItemDef { const path: IPathItemDef[] = []; let folder: Folder = item.getParent(); while (folder && folder.getParent()) { path.unshift({ id: folder.getId(), name: folder.getName() }); folder = folder.getParent(); } return { id: item.getId(), name: item.getName(), type: item.getType(), path, ...item.getData() }; } ================================================ FILE: quix-frontend/client/src/lib/file-explorer/services/index.ts ================================================ export interface IPathItemDef { id: string; name: string; } export interface IItemDef { id: string; name: string; type: string; path: IPathItemDef[]; lazy?: boolean; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/index.ts ================================================ import { SqlBaseLexer } from './lang/presto/SqlBaseLexer'; import { SqlBaseListener } from './lang/presto/SqlBaseListener'; import { SqlBaseParser } from './lang/presto/SqlBaseParser'; import { SqlBaseVisitor } from './lang/presto/SqlBaseVisitor'; export { SqlBaseLexer }; export { SqlBaseListener }; export { SqlBaseParser }; export { SqlBaseVisitor }; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBase.tokens ================================================ T__0=1 T__1=2 T__2=3 T__3=4 T__4=5 T__5=6 T__6=7 T__7=8 T__8=9 SELECT=10 FROM=11 ADD=12 AS=13 ALL=14 SOME=15 ANY=16 DISTINCT=17 WHERE=18 GROUP=19 BY=20 GROUPING=21 SETS=22 CUBE=23 ROLLUP=24 ORDER=25 HAVING=26 LIMIT=27 AT=28 OR=29 AND=30 IN=31 NOT=32 NO=33 EXISTS=34 BETWEEN=35 LIKE=36 IS=37 NULL=38 TRUE=39 FALSE=40 NULLS=41 FIRST=42 LAST=43 ESCAPE=44 ASC=45 DESC=46 SUBSTRING=47 POSITION=48 FOR=49 TINYINT=50 SMALLINT=51 INTEGER=52 DATE=53 TIME=54 TIMESTAMP=55 INTERVAL=56 YEAR=57 MONTH=58 DAY=59 HOUR=60 MINUTE=61 SECOND=62 ZONE=63 CURRENT_DATE=64 CURRENT_TIME=65 CURRENT_TIMESTAMP=66 LOCALTIME=67 LOCALTIMESTAMP=68 EXTRACT=69 CASE=70 WHEN=71 THEN=72 ELSE=73 END=74 JOIN=75 CROSS=76 OUTER=77 INNER=78 LEFT=79 RIGHT=80 FULL=81 NATURAL=82 USING=83 ON=84 FILTER=85 OVER=86 PARTITION=87 RANGE=88 ROWS=89 UNBOUNDED=90 PRECEDING=91 FOLLOWING=92 CURRENT=93 ROW=94 WITH=95 RECURSIVE=96 VALUES=97 CREATE=98 SCHEMA=99 TABLE=100 VIEW=101 REPLACE=102 INSERT=103 DELETE=104 INTO=105 CONSTRAINT=106 DESCRIBE=107 GRANT=108 REVOKE=109 PRIVILEGES=110 PUBLIC=111 OPTION=112 EXPLAIN=113 ANALYZE=114 FORMAT=115 TYPE=116 TEXT=117 GRAPHVIZ=118 LOGICAL=119 DISTRIBUTED=120 CAST=121 TRY_CAST=122 SHOW=123 TABLES=124 SCHEMAS=125 CATALOGS=126 COLUMNS=127 COLUMN=128 USE=129 PARTITIONS=130 FUNCTIONS=131 DROP=132 UNION=133 EXCEPT=134 INTERSECT=135 TO=136 SYSTEM=137 BERNOULLI=138 POISSONIZED=139 TABLESAMPLE=140 ALTER=141 RENAME=142 UNNEST=143 ORDINALITY=144 ARRAY=145 MAP=146 SET=147 RESET=148 SESSION=149 DATA=150 START=151 TRANSACTION=152 COMMIT=153 ROLLBACK=154 WORK=155 ISOLATION=156 LEVEL=157 SERIALIZABLE=158 REPEATABLE=159 COMMITTED=160 UNCOMMITTED=161 READ=162 WRITE=163 ONLY=164 CALL=165 PREPARE=166 DEALLOCATE=167 EXECUTE=168 INPUT=169 OUTPUT=170 CASCADE=171 RESTRICT=172 INCLUDING=173 EXCLUDING=174 PROPERTIES=175 NORMALIZE=176 NFD=177 NFC=178 NFKD=179 NFKC=180 IF=181 NULLIF=182 COALESCE=183 EQ=184 NEQ=185 LT=186 LTE=187 GT=188 GTE=189 PLUS=190 MINUS=191 ASTERISK=192 SLASH=193 PERCENT=194 CONCAT=195 STRING=196 BINARY_LITERAL=197 INTEGER_VALUE=198 DECIMAL_VALUE=199 IDENTIFIER=200 DIGIT_IDENTIFIER=201 QUOTED_IDENTIFIER=202 BACKQUOTED_IDENTIFIER=203 TIME_WITH_TIME_ZONE=204 TIMESTAMP_WITH_TIME_ZONE=205 DOUBLE_PRECISION=206 SIMPLE_COMMENT=207 BRACKETED_COMMENT=208 WS=209 SEMICOLON=210 UNRECOGNIZED=211 DELIMITER=212 '.'=1 '('=2 ','=3 ')'=4 '?'=5 '->'=6 '['=7 ']'=8 '=>'=9 '='=184 '<'=186 '<='=187 '>'=188 '>='=189 '+'=190 '-'=191 '*'=192 '/'=193 '%'=194 '||'=195 ';'=210 ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseLexer.tokens ================================================ T__0=1 T__1=2 T__2=3 T__3=4 T__4=5 T__5=6 T__6=7 T__7=8 T__8=9 SELECT=10 FROM=11 ADD=12 AS=13 ALL=14 SOME=15 ANY=16 DISTINCT=17 WHERE=18 GROUP=19 BY=20 GROUPING=21 SETS=22 CUBE=23 ROLLUP=24 ORDER=25 HAVING=26 LIMIT=27 AT=28 OR=29 AND=30 IN=31 NOT=32 NO=33 EXISTS=34 BETWEEN=35 LIKE=36 IS=37 NULL=38 TRUE=39 FALSE=40 NULLS=41 FIRST=42 LAST=43 ESCAPE=44 ASC=45 DESC=46 SUBSTRING=47 POSITION=48 FOR=49 TINYINT=50 SMALLINT=51 INTEGER=52 DATE=53 TIME=54 TIMESTAMP=55 INTERVAL=56 YEAR=57 MONTH=58 DAY=59 HOUR=60 MINUTE=61 SECOND=62 ZONE=63 CURRENT_DATE=64 CURRENT_TIME=65 CURRENT_TIMESTAMP=66 LOCALTIME=67 LOCALTIMESTAMP=68 EXTRACT=69 CASE=70 WHEN=71 THEN=72 ELSE=73 END=74 JOIN=75 CROSS=76 OUTER=77 INNER=78 LEFT=79 RIGHT=80 FULL=81 NATURAL=82 USING=83 ON=84 FILTER=85 OVER=86 PARTITION=87 RANGE=88 ROWS=89 UNBOUNDED=90 PRECEDING=91 FOLLOWING=92 CURRENT=93 ROW=94 WITH=95 RECURSIVE=96 VALUES=97 CREATE=98 SCHEMA=99 TABLE=100 VIEW=101 REPLACE=102 INSERT=103 DELETE=104 INTO=105 CONSTRAINT=106 DESCRIBE=107 GRANT=108 REVOKE=109 PRIVILEGES=110 PUBLIC=111 OPTION=112 EXPLAIN=113 ANALYZE=114 FORMAT=115 TYPE=116 TEXT=117 GRAPHVIZ=118 LOGICAL=119 DISTRIBUTED=120 CAST=121 TRY_CAST=122 SHOW=123 TABLES=124 SCHEMAS=125 CATALOGS=126 COLUMNS=127 COLUMN=128 USE=129 PARTITIONS=130 FUNCTIONS=131 DROP=132 UNION=133 EXCEPT=134 INTERSECT=135 TO=136 SYSTEM=137 BERNOULLI=138 POISSONIZED=139 TABLESAMPLE=140 ALTER=141 RENAME=142 UNNEST=143 ORDINALITY=144 ARRAY=145 MAP=146 SET=147 RESET=148 SESSION=149 DATA=150 START=151 TRANSACTION=152 COMMIT=153 ROLLBACK=154 WORK=155 ISOLATION=156 LEVEL=157 SERIALIZABLE=158 REPEATABLE=159 COMMITTED=160 UNCOMMITTED=161 READ=162 WRITE=163 ONLY=164 CALL=165 PREPARE=166 DEALLOCATE=167 EXECUTE=168 INPUT=169 OUTPUT=170 CASCADE=171 RESTRICT=172 INCLUDING=173 EXCLUDING=174 PROPERTIES=175 NORMALIZE=176 NFD=177 NFC=178 NFKD=179 NFKC=180 IF=181 NULLIF=182 COALESCE=183 EQ=184 NEQ=185 LT=186 LTE=187 GT=188 GTE=189 PLUS=190 MINUS=191 ASTERISK=192 SLASH=193 PERCENT=194 CONCAT=195 STRING=196 BINARY_LITERAL=197 INTEGER_VALUE=198 DECIMAL_VALUE=199 IDENTIFIER=200 DIGIT_IDENTIFIER=201 QUOTED_IDENTIFIER=202 BACKQUOTED_IDENTIFIER=203 TIME_WITH_TIME_ZONE=204 TIMESTAMP_WITH_TIME_ZONE=205 DOUBLE_PRECISION=206 SIMPLE_COMMENT=207 BRACKETED_COMMENT=208 WS=209 SEMICOLON=210 UNRECOGNIZED=211 '.'=1 '('=2 ','=3 ')'=4 '?'=5 '->'=6 '['=7 ']'=8 '=>'=9 '='=184 '<'=186 '<='=187 '>'=188 '>='=189 '+'=190 '-'=191 '*'=192 '/'=193 '%'=194 '||'=195 ';'=210 ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseLexer.ts ================================================ // Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7 // jshint ignore: start // @ts-nocheck import { atn as _atn, dfa, Lexer, PredictionContextCache, Token } from 'antlr4'; const serializedATN = [ '\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964', '\u0002\u00d5\u0c4e\b\u0001\u0004\u0002\t\u0002\u0004\u0003\t\u0003\u0004', '\u0004\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007\t', '\u0007\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004', '\f\t\f\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010', '\t\u0010\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013', '\u0004\u0014\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017', '\t\u0017\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a', '\u0004\u001b\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e', '\t\u001e\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004"\t"\u0004#', "\t#\u0004$\t$\u0004%\t%\u0004&\t&\u0004'\t'\u0004(\t(\u0004)\t)\u0004", '*\t*\u0004+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u0004', '1\t1\u00042\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u0004', '8\t8\u00049\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004', '?\t?\u0004@\t@\u0004A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004', 'F\tF\u0004G\tG\u0004H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004', 'M\tM\u0004N\tN\u0004O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004', 'T\tT\u0004U\tU\u0004V\tV\u0004W\tW\u0004X\tX\u0004Y\tY\u0004Z\tZ\u0004', '[\t[\u0004\\\t\\\u0004]\t]\u0004^\t^\u0004_\t_\u0004`\t`\u0004a\ta\u0004', 'b\tb\u0004c\tc\u0004d\td\u0004e\te\u0004f\tf\u0004g\tg\u0004h\th\u0004', 'i\ti\u0004j\tj\u0004k\tk\u0004l\tl\u0004m\tm\u0004n\tn\u0004o\to\u0004', 'p\tp\u0004q\tq\u0004r\tr\u0004s\ts\u0004t\tt\u0004u\tu\u0004v\tv\u0004', 'w\tw\u0004x\tx\u0004y\ty\u0004z\tz\u0004{\t{\u0004|\t|\u0004}\t}\u0004', '~\t~\u0004\u007f\t\u007f\u0004\u0080\t\u0080\u0004\u0081\t\u0081\u0004', '\u0082\t\u0082\u0004\u0083\t\u0083\u0004\u0084\t\u0084\u0004\u0085\t', '\u0085\u0004\u0086\t\u0086\u0004\u0087\t\u0087\u0004\u0088\t\u0088\u0004', '\u0089\t\u0089\u0004\u008a\t\u008a\u0004\u008b\t\u008b\u0004\u008c\t', '\u008c\u0004\u008d\t\u008d\u0004\u008e\t\u008e\u0004\u008f\t\u008f\u0004', '\u0090\t\u0090\u0004\u0091\t\u0091\u0004\u0092\t\u0092\u0004\u0093\t', '\u0093\u0004\u0094\t\u0094\u0004\u0095\t\u0095\u0004\u0096\t\u0096\u0004', '\u0097\t\u0097\u0004\u0098\t\u0098\u0004\u0099\t\u0099\u0004\u009a\t', '\u009a\u0004\u009b\t\u009b\u0004\u009c\t\u009c\u0004\u009d\t\u009d\u0004', '\u009e\t\u009e\u0004\u009f\t\u009f\u0004\u00a0\t\u00a0\u0004\u00a1\t', '\u00a1\u0004\u00a2\t\u00a2\u0004\u00a3\t\u00a3\u0004\u00a4\t\u00a4\u0004', '\u00a5\t\u00a5\u0004\u00a6\t\u00a6\u0004\u00a7\t\u00a7\u0004\u00a8\t', '\u00a8\u0004\u00a9\t\u00a9\u0004\u00aa\t\u00aa\u0004\u00ab\t\u00ab\u0004', '\u00ac\t\u00ac\u0004\u00ad\t\u00ad\u0004\u00ae\t\u00ae\u0004\u00af\t', '\u00af\u0004\u00b0\t\u00b0\u0004\u00b1\t\u00b1\u0004\u00b2\t\u00b2\u0004', '\u00b3\t\u00b3\u0004\u00b4\t\u00b4\u0004\u00b5\t\u00b5\u0004\u00b6\t', '\u00b6\u0004\u00b7\t\u00b7\u0004\u00b8\t\u00b8\u0004\u00b9\t\u00b9\u0004', '\u00ba\t\u00ba\u0004\u00bb\t\u00bb\u0004\u00bc\t\u00bc\u0004\u00bd\t', '\u00bd\u0004\u00be\t\u00be\u0004\u00bf\t\u00bf\u0004\u00c0\t\u00c0\u0004', '\u00c1\t\u00c1\u0004\u00c2\t\u00c2\u0004\u00c3\t\u00c3\u0004\u00c4\t', '\u00c4\u0004\u00c5\t\u00c5\u0004\u00c6\t\u00c6\u0004\u00c7\t\u00c7\u0004', '\u00c8\t\u00c8\u0004\u00c9\t\u00c9\u0004\u00ca\t\u00ca\u0004\u00cb\t', '\u00cb\u0004\u00cc\t\u00cc\u0004\u00cd\t\u00cd\u0004\u00ce\t\u00ce\u0004', '\u00cf\t\u00cf\u0004\u00d0\t\u00d0\u0004\u00d1\t\u00d1\u0004\u00d2\t', '\u00d2\u0004\u00d3\t\u00d3\u0004\u00d4\t\u00d4\u0004\u00d5\t\u00d5\u0004', '\u00d6\t\u00d6\u0004\u00d7\t\u00d7\u0003\u0002\u0003\u0002\u0003\u0003', '\u0003\u0003\u0003\u0004\u0003\u0004\u0003\u0005\u0003\u0005\u0003\u0006', '\u0003\u0006\u0003\u0007\u0003\u0007\u0003\u0007\u0003\b\u0003\b\u0003', '\t\u0003\t\u0003\n\u0003\n\u0003\n\u0003\u000b\u0003\u000b\u0003\u000b', '\u0003\u000b\u0003\u000b\u0003\u000b\u0003\u000b\u0003\u000b\u0003\u000b', '\u0003\u000b\u0003\u000b\u0003\u000b\u0005\u000b\u01d0\n\u000b\u0003', '\f\u0003\f\u0003\f\u0003\f\u0003\f\u0003\f\u0003\f\u0003\f\u0005\f\u01da', '\n\f\u0003\r\u0003\r\u0003\r\u0003\r\u0003\r\u0003\r\u0005\r\u01e2\n', '\r\u0003\u000e\u0003\u000e\u0003\u000e\u0003\u000e\u0005\u000e\u01e8', '\n\u000e\u0003\u000f\u0003\u000f\u0003\u000f\u0003\u000f\u0003\u000f', '\u0003\u000f\u0005\u000f\u01f0\n\u000f\u0003\u0010\u0003\u0010\u0003', '\u0010\u0003\u0010\u0003\u0010\u0003\u0010\u0003\u0010\u0003\u0010\u0005', '\u0010\u01fa\n\u0010\u0003\u0011\u0003\u0011\u0003\u0011\u0003\u0011', '\u0003\u0011\u0003\u0011\u0005\u0011\u0202\n\u0011\u0003\u0012\u0003', '\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003', '\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003', '\u0012\u0003\u0012\u0003\u0012\u0005\u0012\u0214\n\u0012\u0003\u0013', '\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013', '\u0003\u0013\u0003\u0013\u0003\u0013\u0005\u0013\u0220\n\u0013\u0003', '\u0014\u0003\u0014\u0003\u0014\u0003\u0014\u0003\u0014\u0003\u0014\u0003', '\u0014\u0003\u0014\u0003\u0014\u0003\u0014\u0005\u0014\u022c\n\u0014', '\u0003\u0015\u0003\u0015\u0003\u0015\u0003\u0015\u0005\u0015\u0232\n', '\u0015\u0003\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0003', '\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0003', '\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0005\u0016\u0244', '\n\u0016\u0003\u0017\u0003\u0017\u0003\u0017\u0003\u0017\u0003\u0017', '\u0003\u0017\u0003\u0017\u0003\u0017\u0005\u0017\u024e\n\u0017\u0003', '\u0018\u0003\u0018\u0003\u0018\u0003\u0018\u0003\u0018\u0003\u0018\u0003', '\u0018\u0003\u0018\u0005\u0018\u0258\n\u0018\u0003\u0019\u0003\u0019', '\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019', '\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0005\u0019\u0266\n', '\u0019\u0003\u001a\u0003\u001a\u0003\u001a\u0003\u001a\u0003\u001a\u0003', '\u001a\u0003\u001a\u0003\u001a\u0003\u001a\u0003\u001a\u0005\u001a\u0272', '\n\u001a\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b', '\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b', '\u0003\u001b\u0005\u001b\u0280\n\u001b\u0003\u001c\u0003\u001c\u0003', '\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003', '\u001c\u0003\u001c\u0005\u001c\u028c\n\u001c\u0003\u001d\u0003\u001d', '\u0003\u001d\u0003\u001d\u0005\u001d\u0292\n\u001d\u0003\u001e\u0003', '\u001e\u0003\u001e\u0003\u001e\u0005\u001e\u0298\n\u001e\u0003\u001f', '\u0003\u001f\u0003\u001f\u0003\u001f\u0003\u001f\u0003\u001f\u0005\u001f', '\u02a0\n\u001f\u0003 \u0003 \u0003 \u0003 \u0005 \u02a6\n \u0003!\u0003', '!\u0003!\u0003!\u0003!\u0003!\u0005!\u02ae\n!\u0003"\u0003"\u0003', '"\u0003"\u0005"\u02b4\n"\u0003#\u0003#\u0003#\u0003#\u0003#\u0003', '#\u0003#\u0003#\u0003#\u0003#\u0003#\u0003#\u0005#\u02c2\n#\u0003$\u0003', '$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003', '$\u0003$\u0003$\u0005$\u02d2\n$\u0003%\u0003%\u0003%\u0003%\u0003%\u0003', '%\u0003%\u0003%\u0005%\u02dc\n%\u0003&\u0003&\u0003&\u0003&\u0005&\u02e2', "\n&\u0003'\u0003'\u0003'\u0003'\u0003'\u0003'\u0003'\u0003'", "\u0005'\u02ec\n'\u0003(\u0003(\u0003(\u0003(\u0003(\u0003(\u0003(", '\u0003(\u0005(\u02f6\n(\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0003', ')\u0003)\u0003)\u0003)\u0005)\u0302\n)\u0003*\u0003*\u0003*\u0003*\u0003', '*\u0003*\u0003*\u0003*\u0003*\u0003*\u0005*\u030e\n*\u0003+\u0003+\u0003', '+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0005+\u031a\n+\u0003', ',\u0003,\u0003,\u0003,\u0003,\u0003,\u0003,\u0003,\u0005,\u0324\n,\u0003', '-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003', '-\u0003-\u0005-\u0332\n-\u0003.\u0003.\u0003.\u0003.\u0003.\u0003.\u0005', '.\u033a\n.\u0003/\u0003/\u0003/\u0003/\u0003/\u0003/\u0003/\u0003/\u0005', '/\u0344\n/\u00030\u00030\u00030\u00030\u00030\u00030\u00030\u00030\u0003', '0\u00030\u00030\u00030\u00030\u00030\u00030\u00030\u00030\u00030\u0005', '0\u0358\n0\u00031\u00031\u00031\u00031\u00031\u00031\u00031\u00031\u0003', '1\u00031\u00031\u00031\u00031\u00031\u00031\u00031\u00051\u036a\n1\u0003', '2\u00032\u00032\u00032\u00032\u00032\u00052\u0372\n2\u00033\u00033\u0003', '3\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u0003', '3\u00033\u00053\u0382\n3\u00034\u00034\u00034\u00034\u00034\u00034\u0003', '4\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u00034\u0005', '4\u0394\n4\u00035\u00035\u00035\u00035\u00035\u00035\u00035\u00035\u0003', '5\u00035\u00035\u00035\u00035\u00035\u00055\u03a4\n5\u00036\u00036\u0003', '6\u00036\u00036\u00036\u00036\u00036\u00056\u03ae\n6\u00037\u00037\u0003', '7\u00037\u00037\u00037\u00037\u00037\u00057\u03b8\n7\u00038\u00038\u0003', '8\u00038\u00038\u00038\u00038\u00038\u00038\u00038\u00038\u00038\u0003', '8\u00038\u00038\u00038\u00038\u00038\u00058\u03cc\n8\u00039\u00039\u0003', '9\u00039\u00039\u00039\u00039\u00039\u00039\u00039\u00039\u00039\u0003', '9\u00039\u00039\u00039\u00059\u03de\n9\u0003:\u0003:\u0003:\u0003:\u0003', ':\u0003:\u0003:\u0003:\u0005:\u03e8\n:\u0003;\u0003;\u0003;\u0003;\u0003', ';\u0003;\u0003;\u0003;\u0003;\u0003;\u0005;\u03f4\n;\u0003<\u0003<\u0003', '<\u0003<\u0003<\u0003<\u0005<\u03fc\n<\u0003=\u0003=\u0003=\u0003=\u0003', '=\u0003=\u0003=\u0003=\u0005=\u0406\n=\u0003>\u0003>\u0003>\u0003>\u0003', '>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0005>\u0414\n>\u0003', '?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003', '?\u0003?\u0005?\u0422\n?\u0003@\u0003@\u0003@\u0003@\u0003@\u0003@\u0003', '@\u0003@\u0005@\u042c\n@\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003', 'A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003', 'A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0003A\u0005A\u0446\nA\u0003', 'B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003', 'B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003B\u0003', 'B\u0003B\u0003B\u0003B\u0005B\u0460\nB\u0003C\u0003C\u0003C\u0003C\u0003', 'C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003', 'C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003', 'C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0003C\u0005', 'C\u0484\nC\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003', 'D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0005', 'D\u0498\nD\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003', 'E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003', 'E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0003E\u0005', 'E\u04b6\nE\u0003F\u0003F\u0003F\u0003F\u0003F\u0003F\u0003F\u0003F\u0003', 'F\u0003F\u0003F\u0003F\u0003F\u0003F\u0005F\u04c6\nF\u0003G\u0003G\u0003', 'G\u0003G\u0003G\u0003G\u0003G\u0003G\u0005G\u04d0\nG\u0003H\u0003H\u0003', 'H\u0003H\u0003H\u0003H\u0003H\u0003H\u0005H\u04da\nH\u0003I\u0003I\u0003', 'I\u0003I\u0003I\u0003I\u0003I\u0003I\u0005I\u04e4\nI\u0003J\u0003J\u0003', 'J\u0003J\u0003J\u0003J\u0003J\u0003J\u0005J\u04ee\nJ\u0003K\u0003K\u0003', 'K\u0003K\u0003K\u0003K\u0005K\u04f6\nK\u0003L\u0003L\u0003L\u0003L\u0003', 'L\u0003L\u0003L\u0003L\u0005L\u0500\nL\u0003M\u0003M\u0003M\u0003M\u0003', 'M\u0003M\u0003M\u0003M\u0003M\u0003M\u0005M\u050c\nM\u0003N\u0003N\u0003', 'N\u0003N\u0003N\u0003N\u0003N\u0003N\u0003N\u0003N\u0005N\u0518\nN\u0003', 'O\u0003O\u0003O\u0003O\u0003O\u0003O\u0003O\u0003O\u0003O\u0003O\u0005', 'O\u0524\nO\u0003P\u0003P\u0003P\u0003P\u0003P\u0003P\u0003P\u0003P\u0005', 'P\u052e\nP\u0003Q\u0003Q\u0003Q\u0003Q\u0003Q\u0003Q\u0003Q\u0003Q\u0003', 'Q\u0003Q\u0005Q\u053a\nQ\u0003R\u0003R\u0003R\u0003R\u0003R\u0003R\u0003', 'R\u0003R\u0005R\u0544\nR\u0003S\u0003S\u0003S\u0003S\u0003S\u0003S\u0003', 'S\u0003S\u0003S\u0003S\u0003S\u0003S\u0003S\u0003S\u0005S\u0554\nS\u0003', 'T\u0003T\u0003T\u0003T\u0003T\u0003T\u0003T\u0003T\u0003T\u0003T\u0005', 'T\u0560\nT\u0003U\u0003U\u0003U\u0003U\u0005U\u0566\nU\u0003V\u0003', 'V\u0003V\u0003V\u0003V\u0003V\u0003V\u0003V\u0003V\u0003V\u0003V\u0003', 'V\u0005V\u0574\nV\u0003W\u0003W\u0003W\u0003W\u0003W\u0003W\u0003W\u0003', 'W\u0005W\u057e\nW\u0003X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003', 'X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003X\u0003', 'X\u0005X\u0592\nX\u0003Y\u0003Y\u0003Y\u0003Y\u0003Y\u0003Y\u0003Y\u0003', 'Y\u0003Y\u0003Y\u0005Y\u059e\nY\u0003Z\u0003Z\u0003Z\u0003Z\u0003Z\u0003', 'Z\u0003Z\u0003Z\u0005Z\u05a8\nZ\u0003[\u0003[\u0003[\u0003[\u0003[\u0003', '[\u0003[\u0003[\u0003[\u0003[\u0003[\u0003[\u0003[\u0003[\u0003[\u0003', '[\u0003[\u0003[\u0005[\u05bc\n[\u0003\\\u0003\\\u0003\\\u0003\\\u0003', '\\\u0003\\\u0003\\\u0003\\\u0003\\\u0003\\\u0003\\\u0003\\\u0003\\\u0003', '\\\u0003\\\u0003\\\u0003\\\u0003\\\u0005\\\u05d0\n\\\u0003]\u0003]\u0003', ']\u0003]\u0003]\u0003]\u0003]\u0003]\u0003]\u0003]\u0003]\u0003]\u0003', ']\u0003]\u0003]\u0003]\u0003]\u0003]\u0005]\u05e4\n]\u0003^\u0003^\u0003', '^\u0003^\u0003^\u0003^\u0003^\u0003^\u0003^\u0003^\u0003^\u0003^\u0003', '^\u0003^\u0005^\u05f4\n^\u0003_\u0003_\u0003_\u0003_\u0003_\u0003_\u0005', '_\u05fc\n_\u0003`\u0003`\u0003`\u0003`\u0003`\u0003`\u0003`\u0003`\u0005', '`\u0606\n`\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003', 'a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0003a\u0005', 'a\u061a\na\u0003b\u0003b\u0003b\u0003b\u0003b\u0003b\u0003b\u0003b\u0003', 'b\u0003b\u0003b\u0003b\u0005b\u0628\nb\u0003c\u0003c\u0003c\u0003c\u0003', 'c\u0003c\u0003c\u0003c\u0003c\u0003c\u0003c\u0003c\u0005c\u0636\nc\u0003', 'd\u0003d\u0003d\u0003d\u0003d\u0003d\u0003d\u0003d\u0003d\u0003d\u0003', 'd\u0003d\u0005d\u0644\nd\u0003e\u0003e\u0003e\u0003e\u0003e\u0003e\u0003', 'e\u0003e\u0003e\u0003e\u0005e\u0650\ne\u0003f\u0003f\u0003f\u0003f\u0003', 'f\u0003f\u0003f\u0003f\u0005f\u065a\nf\u0003g\u0003g\u0003g\u0003g\u0003', 'g\u0003g\u0003g\u0003g\u0003g\u0003g\u0003g\u0003g\u0003g\u0003g\u0005', 'g\u066a\ng\u0003h\u0003h\u0003h\u0003h\u0003h\u0003h\u0003h\u0003h\u0003', 'h\u0003h\u0003h\u0003h\u0005h\u0678\nh\u0003i\u0003i\u0003i\u0003i\u0003', 'i\u0003i\u0003i\u0003i\u0003i\u0003i\u0003i\u0003i\u0005i\u0686\ni\u0003', 'j\u0003j\u0003j\u0003j\u0003j\u0003j\u0003j\u0003j\u0005j\u0690\nj\u0003', 'k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003', 'k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0003k\u0005', 'k\u06a6\nk\u0003l\u0003l\u0003l\u0003l\u0003l\u0003l\u0003l\u0003l\u0003', 'l\u0003l\u0003l\u0003l\u0003l\u0003l\u0003l\u0003l\u0005l\u06b8\nl\u0003', 'm\u0003m\u0003m\u0003m\u0003m\u0003m\u0003m\u0003m\u0003m\u0003m\u0005', 'm\u06c4\nm\u0003n\u0003n\u0003n\u0003n\u0003n\u0003n\u0003n\u0003n\u0003', 'n\u0003n\u0003n\u0003n\u0005n\u06d2\nn\u0003o\u0003o\u0003o\u0003o\u0003', 'o\u0003o\u0003o\u0003o\u0003o\u0003o\u0003o\u0003o\u0003o\u0003o\u0003', 'o\u0003o\u0003o\u0003o\u0003o\u0003o\u0005o\u06e8\no\u0003p\u0003p\u0003', 'p\u0003p\u0003p\u0003p\u0003p\u0003p\u0003p\u0003p\u0003p\u0003p\u0005', 'p\u06f6\np\u0003q\u0003q\u0003q\u0003q\u0003q\u0003q\u0003q\u0003q\u0003', 'q\u0003q\u0003q\u0003q\u0005q\u0704\nq\u0003r\u0003r\u0003r\u0003r\u0003', 'r\u0003r\u0003r\u0003r\u0003r\u0003r\u0003r\u0003r\u0003r\u0003r\u0005', 'r\u0714\nr\u0003s\u0003s\u0003s\u0003s\u0003s\u0003s\u0003s\u0003s\u0003', 's\u0003s\u0003s\u0003s\u0003s\u0003s\u0005s\u0724\ns\u0003t\u0003t\u0003', 't\u0003t\u0003t\u0003t\u0003t\u0003t\u0003t\u0003t\u0003t\u0003t\u0005', 't\u0732\nt\u0003u\u0003u\u0003u\u0003u\u0003u\u0003u\u0003u\u0003u\u0005', 'u\u073c\nu\u0003v\u0003v\u0003v\u0003v\u0003v\u0003v\u0003v\u0003v\u0005', 'v\u0746\nv\u0003w\u0003w\u0003w\u0003w\u0003w\u0003w\u0003w\u0003w\u0003', 'w\u0003w\u0003w\u0003w\u0003w\u0003w\u0003w\u0003w\u0005w\u0758\nw\u0003', 'x\u0003x\u0003x\u0003x\u0003x\u0003x\u0003x\u0003x\u0003x\u0003x\u0003', 'x\u0003x\u0003x\u0003x\u0005x\u0768\nx\u0003y\u0003y\u0003y\u0003y\u0003', 'y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003', 'y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003y\u0003y\u0005y\u0780\ny\u0003', 'z\u0003z\u0003z\u0003z\u0003z\u0003z\u0003z\u0003z\u0005z\u078a\nz\u0003', '{\u0003{\u0003{\u0003{\u0003{\u0003{\u0003{\u0003{\u0003{\u0003{\u0003', '{\u0003{\u0003{\u0003{\u0003{\u0003{\u0005{\u079c\n{\u0003|\u0003|\u0003', '|\u0003|\u0003|\u0003|\u0003|\u0003|\u0005|\u07a6\n|\u0003}\u0003}\u0003', '}\u0003}\u0003}\u0003}\u0003}\u0003}\u0003}\u0003}\u0003}\u0003}\u0005', '}\u07b4\n}\u0003~\u0003~\u0003~\u0003~\u0003~\u0003~\u0003~\u0003~\u0003', '~\u0003~\u0003~\u0003~\u0003~\u0003~\u0005~\u07c4\n~\u0003\u007f\u0003', '\u007f\u0003\u007f\u0003\u007f\u0003\u007f\u0003\u007f\u0003\u007f\u0003', '\u007f\u0003\u007f\u0003\u007f\u0003\u007f\u0003\u007f\u0003\u007f\u0003', '\u007f\u0003\u007f\u0003\u007f\u0005\u007f\u07d6\n\u007f\u0003\u0080', '\u0003\u0080\u0003\u0080\u0003\u0080\u0003\u0080\u0003\u0080\u0003\u0080', '\u0003\u0080\u0003\u0080\u0003\u0080\u0003\u0080\u0003\u0080\u0003\u0080', '\u0003\u0080\u0005\u0080\u07e6\n\u0080\u0003\u0081\u0003\u0081\u0003', '\u0081\u0003\u0081\u0003\u0081\u0003\u0081\u0003\u0081\u0003\u0081\u0003', '\u0081\u0003\u0081\u0003\u0081\u0003\u0081\u0005\u0081\u07f4\n\u0081', '\u0003\u0082\u0003\u0082\u0003\u0082\u0003\u0082\u0003\u0082\u0003\u0082', '\u0005\u0082\u07fc\n\u0082\u0003\u0083\u0003\u0083\u0003\u0083\u0003', '\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003', '\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003', '\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0003\u0083\u0005\u0083\u0812', '\n\u0083\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084', '\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084', '\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084\u0003\u0084', '\u0003\u0084\u0005\u0084\u0826\n\u0084\u0003\u0085\u0003\u0085\u0003', '\u0085\u0003\u0085\u0003\u0085\u0003\u0085\u0003\u0085\u0003\u0085\u0005', '\u0085\u0830\n\u0085\u0003\u0086\u0003\u0086\u0003\u0086\u0003\u0086', '\u0003\u0086\u0003\u0086\u0003\u0086\u0003\u0086\u0003\u0086\u0003\u0086', '\u0005\u0086\u083c\n\u0086\u0003\u0087\u0003\u0087\u0003\u0087\u0003', '\u0087\u0003\u0087\u0003\u0087\u0003\u0087\u0003\u0087\u0003\u0087\u0003', '\u0087\u0003\u0087\u0003\u0087\u0005\u0087\u084a\n\u0087\u0003\u0088', '\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088', '\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088', '\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088\u0003\u0088\u0005\u0088', '\u085e\n\u0088\u0003\u0089\u0003\u0089\u0003\u0089\u0003\u0089\u0005', '\u0089\u0864\n\u0089\u0003\u008a\u0003\u008a\u0003\u008a\u0003\u008a', '\u0003\u008a\u0003\u008a\u0003\u008a\u0003\u008a\u0003\u008a\u0003\u008a', '\u0003\u008a\u0003\u008a\u0005\u008a\u0872\n\u008a\u0003\u008b\u0003', '\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003', '\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003', '\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0003\u008b\u0005\u008b\u0886', '\n\u008b\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c', '\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c', '\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c', '\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0003\u008c\u0005\u008c', '\u089e\n\u008c\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003', '\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003', '\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003', '\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0003\u008d\u0005', '\u008d\u08b6\n\u008d\u0003\u008e\u0003\u008e\u0003\u008e\u0003\u008e', '\u0003\u008e\u0003\u008e\u0003\u008e\u0003\u008e\u0003\u008e\u0003\u008e', '\u0005\u008e\u08c2\n\u008e\u0003\u008f\u0003\u008f\u0003\u008f\u0003', '\u008f\u0003\u008f\u0003\u008f\u0003\u008f\u0003\u008f\u0003\u008f\u0003', '\u008f\u0003\u008f\u0003\u008f\u0005\u008f\u08d0\n\u008f\u0003\u0090', '\u0003\u0090\u0003\u0090\u0003\u0090\u0003\u0090\u0003\u0090\u0003\u0090', '\u0003\u0090\u0003\u0090\u0003\u0090\u0003\u0090\u0003\u0090\u0005\u0090', '\u08de\n\u0090\u0003\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003', '\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003', '\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0003', '\u0091\u0003\u0091\u0003\u0091\u0003\u0091\u0005\u0091\u08f4\n\u0091', '\u0003\u0092\u0003\u0092\u0003\u0092\u0003\u0092\u0003\u0092\u0003\u0092', '\u0003\u0092\u0003\u0092\u0003\u0092\u0003\u0092\u0005\u0092\u0900\n', '\u0092\u0003\u0093\u0003\u0093\u0003\u0093\u0003\u0093\u0003\u0093\u0003', '\u0093\u0005\u0093\u0908\n\u0093\u0003\u0094\u0003\u0094\u0003\u0094', '\u0003\u0094\u0003\u0094\u0003\u0094\u0005\u0094\u0910\n\u0094\u0003', '\u0095\u0003\u0095\u0003\u0095\u0003\u0095\u0003\u0095\u0003\u0095\u0003', '\u0095\u0003\u0095\u0003\u0095\u0003\u0095\u0005\u0095\u091c\n\u0095', '\u0003\u0096\u0003\u0096\u0003\u0096\u0003\u0096\u0003\u0096\u0003\u0096', '\u0003\u0096\u0003\u0096\u0003\u0096\u0003\u0096\u0003\u0096\u0003\u0096', '\u0003\u0096\u0003\u0096\u0005\u0096\u092c\n\u0096\u0003\u0097\u0003', '\u0097\u0003\u0097\u0003\u0097\u0003\u0097\u0003\u0097\u0003\u0097\u0003', '\u0097\u0005\u0097\u0936\n\u0097\u0003\u0098\u0003\u0098\u0003\u0098', '\u0003\u0098\u0003\u0098\u0003\u0098\u0003\u0098\u0003\u0098\u0003\u0098', '\u0003\u0098\u0005\u0098\u0942\n\u0098\u0003\u0099\u0003\u0099\u0003', '\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003', '\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003', '\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003\u0099\u0003', '\u0099\u0003\u0099\u0005\u0099\u095a\n\u0099\u0003\u009a\u0003\u009a', '\u0003\u009a\u0003\u009a\u0003\u009a\u0003\u009a\u0003\u009a\u0003\u009a', '\u0003\u009a\u0003\u009a\u0003\u009a\u0003\u009a\u0005\u009a\u0968\n', '\u009a\u0003\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0003', '\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0003', '\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0003\u009b\u0005\u009b\u097a', '\n\u009b\u0003\u009c\u0003\u009c\u0003\u009c\u0003\u009c\u0003\u009c', '\u0003\u009c\u0003\u009c\u0003\u009c\u0005\u009c\u0984\n\u009c\u0003', '\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003', '\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003', '\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0003\u009d\u0005', '\u009d\u0998\n\u009d\u0003\u009e\u0003\u009e\u0003\u009e\u0003\u009e', '\u0003\u009e\u0003\u009e\u0003\u009e\u0003\u009e\u0003\u009e\u0003\u009e', '\u0005\u009e\u09a4\n\u009e\u0003\u009f\u0003\u009f\u0003\u009f\u0003', '\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003', '\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003', '\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003\u009f\u0003', '\u009f\u0003\u009f\u0003\u009f\u0005\u009f\u09be\n\u009f\u0003\u00a0', '\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0', '\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0', '\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0\u0003\u00a0', '\u0003\u00a0\u0005\u00a0\u09d4\n\u00a0\u0003\u00a1\u0003\u00a1\u0003', '\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0003', '\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0003', '\u00a1\u0003\u00a1\u0003\u00a1\u0003\u00a1\u0005\u00a1\u09e8\n\u00a1', '\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2', '\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2', '\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2', '\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0003\u00a2\u0005\u00a2\u0a00\n', '\u00a2\u0003\u00a3\u0003\u00a3\u0003\u00a3\u0003\u00a3\u0003\u00a3\u0003', '\u00a3\u0003\u00a3\u0003\u00a3\u0005\u00a3\u0a0a\n\u00a3\u0003\u00a4', '\u0003\u00a4\u0003\u00a4\u0003\u00a4\u0003\u00a4\u0003\u00a4\u0003\u00a4', '\u0003\u00a4\u0003\u00a4\u0003\u00a4\u0005\u00a4\u0a16\n\u00a4\u0003', '\u00a5\u0003\u00a5\u0003\u00a5\u0003\u00a5\u0003\u00a5\u0003\u00a5\u0003', '\u00a5\u0003\u00a5\u0005\u00a5\u0a20\n\u00a5\u0003\u00a6\u0003\u00a6', '\u0003\u00a6\u0003\u00a6\u0003\u00a6\u0003\u00a6\u0003\u00a6\u0003\u00a6', '\u0005\u00a6\u0a2a\n\u00a6\u0003\u00a7\u0003\u00a7\u0003\u00a7\u0003', '\u00a7\u0003\u00a7\u0003\u00a7\u0003\u00a7\u0003\u00a7\u0003\u00a7\u0003', '\u00a7\u0003\u00a7\u0003\u00a7\u0003\u00a7\u0003\u00a7\u0005\u00a7\u0a3a', '\n\u00a7\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8', '\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8', '\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0003\u00a8', '\u0003\u00a8\u0003\u00a8\u0003\u00a8\u0005\u00a8\u0a50\n\u00a8\u0003', '\u00a9\u0003\u00a9\u0003\u00a9\u0003\u00a9\u0003\u00a9\u0003\u00a9\u0003', '\u00a9\u0003\u00a9\u0003\u00a9\u0003\u00a9\u0003\u00a9\u0003\u00a9\u0003', '\u00a9\u0003\u00a9\u0005\u00a9\u0a60\n\u00a9\u0003\u00aa\u0003\u00aa', '\u0003\u00aa\u0003\u00aa\u0003\u00aa\u0003\u00aa\u0003\u00aa\u0003\u00aa', '\u0003\u00aa\u0003\u00aa\u0005\u00aa\u0a6c\n\u00aa\u0003\u00ab\u0003', '\u00ab\u0003\u00ab\u0003\u00ab\u0003\u00ab\u0003\u00ab\u0003\u00ab\u0003', '\u00ab\u0003\u00ab\u0003\u00ab\u0003\u00ab\u0003\u00ab\u0005\u00ab\u0a7a', '\n\u00ab\u0003\u00ac\u0003\u00ac\u0003\u00ac\u0003\u00ac\u0003\u00ac', '\u0003\u00ac\u0003\u00ac\u0003\u00ac\u0003\u00ac\u0003\u00ac\u0003\u00ac', '\u0003\u00ac\u0003\u00ac\u0003\u00ac\u0005\u00ac\u0a8a\n\u00ac\u0003', '\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0003', '\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0003', '\u00ad\u0003\u00ad\u0003\u00ad\u0003\u00ad\u0005\u00ad\u0a9c\n\u00ad', '\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae', '\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae', '\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae\u0003\u00ae', '\u0005\u00ae\u0ab0\n\u00ae\u0003\u00af\u0003\u00af\u0003\u00af\u0003', '\u00af\u0003\u00af\u0003\u00af\u0003\u00af\u0003\u00af\u0003\u00af\u0003', '\u00af\u0003\u00af\u0003\u00af\u0003\u00af\u0003\u00af\u0003\u00af\u0003', '\u00af\u0003\u00af\u0003\u00af\u0005\u00af\u0ac4\n\u00af\u0003\u00b0', '\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0', '\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0', '\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0\u0003\u00b0', '\u0003\u00b0\u0005\u00b0\u0ada\n\u00b0\u0003\u00b1\u0003\u00b1\u0003', '\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0003', '\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0003', '\u00b1\u0003\u00b1\u0003\u00b1\u0003\u00b1\u0005\u00b1\u0aee\n\u00b1', '\u0003\u00b2\u0003\u00b2\u0003\u00b2\u0003\u00b2\u0003\u00b2\u0003\u00b2', '\u0003\u00b2\u0003\u00b2\u0005\u00b2\u0af8\n\u00b2\u0003\u00b3\u0003', '\u00b3\u0003\u00b3\u0003\u00b3\u0003\u00b3\u0003\u00b3\u0003\u00b3\u0003', '\u00b3\u0005\u00b3\u0b02\n\u00b3\u0003\u00b4\u0003\u00b4\u0003\u00b4', '\u0003\u00b4\u0003\u00b4\u0003\u00b4\u0003\u00b4\u0003\u00b4\u0003\u00b4', '\u0003\u00b4\u0005\u00b4\u0b0e\n\u00b4\u0003\u00b5\u0003\u00b5\u0003', '\u00b5\u0003\u00b5\u0003\u00b5\u0003\u00b5\u0003\u00b5\u0003\u00b5\u0003', '\u00b5\u0003\u00b5\u0005\u00b5\u0b1a\n\u00b5\u0003\u00b6\u0003\u00b6', '\u0003\u00b6\u0003\u00b6\u0005\u00b6\u0b20\n\u00b6\u0003\u00b7\u0003', '\u00b7\u0003\u00b7\u0003\u00b7\u0003\u00b7\u0003\u00b7\u0003\u00b7\u0003', '\u00b7\u0003\u00b7\u0003\u00b7\u0003\u00b7\u0003\u00b7\u0005\u00b7\u0b2e', '\n\u00b7\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8', '\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8', '\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0003\u00b8\u0005\u00b8', '\u0b40\n\u00b8\u0003\u00b9\u0003\u00b9\u0003\u00ba\u0003\u00ba\u0003', '\u00ba\u0003\u00ba\u0005\u00ba\u0b48\n\u00ba\u0003\u00bb\u0003\u00bb', '\u0003\u00bc\u0003\u00bc\u0003\u00bc\u0003\u00bd\u0003\u00bd\u0003\u00be', '\u0003\u00be\u0003\u00be\u0003\u00bf\u0003\u00bf\u0003\u00c0\u0003\u00c0', '\u0003\u00c1\u0003\u00c1\u0003\u00c2\u0003\u00c2\u0003\u00c3\u0003\u00c3', '\u0003\u00c4\u0003\u00c4\u0003\u00c4\u0003\u00c5\u0003\u00c5\u0003\u00c5', '\u0003\u00c5\u0007\u00c5\u0b65\n\u00c5\f\u00c5\u000e\u00c5\u0b68\u000b', '\u00c5\u0003\u00c5\u0003\u00c5\u0003\u00c6\u0003\u00c6\u0003\u00c6\u0003', '\u00c6\u0007\u00c6\u0b70\n\u00c6\f\u00c6\u000e\u00c6\u0b73\u000b\u00c6', '\u0003\u00c6\u0003\u00c6\u0003\u00c7\u0006\u00c7\u0b78\n\u00c7\r\u00c7', '\u000e\u00c7\u0b79\u0003\u00c8\u0006\u00c8\u0b7d\n\u00c8\r\u00c8\u000e', '\u00c8\u0b7e\u0003\u00c8\u0003\u00c8\u0007\u00c8\u0b83\n\u00c8\f\u00c8', '\u000e\u00c8\u0b86\u000b\u00c8\u0003\u00c8\u0003\u00c8\u0006\u00c8\u0b8a', '\n\u00c8\r\u00c8\u000e\u00c8\u0b8b\u0003\u00c8\u0006\u00c8\u0b8f\n\u00c8', '\r\u00c8\u000e\u00c8\u0b90\u0003\u00c8\u0003\u00c8\u0007\u00c8\u0b95', '\n\u00c8\f\u00c8\u000e\u00c8\u0b98\u000b\u00c8\u0005\u00c8\u0b9a\n\u00c8', '\u0003\u00c8\u0003\u00c8\u0003\u00c8\u0003\u00c8\u0006\u00c8\u0ba0\n', '\u00c8\r\u00c8\u000e\u00c8\u0ba1\u0003\u00c8\u0003\u00c8\u0005\u00c8', '\u0ba6\n\u00c8\u0003\u00c9\u0003\u00c9\u0005\u00c9\u0baa\n\u00c9\u0003', '\u00c9\u0003\u00c9\u0003\u00c9\u0007\u00c9\u0baf\n\u00c9\f\u00c9\u000e', '\u00c9\u0bb2\u000b\u00c9\u0003\u00ca\u0003\u00ca\u0003\u00ca\u0003\u00ca', '\u0006\u00ca\u0bb8\n\u00ca\r\u00ca\u000e\u00ca\u0bb9\u0003\u00cb\u0003', '\u00cb\u0003\u00cb\u0003\u00cb\u0007\u00cb\u0bc0\n\u00cb\f\u00cb\u000e', '\u00cb\u0bc3\u000b\u00cb\u0003\u00cb\u0003\u00cb\u0003\u00cc\u0003\u00cc', '\u0003\u00cc\u0003\u00cc\u0007\u00cc\u0bcb\n\u00cc\f\u00cc\u000e\u00cc', '\u0bce\u000b\u00cc\u0003\u00cc\u0003\u00cc\u0003\u00cd\u0003\u00cd\u0003', '\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003', '\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003', '\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00cd\u0003', '\u00cd\u0003\u00cd\u0003\u00cd\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003', '\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003', '\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003', '\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003', '\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003\u00ce\u0003', '\u00ce\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003', '\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003', '\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003\u00cf\u0003', '\u00cf\u0003\u00d0\u0003\u00d0\u0005\u00d0\u0c19\n\u00d0\u0003\u00d0', '\u0006\u00d0\u0c1c\n\u00d0\r\u00d0\u000e\u00d0\u0c1d\u0003\u00d1\u0003', '\u00d1\u0003\u00d2\u0005\u00d2\u0c23\n\u00d2\u0003\u00d3\u0003\u00d3', '\u0003\u00d3\u0003\u00d3\u0007\u00d3\u0c29\n\u00d3\f\u00d3\u000e\u00d3', '\u0c2c\u000b\u00d3\u0003\u00d3\u0005\u00d3\u0c2f\n\u00d3\u0003\u00d3', '\u0005\u00d3\u0c32\n\u00d3\u0003\u00d3\u0003\u00d3\u0003\u00d4\u0003', '\u00d4\u0003\u00d4\u0003\u00d4\u0007\u00d4\u0c3a\n\u00d4\f\u00d4\u000e', '\u00d4\u0c3d\u000b\u00d4\u0003\u00d4\u0003\u00d4\u0003\u00d4\u0003\u00d4', '\u0003\u00d4\u0003\u00d5\u0006\u00d5\u0c45\n\u00d5\r\u00d5\u000e\u00d5', '\u0c46\u0003\u00d5\u0003\u00d5\u0003\u00d6\u0003\u00d6\u0003\u00d7\u0003', '\u00d7\u0003\u0c3b\u0002\u00d8\u0003\u0003\u0005\u0004\u0007\u0005\t', '\u0006\u000b\u0007\r\b\u000f\t\u0011\n\u0013\u000b\u0015\f\u0017\r\u0019', "\u000e\u001b\u000f\u001d\u0010\u001f\u0011!\u0012#\u0013%\u0014'\u0015", ')\u0016+\u0017-\u0018/\u00191\u001a3\u001b5\u001c7\u001d9\u001e;\u001f', '= ?!A"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o9q:s;u{?}', '@\u007fA\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008dH\u008fI\u0091', 'J\u0093K\u0095L\u0097M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3S\u00a5', 'T\u00a7U\u00a9V\u00abW\u00adX\u00afY\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9', '^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3c\u00c5d\u00c7e\u00c9f\u00cbg\u00cd', 'h\u00cfi\u00d1j\u00d3k\u00d5l\u00d7m\u00d9n\u00dbo\u00ddp\u00dfq\u00e1', 'r\u00e3s\u00e5t\u00e7u\u00e9v\u00ebw\u00edx\u00efy\u00f1z\u00f3{\u00f5', '|\u00f7}\u00f9~\u00fb\u007f\u00fd\u0080\u00ff\u0081\u0101\u0082\u0103', '\u0083\u0105\u0084\u0107\u0085\u0109\u0086\u010b\u0087\u010d\u0088\u010f', '\u0089\u0111\u008a\u0113\u008b\u0115\u008c\u0117\u008d\u0119\u008e\u011b', '\u008f\u011d\u0090\u011f\u0091\u0121\u0092\u0123\u0093\u0125\u0094\u0127', '\u0095\u0129\u0096\u012b\u0097\u012d\u0098\u012f\u0099\u0131\u009a\u0133', '\u009b\u0135\u009c\u0137\u009d\u0139\u009e\u013b\u009f\u013d\u00a0\u013f', '\u00a1\u0141\u00a2\u0143\u00a3\u0145\u00a4\u0147\u00a5\u0149\u00a6\u014b', '\u00a7\u014d\u00a8\u014f\u00a9\u0151\u00aa\u0153\u00ab\u0155\u00ac\u0157', '\u00ad\u0159\u00ae\u015b\u00af\u015d\u00b0\u015f\u00b1\u0161\u00b2\u0163', '\u00b3\u0165\u00b4\u0167\u00b5\u0169\u00b6\u016b\u00b7\u016d\u00b8\u016f', '\u00b9\u0171\u00ba\u0173\u00bb\u0175\u00bc\u0177\u00bd\u0179\u00be\u017b', '\u00bf\u017d\u00c0\u017f\u00c1\u0181\u00c2\u0183\u00c3\u0185\u00c4\u0187', '\u00c5\u0189\u00c6\u018b\u00c7\u018d\u00c8\u018f\u00c9\u0191\u00ca\u0193', '\u00cb\u0195\u00cc\u0197\u00cd\u0199\u00ce\u019b\u00cf\u019d\u00d0\u019f', '\u0002\u01a1\u0002\u01a3\u0002\u01a5\u00d1\u01a7\u00d2\u01a9\u00d3\u01ab', '\u00d4\u01ad\u00d5\u0003\u0002\u000b\u0003\u0002))\u0005\u0002<\u0003\u0002\u0002\u0002', '\u02a1\u02a2\u0007K\u0002\u0002\u02a2\u02a6\u0007P\u0002\u0002\u02a3', '\u02a4\u0007k\u0002\u0002\u02a4\u02a6\u0007p\u0002\u0002\u02a5\u02a1', '\u0003\u0002\u0002\u0002\u02a5\u02a3\u0003\u0002\u0002\u0002\u02a6@', '\u0003\u0002\u0002\u0002\u02a7\u02a8\u0007P\u0002\u0002\u02a8\u02a9', '\u0007Q\u0002\u0002\u02a9\u02ae\u0007V\u0002\u0002\u02aa\u02ab\u0007', 'p\u0002\u0002\u02ab\u02ac\u0007q\u0002\u0002\u02ac\u02ae\u0007v\u0002', '\u0002\u02ad\u02a7\u0003\u0002\u0002\u0002\u02ad\u02aa\u0003\u0002\u0002', '\u0002\u02aeB\u0003\u0002\u0002\u0002\u02af\u02b0\u0007P\u0002\u0002', '\u02b0\u02b4\u0007Q\u0002\u0002\u02b1\u02b2\u0007p\u0002\u0002\u02b2', '\u02b4\u0007q\u0002\u0002\u02b3\u02af\u0003\u0002\u0002\u0002\u02b3', '\u02b1\u0003\u0002\u0002\u0002\u02b4D\u0003\u0002\u0002\u0002\u02b5', '\u02b6\u0007G\u0002\u0002\u02b6\u02b7\u0007Z\u0002\u0002\u02b7\u02b8', '\u0007K\u0002\u0002\u02b8\u02b9\u0007U\u0002\u0002\u02b9\u02ba\u0007', 'V\u0002\u0002\u02ba\u02c2\u0007U\u0002\u0002\u02bb\u02bc\u0007g\u0002', '\u0002\u02bc\u02bd\u0007z\u0002\u0002\u02bd\u02be\u0007k\u0002\u0002', '\u02be\u02bf\u0007u\u0002\u0002\u02bf\u02c0\u0007v\u0002\u0002\u02c0', '\u02c2\u0007u\u0002\u0002\u02c1\u02b5\u0003\u0002\u0002\u0002\u02c1', '\u02bb\u0003\u0002\u0002\u0002\u02c2F\u0003\u0002\u0002\u0002\u02c3', '\u02c4\u0007D\u0002\u0002\u02c4\u02c5\u0007G\u0002\u0002\u02c5\u02c6', '\u0007V\u0002\u0002\u02c6\u02c7\u0007Y\u0002\u0002\u02c7\u02c8\u0007', 'G\u0002\u0002\u02c8\u02c9\u0007G\u0002\u0002\u02c9\u02d2\u0007P\u0002', '\u0002\u02ca\u02cb\u0007d\u0002\u0002\u02cb\u02cc\u0007g\u0002\u0002', '\u02cc\u02cd\u0007v\u0002\u0002\u02cd\u02ce\u0007y\u0002\u0002\u02ce', '\u02cf\u0007g\u0002\u0002\u02cf\u02d0\u0007g\u0002\u0002\u02d0\u02d2', '\u0007p\u0002\u0002\u02d1\u02c3\u0003\u0002\u0002\u0002\u02d1\u02ca', '\u0003\u0002\u0002\u0002\u02d2H\u0003\u0002\u0002\u0002\u02d3\u02d4', '\u0007N\u0002\u0002\u02d4\u02d5\u0007K\u0002\u0002\u02d5\u02d6\u0007', 'M\u0002\u0002\u02d6\u02dc\u0007G\u0002\u0002\u02d7\u02d8\u0007n\u0002', '\u0002\u02d8\u02d9\u0007k\u0002\u0002\u02d9\u02da\u0007m\u0002\u0002', '\u02da\u02dc\u0007g\u0002\u0002\u02db\u02d3\u0003\u0002\u0002\u0002', '\u02db\u02d7\u0003\u0002\u0002\u0002\u02dcJ\u0003\u0002\u0002\u0002', '\u02dd\u02de\u0007K\u0002\u0002\u02de\u02e2\u0007U\u0002\u0002\u02df', '\u02e0\u0007k\u0002\u0002\u02e0\u02e2\u0007u\u0002\u0002\u02e1\u02dd', '\u0003\u0002\u0002\u0002\u02e1\u02df\u0003\u0002\u0002\u0002\u02e2L', '\u0003\u0002\u0002\u0002\u02e3\u02e4\u0007P\u0002\u0002\u02e4\u02e5', '\u0007W\u0002\u0002\u02e5\u02e6\u0007N\u0002\u0002\u02e6\u02ec\u0007', 'N\u0002\u0002\u02e7\u02e8\u0007p\u0002\u0002\u02e8\u02e9\u0007w\u0002', '\u0002\u02e9\u02ea\u0007n\u0002\u0002\u02ea\u02ec\u0007n\u0002\u0002', '\u02eb\u02e3\u0003\u0002\u0002\u0002\u02eb\u02e7\u0003\u0002\u0002\u0002', '\u02ecN\u0003\u0002\u0002\u0002\u02ed\u02ee\u0007V\u0002\u0002\u02ee', '\u02ef\u0007T\u0002\u0002\u02ef\u02f0\u0007W\u0002\u0002\u02f0\u02f6', '\u0007G\u0002\u0002\u02f1\u02f2\u0007v\u0002\u0002\u02f2\u02f3\u0007', 't\u0002\u0002\u02f3\u02f4\u0007w\u0002\u0002\u02f4\u02f6\u0007g\u0002', '\u0002\u02f5\u02ed\u0003\u0002\u0002\u0002\u02f5\u02f1\u0003\u0002\u0002', '\u0002\u02f6P\u0003\u0002\u0002\u0002\u02f7\u02f8\u0007H\u0002\u0002', '\u02f8\u02f9\u0007C\u0002\u0002\u02f9\u02fa\u0007N\u0002\u0002\u02fa', '\u02fb\u0007U\u0002\u0002\u02fb\u0302\u0007G\u0002\u0002\u02fc\u02fd', '\u0007h\u0002\u0002\u02fd\u02fe\u0007c\u0002\u0002\u02fe\u02ff\u0007', 'n\u0002\u0002\u02ff\u0300\u0007u\u0002\u0002\u0300\u0302\u0007g\u0002', '\u0002\u0301\u02f7\u0003\u0002\u0002\u0002\u0301\u02fc\u0003\u0002\u0002', '\u0002\u0302R\u0003\u0002\u0002\u0002\u0303\u0304\u0007P\u0002\u0002', '\u0304\u0305\u0007W\u0002\u0002\u0305\u0306\u0007N\u0002\u0002\u0306', '\u0307\u0007N\u0002\u0002\u0307\u030e\u0007U\u0002\u0002\u0308\u0309', '\u0007p\u0002\u0002\u0309\u030a\u0007w\u0002\u0002\u030a\u030b\u0007', 'n\u0002\u0002\u030b\u030c\u0007n\u0002\u0002\u030c\u030e\u0007u\u0002', '\u0002\u030d\u0303\u0003\u0002\u0002\u0002\u030d\u0308\u0003\u0002\u0002', '\u0002\u030eT\u0003\u0002\u0002\u0002\u030f\u0310\u0007H\u0002\u0002', '\u0310\u0311\u0007K\u0002\u0002\u0311\u0312\u0007T\u0002\u0002\u0312', '\u0313\u0007U\u0002\u0002\u0313\u031a\u0007V\u0002\u0002\u0314\u0315', '\u0007h\u0002\u0002\u0315\u0316\u0007k\u0002\u0002\u0316\u0317\u0007', 't\u0002\u0002\u0317\u0318\u0007u\u0002\u0002\u0318\u031a\u0007v\u0002', '\u0002\u0319\u030f\u0003\u0002\u0002\u0002\u0319\u0314\u0003\u0002\u0002', '\u0002\u031aV\u0003\u0002\u0002\u0002\u031b\u031c\u0007N\u0002\u0002', '\u031c\u031d\u0007C\u0002\u0002\u031d\u031e\u0007U\u0002\u0002\u031e', '\u0324\u0007V\u0002\u0002\u031f\u0320\u0007n\u0002\u0002\u0320\u0321', '\u0007c\u0002\u0002\u0321\u0322\u0007u\u0002\u0002\u0322\u0324\u0007', 'v\u0002\u0002\u0323\u031b\u0003\u0002\u0002\u0002\u0323\u031f\u0003', '\u0002\u0002\u0002\u0324X\u0003\u0002\u0002\u0002\u0325\u0326\u0007', 'G\u0002\u0002\u0326\u0327\u0007U\u0002\u0002\u0327\u0328\u0007E\u0002', '\u0002\u0328\u0329\u0007C\u0002\u0002\u0329\u032a\u0007R\u0002\u0002', '\u032a\u0332\u0007G\u0002\u0002\u032b\u032c\u0007g\u0002\u0002\u032c', '\u032d\u0007u\u0002\u0002\u032d\u032e\u0007e\u0002\u0002\u032e\u032f', '\u0007c\u0002\u0002\u032f\u0330\u0007r\u0002\u0002\u0330\u0332\u0007', 'g\u0002\u0002\u0331\u0325\u0003\u0002\u0002\u0002\u0331\u032b\u0003', '\u0002\u0002\u0002\u0332Z\u0003\u0002\u0002\u0002\u0333\u0334\u0007', 'C\u0002\u0002\u0334\u0335\u0007U\u0002\u0002\u0335\u033a\u0007E\u0002', '\u0002\u0336\u0337\u0007c\u0002\u0002\u0337\u0338\u0007u\u0002\u0002', '\u0338\u033a\u0007e\u0002\u0002\u0339\u0333\u0003\u0002\u0002\u0002', '\u0339\u0336\u0003\u0002\u0002\u0002\u033a\\\u0003\u0002\u0002\u0002', '\u033b\u033c\u0007F\u0002\u0002\u033c\u033d\u0007G\u0002\u0002\u033d', '\u033e\u0007U\u0002\u0002\u033e\u0344\u0007E\u0002\u0002\u033f\u0340', '\u0007f\u0002\u0002\u0340\u0341\u0007g\u0002\u0002\u0341\u0342\u0007', 'u\u0002\u0002\u0342\u0344\u0007e\u0002\u0002\u0343\u033b\u0003\u0002', '\u0002\u0002\u0343\u033f\u0003\u0002\u0002\u0002\u0344^\u0003\u0002', '\u0002\u0002\u0345\u0346\u0007U\u0002\u0002\u0346\u0347\u0007W\u0002', '\u0002\u0347\u0348\u0007D\u0002\u0002\u0348\u0349\u0007U\u0002\u0002', '\u0349\u034a\u0007V\u0002\u0002\u034a\u034b\u0007T\u0002\u0002\u034b', '\u034c\u0007K\u0002\u0002\u034c\u034d\u0007P\u0002\u0002\u034d\u0358', '\u0007I\u0002\u0002\u034e\u034f\u0007u\u0002\u0002\u034f\u0350\u0007', 'w\u0002\u0002\u0350\u0351\u0007d\u0002\u0002\u0351\u0352\u0007u\u0002', '\u0002\u0352\u0353\u0007v\u0002\u0002\u0353\u0354\u0007t\u0002\u0002', '\u0354\u0355\u0007k\u0002\u0002\u0355\u0356\u0007p\u0002\u0002\u0356', '\u0358\u0007i\u0002\u0002\u0357\u0345\u0003\u0002\u0002\u0002\u0357', '\u034e\u0003\u0002\u0002\u0002\u0358`\u0003\u0002\u0002\u0002\u0359', '\u035a\u0007R\u0002\u0002\u035a\u035b\u0007Q\u0002\u0002\u035b\u035c', '\u0007U\u0002\u0002\u035c\u035d\u0007K\u0002\u0002\u035d\u035e\u0007', 'V\u0002\u0002\u035e\u035f\u0007K\u0002\u0002\u035f\u0360\u0007Q\u0002', '\u0002\u0360\u036a\u0007P\u0002\u0002\u0361\u0362\u0007r\u0002\u0002', '\u0362\u0363\u0007q\u0002\u0002\u0363\u0364\u0007u\u0002\u0002\u0364', '\u0365\u0007k\u0002\u0002\u0365\u0366\u0007v\u0002\u0002\u0366\u0367', '\u0007k\u0002\u0002\u0367\u0368\u0007q\u0002\u0002\u0368\u036a\u0007', 'p\u0002\u0002\u0369\u0359\u0003\u0002\u0002\u0002\u0369\u0361\u0003', '\u0002\u0002\u0002\u036ab\u0003\u0002\u0002\u0002\u036b\u036c\u0007', 'H\u0002\u0002\u036c\u036d\u0007Q\u0002\u0002\u036d\u0372\u0007T\u0002', '\u0002\u036e\u036f\u0007h\u0002\u0002\u036f\u0370\u0007q\u0002\u0002', '\u0370\u0372\u0007t\u0002\u0002\u0371\u036b\u0003\u0002\u0002\u0002', '\u0371\u036e\u0003\u0002\u0002\u0002\u0372d\u0003\u0002\u0002\u0002', '\u0373\u0374\u0007V\u0002\u0002\u0374\u0375\u0007K\u0002\u0002\u0375', '\u0376\u0007P\u0002\u0002\u0376\u0377\u0007[\u0002\u0002\u0377\u0378', '\u0007K\u0002\u0002\u0378\u0379\u0007P\u0002\u0002\u0379\u0382\u0007', 'V\u0002\u0002\u037a\u037b\u0007v\u0002\u0002\u037b\u037c\u0007k\u0002', '\u0002\u037c\u037d\u0007p\u0002\u0002\u037d\u037e\u0007{\u0002\u0002', '\u037e\u037f\u0007k\u0002\u0002\u037f\u0380\u0007p\u0002\u0002\u0380', '\u0382\u0007v\u0002\u0002\u0381\u0373\u0003\u0002\u0002\u0002\u0381', '\u037a\u0003\u0002\u0002\u0002\u0382f\u0003\u0002\u0002\u0002\u0383', '\u0384\u0007U\u0002\u0002\u0384\u0385\u0007O\u0002\u0002\u0385\u0386', '\u0007C\u0002\u0002\u0386\u0387\u0007N\u0002\u0002\u0387\u0388\u0007', 'N\u0002\u0002\u0388\u0389\u0007K\u0002\u0002\u0389\u038a\u0007P\u0002', '\u0002\u038a\u0394\u0007V\u0002\u0002\u038b\u038c\u0007u\u0002\u0002', '\u038c\u038d\u0007o\u0002\u0002\u038d\u038e\u0007c\u0002\u0002\u038e', '\u038f\u0007n\u0002\u0002\u038f\u0390\u0007n\u0002\u0002\u0390\u0391', '\u0007k\u0002\u0002\u0391\u0392\u0007p\u0002\u0002\u0392\u0394\u0007', 'v\u0002\u0002\u0393\u0383\u0003\u0002\u0002\u0002\u0393\u038b\u0003', '\u0002\u0002\u0002\u0394h\u0003\u0002\u0002\u0002\u0395\u0396\u0007', 'K\u0002\u0002\u0396\u0397\u0007P\u0002\u0002\u0397\u0398\u0007V\u0002', '\u0002\u0398\u0399\u0007G\u0002\u0002\u0399\u039a\u0007I\u0002\u0002', '\u039a\u039b\u0007G\u0002\u0002\u039b\u03a4\u0007T\u0002\u0002\u039c', '\u039d\u0007k\u0002\u0002\u039d\u039e\u0007p\u0002\u0002\u039e\u039f', '\u0007v\u0002\u0002\u039f\u03a0\u0007g\u0002\u0002\u03a0\u03a1\u0007', 'i\u0002\u0002\u03a1\u03a2\u0007g\u0002\u0002\u03a2\u03a4\u0007t\u0002', '\u0002\u03a3\u0395\u0003\u0002\u0002\u0002\u03a3\u039c\u0003\u0002\u0002', '\u0002\u03a4j\u0003\u0002\u0002\u0002\u03a5\u03a6\u0007F\u0002\u0002', '\u03a6\u03a7\u0007C\u0002\u0002\u03a7\u03a8\u0007V\u0002\u0002\u03a8', '\u03ae\u0007G\u0002\u0002\u03a9\u03aa\u0007f\u0002\u0002\u03aa\u03ab', '\u0007c\u0002\u0002\u03ab\u03ac\u0007v\u0002\u0002\u03ac\u03ae\u0007', 'g\u0002\u0002\u03ad\u03a5\u0003\u0002\u0002\u0002\u03ad\u03a9\u0003', '\u0002\u0002\u0002\u03ael\u0003\u0002\u0002\u0002\u03af\u03b0\u0007', 'V\u0002\u0002\u03b0\u03b1\u0007K\u0002\u0002\u03b1\u03b2\u0007O\u0002', '\u0002\u03b2\u03b8\u0007G\u0002\u0002\u03b3\u03b4\u0007v\u0002\u0002', '\u03b4\u03b5\u0007k\u0002\u0002\u03b5\u03b6\u0007o\u0002\u0002\u03b6', '\u03b8\u0007g\u0002\u0002\u03b7\u03af\u0003\u0002\u0002\u0002\u03b7', '\u03b3\u0003\u0002\u0002\u0002\u03b8n\u0003\u0002\u0002\u0002\u03b9', '\u03ba\u0007V\u0002\u0002\u03ba\u03bb\u0007K\u0002\u0002\u03bb\u03bc', '\u0007O\u0002\u0002\u03bc\u03bd\u0007G\u0002\u0002\u03bd\u03be\u0007', 'U\u0002\u0002\u03be\u03bf\u0007V\u0002\u0002\u03bf\u03c0\u0007C\u0002', '\u0002\u03c0\u03c1\u0007O\u0002\u0002\u03c1\u03cc\u0007R\u0002\u0002', '\u03c2\u03c3\u0007v\u0002\u0002\u03c3\u03c4\u0007k\u0002\u0002\u03c4', '\u03c5\u0007o\u0002\u0002\u03c5\u03c6\u0007g\u0002\u0002\u03c6\u03c7', '\u0007u\u0002\u0002\u03c7\u03c8\u0007v\u0002\u0002\u03c8\u03c9\u0007', 'c\u0002\u0002\u03c9\u03ca\u0007o\u0002\u0002\u03ca\u03cc\u0007r\u0002', '\u0002\u03cb\u03b9\u0003\u0002\u0002\u0002\u03cb\u03c2\u0003\u0002\u0002', '\u0002\u03ccp\u0003\u0002\u0002\u0002\u03cd\u03ce\u0007K\u0002\u0002', '\u03ce\u03cf\u0007P\u0002\u0002\u03cf\u03d0\u0007V\u0002\u0002\u03d0', '\u03d1\u0007G\u0002\u0002\u03d1\u03d2\u0007T\u0002\u0002\u03d2\u03d3', '\u0007X\u0002\u0002\u03d3\u03d4\u0007C\u0002\u0002\u03d4\u03de\u0007', 'N\u0002\u0002\u03d5\u03d6\u0007k\u0002\u0002\u03d6\u03d7\u0007p\u0002', '\u0002\u03d7\u03d8\u0007v\u0002\u0002\u03d8\u03d9\u0007g\u0002\u0002', '\u03d9\u03da\u0007t\u0002\u0002\u03da\u03db\u0007x\u0002\u0002\u03db', '\u03dc\u0007c\u0002\u0002\u03dc\u03de\u0007n\u0002\u0002\u03dd\u03cd', '\u0003\u0002\u0002\u0002\u03dd\u03d5\u0003\u0002\u0002\u0002\u03der', '\u0003\u0002\u0002\u0002\u03df\u03e0\u0007[\u0002\u0002\u03e0\u03e1', '\u0007G\u0002\u0002\u03e1\u03e2\u0007C\u0002\u0002\u03e2\u03e8\u0007', 'T\u0002\u0002\u03e3\u03e4\u0007{\u0002\u0002\u03e4\u03e5\u0007g\u0002', '\u0002\u03e5\u03e6\u0007c\u0002\u0002\u03e6\u03e8\u0007t\u0002\u0002', '\u03e7\u03df\u0003\u0002\u0002\u0002\u03e7\u03e3\u0003\u0002\u0002\u0002', '\u03e8t\u0003\u0002\u0002\u0002\u03e9\u03ea\u0007O\u0002\u0002\u03ea', '\u03eb\u0007Q\u0002\u0002\u03eb\u03ec\u0007P\u0002\u0002\u03ec\u03ed', '\u0007V\u0002\u0002\u03ed\u03f4\u0007J\u0002\u0002\u03ee\u03ef\u0007', 'o\u0002\u0002\u03ef\u03f0\u0007q\u0002\u0002\u03f0\u03f1\u0007p\u0002', '\u0002\u03f1\u03f2\u0007v\u0002\u0002\u03f2\u03f4\u0007j\u0002\u0002', '\u03f3\u03e9\u0003\u0002\u0002\u0002\u03f3\u03ee\u0003\u0002\u0002\u0002', '\u03f4v\u0003\u0002\u0002\u0002\u03f5\u03f6\u0007F\u0002\u0002\u03f6', '\u03f7\u0007C\u0002\u0002\u03f7\u03fc\u0007[\u0002\u0002\u03f8\u03f9', '\u0007f\u0002\u0002\u03f9\u03fa\u0007c\u0002\u0002\u03fa\u03fc\u0007', '{\u0002\u0002\u03fb\u03f5\u0003\u0002\u0002\u0002\u03fb\u03f8\u0003', '\u0002\u0002\u0002\u03fcx\u0003\u0002\u0002\u0002\u03fd\u03fe\u0007', 'J\u0002\u0002\u03fe\u03ff\u0007Q\u0002\u0002\u03ff\u0400\u0007W\u0002', '\u0002\u0400\u0406\u0007T\u0002\u0002\u0401\u0402\u0007j\u0002\u0002', '\u0402\u0403\u0007q\u0002\u0002\u0403\u0404\u0007w\u0002\u0002\u0404', '\u0406\u0007t\u0002\u0002\u0405\u03fd\u0003\u0002\u0002\u0002\u0405', '\u0401\u0003\u0002\u0002\u0002\u0406z\u0003\u0002\u0002\u0002\u0407', '\u0408\u0007O\u0002\u0002\u0408\u0409\u0007K\u0002\u0002\u0409\u040a', '\u0007P\u0002\u0002\u040a\u040b\u0007W\u0002\u0002\u040b\u040c\u0007', 'V\u0002\u0002\u040c\u0414\u0007G\u0002\u0002\u040d\u040e\u0007o\u0002', '\u0002\u040e\u040f\u0007k\u0002\u0002\u040f\u0410\u0007p\u0002\u0002', '\u0410\u0411\u0007w\u0002\u0002\u0411\u0412\u0007v\u0002\u0002\u0412', '\u0414\u0007g\u0002\u0002\u0413\u0407\u0003\u0002\u0002\u0002\u0413', '\u040d\u0003\u0002\u0002\u0002\u0414|\u0003\u0002\u0002\u0002\u0415', '\u0416\u0007U\u0002\u0002\u0416\u0417\u0007G\u0002\u0002\u0417\u0418', '\u0007E\u0002\u0002\u0418\u0419\u0007Q\u0002\u0002\u0419\u041a\u0007', 'P\u0002\u0002\u041a\u0422\u0007F\u0002\u0002\u041b\u041c\u0007u\u0002', '\u0002\u041c\u041d\u0007g\u0002\u0002\u041d\u041e\u0007e\u0002\u0002', '\u041e\u041f\u0007q\u0002\u0002\u041f\u0420\u0007p\u0002\u0002\u0420', '\u0422\u0007f\u0002\u0002\u0421\u0415\u0003\u0002\u0002\u0002\u0421', '\u041b\u0003\u0002\u0002\u0002\u0422~\u0003\u0002\u0002\u0002\u0423', '\u0424\u0007\\\u0002\u0002\u0424\u0425\u0007Q\u0002\u0002\u0425\u0426', '\u0007P\u0002\u0002\u0426\u042c\u0007G\u0002\u0002\u0427\u0428\u0007', '|\u0002\u0002\u0428\u0429\u0007q\u0002\u0002\u0429\u042a\u0007p\u0002', '\u0002\u042a\u042c\u0007g\u0002\u0002\u042b\u0423\u0003\u0002\u0002', '\u0002\u042b\u0427\u0003\u0002\u0002\u0002\u042c\u0080\u0003\u0002\u0002', '\u0002\u042d\u042e\u0007E\u0002\u0002\u042e\u042f\u0007W\u0002\u0002', '\u042f\u0430\u0007T\u0002\u0002\u0430\u0431\u0007T\u0002\u0002\u0431', '\u0432\u0007G\u0002\u0002\u0432\u0433\u0007P\u0002\u0002\u0433\u0434', '\u0007V\u0002\u0002\u0434\u0435\u0007a\u0002\u0002\u0435\u0436\u0007', 'F\u0002\u0002\u0436\u0437\u0007C\u0002\u0002\u0437\u0438\u0007V\u0002', '\u0002\u0438\u0446\u0007G\u0002\u0002\u0439\u043a\u0007e\u0002\u0002', '\u043a\u043b\u0007w\u0002\u0002\u043b\u043c\u0007t\u0002\u0002\u043c', '\u043d\u0007t\u0002\u0002\u043d\u043e\u0007g\u0002\u0002\u043e\u043f', '\u0007p\u0002\u0002\u043f\u0440\u0007v\u0002\u0002\u0440\u0441\u0007', 'a\u0002\u0002\u0441\u0442\u0007f\u0002\u0002\u0442\u0443\u0007c\u0002', '\u0002\u0443\u0444\u0007v\u0002\u0002\u0444\u0446\u0007g\u0002\u0002', '\u0445\u042d\u0003\u0002\u0002\u0002\u0445\u0439\u0003\u0002\u0002\u0002', '\u0446\u0082\u0003\u0002\u0002\u0002\u0447\u0448\u0007E\u0002\u0002', '\u0448\u0449\u0007W\u0002\u0002\u0449\u044a\u0007T\u0002\u0002\u044a', '\u044b\u0007T\u0002\u0002\u044b\u044c\u0007G\u0002\u0002\u044c\u044d', '\u0007P\u0002\u0002\u044d\u044e\u0007V\u0002\u0002\u044e\u044f\u0007', 'a\u0002\u0002\u044f\u0450\u0007V\u0002\u0002\u0450\u0451\u0007K\u0002', '\u0002\u0451\u0452\u0007O\u0002\u0002\u0452\u0460\u0007G\u0002\u0002', '\u0453\u0454\u0007e\u0002\u0002\u0454\u0455\u0007w\u0002\u0002\u0455', '\u0456\u0007t\u0002\u0002\u0456\u0457\u0007t\u0002\u0002\u0457\u0458', '\u0007g\u0002\u0002\u0458\u0459\u0007p\u0002\u0002\u0459\u045a\u0007', 'v\u0002\u0002\u045a\u045b\u0007a\u0002\u0002\u045b\u045c\u0007v\u0002', '\u0002\u045c\u045d\u0007k\u0002\u0002\u045d\u045e\u0007o\u0002\u0002', '\u045e\u0460\u0007g\u0002\u0002\u045f\u0447\u0003\u0002\u0002\u0002', '\u045f\u0453\u0003\u0002\u0002\u0002\u0460\u0084\u0003\u0002\u0002\u0002', '\u0461\u0462\u0007E\u0002\u0002\u0462\u0463\u0007W\u0002\u0002\u0463', '\u0464\u0007T\u0002\u0002\u0464\u0465\u0007T\u0002\u0002\u0465\u0466', '\u0007G\u0002\u0002\u0466\u0467\u0007P\u0002\u0002\u0467\u0468\u0007', 'V\u0002\u0002\u0468\u0469\u0007a\u0002\u0002\u0469\u046a\u0007V\u0002', '\u0002\u046a\u046b\u0007K\u0002\u0002\u046b\u046c\u0007O\u0002\u0002', '\u046c\u046d\u0007G\u0002\u0002\u046d\u046e\u0007U\u0002\u0002\u046e', '\u046f\u0007V\u0002\u0002\u046f\u0470\u0007C\u0002\u0002\u0470\u0471', '\u0007O\u0002\u0002\u0471\u0484\u0007R\u0002\u0002\u0472\u0473\u0007', 'e\u0002\u0002\u0473\u0474\u0007w\u0002\u0002\u0474\u0475\u0007t\u0002', '\u0002\u0475\u0476\u0007t\u0002\u0002\u0476\u0477\u0007g\u0002\u0002', '\u0477\u0478\u0007p\u0002\u0002\u0478\u0479\u0007v\u0002\u0002\u0479', '\u047a\u0007a\u0002\u0002\u047a\u047b\u0007v\u0002\u0002\u047b\u047c', '\u0007k\u0002\u0002\u047c\u047d\u0007o\u0002\u0002\u047d\u047e\u0007', 'g\u0002\u0002\u047e\u047f\u0007u\u0002\u0002\u047f\u0480\u0007v\u0002', '\u0002\u0480\u0481\u0007c\u0002\u0002\u0481\u0482\u0007o\u0002\u0002', '\u0482\u0484\u0007r\u0002\u0002\u0483\u0461\u0003\u0002\u0002\u0002', '\u0483\u0472\u0003\u0002\u0002\u0002\u0484\u0086\u0003\u0002\u0002\u0002', '\u0485\u0486\u0007N\u0002\u0002\u0486\u0487\u0007Q\u0002\u0002\u0487', '\u0488\u0007E\u0002\u0002\u0488\u0489\u0007C\u0002\u0002\u0489\u048a', '\u0007N\u0002\u0002\u048a\u048b\u0007V\u0002\u0002\u048b\u048c\u0007', 'K\u0002\u0002\u048c\u048d\u0007O\u0002\u0002\u048d\u0498\u0007G\u0002', '\u0002\u048e\u048f\u0007n\u0002\u0002\u048f\u0490\u0007q\u0002\u0002', '\u0490\u0491\u0007e\u0002\u0002\u0491\u0492\u0007c\u0002\u0002\u0492', '\u0493\u0007n\u0002\u0002\u0493\u0494\u0007v\u0002\u0002\u0494\u0495', '\u0007k\u0002\u0002\u0495\u0496\u0007o\u0002\u0002\u0496\u0498\u0007', 'g\u0002\u0002\u0497\u0485\u0003\u0002\u0002\u0002\u0497\u048e\u0003', '\u0002\u0002\u0002\u0498\u0088\u0003\u0002\u0002\u0002\u0499\u049a\u0007', 'N\u0002\u0002\u049a\u049b\u0007Q\u0002\u0002\u049b\u049c\u0007E\u0002', '\u0002\u049c\u049d\u0007C\u0002\u0002\u049d\u049e\u0007N\u0002\u0002', '\u049e\u049f\u0007V\u0002\u0002\u049f\u04a0\u0007K\u0002\u0002\u04a0', '\u04a1\u0007O\u0002\u0002\u04a1\u04a2\u0007G\u0002\u0002\u04a2\u04a3', '\u0007U\u0002\u0002\u04a3\u04a4\u0007V\u0002\u0002\u04a4\u04a5\u0007', 'C\u0002\u0002\u04a5\u04a6\u0007O\u0002\u0002\u04a6\u04b6\u0007R\u0002', '\u0002\u04a7\u04a8\u0007n\u0002\u0002\u04a8\u04a9\u0007q\u0002\u0002', '\u04a9\u04aa\u0007e\u0002\u0002\u04aa\u04ab\u0007c\u0002\u0002\u04ab', '\u04ac\u0007n\u0002\u0002\u04ac\u04ad\u0007v\u0002\u0002\u04ad\u04ae', '\u0007k\u0002\u0002\u04ae\u04af\u0007o\u0002\u0002\u04af\u04b0\u0007', 'g\u0002\u0002\u04b0\u04b1\u0007u\u0002\u0002\u04b1\u04b2\u0007v\u0002', '\u0002\u04b2\u04b3\u0007c\u0002\u0002\u04b3\u04b4\u0007o\u0002\u0002', '\u04b4\u04b6\u0007r\u0002\u0002\u04b5\u0499\u0003\u0002\u0002\u0002', '\u04b5\u04a7\u0003\u0002\u0002\u0002\u04b6\u008a\u0003\u0002\u0002\u0002', '\u04b7\u04b8\u0007G\u0002\u0002\u04b8\u04b9\u0007Z\u0002\u0002\u04b9', '\u04ba\u0007V\u0002\u0002\u04ba\u04bb\u0007T\u0002\u0002\u04bb\u04bc', '\u0007C\u0002\u0002\u04bc\u04bd\u0007E\u0002\u0002\u04bd\u04c6\u0007', 'V\u0002\u0002\u04be\u04bf\u0007g\u0002\u0002\u04bf\u04c0\u0007z\u0002', '\u0002\u04c0\u04c1\u0007v\u0002\u0002\u04c1\u04c2\u0007t\u0002\u0002', '\u04c2\u04c3\u0007c\u0002\u0002\u04c3\u04c4\u0007e\u0002\u0002\u04c4', '\u04c6\u0007v\u0002\u0002\u04c5\u04b7\u0003\u0002\u0002\u0002\u04c5', '\u04be\u0003\u0002\u0002\u0002\u04c6\u008c\u0003\u0002\u0002\u0002\u04c7', '\u04c8\u0007E\u0002\u0002\u04c8\u04c9\u0007C\u0002\u0002\u04c9\u04ca', '\u0007U\u0002\u0002\u04ca\u04d0\u0007G\u0002\u0002\u04cb\u04cc\u0007', 'e\u0002\u0002\u04cc\u04cd\u0007c\u0002\u0002\u04cd\u04ce\u0007u\u0002', '\u0002\u04ce\u04d0\u0007g\u0002\u0002\u04cf\u04c7\u0003\u0002\u0002', '\u0002\u04cf\u04cb\u0003\u0002\u0002\u0002\u04d0\u008e\u0003\u0002\u0002', '\u0002\u04d1\u04d2\u0007Y\u0002\u0002\u04d2\u04d3\u0007J\u0002\u0002', '\u04d3\u04d4\u0007G\u0002\u0002\u04d4\u04da\u0007P\u0002\u0002\u04d5', '\u04d6\u0007y\u0002\u0002\u04d6\u04d7\u0007j\u0002\u0002\u04d7\u04d8', '\u0007g\u0002\u0002\u04d8\u04da\u0007p\u0002\u0002\u04d9\u04d1\u0003', '\u0002\u0002\u0002\u04d9\u04d5\u0003\u0002\u0002\u0002\u04da\u0090\u0003', '\u0002\u0002\u0002\u04db\u04dc\u0007V\u0002\u0002\u04dc\u04dd\u0007', 'J\u0002\u0002\u04dd\u04de\u0007G\u0002\u0002\u04de\u04e4\u0007P\u0002', '\u0002\u04df\u04e0\u0007v\u0002\u0002\u04e0\u04e1\u0007j\u0002\u0002', '\u04e1\u04e2\u0007g\u0002\u0002\u04e2\u04e4\u0007p\u0002\u0002\u04e3', '\u04db\u0003\u0002\u0002\u0002\u04e3\u04df\u0003\u0002\u0002\u0002\u04e4', '\u0092\u0003\u0002\u0002\u0002\u04e5\u04e6\u0007G\u0002\u0002\u04e6', '\u04e7\u0007N\u0002\u0002\u04e7\u04e8\u0007U\u0002\u0002\u04e8\u04ee', '\u0007G\u0002\u0002\u04e9\u04ea\u0007g\u0002\u0002\u04ea\u04eb\u0007', 'n\u0002\u0002\u04eb\u04ec\u0007u\u0002\u0002\u04ec\u04ee\u0007g\u0002', '\u0002\u04ed\u04e5\u0003\u0002\u0002\u0002\u04ed\u04e9\u0003\u0002\u0002', '\u0002\u04ee\u0094\u0003\u0002\u0002\u0002\u04ef\u04f0\u0007G\u0002', '\u0002\u04f0\u04f1\u0007P\u0002\u0002\u04f1\u04f6\u0007F\u0002\u0002', '\u04f2\u04f3\u0007g\u0002\u0002\u04f3\u04f4\u0007p\u0002\u0002\u04f4', '\u04f6\u0007f\u0002\u0002\u04f5\u04ef\u0003\u0002\u0002\u0002\u04f5', '\u04f2\u0003\u0002\u0002\u0002\u04f6\u0096\u0003\u0002\u0002\u0002\u04f7', '\u04f8\u0007L\u0002\u0002\u04f8\u04f9\u0007Q\u0002\u0002\u04f9\u04fa', '\u0007K\u0002\u0002\u04fa\u0500\u0007P\u0002\u0002\u04fb\u04fc\u0007', 'l\u0002\u0002\u04fc\u04fd\u0007q\u0002\u0002\u04fd\u04fe\u0007k\u0002', '\u0002\u04fe\u0500\u0007p\u0002\u0002\u04ff\u04f7\u0003\u0002\u0002', '\u0002\u04ff\u04fb\u0003\u0002\u0002\u0002\u0500\u0098\u0003\u0002\u0002', '\u0002\u0501\u0502\u0007E\u0002\u0002\u0502\u0503\u0007T\u0002\u0002', '\u0503\u0504\u0007Q\u0002\u0002\u0504\u0505\u0007U\u0002\u0002\u0505', '\u050c\u0007U\u0002\u0002\u0506\u0507\u0007e\u0002\u0002\u0507\u0508', '\u0007t\u0002\u0002\u0508\u0509\u0007q\u0002\u0002\u0509\u050a\u0007', 'u\u0002\u0002\u050a\u050c\u0007u\u0002\u0002\u050b\u0501\u0003\u0002', '\u0002\u0002\u050b\u0506\u0003\u0002\u0002\u0002\u050c\u009a\u0003\u0002', '\u0002\u0002\u050d\u050e\u0007Q\u0002\u0002\u050e\u050f\u0007W\u0002', '\u0002\u050f\u0510\u0007V\u0002\u0002\u0510\u0511\u0007G\u0002\u0002', '\u0511\u0518\u0007T\u0002\u0002\u0512\u0513\u0007q\u0002\u0002\u0513', '\u0514\u0007w\u0002\u0002\u0514\u0515\u0007v\u0002\u0002\u0515\u0516', '\u0007g\u0002\u0002\u0516\u0518\u0007t\u0002\u0002\u0517\u050d\u0003', '\u0002\u0002\u0002\u0517\u0512\u0003\u0002\u0002\u0002\u0518\u009c\u0003', '\u0002\u0002\u0002\u0519\u051a\u0007K\u0002\u0002\u051a\u051b\u0007', 'P\u0002\u0002\u051b\u051c\u0007P\u0002\u0002\u051c\u051d\u0007G\u0002', '\u0002\u051d\u0524\u0007T\u0002\u0002\u051e\u051f\u0007k\u0002\u0002', '\u051f\u0520\u0007p\u0002\u0002\u0520\u0521\u0007p\u0002\u0002\u0521', '\u0522\u0007g\u0002\u0002\u0522\u0524\u0007t\u0002\u0002\u0523\u0519', '\u0003\u0002\u0002\u0002\u0523\u051e\u0003\u0002\u0002\u0002\u0524\u009e', '\u0003\u0002\u0002\u0002\u0525\u0526\u0007N\u0002\u0002\u0526\u0527', '\u0007G\u0002\u0002\u0527\u0528\u0007H\u0002\u0002\u0528\u052e\u0007', 'V\u0002\u0002\u0529\u052a\u0007n\u0002\u0002\u052a\u052b\u0007g\u0002', '\u0002\u052b\u052c\u0007h\u0002\u0002\u052c\u052e\u0007v\u0002\u0002', '\u052d\u0525\u0003\u0002\u0002\u0002\u052d\u0529\u0003\u0002\u0002\u0002', '\u052e\u00a0\u0003\u0002\u0002\u0002\u052f\u0530\u0007T\u0002\u0002', '\u0530\u0531\u0007K\u0002\u0002\u0531\u0532\u0007I\u0002\u0002\u0532', '\u0533\u0007J\u0002\u0002\u0533\u053a\u0007V\u0002\u0002\u0534\u0535', '\u0007t\u0002\u0002\u0535\u0536\u0007k\u0002\u0002\u0536\u0537\u0007', 'i\u0002\u0002\u0537\u0538\u0007j\u0002\u0002\u0538\u053a\u0007v\u0002', '\u0002\u0539\u052f\u0003\u0002\u0002\u0002\u0539\u0534\u0003\u0002\u0002', '\u0002\u053a\u00a2\u0003\u0002\u0002\u0002\u053b\u053c\u0007H\u0002', '\u0002\u053c\u053d\u0007W\u0002\u0002\u053d\u053e\u0007N\u0002\u0002', '\u053e\u0544\u0007N\u0002\u0002\u053f\u0540\u0007h\u0002\u0002\u0540', '\u0541\u0007w\u0002\u0002\u0541\u0542\u0007n\u0002\u0002\u0542\u0544', '\u0007n\u0002\u0002\u0543\u053b\u0003\u0002\u0002\u0002\u0543\u053f', '\u0003\u0002\u0002\u0002\u0544\u00a4\u0003\u0002\u0002\u0002\u0545\u0546', '\u0007P\u0002\u0002\u0546\u0547\u0007C\u0002\u0002\u0547\u0548\u0007', 'V\u0002\u0002\u0548\u0549\u0007W\u0002\u0002\u0549\u054a\u0007T\u0002', '\u0002\u054a\u054b\u0007C\u0002\u0002\u054b\u0554\u0007N\u0002\u0002', '\u054c\u054d\u0007p\u0002\u0002\u054d\u054e\u0007c\u0002\u0002\u054e', '\u054f\u0007v\u0002\u0002\u054f\u0550\u0007w\u0002\u0002\u0550\u0551', '\u0007t\u0002\u0002\u0551\u0552\u0007c\u0002\u0002\u0552\u0554\u0007', 'n\u0002\u0002\u0553\u0545\u0003\u0002\u0002\u0002\u0553\u054c\u0003', '\u0002\u0002\u0002\u0554\u00a6\u0003\u0002\u0002\u0002\u0555\u0556\u0007', 'W\u0002\u0002\u0556\u0557\u0007U\u0002\u0002\u0557\u0558\u0007K\u0002', '\u0002\u0558\u0559\u0007P\u0002\u0002\u0559\u0560\u0007I\u0002\u0002', '\u055a\u055b\u0007w\u0002\u0002\u055b\u055c\u0007u\u0002\u0002\u055c', '\u055d\u0007k\u0002\u0002\u055d\u055e\u0007p\u0002\u0002\u055e\u0560', '\u0007i\u0002\u0002\u055f\u0555\u0003\u0002\u0002\u0002\u055f\u055a', '\u0003\u0002\u0002\u0002\u0560\u00a8\u0003\u0002\u0002\u0002\u0561\u0562', '\u0007Q\u0002\u0002\u0562\u0566\u0007P\u0002\u0002\u0563\u0564\u0007', 'q\u0002\u0002\u0564\u0566\u0007p\u0002\u0002\u0565\u0561\u0003\u0002', '\u0002\u0002\u0565\u0563\u0003\u0002\u0002\u0002\u0566\u00aa\u0003\u0002', '\u0002\u0002\u0567\u0568\u0007H\u0002\u0002\u0568\u0569\u0007K\u0002', '\u0002\u0569\u056a\u0007N\u0002\u0002\u056a\u056b\u0007V\u0002\u0002', '\u056b\u056c\u0007G\u0002\u0002\u056c\u0574\u0007T\u0002\u0002\u056d', '\u056e\u0007h\u0002\u0002\u056e\u056f\u0007k\u0002\u0002\u056f\u0570', '\u0007n\u0002\u0002\u0570\u0571\u0007v\u0002\u0002\u0571\u0572\u0007', 'g\u0002\u0002\u0572\u0574\u0007t\u0002\u0002\u0573\u0567\u0003\u0002', '\u0002\u0002\u0573\u056d\u0003\u0002\u0002\u0002\u0574\u00ac\u0003\u0002', '\u0002\u0002\u0575\u0576\u0007Q\u0002\u0002\u0576\u0577\u0007X\u0002', '\u0002\u0577\u0578\u0007G\u0002\u0002\u0578\u057e\u0007T\u0002\u0002', '\u0579\u057a\u0007q\u0002\u0002\u057a\u057b\u0007x\u0002\u0002\u057b', '\u057c\u0007g\u0002\u0002\u057c\u057e\u0007t\u0002\u0002\u057d\u0575', '\u0003\u0002\u0002\u0002\u057d\u0579\u0003\u0002\u0002\u0002\u057e\u00ae', '\u0003\u0002\u0002\u0002\u057f\u0580\u0007R\u0002\u0002\u0580\u0581', '\u0007C\u0002\u0002\u0581\u0582\u0007T\u0002\u0002\u0582\u0583\u0007', 'V\u0002\u0002\u0583\u0584\u0007K\u0002\u0002\u0584\u0585\u0007V\u0002', '\u0002\u0585\u0586\u0007K\u0002\u0002\u0586\u0587\u0007Q\u0002\u0002', '\u0587\u0592\u0007P\u0002\u0002\u0588\u0589\u0007r\u0002\u0002\u0589', '\u058a\u0007c\u0002\u0002\u058a\u058b\u0007t\u0002\u0002\u058b\u058c', '\u0007v\u0002\u0002\u058c\u058d\u0007k\u0002\u0002\u058d\u058e\u0007', 'v\u0002\u0002\u058e\u058f\u0007k\u0002\u0002\u058f\u0590\u0007q\u0002', '\u0002\u0590\u0592\u0007p\u0002\u0002\u0591\u057f\u0003\u0002\u0002', '\u0002\u0591\u0588\u0003\u0002\u0002\u0002\u0592\u00b0\u0003\u0002\u0002', '\u0002\u0593\u0594\u0007T\u0002\u0002\u0594\u0595\u0007C\u0002\u0002', '\u0595\u0596\u0007P\u0002\u0002\u0596\u0597\u0007I\u0002\u0002\u0597', '\u059e\u0007G\u0002\u0002\u0598\u0599\u0007t\u0002\u0002\u0599\u059a', '\u0007c\u0002\u0002\u059a\u059b\u0007p\u0002\u0002\u059b\u059c\u0007', 'i\u0002\u0002\u059c\u059e\u0007g\u0002\u0002\u059d\u0593\u0003\u0002', '\u0002\u0002\u059d\u0598\u0003\u0002\u0002\u0002\u059e\u00b2\u0003\u0002', '\u0002\u0002\u059f\u05a0\u0007T\u0002\u0002\u05a0\u05a1\u0007Q\u0002', '\u0002\u05a1\u05a2\u0007Y\u0002\u0002\u05a2\u05a8\u0007U\u0002\u0002', '\u05a3\u05a4\u0007t\u0002\u0002\u05a4\u05a5\u0007q\u0002\u0002\u05a5', '\u05a6\u0007y\u0002\u0002\u05a6\u05a8\u0007u\u0002\u0002\u05a7\u059f', '\u0003\u0002\u0002\u0002\u05a7\u05a3\u0003\u0002\u0002\u0002\u05a8\u00b4', '\u0003\u0002\u0002\u0002\u05a9\u05aa\u0007W\u0002\u0002\u05aa\u05ab', '\u0007P\u0002\u0002\u05ab\u05ac\u0007D\u0002\u0002\u05ac\u05ad\u0007', 'Q\u0002\u0002\u05ad\u05ae\u0007W\u0002\u0002\u05ae\u05af\u0007P\u0002', '\u0002\u05af\u05b0\u0007F\u0002\u0002\u05b0\u05b1\u0007G\u0002\u0002', '\u05b1\u05bc\u0007F\u0002\u0002\u05b2\u05b3\u0007w\u0002\u0002\u05b3', '\u05b4\u0007p\u0002\u0002\u05b4\u05b5\u0007d\u0002\u0002\u05b5\u05b6', '\u0007q\u0002\u0002\u05b6\u05b7\u0007w\u0002\u0002\u05b7\u05b8\u0007', 'p\u0002\u0002\u05b8\u05b9\u0007f\u0002\u0002\u05b9\u05ba\u0007g\u0002', '\u0002\u05ba\u05bc\u0007f\u0002\u0002\u05bb\u05a9\u0003\u0002\u0002', '\u0002\u05bb\u05b2\u0003\u0002\u0002\u0002\u05bc\u00b6\u0003\u0002\u0002', '\u0002\u05bd\u05be\u0007R\u0002\u0002\u05be\u05bf\u0007T\u0002\u0002', '\u05bf\u05c0\u0007G\u0002\u0002\u05c0\u05c1\u0007E\u0002\u0002\u05c1', '\u05c2\u0007G\u0002\u0002\u05c2\u05c3\u0007F\u0002\u0002\u05c3\u05c4', '\u0007K\u0002\u0002\u05c4\u05c5\u0007P\u0002\u0002\u05c5\u05d0\u0007', 'I\u0002\u0002\u05c6\u05c7\u0007r\u0002\u0002\u05c7\u05c8\u0007t\u0002', '\u0002\u05c8\u05c9\u0007g\u0002\u0002\u05c9\u05ca\u0007e\u0002\u0002', '\u05ca\u05cb\u0007g\u0002\u0002\u05cb\u05cc\u0007f\u0002\u0002\u05cc', '\u05cd\u0007k\u0002\u0002\u05cd\u05ce\u0007p\u0002\u0002\u05ce\u05d0', '\u0007i\u0002\u0002\u05cf\u05bd\u0003\u0002\u0002\u0002\u05cf\u05c6', '\u0003\u0002\u0002\u0002\u05d0\u00b8\u0003\u0002\u0002\u0002\u05d1\u05d2', '\u0007H\u0002\u0002\u05d2\u05d3\u0007Q\u0002\u0002\u05d3\u05d4\u0007', 'N\u0002\u0002\u05d4\u05d5\u0007N\u0002\u0002\u05d5\u05d6\u0007Q\u0002', '\u0002\u05d6\u05d7\u0007Y\u0002\u0002\u05d7\u05d8\u0007K\u0002\u0002', '\u05d8\u05d9\u0007P\u0002\u0002\u05d9\u05e4\u0007I\u0002\u0002\u05da', '\u05db\u0007h\u0002\u0002\u05db\u05dc\u0007q\u0002\u0002\u05dc\u05dd', '\u0007n\u0002\u0002\u05dd\u05de\u0007n\u0002\u0002\u05de\u05df\u0007', 'q\u0002\u0002\u05df\u05e0\u0007y\u0002\u0002\u05e0\u05e1\u0007k\u0002', '\u0002\u05e1\u05e2\u0007p\u0002\u0002\u05e2\u05e4\u0007i\u0002\u0002', '\u05e3\u05d1\u0003\u0002\u0002\u0002\u05e3\u05da\u0003\u0002\u0002\u0002', '\u05e4\u00ba\u0003\u0002\u0002\u0002\u05e5\u05e6\u0007E\u0002\u0002', '\u05e6\u05e7\u0007W\u0002\u0002\u05e7\u05e8\u0007T\u0002\u0002\u05e8', '\u05e9\u0007T\u0002\u0002\u05e9\u05ea\u0007G\u0002\u0002\u05ea\u05eb', '\u0007P\u0002\u0002\u05eb\u05f4\u0007V\u0002\u0002\u05ec\u05ed\u0007', 'e\u0002\u0002\u05ed\u05ee\u0007w\u0002\u0002\u05ee\u05ef\u0007t\u0002', '\u0002\u05ef\u05f0\u0007t\u0002\u0002\u05f0\u05f1\u0007g\u0002\u0002', '\u05f1\u05f2\u0007p\u0002\u0002\u05f2\u05f4\u0007v\u0002\u0002\u05f3', '\u05e5\u0003\u0002\u0002\u0002\u05f3\u05ec\u0003\u0002\u0002\u0002\u05f4', '\u00bc\u0003\u0002\u0002\u0002\u05f5\u05f6\u0007T\u0002\u0002\u05f6', '\u05f7\u0007Q\u0002\u0002\u05f7\u05fc\u0007Y\u0002\u0002\u05f8\u05f9', '\u0007t\u0002\u0002\u05f9\u05fa\u0007q\u0002\u0002\u05fa\u05fc\u0007', 'y\u0002\u0002\u05fb\u05f5\u0003\u0002\u0002\u0002\u05fb\u05f8\u0003', '\u0002\u0002\u0002\u05fc\u00be\u0003\u0002\u0002\u0002\u05fd\u05fe\u0007', 'Y\u0002\u0002\u05fe\u05ff\u0007K\u0002\u0002\u05ff\u0600\u0007V\u0002', '\u0002\u0600\u0606\u0007J\u0002\u0002\u0601\u0602\u0007y\u0002\u0002', '\u0602\u0603\u0007k\u0002\u0002\u0603\u0604\u0007v\u0002\u0002\u0604', '\u0606\u0007j\u0002\u0002\u0605\u05fd\u0003\u0002\u0002\u0002\u0605', '\u0601\u0003\u0002\u0002\u0002\u0606\u00c0\u0003\u0002\u0002\u0002\u0607', '\u0608\u0007T\u0002\u0002\u0608\u0609\u0007G\u0002\u0002\u0609\u060a', '\u0007E\u0002\u0002\u060a\u060b\u0007W\u0002\u0002\u060b\u060c\u0007', 'T\u0002\u0002\u060c\u060d\u0007U\u0002\u0002\u060d\u060e\u0007K\u0002', '\u0002\u060e\u060f\u0007X\u0002\u0002\u060f\u061a\u0007G\u0002\u0002', '\u0610\u0611\u0007t\u0002\u0002\u0611\u0612\u0007g\u0002\u0002\u0612', '\u0613\u0007e\u0002\u0002\u0613\u0614\u0007w\u0002\u0002\u0614\u0615', '\u0007t\u0002\u0002\u0615\u0616\u0007u\u0002\u0002\u0616\u0617\u0007', 'k\u0002\u0002\u0617\u0618\u0007x\u0002\u0002\u0618\u061a\u0007g\u0002', '\u0002\u0619\u0607\u0003\u0002\u0002\u0002\u0619\u0610\u0003\u0002\u0002', '\u0002\u061a\u00c2\u0003\u0002\u0002\u0002\u061b\u061c\u0007X\u0002', '\u0002\u061c\u061d\u0007C\u0002\u0002\u061d\u061e\u0007N\u0002\u0002', '\u061e\u061f\u0007W\u0002\u0002\u061f\u0620\u0007G\u0002\u0002\u0620', '\u0628\u0007U\u0002\u0002\u0621\u0622\u0007x\u0002\u0002\u0622\u0623', '\u0007c\u0002\u0002\u0623\u0624\u0007n\u0002\u0002\u0624\u0625\u0007', 'w\u0002\u0002\u0625\u0626\u0007g\u0002\u0002\u0626\u0628\u0007u\u0002', '\u0002\u0627\u061b\u0003\u0002\u0002\u0002\u0627\u0621\u0003\u0002\u0002', '\u0002\u0628\u00c4\u0003\u0002\u0002\u0002\u0629\u062a\u0007E\u0002', '\u0002\u062a\u062b\u0007T\u0002\u0002\u062b\u062c\u0007G\u0002\u0002', '\u062c\u062d\u0007C\u0002\u0002\u062d\u062e\u0007V\u0002\u0002\u062e', '\u0636\u0007G\u0002\u0002\u062f\u0630\u0007e\u0002\u0002\u0630\u0631', '\u0007t\u0002\u0002\u0631\u0632\u0007g\u0002\u0002\u0632\u0633\u0007', 'c\u0002\u0002\u0633\u0634\u0007v\u0002\u0002\u0634\u0636\u0007g\u0002', '\u0002\u0635\u0629\u0003\u0002\u0002\u0002\u0635\u062f\u0003\u0002\u0002', '\u0002\u0636\u00c6\u0003\u0002\u0002\u0002\u0637\u0638\u0007U\u0002', '\u0002\u0638\u0639\u0007E\u0002\u0002\u0639\u063a\u0007J\u0002\u0002', '\u063a\u063b\u0007G\u0002\u0002\u063b\u063c\u0007O\u0002\u0002\u063c', '\u0644\u0007C\u0002\u0002\u063d\u063e\u0007u\u0002\u0002\u063e\u063f', '\u0007e\u0002\u0002\u063f\u0640\u0007j\u0002\u0002\u0640\u0641\u0007', 'g\u0002\u0002\u0641\u0642\u0007o\u0002\u0002\u0642\u0644\u0007c\u0002', '\u0002\u0643\u0637\u0003\u0002\u0002\u0002\u0643\u063d\u0003\u0002\u0002', '\u0002\u0644\u00c8\u0003\u0002\u0002\u0002\u0645\u0646\u0007V\u0002', '\u0002\u0646\u0647\u0007C\u0002\u0002\u0647\u0648\u0007D\u0002\u0002', '\u0648\u0649\u0007N\u0002\u0002\u0649\u0650\u0007G\u0002\u0002\u064a', '\u064b\u0007v\u0002\u0002\u064b\u064c\u0007c\u0002\u0002\u064c\u064d', '\u0007d\u0002\u0002\u064d\u064e\u0007n\u0002\u0002\u064e\u0650\u0007', 'g\u0002\u0002\u064f\u0645\u0003\u0002\u0002\u0002\u064f\u064a\u0003', '\u0002\u0002\u0002\u0650\u00ca\u0003\u0002\u0002\u0002\u0651\u0652\u0007', 'X\u0002\u0002\u0652\u0653\u0007K\u0002\u0002\u0653\u0654\u0007G\u0002', '\u0002\u0654\u065a\u0007Y\u0002\u0002\u0655\u0656\u0007x\u0002\u0002', '\u0656\u0657\u0007k\u0002\u0002\u0657\u0658\u0007g\u0002\u0002\u0658', '\u065a\u0007y\u0002\u0002\u0659\u0651\u0003\u0002\u0002\u0002\u0659', '\u0655\u0003\u0002\u0002\u0002\u065a\u00cc\u0003\u0002\u0002\u0002\u065b', '\u065c\u0007T\u0002\u0002\u065c\u065d\u0007G\u0002\u0002\u065d\u065e', '\u0007R\u0002\u0002\u065e\u065f\u0007N\u0002\u0002\u065f\u0660\u0007', 'C\u0002\u0002\u0660\u0661\u0007E\u0002\u0002\u0661\u066a\u0007G\u0002', '\u0002\u0662\u0663\u0007t\u0002\u0002\u0663\u0664\u0007g\u0002\u0002', '\u0664\u0665\u0007r\u0002\u0002\u0665\u0666\u0007n\u0002\u0002\u0666', '\u0667\u0007c\u0002\u0002\u0667\u0668\u0007e\u0002\u0002\u0668\u066a', '\u0007g\u0002\u0002\u0669\u065b\u0003\u0002\u0002\u0002\u0669\u0662', '\u0003\u0002\u0002\u0002\u066a\u00ce\u0003\u0002\u0002\u0002\u066b\u066c', '\u0007K\u0002\u0002\u066c\u066d\u0007P\u0002\u0002\u066d\u066e\u0007', 'U\u0002\u0002\u066e\u066f\u0007G\u0002\u0002\u066f\u0670\u0007T\u0002', '\u0002\u0670\u0678\u0007V\u0002\u0002\u0671\u0672\u0007k\u0002\u0002', '\u0672\u0673\u0007p\u0002\u0002\u0673\u0674\u0007u\u0002\u0002\u0674', '\u0675\u0007g\u0002\u0002\u0675\u0676\u0007t\u0002\u0002\u0676\u0678', '\u0007v\u0002\u0002\u0677\u066b\u0003\u0002\u0002\u0002\u0677\u0671', '\u0003\u0002\u0002\u0002\u0678\u00d0\u0003\u0002\u0002\u0002\u0679\u067a', '\u0007F\u0002\u0002\u067a\u067b\u0007G\u0002\u0002\u067b\u067c\u0007', 'N\u0002\u0002\u067c\u067d\u0007G\u0002\u0002\u067d\u067e\u0007V\u0002', '\u0002\u067e\u0686\u0007G\u0002\u0002\u067f\u0680\u0007f\u0002\u0002', '\u0680\u0681\u0007g\u0002\u0002\u0681\u0682\u0007n\u0002\u0002\u0682', '\u0683\u0007g\u0002\u0002\u0683\u0684\u0007v\u0002\u0002\u0684\u0686', '\u0007g\u0002\u0002\u0685\u0679\u0003\u0002\u0002\u0002\u0685\u067f', '\u0003\u0002\u0002\u0002\u0686\u00d2\u0003\u0002\u0002\u0002\u0687\u0688', '\u0007K\u0002\u0002\u0688\u0689\u0007P\u0002\u0002\u0689\u068a\u0007', 'V\u0002\u0002\u068a\u0690\u0007Q\u0002\u0002\u068b\u068c\u0007k\u0002', '\u0002\u068c\u068d\u0007p\u0002\u0002\u068d\u068e\u0007v\u0002\u0002', '\u068e\u0690\u0007q\u0002\u0002\u068f\u0687\u0003\u0002\u0002\u0002', '\u068f\u068b\u0003\u0002\u0002\u0002\u0690\u00d4\u0003\u0002\u0002\u0002', '\u0691\u0692\u0007E\u0002\u0002\u0692\u0693\u0007Q\u0002\u0002\u0693', '\u0694\u0007P\u0002\u0002\u0694\u0695\u0007U\u0002\u0002\u0695\u0696', '\u0007V\u0002\u0002\u0696\u0697\u0007T\u0002\u0002\u0697\u0698\u0007', 'C\u0002\u0002\u0698\u0699\u0007K\u0002\u0002\u0699\u069a\u0007P\u0002', '\u0002\u069a\u06a6\u0007V\u0002\u0002\u069b\u069c\u0007e\u0002\u0002', '\u069c\u069d\u0007q\u0002\u0002\u069d\u069e\u0007p\u0002\u0002\u069e', '\u069f\u0007u\u0002\u0002\u069f\u06a0\u0007v\u0002\u0002\u06a0\u06a1', '\u0007t\u0002\u0002\u06a1\u06a2\u0007c\u0002\u0002\u06a2\u06a3\u0007', 'k\u0002\u0002\u06a3\u06a4\u0007p\u0002\u0002\u06a4\u06a6\u0007v\u0002', '\u0002\u06a5\u0691\u0003\u0002\u0002\u0002\u06a5\u069b\u0003\u0002\u0002', '\u0002\u06a6\u00d6\u0003\u0002\u0002\u0002\u06a7\u06a8\u0007F\u0002', '\u0002\u06a8\u06a9\u0007G\u0002\u0002\u06a9\u06aa\u0007U\u0002\u0002', '\u06aa\u06ab\u0007E\u0002\u0002\u06ab\u06ac\u0007T\u0002\u0002\u06ac', '\u06ad\u0007K\u0002\u0002\u06ad\u06ae\u0007D\u0002\u0002\u06ae\u06b8', '\u0007G\u0002\u0002\u06af\u06b0\u0007f\u0002\u0002\u06b0\u06b1\u0007', 'g\u0002\u0002\u06b1\u06b2\u0007u\u0002\u0002\u06b2\u06b3\u0007e\u0002', '\u0002\u06b3\u06b4\u0007t\u0002\u0002\u06b4\u06b5\u0007k\u0002\u0002', '\u06b5\u06b6\u0007d\u0002\u0002\u06b6\u06b8\u0007g\u0002\u0002\u06b7', '\u06a7\u0003\u0002\u0002\u0002\u06b7\u06af\u0003\u0002\u0002\u0002\u06b8', '\u00d8\u0003\u0002\u0002\u0002\u06b9\u06ba\u0007I\u0002\u0002\u06ba', '\u06bb\u0007T\u0002\u0002\u06bb\u06bc\u0007C\u0002\u0002\u06bc\u06bd', '\u0007P\u0002\u0002\u06bd\u06c4\u0007V\u0002\u0002\u06be\u06bf\u0007', 'i\u0002\u0002\u06bf\u06c0\u0007t\u0002\u0002\u06c0\u06c1\u0007c\u0002', '\u0002\u06c1\u06c2\u0007p\u0002\u0002\u06c2\u06c4\u0007v\u0002\u0002', '\u06c3\u06b9\u0003\u0002\u0002\u0002\u06c3\u06be\u0003\u0002\u0002\u0002', '\u06c4\u00da\u0003\u0002\u0002\u0002\u06c5\u06c6\u0007T\u0002\u0002', '\u06c6\u06c7\u0007G\u0002\u0002\u06c7\u06c8\u0007X\u0002\u0002\u06c8', '\u06c9\u0007Q\u0002\u0002\u06c9\u06ca\u0007M\u0002\u0002\u06ca\u06d2', '\u0007G\u0002\u0002\u06cb\u06cc\u0007t\u0002\u0002\u06cc\u06cd\u0007', 'g\u0002\u0002\u06cd\u06ce\u0007x\u0002\u0002\u06ce\u06cf\u0007q\u0002', '\u0002\u06cf\u06d0\u0007m\u0002\u0002\u06d0\u06d2\u0007g\u0002\u0002', '\u06d1\u06c5\u0003\u0002\u0002\u0002\u06d1\u06cb\u0003\u0002\u0002\u0002', '\u06d2\u00dc\u0003\u0002\u0002\u0002\u06d3\u06d4\u0007R\u0002\u0002', '\u06d4\u06d5\u0007T\u0002\u0002\u06d5\u06d6\u0007K\u0002\u0002\u06d6', '\u06d7\u0007X\u0002\u0002\u06d7\u06d8\u0007K\u0002\u0002\u06d8\u06d9', '\u0007N\u0002\u0002\u06d9\u06da\u0007G\u0002\u0002\u06da\u06db\u0007', 'I\u0002\u0002\u06db\u06dc\u0007G\u0002\u0002\u06dc\u06e8\u0007U\u0002', '\u0002\u06dd\u06de\u0007r\u0002\u0002\u06de\u06df\u0007t\u0002\u0002', '\u06df\u06e0\u0007k\u0002\u0002\u06e0\u06e1\u0007x\u0002\u0002\u06e1', '\u06e2\u0007k\u0002\u0002\u06e2\u06e3\u0007n\u0002\u0002\u06e3\u06e4', '\u0007g\u0002\u0002\u06e4\u06e5\u0007i\u0002\u0002\u06e5\u06e6\u0007', 'g\u0002\u0002\u06e6\u06e8\u0007u\u0002\u0002\u06e7\u06d3\u0003\u0002', '\u0002\u0002\u06e7\u06dd\u0003\u0002\u0002\u0002\u06e8\u00de\u0003\u0002', '\u0002\u0002\u06e9\u06ea\u0007R\u0002\u0002\u06ea\u06eb\u0007W\u0002', '\u0002\u06eb\u06ec\u0007D\u0002\u0002\u06ec\u06ed\u0007N\u0002\u0002', '\u06ed\u06ee\u0007K\u0002\u0002\u06ee\u06f6\u0007E\u0002\u0002\u06ef', '\u06f0\u0007r\u0002\u0002\u06f0\u06f1\u0007w\u0002\u0002\u06f1\u06f2', '\u0007d\u0002\u0002\u06f2\u06f3\u0007n\u0002\u0002\u06f3\u06f4\u0007', 'k\u0002\u0002\u06f4\u06f6\u0007e\u0002\u0002\u06f5\u06e9\u0003\u0002', '\u0002\u0002\u06f5\u06ef\u0003\u0002\u0002\u0002\u06f6\u00e0\u0003\u0002', '\u0002\u0002\u06f7\u06f8\u0007Q\u0002\u0002\u06f8\u06f9\u0007R\u0002', '\u0002\u06f9\u06fa\u0007V\u0002\u0002\u06fa\u06fb\u0007K\u0002\u0002', '\u06fb\u06fc\u0007Q\u0002\u0002\u06fc\u0704\u0007P\u0002\u0002\u06fd', '\u06fe\u0007q\u0002\u0002\u06fe\u06ff\u0007r\u0002\u0002\u06ff\u0700', '\u0007v\u0002\u0002\u0700\u0701\u0007k\u0002\u0002\u0701\u0702\u0007', 'q\u0002\u0002\u0702\u0704\u0007p\u0002\u0002\u0703\u06f7\u0003\u0002', '\u0002\u0002\u0703\u06fd\u0003\u0002\u0002\u0002\u0704\u00e2\u0003\u0002', '\u0002\u0002\u0705\u0706\u0007G\u0002\u0002\u0706\u0707\u0007Z\u0002', '\u0002\u0707\u0708\u0007R\u0002\u0002\u0708\u0709\u0007N\u0002\u0002', '\u0709\u070a\u0007C\u0002\u0002\u070a\u070b\u0007K\u0002\u0002\u070b', '\u0714\u0007P\u0002\u0002\u070c\u070d\u0007g\u0002\u0002\u070d\u070e', '\u0007z\u0002\u0002\u070e\u070f\u0007r\u0002\u0002\u070f\u0710\u0007', 'n\u0002\u0002\u0710\u0711\u0007c\u0002\u0002\u0711\u0712\u0007k\u0002', '\u0002\u0712\u0714\u0007p\u0002\u0002\u0713\u0705\u0003\u0002\u0002', '\u0002\u0713\u070c\u0003\u0002\u0002\u0002\u0714\u00e4\u0003\u0002\u0002', '\u0002\u0715\u0716\u0007C\u0002\u0002\u0716\u0717\u0007P\u0002\u0002', '\u0717\u0718\u0007C\u0002\u0002\u0718\u0719\u0007N\u0002\u0002\u0719', '\u071a\u0007[\u0002\u0002\u071a\u071b\u0007\\\u0002\u0002\u071b\u0724', '\u0007G\u0002\u0002\u071c\u071d\u0007c\u0002\u0002\u071d\u071e\u0007', 'p\u0002\u0002\u071e\u071f\u0007c\u0002\u0002\u071f\u0720\u0007n\u0002', '\u0002\u0720\u0721\u0007{\u0002\u0002\u0721\u0722\u0007|\u0002\u0002', '\u0722\u0724\u0007g\u0002\u0002\u0723\u0715\u0003\u0002\u0002\u0002', '\u0723\u071c\u0003\u0002\u0002\u0002\u0724\u00e6\u0003\u0002\u0002\u0002', '\u0725\u0726\u0007H\u0002\u0002\u0726\u0727\u0007Q\u0002\u0002\u0727', '\u0728\u0007T\u0002\u0002\u0728\u0729\u0007O\u0002\u0002\u0729\u072a', '\u0007C\u0002\u0002\u072a\u0732\u0007V\u0002\u0002\u072b\u072c\u0007', 'h\u0002\u0002\u072c\u072d\u0007q\u0002\u0002\u072d\u072e\u0007t\u0002', '\u0002\u072e\u072f\u0007o\u0002\u0002\u072f\u0730\u0007c\u0002\u0002', '\u0730\u0732\u0007v\u0002\u0002\u0731\u0725\u0003\u0002\u0002\u0002', '\u0731\u072b\u0003\u0002\u0002\u0002\u0732\u00e8\u0003\u0002\u0002\u0002', '\u0733\u0734\u0007V\u0002\u0002\u0734\u0735\u0007[\u0002\u0002\u0735', '\u0736\u0007R\u0002\u0002\u0736\u073c\u0007G\u0002\u0002\u0737\u0738', '\u0007v\u0002\u0002\u0738\u0739\u0007{\u0002\u0002\u0739\u073a\u0007', 'r\u0002\u0002\u073a\u073c\u0007g\u0002\u0002\u073b\u0733\u0003\u0002', '\u0002\u0002\u073b\u0737\u0003\u0002\u0002\u0002\u073c\u00ea\u0003\u0002', '\u0002\u0002\u073d\u073e\u0007V\u0002\u0002\u073e\u073f\u0007G\u0002', '\u0002\u073f\u0740\u0007Z\u0002\u0002\u0740\u0746\u0007V\u0002\u0002', '\u0741\u0742\u0007v\u0002\u0002\u0742\u0743\u0007g\u0002\u0002\u0743', '\u0744\u0007z\u0002\u0002\u0744\u0746\u0007v\u0002\u0002\u0745\u073d', '\u0003\u0002\u0002\u0002\u0745\u0741\u0003\u0002\u0002\u0002\u0746\u00ec', '\u0003\u0002\u0002\u0002\u0747\u0748\u0007I\u0002\u0002\u0748\u0749', '\u0007T\u0002\u0002\u0749\u074a\u0007C\u0002\u0002\u074a\u074b\u0007', 'R\u0002\u0002\u074b\u074c\u0007J\u0002\u0002\u074c\u074d\u0007X\u0002', '\u0002\u074d\u074e\u0007K\u0002\u0002\u074e\u0758\u0007\\\u0002\u0002', '\u074f\u0750\u0007i\u0002\u0002\u0750\u0751\u0007t\u0002\u0002\u0751', '\u0752\u0007c\u0002\u0002\u0752\u0753\u0007r\u0002\u0002\u0753\u0754', '\u0007j\u0002\u0002\u0754\u0755\u0007x\u0002\u0002\u0755\u0756\u0007', 'k\u0002\u0002\u0756\u0758\u0007|\u0002\u0002\u0757\u0747\u0003\u0002', '\u0002\u0002\u0757\u074f\u0003\u0002\u0002\u0002\u0758\u00ee\u0003\u0002', '\u0002\u0002\u0759\u075a\u0007N\u0002\u0002\u075a\u075b\u0007Q\u0002', '\u0002\u075b\u075c\u0007I\u0002\u0002\u075c\u075d\u0007K\u0002\u0002', '\u075d\u075e\u0007E\u0002\u0002\u075e\u075f\u0007C\u0002\u0002\u075f', '\u0768\u0007N\u0002\u0002\u0760\u0761\u0007n\u0002\u0002\u0761\u0762', '\u0007q\u0002\u0002\u0762\u0763\u0007i\u0002\u0002\u0763\u0764\u0007', 'k\u0002\u0002\u0764\u0765\u0007e\u0002\u0002\u0765\u0766\u0007c\u0002', '\u0002\u0766\u0768\u0007n\u0002\u0002\u0767\u0759\u0003\u0002\u0002', '\u0002\u0767\u0760\u0003\u0002\u0002\u0002\u0768\u00f0\u0003\u0002\u0002', '\u0002\u0769\u076a\u0007F\u0002\u0002\u076a\u076b\u0007K\u0002\u0002', '\u076b\u076c\u0007U\u0002\u0002\u076c\u076d\u0007V\u0002\u0002\u076d', '\u076e\u0007T\u0002\u0002\u076e\u076f\u0007K\u0002\u0002\u076f\u0770', '\u0007D\u0002\u0002\u0770\u0771\u0007W\u0002\u0002\u0771\u0772\u0007', 'V\u0002\u0002\u0772\u0773\u0007G\u0002\u0002\u0773\u0780\u0007F\u0002', '\u0002\u0774\u0775\u0007f\u0002\u0002\u0775\u0776\u0007k\u0002\u0002', '\u0776\u0777\u0007u\u0002\u0002\u0777\u0778\u0007v\u0002\u0002\u0778', '\u0779\u0007t\u0002\u0002\u0779\u077a\u0007k\u0002\u0002\u077a\u077b', '\u0007d\u0002\u0002\u077b\u077c\u0007w\u0002\u0002\u077c\u077d\u0007', 'v\u0002\u0002\u077d\u077e\u0007g\u0002\u0002\u077e\u0780\u0007f\u0002', '\u0002\u077f\u0769\u0003\u0002\u0002\u0002\u077f\u0774\u0003\u0002\u0002', '\u0002\u0780\u00f2\u0003\u0002\u0002\u0002\u0781\u0782\u0007E\u0002', '\u0002\u0782\u0783\u0007C\u0002\u0002\u0783\u0784\u0007U\u0002\u0002', '\u0784\u078a\u0007V\u0002\u0002\u0785\u0786\u0007e\u0002\u0002\u0786', '\u0787\u0007c\u0002\u0002\u0787\u0788\u0007u\u0002\u0002\u0788\u078a', '\u0007v\u0002\u0002\u0789\u0781\u0003\u0002\u0002\u0002\u0789\u0785', '\u0003\u0002\u0002\u0002\u078a\u00f4\u0003\u0002\u0002\u0002\u078b\u078c', '\u0007V\u0002\u0002\u078c\u078d\u0007T\u0002\u0002\u078d\u078e\u0007', '[\u0002\u0002\u078e\u078f\u0007a\u0002\u0002\u078f\u0790\u0007E\u0002', '\u0002\u0790\u0791\u0007C\u0002\u0002\u0791\u0792\u0007U\u0002\u0002', '\u0792\u079c\u0007V\u0002\u0002\u0793\u0794\u0007v\u0002\u0002\u0794', '\u0795\u0007t\u0002\u0002\u0795\u0796\u0007{\u0002\u0002\u0796\u0797', '\u0007a\u0002\u0002\u0797\u0798\u0007e\u0002\u0002\u0798\u0799\u0007', 'c\u0002\u0002\u0799\u079a\u0007u\u0002\u0002\u079a\u079c\u0007v\u0002', '\u0002\u079b\u078b\u0003\u0002\u0002\u0002\u079b\u0793\u0003\u0002\u0002', '\u0002\u079c\u00f6\u0003\u0002\u0002\u0002\u079d\u079e\u0007U\u0002', '\u0002\u079e\u079f\u0007J\u0002\u0002\u079f\u07a0\u0007Q\u0002\u0002', '\u07a0\u07a6\u0007Y\u0002\u0002\u07a1\u07a2\u0007u\u0002\u0002\u07a2', '\u07a3\u0007j\u0002\u0002\u07a3\u07a4\u0007q\u0002\u0002\u07a4\u07a6', '\u0007y\u0002\u0002\u07a5\u079d\u0003\u0002\u0002\u0002\u07a5\u07a1', '\u0003\u0002\u0002\u0002\u07a6\u00f8\u0003\u0002\u0002\u0002\u07a7\u07a8', '\u0007V\u0002\u0002\u07a8\u07a9\u0007C\u0002\u0002\u07a9\u07aa\u0007', 'D\u0002\u0002\u07aa\u07ab\u0007N\u0002\u0002\u07ab\u07ac\u0007G\u0002', '\u0002\u07ac\u07b4\u0007U\u0002\u0002\u07ad\u07ae\u0007v\u0002\u0002', '\u07ae\u07af\u0007c\u0002\u0002\u07af\u07b0\u0007d\u0002\u0002\u07b0', '\u07b1\u0007n\u0002\u0002\u07b1\u07b2\u0007g\u0002\u0002\u07b2\u07b4', '\u0007u\u0002\u0002\u07b3\u07a7\u0003\u0002\u0002\u0002\u07b3\u07ad', '\u0003\u0002\u0002\u0002\u07b4\u00fa\u0003\u0002\u0002\u0002\u07b5\u07b6', '\u0007U\u0002\u0002\u07b6\u07b7\u0007E\u0002\u0002\u07b7\u07b8\u0007', 'J\u0002\u0002\u07b8\u07b9\u0007G\u0002\u0002\u07b9\u07ba\u0007O\u0002', '\u0002\u07ba\u07bb\u0007C\u0002\u0002\u07bb\u07c4\u0007U\u0002\u0002', '\u07bc\u07bd\u0007u\u0002\u0002\u07bd\u07be\u0007e\u0002\u0002\u07be', '\u07bf\u0007j\u0002\u0002\u07bf\u07c0\u0007g\u0002\u0002\u07c0\u07c1', '\u0007o\u0002\u0002\u07c1\u07c2\u0007c\u0002\u0002\u07c2\u07c4\u0007', 'u\u0002\u0002\u07c3\u07b5\u0003\u0002\u0002\u0002\u07c3\u07bc\u0003', '\u0002\u0002\u0002\u07c4\u00fc\u0003\u0002\u0002\u0002\u07c5\u07c6\u0007', 'E\u0002\u0002\u07c6\u07c7\u0007C\u0002\u0002\u07c7\u07c8\u0007V\u0002', '\u0002\u07c8\u07c9\u0007C\u0002\u0002\u07c9\u07ca\u0007N\u0002\u0002', '\u07ca\u07cb\u0007Q\u0002\u0002\u07cb\u07cc\u0007I\u0002\u0002\u07cc', '\u07d6\u0007U\u0002\u0002\u07cd\u07ce\u0007e\u0002\u0002\u07ce\u07cf', '\u0007c\u0002\u0002\u07cf\u07d0\u0007v\u0002\u0002\u07d0\u07d1\u0007', 'c\u0002\u0002\u07d1\u07d2\u0007n\u0002\u0002\u07d2\u07d3\u0007q\u0002', '\u0002\u07d3\u07d4\u0007i\u0002\u0002\u07d4\u07d6\u0007u\u0002\u0002', '\u07d5\u07c5\u0003\u0002\u0002\u0002\u07d5\u07cd\u0003\u0002\u0002\u0002', '\u07d6\u00fe\u0003\u0002\u0002\u0002\u07d7\u07d8\u0007E\u0002\u0002', '\u07d8\u07d9\u0007Q\u0002\u0002\u07d9\u07da\u0007N\u0002\u0002\u07da', '\u07db\u0007W\u0002\u0002\u07db\u07dc\u0007O\u0002\u0002\u07dc\u07dd', '\u0007P\u0002\u0002\u07dd\u07e6\u0007U\u0002\u0002\u07de\u07df\u0007', 'e\u0002\u0002\u07df\u07e0\u0007q\u0002\u0002\u07e0\u07e1\u0007n\u0002', '\u0002\u07e1\u07e2\u0007w\u0002\u0002\u07e2\u07e3\u0007o\u0002\u0002', '\u07e3\u07e4\u0007p\u0002\u0002\u07e4\u07e6\u0007u\u0002\u0002\u07e5', '\u07d7\u0003\u0002\u0002\u0002\u07e5\u07de\u0003\u0002\u0002\u0002\u07e6', '\u0100\u0003\u0002\u0002\u0002\u07e7\u07e8\u0007E\u0002\u0002\u07e8', '\u07e9\u0007Q\u0002\u0002\u07e9\u07ea\u0007N\u0002\u0002\u07ea\u07eb', '\u0007W\u0002\u0002\u07eb\u07ec\u0007O\u0002\u0002\u07ec\u07f4\u0007', 'P\u0002\u0002\u07ed\u07ee\u0007e\u0002\u0002\u07ee\u07ef\u0007q\u0002', '\u0002\u07ef\u07f0\u0007n\u0002\u0002\u07f0\u07f1\u0007w\u0002\u0002', '\u07f1\u07f2\u0007o\u0002\u0002\u07f2\u07f4\u0007p\u0002\u0002\u07f3', '\u07e7\u0003\u0002\u0002\u0002\u07f3\u07ed\u0003\u0002\u0002\u0002\u07f4', '\u0102\u0003\u0002\u0002\u0002\u07f5\u07f6\u0007W\u0002\u0002\u07f6', '\u07f7\u0007U\u0002\u0002\u07f7\u07fc\u0007G\u0002\u0002\u07f8\u07f9', '\u0007w\u0002\u0002\u07f9\u07fa\u0007u\u0002\u0002\u07fa\u07fc\u0007', 'g\u0002\u0002\u07fb\u07f5\u0003\u0002\u0002\u0002\u07fb\u07f8\u0003', '\u0002\u0002\u0002\u07fc\u0104\u0003\u0002\u0002\u0002\u07fd\u07fe\u0007', 'R\u0002\u0002\u07fe\u07ff\u0007C\u0002\u0002\u07ff\u0800\u0007T\u0002', '\u0002\u0800\u0801\u0007V\u0002\u0002\u0801\u0802\u0007K\u0002\u0002', '\u0802\u0803\u0007V\u0002\u0002\u0803\u0804\u0007K\u0002\u0002\u0804', '\u0805\u0007Q\u0002\u0002\u0805\u0806\u0007P\u0002\u0002\u0806\u0812', '\u0007U\u0002\u0002\u0807\u0808\u0007r\u0002\u0002\u0808\u0809\u0007', 'c\u0002\u0002\u0809\u080a\u0007t\u0002\u0002\u080a\u080b\u0007v\u0002', '\u0002\u080b\u080c\u0007k\u0002\u0002\u080c\u080d\u0007v\u0002\u0002', '\u080d\u080e\u0007k\u0002\u0002\u080e\u080f\u0007q\u0002\u0002\u080f', '\u0810\u0007p\u0002\u0002\u0810\u0812\u0007u\u0002\u0002\u0811\u07fd', '\u0003\u0002\u0002\u0002\u0811\u0807\u0003\u0002\u0002\u0002\u0812\u0106', '\u0003\u0002\u0002\u0002\u0813\u0814\u0007H\u0002\u0002\u0814\u0815', '\u0007W\u0002\u0002\u0815\u0816\u0007P\u0002\u0002\u0816\u0817\u0007', 'E\u0002\u0002\u0817\u0818\u0007V\u0002\u0002\u0818\u0819\u0007K\u0002', '\u0002\u0819\u081a\u0007Q\u0002\u0002\u081a\u081b\u0007P\u0002\u0002', '\u081b\u0826\u0007U\u0002\u0002\u081c\u081d\u0007h\u0002\u0002\u081d', '\u081e\u0007w\u0002\u0002\u081e\u081f\u0007p\u0002\u0002\u081f\u0820', '\u0007e\u0002\u0002\u0820\u0821\u0007v\u0002\u0002\u0821\u0822\u0007', 'k\u0002\u0002\u0822\u0823\u0007q\u0002\u0002\u0823\u0824\u0007p\u0002', '\u0002\u0824\u0826\u0007u\u0002\u0002\u0825\u0813\u0003\u0002\u0002', '\u0002\u0825\u081c\u0003\u0002\u0002\u0002\u0826\u0108\u0003\u0002\u0002', '\u0002\u0827\u0828\u0007F\u0002\u0002\u0828\u0829\u0007T\u0002\u0002', '\u0829\u082a\u0007Q\u0002\u0002\u082a\u0830\u0007R\u0002\u0002\u082b', '\u082c\u0007f\u0002\u0002\u082c\u082d\u0007t\u0002\u0002\u082d\u082e', '\u0007q\u0002\u0002\u082e\u0830\u0007r\u0002\u0002\u082f\u0827\u0003', '\u0002\u0002\u0002\u082f\u082b\u0003\u0002\u0002\u0002\u0830\u010a\u0003', '\u0002\u0002\u0002\u0831\u0832\u0007W\u0002\u0002\u0832\u0833\u0007', 'P\u0002\u0002\u0833\u0834\u0007K\u0002\u0002\u0834\u0835\u0007Q\u0002', '\u0002\u0835\u083c\u0007P\u0002\u0002\u0836\u0837\u0007w\u0002\u0002', '\u0837\u0838\u0007p\u0002\u0002\u0838\u0839\u0007k\u0002\u0002\u0839', '\u083a\u0007q\u0002\u0002\u083a\u083c\u0007p\u0002\u0002\u083b\u0831', '\u0003\u0002\u0002\u0002\u083b\u0836\u0003\u0002\u0002\u0002\u083c\u010c', '\u0003\u0002\u0002\u0002\u083d\u083e\u0007G\u0002\u0002\u083e\u083f', '\u0007Z\u0002\u0002\u083f\u0840\u0007E\u0002\u0002\u0840\u0841\u0007', 'G\u0002\u0002\u0841\u0842\u0007R\u0002\u0002\u0842\u084a\u0007V\u0002', '\u0002\u0843\u0844\u0007g\u0002\u0002\u0844\u0845\u0007z\u0002\u0002', '\u0845\u0846\u0007e\u0002\u0002\u0846\u0847\u0007g\u0002\u0002\u0847', '\u0848\u0007r\u0002\u0002\u0848\u084a\u0007v\u0002\u0002\u0849\u083d', '\u0003\u0002\u0002\u0002\u0849\u0843\u0003\u0002\u0002\u0002\u084a\u010e', '\u0003\u0002\u0002\u0002\u084b\u084c\u0007K\u0002\u0002\u084c\u084d', '\u0007P\u0002\u0002\u084d\u084e\u0007V\u0002\u0002\u084e\u084f\u0007', 'G\u0002\u0002\u084f\u0850\u0007T\u0002\u0002\u0850\u0851\u0007U\u0002', '\u0002\u0851\u0852\u0007G\u0002\u0002\u0852\u0853\u0007E\u0002\u0002', '\u0853\u085e\u0007V\u0002\u0002\u0854\u0855\u0007k\u0002\u0002\u0855', '\u0856\u0007p\u0002\u0002\u0856\u0857\u0007v\u0002\u0002\u0857\u0858', '\u0007g\u0002\u0002\u0858\u0859\u0007t\u0002\u0002\u0859\u085a\u0007', 'u\u0002\u0002\u085a\u085b\u0007g\u0002\u0002\u085b\u085c\u0007e\u0002', '\u0002\u085c\u085e\u0007v\u0002\u0002\u085d\u084b\u0003\u0002\u0002', '\u0002\u085d\u0854\u0003\u0002\u0002\u0002\u085e\u0110\u0003\u0002\u0002', '\u0002\u085f\u0860\u0007V\u0002\u0002\u0860\u0864\u0007Q\u0002\u0002', '\u0861\u0862\u0007v\u0002\u0002\u0862\u0864\u0007q\u0002\u0002\u0863', '\u085f\u0003\u0002\u0002\u0002\u0863\u0861\u0003\u0002\u0002\u0002\u0864', '\u0112\u0003\u0002\u0002\u0002\u0865\u0866\u0007U\u0002\u0002\u0866', '\u0867\u0007[\u0002\u0002\u0867\u0868\u0007U\u0002\u0002\u0868\u0869', '\u0007V\u0002\u0002\u0869\u086a\u0007G\u0002\u0002\u086a\u0872\u0007', 'O\u0002\u0002\u086b\u086c\u0007u\u0002\u0002\u086c\u086d\u0007{\u0002', '\u0002\u086d\u086e\u0007u\u0002\u0002\u086e\u086f\u0007v\u0002\u0002', '\u086f\u0870\u0007g\u0002\u0002\u0870\u0872\u0007o\u0002\u0002\u0871', '\u0865\u0003\u0002\u0002\u0002\u0871\u086b\u0003\u0002\u0002\u0002\u0872', '\u0114\u0003\u0002\u0002\u0002\u0873\u0874\u0007D\u0002\u0002\u0874', '\u0875\u0007G\u0002\u0002\u0875\u0876\u0007T\u0002\u0002\u0876\u0877', '\u0007P\u0002\u0002\u0877\u0878\u0007Q\u0002\u0002\u0878\u0879\u0007', 'W\u0002\u0002\u0879\u087a\u0007N\u0002\u0002\u087a\u087b\u0007N\u0002', '\u0002\u087b\u0886\u0007K\u0002\u0002\u087c\u087d\u0007d\u0002\u0002', '\u087d\u087e\u0007g\u0002\u0002\u087e\u087f\u0007t\u0002\u0002\u087f', '\u0880\u0007p\u0002\u0002\u0880\u0881\u0007q\u0002\u0002\u0881\u0882', '\u0007w\u0002\u0002\u0882\u0883\u0007n\u0002\u0002\u0883\u0884\u0007', 'n\u0002\u0002\u0884\u0886\u0007k\u0002\u0002\u0885\u0873\u0003\u0002', '\u0002\u0002\u0885\u087c\u0003\u0002\u0002\u0002\u0886\u0116\u0003\u0002', '\u0002\u0002\u0887\u0888\u0007R\u0002\u0002\u0888\u0889\u0007Q\u0002', '\u0002\u0889\u088a\u0007K\u0002\u0002\u088a\u088b\u0007U\u0002\u0002', '\u088b\u088c\u0007U\u0002\u0002\u088c\u088d\u0007Q\u0002\u0002\u088d', '\u088e\u0007P\u0002\u0002\u088e\u088f\u0007K\u0002\u0002\u088f\u0890', '\u0007\\\u0002\u0002\u0890\u0891\u0007G\u0002\u0002\u0891\u089e\u0007', 'F\u0002\u0002\u0892\u0893\u0007r\u0002\u0002\u0893\u0894\u0007q\u0002', '\u0002\u0894\u0895\u0007k\u0002\u0002\u0895\u0896\u0007u\u0002\u0002', '\u0896\u0897\u0007u\u0002\u0002\u0897\u0898\u0007q\u0002\u0002\u0898', '\u0899\u0007p\u0002\u0002\u0899\u089a\u0007k\u0002\u0002\u089a\u089b', '\u0007|\u0002\u0002\u089b\u089c\u0007g\u0002\u0002\u089c\u089e\u0007', 'f\u0002\u0002\u089d\u0887\u0003\u0002\u0002\u0002\u089d\u0892\u0003', '\u0002\u0002\u0002\u089e\u0118\u0003\u0002\u0002\u0002\u089f\u08a0\u0007', 'V\u0002\u0002\u08a0\u08a1\u0007C\u0002\u0002\u08a1\u08a2\u0007D\u0002', '\u0002\u08a2\u08a3\u0007N\u0002\u0002\u08a3\u08a4\u0007G\u0002\u0002', '\u08a4\u08a5\u0007U\u0002\u0002\u08a5\u08a6\u0007C\u0002\u0002\u08a6', '\u08a7\u0007O\u0002\u0002\u08a7\u08a8\u0007R\u0002\u0002\u08a8\u08a9', '\u0007N\u0002\u0002\u08a9\u08b6\u0007G\u0002\u0002\u08aa\u08ab\u0007', 'v\u0002\u0002\u08ab\u08ac\u0007c\u0002\u0002\u08ac\u08ad\u0007d\u0002', '\u0002\u08ad\u08ae\u0007n\u0002\u0002\u08ae\u08af\u0007g\u0002\u0002', '\u08af\u08b0\u0007u\u0002\u0002\u08b0\u08b1\u0007c\u0002\u0002\u08b1', '\u08b2\u0007o\u0002\u0002\u08b2\u08b3\u0007r\u0002\u0002\u08b3\u08b4', '\u0007n\u0002\u0002\u08b4\u08b6\u0007g\u0002\u0002\u08b5\u089f\u0003', '\u0002\u0002\u0002\u08b5\u08aa\u0003\u0002\u0002\u0002\u08b6\u011a\u0003', '\u0002\u0002\u0002\u08b7\u08b8\u0007C\u0002\u0002\u08b8\u08b9\u0007', 'N\u0002\u0002\u08b9\u08ba\u0007V\u0002\u0002\u08ba\u08bb\u0007G\u0002', '\u0002\u08bb\u08c2\u0007T\u0002\u0002\u08bc\u08bd\u0007c\u0002\u0002', '\u08bd\u08be\u0007n\u0002\u0002\u08be\u08bf\u0007v\u0002\u0002\u08bf', '\u08c0\u0007g\u0002\u0002\u08c0\u08c2\u0007t\u0002\u0002\u08c1\u08b7', '\u0003\u0002\u0002\u0002\u08c1\u08bc\u0003\u0002\u0002\u0002\u08c2\u011c', '\u0003\u0002\u0002\u0002\u08c3\u08c4\u0007T\u0002\u0002\u08c4\u08c5', '\u0007G\u0002\u0002\u08c5\u08c6\u0007P\u0002\u0002\u08c6\u08c7\u0007', 'C\u0002\u0002\u08c7\u08c8\u0007O\u0002\u0002\u08c8\u08d0\u0007G\u0002', '\u0002\u08c9\u08ca\u0007t\u0002\u0002\u08ca\u08cb\u0007g\u0002\u0002', '\u08cb\u08cc\u0007p\u0002\u0002\u08cc\u08cd\u0007c\u0002\u0002\u08cd', '\u08ce\u0007o\u0002\u0002\u08ce\u08d0\u0007g\u0002\u0002\u08cf\u08c3', '\u0003\u0002\u0002\u0002\u08cf\u08c9\u0003\u0002\u0002\u0002\u08d0\u011e', '\u0003\u0002\u0002\u0002\u08d1\u08d2\u0007W\u0002\u0002\u08d2\u08d3', '\u0007P\u0002\u0002\u08d3\u08d4\u0007P\u0002\u0002\u08d4\u08d5\u0007', 'G\u0002\u0002\u08d5\u08d6\u0007U\u0002\u0002\u08d6\u08de\u0007V\u0002', '\u0002\u08d7\u08d8\u0007w\u0002\u0002\u08d8\u08d9\u0007p\u0002\u0002', '\u08d9\u08da\u0007p\u0002\u0002\u08da\u08db\u0007g\u0002\u0002\u08db', '\u08dc\u0007u\u0002\u0002\u08dc\u08de\u0007v\u0002\u0002\u08dd\u08d1', '\u0003\u0002\u0002\u0002\u08dd\u08d7\u0003\u0002\u0002\u0002\u08de\u0120', '\u0003\u0002\u0002\u0002\u08df\u08e0\u0007Q\u0002\u0002\u08e0\u08e1', '\u0007T\u0002\u0002\u08e1\u08e2\u0007F\u0002\u0002\u08e2\u08e3\u0007', 'K\u0002\u0002\u08e3\u08e4\u0007P\u0002\u0002\u08e4\u08e5\u0007C\u0002', '\u0002\u08e5\u08e6\u0007N\u0002\u0002\u08e6\u08e7\u0007K\u0002\u0002', '\u08e7\u08e8\u0007V\u0002\u0002\u08e8\u08f4\u0007[\u0002\u0002\u08e9', '\u08ea\u0007q\u0002\u0002\u08ea\u08eb\u0007t\u0002\u0002\u08eb\u08ec', '\u0007f\u0002\u0002\u08ec\u08ed\u0007k\u0002\u0002\u08ed\u08ee\u0007', 'p\u0002\u0002\u08ee\u08ef\u0007c\u0002\u0002\u08ef\u08f0\u0007n\u0002', '\u0002\u08f0\u08f1\u0007k\u0002\u0002\u08f1\u08f2\u0007v\u0002\u0002', '\u08f2\u08f4\u0007{\u0002\u0002\u08f3\u08df\u0003\u0002\u0002\u0002', '\u08f3\u08e9\u0003\u0002\u0002\u0002\u08f4\u0122\u0003\u0002\u0002\u0002', '\u08f5\u08f6\u0007C\u0002\u0002\u08f6\u08f7\u0007T\u0002\u0002\u08f7', '\u08f8\u0007T\u0002\u0002\u08f8\u08f9\u0007C\u0002\u0002\u08f9\u0900', '\u0007[\u0002\u0002\u08fa\u08fb\u0007c\u0002\u0002\u08fb\u08fc\u0007', 't\u0002\u0002\u08fc\u08fd\u0007t\u0002\u0002\u08fd\u08fe\u0007c\u0002', '\u0002\u08fe\u0900\u0007{\u0002\u0002\u08ff\u08f5\u0003\u0002\u0002', '\u0002\u08ff\u08fa\u0003\u0002\u0002\u0002\u0900\u0124\u0003\u0002\u0002', '\u0002\u0901\u0902\u0007O\u0002\u0002\u0902\u0903\u0007C\u0002\u0002', '\u0903\u0908\u0007R\u0002\u0002\u0904\u0905\u0007o\u0002\u0002\u0905', '\u0906\u0007c\u0002\u0002\u0906\u0908\u0007r\u0002\u0002\u0907\u0901', '\u0003\u0002\u0002\u0002\u0907\u0904\u0003\u0002\u0002\u0002\u0908\u0126', '\u0003\u0002\u0002\u0002\u0909\u090a\u0007U\u0002\u0002\u090a\u090b', '\u0007G\u0002\u0002\u090b\u0910\u0007V\u0002\u0002\u090c\u090d\u0007', 'u\u0002\u0002\u090d\u090e\u0007g\u0002\u0002\u090e\u0910\u0007v\u0002', '\u0002\u090f\u0909\u0003\u0002\u0002\u0002\u090f\u090c\u0003\u0002\u0002', '\u0002\u0910\u0128\u0003\u0002\u0002\u0002\u0911\u0912\u0007T\u0002', '\u0002\u0912\u0913\u0007G\u0002\u0002\u0913\u0914\u0007U\u0002\u0002', '\u0914\u0915\u0007G\u0002\u0002\u0915\u091c\u0007V\u0002\u0002\u0916', '\u0917\u0007t\u0002\u0002\u0917\u0918\u0007g\u0002\u0002\u0918\u0919', '\u0007u\u0002\u0002\u0919\u091a\u0007g\u0002\u0002\u091a\u091c\u0007', 'v\u0002\u0002\u091b\u0911\u0003\u0002\u0002\u0002\u091b\u0916\u0003', '\u0002\u0002\u0002\u091c\u012a\u0003\u0002\u0002\u0002\u091d\u091e\u0007', 'U\u0002\u0002\u091e\u091f\u0007G\u0002\u0002\u091f\u0920\u0007U\u0002', '\u0002\u0920\u0921\u0007U\u0002\u0002\u0921\u0922\u0007K\u0002\u0002', '\u0922\u0923\u0007Q\u0002\u0002\u0923\u092c\u0007P\u0002\u0002\u0924', '\u0925\u0007u\u0002\u0002\u0925\u0926\u0007g\u0002\u0002\u0926\u0927', '\u0007u\u0002\u0002\u0927\u0928\u0007u\u0002\u0002\u0928\u0929\u0007', 'k\u0002\u0002\u0929\u092a\u0007q\u0002\u0002\u092a\u092c\u0007p\u0002', '\u0002\u092b\u091d\u0003\u0002\u0002\u0002\u092b\u0924\u0003\u0002\u0002', '\u0002\u092c\u012c\u0003\u0002\u0002\u0002\u092d\u092e\u0007F\u0002', '\u0002\u092e\u092f\u0007C\u0002\u0002\u092f\u0930\u0007V\u0002\u0002', '\u0930\u0936\u0007C\u0002\u0002\u0931\u0932\u0007f\u0002\u0002\u0932', '\u0933\u0007c\u0002\u0002\u0933\u0934\u0007v\u0002\u0002\u0934\u0936', '\u0007c\u0002\u0002\u0935\u092d\u0003\u0002\u0002\u0002\u0935\u0931', '\u0003\u0002\u0002\u0002\u0936\u012e\u0003\u0002\u0002\u0002\u0937\u0938', '\u0007U\u0002\u0002\u0938\u0939\u0007V\u0002\u0002\u0939\u093a\u0007', 'C\u0002\u0002\u093a\u093b\u0007T\u0002\u0002\u093b\u0942\u0007V\u0002', '\u0002\u093c\u093d\u0007u\u0002\u0002\u093d\u093e\u0007v\u0002\u0002', '\u093e\u093f\u0007c\u0002\u0002\u093f\u0940\u0007t\u0002\u0002\u0940', '\u0942\u0007v\u0002\u0002\u0941\u0937\u0003\u0002\u0002\u0002\u0941', '\u093c\u0003\u0002\u0002\u0002\u0942\u0130\u0003\u0002\u0002\u0002\u0943', '\u0944\u0007V\u0002\u0002\u0944\u0945\u0007T\u0002\u0002\u0945\u0946', '\u0007C\u0002\u0002\u0946\u0947\u0007P\u0002\u0002\u0947\u0948\u0007', 'U\u0002\u0002\u0948\u0949\u0007C\u0002\u0002\u0949\u094a\u0007E\u0002', '\u0002\u094a\u094b\u0007V\u0002\u0002\u094b\u094c\u0007K\u0002\u0002', '\u094c\u094d\u0007Q\u0002\u0002\u094d\u095a\u0007P\u0002\u0002\u094e', '\u094f\u0007v\u0002\u0002\u094f\u0950\u0007t\u0002\u0002\u0950\u0951', '\u0007c\u0002\u0002\u0951\u0952\u0007p\u0002\u0002\u0952\u0953\u0007', 'u\u0002\u0002\u0953\u0954\u0007c\u0002\u0002\u0954\u0955\u0007e\u0002', '\u0002\u0955\u0956\u0007v\u0002\u0002\u0956\u0957\u0007k\u0002\u0002', '\u0957\u0958\u0007q\u0002\u0002\u0958\u095a\u0007p\u0002\u0002\u0959', '\u0943\u0003\u0002\u0002\u0002\u0959\u094e\u0003\u0002\u0002\u0002\u095a', '\u0132\u0003\u0002\u0002\u0002\u095b\u095c\u0007E\u0002\u0002\u095c', '\u095d\u0007Q\u0002\u0002\u095d\u095e\u0007O\u0002\u0002\u095e\u095f', '\u0007O\u0002\u0002\u095f\u0960\u0007K\u0002\u0002\u0960\u0968\u0007', 'V\u0002\u0002\u0961\u0962\u0007e\u0002\u0002\u0962\u0963\u0007q\u0002', '\u0002\u0963\u0964\u0007o\u0002\u0002\u0964\u0965\u0007o\u0002\u0002', '\u0965\u0966\u0007k\u0002\u0002\u0966\u0968\u0007v\u0002\u0002\u0967', '\u095b\u0003\u0002\u0002\u0002\u0967\u0961\u0003\u0002\u0002\u0002\u0968', '\u0134\u0003\u0002\u0002\u0002\u0969\u096a\u0007T\u0002\u0002\u096a', '\u096b\u0007Q\u0002\u0002\u096b\u096c\u0007N\u0002\u0002\u096c\u096d', '\u0007N\u0002\u0002\u096d\u096e\u0007D\u0002\u0002\u096e\u096f\u0007', 'C\u0002\u0002\u096f\u0970\u0007E\u0002\u0002\u0970\u097a\u0007M\u0002', '\u0002\u0971\u0972\u0007t\u0002\u0002\u0972\u0973\u0007q\u0002\u0002', '\u0973\u0974\u0007n\u0002\u0002\u0974\u0975\u0007n\u0002\u0002\u0975', '\u0976\u0007d\u0002\u0002\u0976\u0977\u0007c\u0002\u0002\u0977\u0978', '\u0007e\u0002\u0002\u0978\u097a\u0007m\u0002\u0002\u0979\u0969\u0003', '\u0002\u0002\u0002\u0979\u0971\u0003\u0002\u0002\u0002\u097a\u0136\u0003', '\u0002\u0002\u0002\u097b\u097c\u0007Y\u0002\u0002\u097c\u097d\u0007', 'Q\u0002\u0002\u097d\u097e\u0007T\u0002\u0002\u097e\u0984\u0007M\u0002', '\u0002\u097f\u0980\u0007y\u0002\u0002\u0980\u0981\u0007q\u0002\u0002', '\u0981\u0982\u0007t\u0002\u0002\u0982\u0984\u0007m\u0002\u0002\u0983', '\u097b\u0003\u0002\u0002\u0002\u0983\u097f\u0003\u0002\u0002\u0002\u0984', '\u0138\u0003\u0002\u0002\u0002\u0985\u0986\u0007K\u0002\u0002\u0986', '\u0987\u0007U\u0002\u0002\u0987\u0988\u0007Q\u0002\u0002\u0988\u0989', '\u0007N\u0002\u0002\u0989\u098a\u0007C\u0002\u0002\u098a\u098b\u0007', 'V\u0002\u0002\u098b\u098c\u0007K\u0002\u0002\u098c\u098d\u0007Q\u0002', '\u0002\u098d\u0998\u0007P\u0002\u0002\u098e\u098f\u0007k\u0002\u0002', '\u098f\u0990\u0007u\u0002\u0002\u0990\u0991\u0007q\u0002\u0002\u0991', '\u0992\u0007n\u0002\u0002\u0992\u0993\u0007c\u0002\u0002\u0993\u0994', '\u0007v\u0002\u0002\u0994\u0995\u0007k\u0002\u0002\u0995\u0996\u0007', 'q\u0002\u0002\u0996\u0998\u0007p\u0002\u0002\u0997\u0985\u0003\u0002', '\u0002\u0002\u0997\u098e\u0003\u0002\u0002\u0002\u0998\u013a\u0003\u0002', '\u0002\u0002\u0999\u099a\u0007N\u0002\u0002\u099a\u099b\u0007G\u0002', '\u0002\u099b\u099c\u0007X\u0002\u0002\u099c\u099d\u0007G\u0002\u0002', '\u099d\u09a4\u0007N\u0002\u0002\u099e\u099f\u0007n\u0002\u0002\u099f', '\u09a0\u0007g\u0002\u0002\u09a0\u09a1\u0007x\u0002\u0002\u09a1\u09a2', '\u0007g\u0002\u0002\u09a2\u09a4\u0007n\u0002\u0002\u09a3\u0999\u0003', '\u0002\u0002\u0002\u09a3\u099e\u0003\u0002\u0002\u0002\u09a4\u013c\u0003', '\u0002\u0002\u0002\u09a5\u09a6\u0007U\u0002\u0002\u09a6\u09a7\u0007', 'G\u0002\u0002\u09a7\u09a8\u0007T\u0002\u0002\u09a8\u09a9\u0007K\u0002', '\u0002\u09a9\u09aa\u0007C\u0002\u0002\u09aa\u09ab\u0007N\u0002\u0002', '\u09ab\u09ac\u0007K\u0002\u0002\u09ac\u09ad\u0007\\\u0002\u0002\u09ad', '\u09ae\u0007C\u0002\u0002\u09ae\u09af\u0007D\u0002\u0002\u09af\u09b0', '\u0007N\u0002\u0002\u09b0\u09be\u0007G\u0002\u0002\u09b1\u09b2\u0007', 'u\u0002\u0002\u09b2\u09b3\u0007g\u0002\u0002\u09b3\u09b4\u0007t\u0002', '\u0002\u09b4\u09b5\u0007k\u0002\u0002\u09b5\u09b6\u0007c\u0002\u0002', '\u09b6\u09b7\u0007n\u0002\u0002\u09b7\u09b8\u0007k\u0002\u0002\u09b8', '\u09b9\u0007|\u0002\u0002\u09b9\u09ba\u0007c\u0002\u0002\u09ba\u09bb', '\u0007d\u0002\u0002\u09bb\u09bc\u0007n\u0002\u0002\u09bc\u09be\u0007', 'g\u0002\u0002\u09bd\u09a5\u0003\u0002\u0002\u0002\u09bd\u09b1\u0003', '\u0002\u0002\u0002\u09be\u013e\u0003\u0002\u0002\u0002\u09bf\u09c0\u0007', 'T\u0002\u0002\u09c0\u09c1\u0007G\u0002\u0002\u09c1\u09c2\u0007R\u0002', '\u0002\u09c2\u09c3\u0007G\u0002\u0002\u09c3\u09c4\u0007C\u0002\u0002', '\u09c4\u09c5\u0007V\u0002\u0002\u09c5\u09c6\u0007C\u0002\u0002\u09c6', '\u09c7\u0007D\u0002\u0002\u09c7\u09c8\u0007N\u0002\u0002\u09c8\u09d4', '\u0007G\u0002\u0002\u09c9\u09ca\u0007t\u0002\u0002\u09ca\u09cb\u0007', 'g\u0002\u0002\u09cb\u09cc\u0007r\u0002\u0002\u09cc\u09cd\u0007g\u0002', '\u0002\u09cd\u09ce\u0007c\u0002\u0002\u09ce\u09cf\u0007v\u0002\u0002', '\u09cf\u09d0\u0007c\u0002\u0002\u09d0\u09d1\u0007d\u0002\u0002\u09d1', '\u09d2\u0007n\u0002\u0002\u09d2\u09d4\u0007g\u0002\u0002\u09d3\u09bf', '\u0003\u0002\u0002\u0002\u09d3\u09c9\u0003\u0002\u0002\u0002\u09d4\u0140', '\u0003\u0002\u0002\u0002\u09d5\u09d6\u0007E\u0002\u0002\u09d6\u09d7', '\u0007Q\u0002\u0002\u09d7\u09d8\u0007O\u0002\u0002\u09d8\u09d9\u0007', 'O\u0002\u0002\u09d9\u09da\u0007K\u0002\u0002\u09da\u09db\u0007V\u0002', '\u0002\u09db\u09dc\u0007V\u0002\u0002\u09dc\u09dd\u0007G\u0002\u0002', '\u09dd\u09e8\u0007F\u0002\u0002\u09de\u09df\u0007e\u0002\u0002\u09df', '\u09e0\u0007q\u0002\u0002\u09e0\u09e1\u0007o\u0002\u0002\u09e1\u09e2', '\u0007o\u0002\u0002\u09e2\u09e3\u0007k\u0002\u0002\u09e3\u09e4\u0007', 'v\u0002\u0002\u09e4\u09e5\u0007v\u0002\u0002\u09e5\u09e6\u0007g\u0002', '\u0002\u09e6\u09e8\u0007f\u0002\u0002\u09e7\u09d5\u0003\u0002\u0002', '\u0002\u09e7\u09de\u0003\u0002\u0002\u0002\u09e8\u0142\u0003\u0002\u0002', '\u0002\u09e9\u09ea\u0007W\u0002\u0002\u09ea\u09eb\u0007P\u0002\u0002', '\u09eb\u09ec\u0007E\u0002\u0002\u09ec\u09ed\u0007Q\u0002\u0002\u09ed', '\u09ee\u0007O\u0002\u0002\u09ee\u09ef\u0007O\u0002\u0002\u09ef\u09f0', '\u0007K\u0002\u0002\u09f0\u09f1\u0007V\u0002\u0002\u09f1\u09f2\u0007', 'V\u0002\u0002\u09f2\u09f3\u0007G\u0002\u0002\u09f3\u0a00\u0007F\u0002', '\u0002\u09f4\u09f5\u0007w\u0002\u0002\u09f5\u09f6\u0007p\u0002\u0002', '\u09f6\u09f7\u0007e\u0002\u0002\u09f7\u09f8\u0007q\u0002\u0002\u09f8', '\u09f9\u0007o\u0002\u0002\u09f9\u09fa\u0007o\u0002\u0002\u09fa\u09fb', '\u0007k\u0002\u0002\u09fb\u09fc\u0007v\u0002\u0002\u09fc\u09fd\u0007', 'v\u0002\u0002\u09fd\u09fe\u0007g\u0002\u0002\u09fe\u0a00\u0007f\u0002', '\u0002\u09ff\u09e9\u0003\u0002\u0002\u0002\u09ff\u09f4\u0003\u0002\u0002', '\u0002\u0a00\u0144\u0003\u0002\u0002\u0002\u0a01\u0a02\u0007T\u0002', '\u0002\u0a02\u0a03\u0007G\u0002\u0002\u0a03\u0a04\u0007C\u0002\u0002', '\u0a04\u0a0a\u0007F\u0002\u0002\u0a05\u0a06\u0007t\u0002\u0002\u0a06', '\u0a07\u0007g\u0002\u0002\u0a07\u0a08\u0007c\u0002\u0002\u0a08\u0a0a', '\u0007f\u0002\u0002\u0a09\u0a01\u0003\u0002\u0002\u0002\u0a09\u0a05', '\u0003\u0002\u0002\u0002\u0a0a\u0146\u0003\u0002\u0002\u0002\u0a0b\u0a0c', '\u0007Y\u0002\u0002\u0a0c\u0a0d\u0007T\u0002\u0002\u0a0d\u0a0e\u0007', 'K\u0002\u0002\u0a0e\u0a0f\u0007V\u0002\u0002\u0a0f\u0a16\u0007G\u0002', '\u0002\u0a10\u0a11\u0007y\u0002\u0002\u0a11\u0a12\u0007t\u0002\u0002', '\u0a12\u0a13\u0007k\u0002\u0002\u0a13\u0a14\u0007v\u0002\u0002\u0a14', '\u0a16\u0007g\u0002\u0002\u0a15\u0a0b\u0003\u0002\u0002\u0002\u0a15', '\u0a10\u0003\u0002\u0002\u0002\u0a16\u0148\u0003\u0002\u0002\u0002\u0a17', '\u0a18\u0007Q\u0002\u0002\u0a18\u0a19\u0007P\u0002\u0002\u0a19\u0a1a', '\u0007N\u0002\u0002\u0a1a\u0a20\u0007[\u0002\u0002\u0a1b\u0a1c\u0007', 'q\u0002\u0002\u0a1c\u0a1d\u0007p\u0002\u0002\u0a1d\u0a1e\u0007n\u0002', '\u0002\u0a1e\u0a20\u0007{\u0002\u0002\u0a1f\u0a17\u0003\u0002\u0002', '\u0002\u0a1f\u0a1b\u0003\u0002\u0002\u0002\u0a20\u014a\u0003\u0002\u0002', '\u0002\u0a21\u0a22\u0007E\u0002\u0002\u0a22\u0a23\u0007C\u0002\u0002', '\u0a23\u0a24\u0007N\u0002\u0002\u0a24\u0a2a\u0007N\u0002\u0002\u0a25', '\u0a26\u0007e\u0002\u0002\u0a26\u0a27\u0007c\u0002\u0002\u0a27\u0a28', '\u0007n\u0002\u0002\u0a28\u0a2a\u0007n\u0002\u0002\u0a29\u0a21\u0003', '\u0002\u0002\u0002\u0a29\u0a25\u0003\u0002\u0002\u0002\u0a2a\u014c\u0003', '\u0002\u0002\u0002\u0a2b\u0a2c\u0007R\u0002\u0002\u0a2c\u0a2d\u0007', 'T\u0002\u0002\u0a2d\u0a2e\u0007G\u0002\u0002\u0a2e\u0a2f\u0007R\u0002', '\u0002\u0a2f\u0a30\u0007C\u0002\u0002\u0a30\u0a31\u0007T\u0002\u0002', '\u0a31\u0a3a\u0007G\u0002\u0002\u0a32\u0a33\u0007r\u0002\u0002\u0a33', '\u0a34\u0007t\u0002\u0002\u0a34\u0a35\u0007g\u0002\u0002\u0a35\u0a36', '\u0007r\u0002\u0002\u0a36\u0a37\u0007c\u0002\u0002\u0a37\u0a38\u0007', 't\u0002\u0002\u0a38\u0a3a\u0007g\u0002\u0002\u0a39\u0a2b\u0003\u0002', '\u0002\u0002\u0a39\u0a32\u0003\u0002\u0002\u0002\u0a3a\u014e\u0003\u0002', '\u0002\u0002\u0a3b\u0a3c\u0007F\u0002\u0002\u0a3c\u0a3d\u0007G\u0002', '\u0002\u0a3d\u0a3e\u0007C\u0002\u0002\u0a3e\u0a3f\u0007N\u0002\u0002', '\u0a3f\u0a40\u0007N\u0002\u0002\u0a40\u0a41\u0007Q\u0002\u0002\u0a41', '\u0a42\u0007E\u0002\u0002\u0a42\u0a43\u0007C\u0002\u0002\u0a43\u0a44', '\u0007V\u0002\u0002\u0a44\u0a50\u0007G\u0002\u0002\u0a45\u0a46\u0007', 'f\u0002\u0002\u0a46\u0a47\u0007g\u0002\u0002\u0a47\u0a48\u0007c\u0002', '\u0002\u0a48\u0a49\u0007n\u0002\u0002\u0a49\u0a4a\u0007n\u0002\u0002', '\u0a4a\u0a4b\u0007q\u0002\u0002\u0a4b\u0a4c\u0007e\u0002\u0002\u0a4c', '\u0a4d\u0007c\u0002\u0002\u0a4d\u0a4e\u0007v\u0002\u0002\u0a4e\u0a50', '\u0007g\u0002\u0002\u0a4f\u0a3b\u0003\u0002\u0002\u0002\u0a4f\u0a45', '\u0003\u0002\u0002\u0002\u0a50\u0150\u0003\u0002\u0002\u0002\u0a51\u0a52', '\u0007G\u0002\u0002\u0a52\u0a53\u0007Z\u0002\u0002\u0a53\u0a54\u0007', 'G\u0002\u0002\u0a54\u0a55\u0007E\u0002\u0002\u0a55\u0a56\u0007W\u0002', '\u0002\u0a56\u0a57\u0007V\u0002\u0002\u0a57\u0a60\u0007G\u0002\u0002', '\u0a58\u0a59\u0007g\u0002\u0002\u0a59\u0a5a\u0007z\u0002\u0002\u0a5a', '\u0a5b\u0007g\u0002\u0002\u0a5b\u0a5c\u0007e\u0002\u0002\u0a5c\u0a5d', '\u0007w\u0002\u0002\u0a5d\u0a5e\u0007v\u0002\u0002\u0a5e\u0a60\u0007', 'g\u0002\u0002\u0a5f\u0a51\u0003\u0002\u0002\u0002\u0a5f\u0a58\u0003', '\u0002\u0002\u0002\u0a60\u0152\u0003\u0002\u0002\u0002\u0a61\u0a62\u0007', 'K\u0002\u0002\u0a62\u0a63\u0007P\u0002\u0002\u0a63\u0a64\u0007R\u0002', '\u0002\u0a64\u0a65\u0007W\u0002\u0002\u0a65\u0a6c\u0007V\u0002\u0002', '\u0a66\u0a67\u0007k\u0002\u0002\u0a67\u0a68\u0007p\u0002\u0002\u0a68', '\u0a69\u0007r\u0002\u0002\u0a69\u0a6a\u0007w\u0002\u0002\u0a6a\u0a6c', '\u0007v\u0002\u0002\u0a6b\u0a61\u0003\u0002\u0002\u0002\u0a6b\u0a66', '\u0003\u0002\u0002\u0002\u0a6c\u0154\u0003\u0002\u0002\u0002\u0a6d\u0a6e', '\u0007Q\u0002\u0002\u0a6e\u0a6f\u0007W\u0002\u0002\u0a6f\u0a70\u0007', 'V\u0002\u0002\u0a70\u0a71\u0007R\u0002\u0002\u0a71\u0a72\u0007W\u0002', '\u0002\u0a72\u0a7a\u0007V\u0002\u0002\u0a73\u0a74\u0007q\u0002\u0002', '\u0a74\u0a75\u0007w\u0002\u0002\u0a75\u0a76\u0007v\u0002\u0002\u0a76', '\u0a77\u0007r\u0002\u0002\u0a77\u0a78\u0007w\u0002\u0002\u0a78\u0a7a', '\u0007v\u0002\u0002\u0a79\u0a6d\u0003\u0002\u0002\u0002\u0a79\u0a73', '\u0003\u0002\u0002\u0002\u0a7a\u0156\u0003\u0002\u0002\u0002\u0a7b\u0a7c', '\u0007E\u0002\u0002\u0a7c\u0a7d\u0007C\u0002\u0002\u0a7d\u0a7e\u0007', 'U\u0002\u0002\u0a7e\u0a7f\u0007E\u0002\u0002\u0a7f\u0a80\u0007C\u0002', '\u0002\u0a80\u0a81\u0007F\u0002\u0002\u0a81\u0a8a\u0007G\u0002\u0002', '\u0a82\u0a83\u0007e\u0002\u0002\u0a83\u0a84\u0007c\u0002\u0002\u0a84', '\u0a85\u0007u\u0002\u0002\u0a85\u0a86\u0007e\u0002\u0002\u0a86\u0a87', '\u0007c\u0002\u0002\u0a87\u0a88\u0007f\u0002\u0002\u0a88\u0a8a\u0007', 'g\u0002\u0002\u0a89\u0a7b\u0003\u0002\u0002\u0002\u0a89\u0a82\u0003', '\u0002\u0002\u0002\u0a8a\u0158\u0003\u0002\u0002\u0002\u0a8b\u0a8c\u0007', 'T\u0002\u0002\u0a8c\u0a8d\u0007G\u0002\u0002\u0a8d\u0a8e\u0007U\u0002', '\u0002\u0a8e\u0a8f\u0007V\u0002\u0002\u0a8f\u0a90\u0007T\u0002\u0002', '\u0a90\u0a91\u0007K\u0002\u0002\u0a91\u0a92\u0007E\u0002\u0002\u0a92', '\u0a9c\u0007V\u0002\u0002\u0a93\u0a94\u0007t\u0002\u0002\u0a94\u0a95', '\u0007g\u0002\u0002\u0a95\u0a96\u0007u\u0002\u0002\u0a96\u0a97\u0007', 'v\u0002\u0002\u0a97\u0a98\u0007t\u0002\u0002\u0a98\u0a99\u0007k\u0002', '\u0002\u0a99\u0a9a\u0007e\u0002\u0002\u0a9a\u0a9c\u0007v\u0002\u0002', '\u0a9b\u0a8b\u0003\u0002\u0002\u0002\u0a9b\u0a93\u0003\u0002\u0002\u0002', '\u0a9c\u015a\u0003\u0002\u0002\u0002\u0a9d\u0a9e\u0007K\u0002\u0002', '\u0a9e\u0a9f\u0007P\u0002\u0002\u0a9f\u0aa0\u0007E\u0002\u0002\u0aa0', '\u0aa1\u0007N\u0002\u0002\u0aa1\u0aa2\u0007W\u0002\u0002\u0aa2\u0aa3', '\u0007F\u0002\u0002\u0aa3\u0aa4\u0007K\u0002\u0002\u0aa4\u0aa5\u0007', 'P\u0002\u0002\u0aa5\u0ab0\u0007I\u0002\u0002\u0aa6\u0aa7\u0007k\u0002', '\u0002\u0aa7\u0aa8\u0007p\u0002\u0002\u0aa8\u0aa9\u0007e\u0002\u0002', '\u0aa9\u0aaa\u0007n\u0002\u0002\u0aaa\u0aab\u0007w\u0002\u0002\u0aab', '\u0aac\u0007f\u0002\u0002\u0aac\u0aad\u0007k\u0002\u0002\u0aad\u0aae', '\u0007p\u0002\u0002\u0aae\u0ab0\u0007i\u0002\u0002\u0aaf\u0a9d\u0003', '\u0002\u0002\u0002\u0aaf\u0aa6\u0003\u0002\u0002\u0002\u0ab0\u015c\u0003', '\u0002\u0002\u0002\u0ab1\u0ab2\u0007G\u0002\u0002\u0ab2\u0ab3\u0007', 'Z\u0002\u0002\u0ab3\u0ab4\u0007E\u0002\u0002\u0ab4\u0ab5\u0007N\u0002', '\u0002\u0ab5\u0ab6\u0007W\u0002\u0002\u0ab6\u0ab7\u0007F\u0002\u0002', '\u0ab7\u0ab8\u0007K\u0002\u0002\u0ab8\u0ab9\u0007P\u0002\u0002\u0ab9', '\u0ac4\u0007I\u0002\u0002\u0aba\u0abb\u0007g\u0002\u0002\u0abb\u0abc', '\u0007z\u0002\u0002\u0abc\u0abd\u0007e\u0002\u0002\u0abd\u0abe\u0007', 'n\u0002\u0002\u0abe\u0abf\u0007w\u0002\u0002\u0abf\u0ac0\u0007f\u0002', '\u0002\u0ac0\u0ac1\u0007k\u0002\u0002\u0ac1\u0ac2\u0007p\u0002\u0002', '\u0ac2\u0ac4\u0007i\u0002\u0002\u0ac3\u0ab1\u0003\u0002\u0002\u0002', '\u0ac3\u0aba\u0003\u0002\u0002\u0002\u0ac4\u015e\u0003\u0002\u0002\u0002', '\u0ac5\u0ac6\u0007R\u0002\u0002\u0ac6\u0ac7\u0007T\u0002\u0002\u0ac7', '\u0ac8\u0007Q\u0002\u0002\u0ac8\u0ac9\u0007R\u0002\u0002\u0ac9\u0aca', '\u0007G\u0002\u0002\u0aca\u0acb\u0007T\u0002\u0002\u0acb\u0acc\u0007', 'V\u0002\u0002\u0acc\u0acd\u0007K\u0002\u0002\u0acd\u0ace\u0007G\u0002', '\u0002\u0ace\u0ada\u0007U\u0002\u0002\u0acf\u0ad0\u0007r\u0002\u0002', '\u0ad0\u0ad1\u0007t\u0002\u0002\u0ad1\u0ad2\u0007q\u0002\u0002\u0ad2', '\u0ad3\u0007r\u0002\u0002\u0ad3\u0ad4\u0007g\u0002\u0002\u0ad4\u0ad5', '\u0007t\u0002\u0002\u0ad5\u0ad6\u0007v\u0002\u0002\u0ad6\u0ad7\u0007', 'k\u0002\u0002\u0ad7\u0ad8\u0007g\u0002\u0002\u0ad8\u0ada\u0007u\u0002', '\u0002\u0ad9\u0ac5\u0003\u0002\u0002\u0002\u0ad9\u0acf\u0003\u0002\u0002', '\u0002\u0ada\u0160\u0003\u0002\u0002\u0002\u0adb\u0adc\u0007P\u0002', '\u0002\u0adc\u0add\u0007Q\u0002\u0002\u0add\u0ade\u0007T\u0002\u0002', '\u0ade\u0adf\u0007O\u0002\u0002\u0adf\u0ae0\u0007C\u0002\u0002\u0ae0', '\u0ae1\u0007N\u0002\u0002\u0ae1\u0ae2\u0007K\u0002\u0002\u0ae2\u0ae3', '\u0007\\\u0002\u0002\u0ae3\u0aee\u0007G\u0002\u0002\u0ae4\u0ae5\u0007', 'p\u0002\u0002\u0ae5\u0ae6\u0007q\u0002\u0002\u0ae6\u0ae7\u0007t\u0002', '\u0002\u0ae7\u0ae8\u0007o\u0002\u0002\u0ae8\u0ae9\u0007c\u0002\u0002', '\u0ae9\u0aea\u0007n\u0002\u0002\u0aea\u0aeb\u0007k\u0002\u0002\u0aeb', '\u0aec\u0007|\u0002\u0002\u0aec\u0aee\u0007g\u0002\u0002\u0aed\u0adb', '\u0003\u0002\u0002\u0002\u0aed\u0ae4\u0003\u0002\u0002\u0002\u0aee\u0162', '\u0003\u0002\u0002\u0002\u0aef\u0af0\u0007P\u0002\u0002\u0af0\u0af1', '\u0007H\u0002\u0002\u0af1\u0af2\u0007F\u0002\u0002\u0af2\u0af8\u0007', '"\u0002\u0002\u0af3\u0af4\u0007p\u0002\u0002\u0af4\u0af5\u0007h\u0002', '\u0002\u0af5\u0af6\u0007f\u0002\u0002\u0af6\u0af8\u0007"\u0002\u0002', '\u0af7\u0aef\u0003\u0002\u0002\u0002\u0af7\u0af3\u0003\u0002\u0002\u0002', '\u0af8\u0164\u0003\u0002\u0002\u0002\u0af9\u0afa\u0007P\u0002\u0002', '\u0afa\u0afb\u0007H\u0002\u0002\u0afb\u0afc\u0007E\u0002\u0002\u0afc', '\u0b02\u0007"\u0002\u0002\u0afd\u0afe\u0007p\u0002\u0002\u0afe\u0aff', '\u0007h\u0002\u0002\u0aff\u0b00\u0007e\u0002\u0002\u0b00\u0b02\u0007', '"\u0002\u0002\u0b01\u0af9\u0003\u0002\u0002\u0002\u0b01\u0afd\u0003', '\u0002\u0002\u0002\u0b02\u0166\u0003\u0002\u0002\u0002\u0b03\u0b04\u0007', 'P\u0002\u0002\u0b04\u0b05\u0007H\u0002\u0002\u0b05\u0b06\u0007M\u0002', '\u0002\u0b06\u0b07\u0007F\u0002\u0002\u0b07\u0b0e\u0007"\u0002\u0002', '\u0b08\u0b09\u0007p\u0002\u0002\u0b09\u0b0a\u0007h\u0002\u0002\u0b0a', '\u0b0b\u0007m\u0002\u0002\u0b0b\u0b0c\u0007f\u0002\u0002\u0b0c\u0b0e', '\u0007"\u0002\u0002\u0b0d\u0b03\u0003\u0002\u0002\u0002\u0b0d\u0b08', '\u0003\u0002\u0002\u0002\u0b0e\u0168\u0003\u0002\u0002\u0002\u0b0f\u0b10', '\u0007P\u0002\u0002\u0b10\u0b11\u0007H\u0002\u0002\u0b11\u0b12\u0007', 'M\u0002\u0002\u0b12\u0b13\u0007E\u0002\u0002\u0b13\u0b1a\u0007"\u0002', '\u0002\u0b14\u0b15\u0007p\u0002\u0002\u0b15\u0b16\u0007h\u0002\u0002', '\u0b16\u0b17\u0007m\u0002\u0002\u0b17\u0b18\u0007e\u0002\u0002\u0b18', '\u0b1a\u0007"\u0002\u0002\u0b19\u0b0f\u0003\u0002\u0002\u0002\u0b19', '\u0b14\u0003\u0002\u0002\u0002\u0b1a\u016a\u0003\u0002\u0002\u0002\u0b1b', '\u0b1c\u0007K\u0002\u0002\u0b1c\u0b20\u0007H\u0002\u0002\u0b1d\u0b1e', '\u0007k\u0002\u0002\u0b1e\u0b20\u0007h\u0002\u0002\u0b1f\u0b1b\u0003', '\u0002\u0002\u0002\u0b1f\u0b1d\u0003\u0002\u0002\u0002\u0b20\u016c\u0003', '\u0002\u0002\u0002\u0b21\u0b22\u0007P\u0002\u0002\u0b22\u0b23\u0007', 'W\u0002\u0002\u0b23\u0b24\u0007N\u0002\u0002\u0b24\u0b25\u0007N\u0002', '\u0002\u0b25\u0b26\u0007K\u0002\u0002\u0b26\u0b2e\u0007H\u0002\u0002', '\u0b27\u0b28\u0007p\u0002\u0002\u0b28\u0b29\u0007w\u0002\u0002\u0b29', '\u0b2a\u0007n\u0002\u0002\u0b2a\u0b2b\u0007n\u0002\u0002\u0b2b\u0b2c', '\u0007k\u0002\u0002\u0b2c\u0b2e\u0007h\u0002\u0002\u0b2d\u0b21\u0003', '\u0002\u0002\u0002\u0b2d\u0b27\u0003\u0002\u0002\u0002\u0b2e\u016e\u0003', '\u0002\u0002\u0002\u0b2f\u0b30\u0007E\u0002\u0002\u0b30\u0b31\u0007', 'Q\u0002\u0002\u0b31\u0b32\u0007C\u0002\u0002\u0b32\u0b33\u0007N\u0002', '\u0002\u0b33\u0b34\u0007G\u0002\u0002\u0b34\u0b35\u0007U\u0002\u0002', '\u0b35\u0b36\u0007E\u0002\u0002\u0b36\u0b40\u0007G\u0002\u0002\u0b37', '\u0b38\u0007e\u0002\u0002\u0b38\u0b39\u0007q\u0002\u0002\u0b39\u0b3a', '\u0007c\u0002\u0002\u0b3a\u0b3b\u0007n\u0002\u0002\u0b3b\u0b3c\u0007', 'g\u0002\u0002\u0b3c\u0b3d\u0007u\u0002\u0002\u0b3d\u0b3e\u0007e\u0002', '\u0002\u0b3e\u0b40\u0007g\u0002\u0002\u0b3f\u0b2f\u0003\u0002\u0002', '\u0002\u0b3f\u0b37\u0003\u0002\u0002\u0002\u0b40\u0170\u0003\u0002\u0002', '\u0002\u0b41\u0b42\u0007?\u0002\u0002\u0b42\u0172\u0003\u0002\u0002', '\u0002\u0b43\u0b44\u0007>\u0002\u0002\u0b44\u0b48\u0007@\u0002\u0002', '\u0b45\u0b46\u0007#\u0002\u0002\u0b46\u0b48\u0007?\u0002\u0002\u0b47', '\u0b43\u0003\u0002\u0002\u0002\u0b47\u0b45\u0003\u0002\u0002\u0002\u0b48', '\u0174\u0003\u0002\u0002\u0002\u0b49\u0b4a\u0007>\u0002\u0002\u0b4a', '\u0176\u0003\u0002\u0002\u0002\u0b4b\u0b4c\u0007>\u0002\u0002\u0b4c', '\u0b4d\u0007?\u0002\u0002\u0b4d\u0178\u0003\u0002\u0002\u0002\u0b4e', '\u0b4f\u0007@\u0002\u0002\u0b4f\u017a\u0003\u0002\u0002\u0002\u0b50', '\u0b51\u0007@\u0002\u0002\u0b51\u0b52\u0007?\u0002\u0002\u0b52\u017c', '\u0003\u0002\u0002\u0002\u0b53\u0b54\u0007-\u0002\u0002\u0b54\u017e', '\u0003\u0002\u0002\u0002\u0b55\u0b56\u0007/\u0002\u0002\u0b56\u0180', '\u0003\u0002\u0002\u0002\u0b57\u0b58\u0007,\u0002\u0002\u0b58\u0182', '\u0003\u0002\u0002\u0002\u0b59\u0b5a\u00071\u0002\u0002\u0b5a\u0184', "\u0003\u0002\u0002\u0002\u0b5b\u0b5c\u0007'\u0002\u0002\u0b5c\u0186", '\u0003\u0002\u0002\u0002\u0b5d\u0b5e\u0007~\u0002\u0002\u0b5e\u0b5f', '\u0007~\u0002\u0002\u0b5f\u0188\u0003\u0002\u0002\u0002\u0b60\u0b66', '\u0007)\u0002\u0002\u0b61\u0b65\n\u0002\u0002\u0002\u0b62\u0b63\u0007', ')\u0002\u0002\u0b63\u0b65\u0007)\u0002\u0002\u0b64\u0b61\u0003\u0002', '\u0002\u0002\u0b64\u0b62\u0003\u0002\u0002\u0002\u0b65\u0b68\u0003\u0002', '\u0002\u0002\u0b66\u0b64\u0003\u0002\u0002\u0002\u0b66\u0b67\u0003\u0002', '\u0002\u0002\u0b67\u0b69\u0003\u0002\u0002\u0002\u0b68\u0b66\u0003\u0002', '\u0002\u0002\u0b69\u0b6a\u0007)\u0002\u0002\u0b6a\u018a\u0003\u0002', '\u0002\u0002\u0b6b\u0b6c\u0007Z\u0002\u0002\u0b6c\u0b6d\u0007)\u0002', '\u0002\u0b6d\u0b71\u0003\u0002\u0002\u0002\u0b6e\u0b70\n\u0002\u0002', '\u0002\u0b6f\u0b6e\u0003\u0002\u0002\u0002\u0b70\u0b73\u0003\u0002\u0002', '\u0002\u0b71\u0b6f\u0003\u0002\u0002\u0002\u0b71\u0b72\u0003\u0002\u0002', '\u0002\u0b72\u0b74\u0003\u0002\u0002\u0002\u0b73\u0b71\u0003\u0002\u0002', '\u0002\u0b74\u0b75\u0007)\u0002\u0002\u0b75\u018c\u0003\u0002\u0002', '\u0002\u0b76\u0b78\u0005\u01a1\u00d1\u0002\u0b77\u0b76\u0003\u0002\u0002', '\u0002\u0b78\u0b79\u0003\u0002\u0002\u0002\u0b79\u0b77\u0003\u0002\u0002', '\u0002\u0b79\u0b7a\u0003\u0002\u0002\u0002\u0b7a\u018e\u0003\u0002\u0002', '\u0002\u0b7b\u0b7d\u0005\u01a1\u00d1\u0002\u0b7c\u0b7b\u0003\u0002\u0002', '\u0002\u0b7d\u0b7e\u0003\u0002\u0002\u0002\u0b7e\u0b7c\u0003\u0002\u0002', '\u0002\u0b7e\u0b7f\u0003\u0002\u0002\u0002\u0b7f\u0b80\u0003\u0002\u0002', '\u0002\u0b80\u0b84\u00070\u0002\u0002\u0b81\u0b83\u0005\u01a1\u00d1', '\u0002\u0b82\u0b81\u0003\u0002\u0002\u0002\u0b83\u0b86\u0003\u0002\u0002', '\u0002\u0b84\u0b82\u0003\u0002\u0002\u0002\u0b84\u0b85\u0003\u0002\u0002', '\u0002\u0b85\u0ba6\u0003\u0002\u0002\u0002\u0b86\u0b84\u0003\u0002\u0002', '\u0002\u0b87\u0b89\u00070\u0002\u0002\u0b88\u0b8a\u0005\u01a1\u00d1', '\u0002\u0b89\u0b88\u0003\u0002\u0002\u0002\u0b8a\u0b8b\u0003\u0002\u0002', '\u0002\u0b8b\u0b89\u0003\u0002\u0002\u0002\u0b8b\u0b8c\u0003\u0002\u0002', '\u0002\u0b8c\u0ba6\u0003\u0002\u0002\u0002\u0b8d\u0b8f\u0005\u01a1\u00d1', '\u0002\u0b8e\u0b8d\u0003\u0002\u0002\u0002\u0b8f\u0b90\u0003\u0002\u0002', '\u0002\u0b90\u0b8e\u0003\u0002\u0002\u0002\u0b90\u0b91\u0003\u0002\u0002', '\u0002\u0b91\u0b99\u0003\u0002\u0002\u0002\u0b92\u0b96\u00070\u0002', '\u0002\u0b93\u0b95\u0005\u01a1\u00d1\u0002\u0b94\u0b93\u0003\u0002\u0002', '\u0002\u0b95\u0b98\u0003\u0002\u0002\u0002\u0b96\u0b94\u0003\u0002\u0002', '\u0002\u0b96\u0b97\u0003\u0002\u0002\u0002\u0b97\u0b9a\u0003\u0002\u0002', '\u0002\u0b98\u0b96\u0003\u0002\u0002\u0002\u0b99\u0b92\u0003\u0002\u0002', '\u0002\u0b99\u0b9a\u0003\u0002\u0002\u0002\u0b9a\u0b9b\u0003\u0002\u0002', '\u0002\u0b9b\u0b9c\u0005\u019f\u00d0\u0002\u0b9c\u0ba6\u0003\u0002\u0002', '\u0002\u0b9d\u0b9f\u00070\u0002\u0002\u0b9e\u0ba0\u0005\u01a1\u00d1', '\u0002\u0b9f\u0b9e\u0003\u0002\u0002\u0002\u0ba0\u0ba1\u0003\u0002\u0002', '\u0002\u0ba1\u0b9f\u0003\u0002\u0002\u0002\u0ba1\u0ba2\u0003\u0002\u0002', '\u0002\u0ba2\u0ba3\u0003\u0002\u0002\u0002\u0ba3\u0ba4\u0005\u019f\u00d0', '\u0002\u0ba4\u0ba6\u0003\u0002\u0002\u0002\u0ba5\u0b7c\u0003\u0002\u0002', '\u0002\u0ba5\u0b87\u0003\u0002\u0002\u0002\u0ba5\u0b8e\u0003\u0002\u0002', '\u0002\u0ba5\u0b9d\u0003\u0002\u0002\u0002\u0ba6\u0190\u0003\u0002\u0002', '\u0002\u0ba7\u0baa\u0005\u01a3\u00d2\u0002\u0ba8\u0baa\u0007a\u0002', '\u0002\u0ba9\u0ba7\u0003\u0002\u0002\u0002\u0ba9\u0ba8\u0003\u0002\u0002', '\u0002\u0baa\u0bb0\u0003\u0002\u0002\u0002\u0bab\u0baf\u0005\u01a3\u00d2', '\u0002\u0bac\u0baf\u0005\u01a1\u00d1\u0002\u0bad\u0baf\t\u0003\u0002', '\u0002\u0bae\u0bab\u0003\u0002\u0002\u0002\u0bae\u0bac\u0003\u0002\u0002', '\u0002\u0bae\u0bad\u0003\u0002\u0002\u0002\u0baf\u0bb2\u0003\u0002\u0002', '\u0002\u0bb0\u0bae\u0003\u0002\u0002\u0002\u0bb0\u0bb1\u0003\u0002\u0002', '\u0002\u0bb1\u0192\u0003\u0002\u0002\u0002\u0bb2\u0bb0\u0003\u0002\u0002', '\u0002\u0bb3\u0bb7\u0005\u01a1\u00d1\u0002\u0bb4\u0bb8\u0005\u01a3\u00d2', '\u0002\u0bb5\u0bb8\u0005\u01a1\u00d1\u0002\u0bb6\u0bb8\t\u0003\u0002', '\u0002\u0bb7\u0bb4\u0003\u0002\u0002\u0002\u0bb7\u0bb5\u0003\u0002\u0002', '\u0002\u0bb7\u0bb6\u0003\u0002\u0002\u0002\u0bb8\u0bb9\u0003\u0002\u0002', '\u0002\u0bb9\u0bb7\u0003\u0002\u0002\u0002\u0bb9\u0bba\u0003\u0002\u0002', '\u0002\u0bba\u0194\u0003\u0002\u0002\u0002\u0bbb\u0bc1\u0007$\u0002', '\u0002\u0bbc\u0bc0\n\u0004\u0002\u0002\u0bbd\u0bbe\u0007$\u0002\u0002', '\u0bbe\u0bc0\u0007$\u0002\u0002\u0bbf\u0bbc\u0003\u0002\u0002\u0002', '\u0bbf\u0bbd\u0003\u0002\u0002\u0002\u0bc0\u0bc3\u0003\u0002\u0002\u0002', '\u0bc1\u0bbf\u0003\u0002\u0002\u0002\u0bc1\u0bc2\u0003\u0002\u0002\u0002', '\u0bc2\u0bc4\u0003\u0002\u0002\u0002\u0bc3\u0bc1\u0003\u0002\u0002\u0002', '\u0bc4\u0bc5\u0007$\u0002\u0002\u0bc5\u0196\u0003\u0002\u0002\u0002', '\u0bc6\u0bcc\u0007b\u0002\u0002\u0bc7\u0bcb\n\u0005\u0002\u0002\u0bc8', '\u0bc9\u0007b\u0002\u0002\u0bc9\u0bcb\u0007b\u0002\u0002\u0bca\u0bc7', '\u0003\u0002\u0002\u0002\u0bca\u0bc8\u0003\u0002\u0002\u0002\u0bcb\u0bce', '\u0003\u0002\u0002\u0002\u0bcc\u0bca\u0003\u0002\u0002\u0002\u0bcc\u0bcd', '\u0003\u0002\u0002\u0002\u0bcd\u0bcf\u0003\u0002\u0002\u0002\u0bce\u0bcc', '\u0003\u0002\u0002\u0002\u0bcf\u0bd0\u0007b\u0002\u0002\u0bd0\u0198', '\u0003\u0002\u0002\u0002\u0bd1\u0bd2\u0007V\u0002\u0002\u0bd2\u0bd3', '\u0007K\u0002\u0002\u0bd3\u0bd4\u0007O\u0002\u0002\u0bd4\u0bd5\u0007', 'G\u0002\u0002\u0bd5\u0bd6\u0003\u0002\u0002\u0002\u0bd6\u0bd7\u0005', '\u01a9\u00d5\u0002\u0bd7\u0bd8\u0007Y\u0002\u0002\u0bd8\u0bd9\u0007', 'K\u0002\u0002\u0bd9\u0bda\u0007V\u0002\u0002\u0bda\u0bdb\u0007J\u0002', '\u0002\u0bdb\u0bdc\u0003\u0002\u0002\u0002\u0bdc\u0bdd\u0005\u01a9\u00d5', '\u0002\u0bdd\u0bde\u0007V\u0002\u0002\u0bde\u0bdf\u0007K\u0002\u0002', '\u0bdf\u0be0\u0007O\u0002\u0002\u0be0\u0be1\u0007G\u0002\u0002\u0be1', '\u0be2\u0003\u0002\u0002\u0002\u0be2\u0be3\u0005\u01a9\u00d5\u0002\u0be3', '\u0be4\u0007\\\u0002\u0002\u0be4\u0be5\u0007Q\u0002\u0002\u0be5\u0be6', '\u0007P\u0002\u0002\u0be6\u0be7\u0007G\u0002\u0002\u0be7\u019a\u0003', '\u0002\u0002\u0002\u0be8\u0be9\u0007V\u0002\u0002\u0be9\u0bea\u0007', 'K\u0002\u0002\u0bea\u0beb\u0007O\u0002\u0002\u0beb\u0bec\u0007G\u0002', '\u0002\u0bec\u0bed\u0007U\u0002\u0002\u0bed\u0bee\u0007V\u0002\u0002', '\u0bee\u0bef\u0007C\u0002\u0002\u0bef\u0bf0\u0007O\u0002\u0002\u0bf0', '\u0bf1\u0007R\u0002\u0002\u0bf1\u0bf2\u0003\u0002\u0002\u0002\u0bf2', '\u0bf3\u0005\u01a9\u00d5\u0002\u0bf3\u0bf4\u0007Y\u0002\u0002\u0bf4', '\u0bf5\u0007K\u0002\u0002\u0bf5\u0bf6\u0007V\u0002\u0002\u0bf6\u0bf7', '\u0007J\u0002\u0002\u0bf7\u0bf8\u0003\u0002\u0002\u0002\u0bf8\u0bf9', '\u0005\u01a9\u00d5\u0002\u0bf9\u0bfa\u0007V\u0002\u0002\u0bfa\u0bfb', '\u0007K\u0002\u0002\u0bfb\u0bfc\u0007O\u0002\u0002\u0bfc\u0bfd\u0007', 'G\u0002\u0002\u0bfd\u0bfe\u0003\u0002\u0002\u0002\u0bfe\u0bff\u0005', '\u01a9\u00d5\u0002\u0bff\u0c00\u0007\\\u0002\u0002\u0c00\u0c01\u0007', 'Q\u0002\u0002\u0c01\u0c02\u0007P\u0002\u0002\u0c02\u0c03\u0007G\u0002', '\u0002\u0c03\u019c\u0003\u0002\u0002\u0002\u0c04\u0c05\u0007F\u0002', '\u0002\u0c05\u0c06\u0007Q\u0002\u0002\u0c06\u0c07\u0007W\u0002\u0002', '\u0c07\u0c08\u0007D\u0002\u0002\u0c08\u0c09\u0007N\u0002\u0002\u0c09', '\u0c0a\u0007G\u0002\u0002\u0c0a\u0c0b\u0003\u0002\u0002\u0002\u0c0b', '\u0c0c\u0005\u01a9\u00d5\u0002\u0c0c\u0c0d\u0007R\u0002\u0002\u0c0d', '\u0c0e\u0007T\u0002\u0002\u0c0e\u0c0f\u0007G\u0002\u0002\u0c0f\u0c10', '\u0007E\u0002\u0002\u0c10\u0c11\u0007K\u0002\u0002\u0c11\u0c12\u0007', 'U\u0002\u0002\u0c12\u0c13\u0007K\u0002\u0002\u0c13\u0c14\u0007Q\u0002', '\u0002\u0c14\u0c15\u0007P\u0002\u0002\u0c15\u019e\u0003\u0002\u0002', '\u0002\u0c16\u0c18\u0007G\u0002\u0002\u0c17\u0c19\t\u0006\u0002\u0002', '\u0c18\u0c17\u0003\u0002\u0002\u0002\u0c18\u0c19\u0003\u0002\u0002\u0002', '\u0c19\u0c1b\u0003\u0002\u0002\u0002\u0c1a\u0c1c\u0005\u01a1\u00d1\u0002', '\u0c1b\u0c1a\u0003\u0002\u0002\u0002\u0c1c\u0c1d\u0003\u0002\u0002\u0002', '\u0c1d\u0c1b\u0003\u0002\u0002\u0002\u0c1d\u0c1e\u0003\u0002\u0002\u0002', '\u0c1e\u01a0\u0003\u0002\u0002\u0002\u0c1f\u0c20\t\u0007\u0002\u0002', '\u0c20\u01a2\u0003\u0002\u0002\u0002\u0c21\u0c23\t\b\u0002\u0002\u0c22', '\u0c21\u0003\u0002\u0002\u0002\u0c23\u01a4\u0003\u0002\u0002\u0002\u0c24', '\u0c25\u0007/\u0002\u0002\u0c25\u0c26\u0007/\u0002\u0002\u0c26\u0c2a', '\u0003\u0002\u0002\u0002\u0c27\u0c29\n\t\u0002\u0002\u0c28\u0c27\u0003', '\u0002\u0002\u0002\u0c29\u0c2c\u0003\u0002\u0002\u0002\u0c2a\u0c28\u0003', '\u0002\u0002\u0002\u0c2a\u0c2b\u0003\u0002\u0002\u0002\u0c2b\u0c2e\u0003', '\u0002\u0002\u0002\u0c2c\u0c2a\u0003\u0002\u0002\u0002\u0c2d\u0c2f\u0007', '\u000f\u0002\u0002\u0c2e\u0c2d\u0003\u0002\u0002\u0002\u0c2e\u0c2f\u0003', '\u0002\u0002\u0002\u0c2f\u0c31\u0003\u0002\u0002\u0002\u0c30\u0c32\u0007', '\f\u0002\u0002\u0c31\u0c30\u0003\u0002\u0002\u0002\u0c31\u0c32\u0003', '\u0002\u0002\u0002\u0c32\u0c33\u0003\u0002\u0002\u0002\u0c33\u0c34\b', '\u00d3\u0002\u0002\u0c34\u01a6\u0003\u0002\u0002\u0002\u0c35\u0c36\u0007', '1\u0002\u0002\u0c36\u0c37\u0007,\u0002\u0002\u0c37\u0c3b\u0003\u0002', '\u0002\u0002\u0c38\u0c3a\u000b\u0002\u0002\u0002\u0c39\u0c38\u0003\u0002', '\u0002\u0002\u0c3a\u0c3d\u0003\u0002\u0002\u0002\u0c3b\u0c3c\u0003\u0002', '\u0002\u0002\u0c3b\u0c39\u0003\u0002\u0002\u0002\u0c3c\u0c3e\u0003\u0002', '\u0002\u0002\u0c3d\u0c3b\u0003\u0002\u0002\u0002\u0c3e\u0c3f\u0007,', '\u0002\u0002\u0c3f\u0c40\u00071\u0002\u0002\u0c40\u0c41\u0003\u0002', '\u0002\u0002\u0c41\u0c42\b\u00d4\u0002\u0002\u0c42\u01a8\u0003\u0002', '\u0002\u0002\u0c43\u0c45\t\n\u0002\u0002\u0c44\u0c43\u0003\u0002\u0002', '\u0002\u0c45\u0c46\u0003\u0002\u0002\u0002\u0c46\u0c44\u0003\u0002\u0002', '\u0002\u0c46\u0c47\u0003\u0002\u0002\u0002\u0c47\u0c48\u0003\u0002\u0002', '\u0002\u0c48\u0c49\b\u00d5\u0002\u0002\u0c49\u01aa\u0003\u0002\u0002', '\u0002\u0c4a\u0c4b\u0007=\u0002\u0002\u0c4b\u01ac\u0003\u0002\u0002', '\u0002\u0c4c\u0c4d\u000b\u0002\u0002\u0002\u0c4d\u01ae\u0003\u0002\u0002', '\u0002\u00cf\u0002\u01cf\u01d9\u01e1\u01e7\u01ef\u01f9\u0201\u0213\u021f', '\u022b\u0231\u0243\u024d\u0257\u0265\u0271\u027f\u028b\u0291\u0297\u029f', '\u02a5\u02ad\u02b3\u02c1\u02d1\u02db\u02e1\u02eb\u02f5\u0301\u030d\u0319', '\u0323\u0331\u0339\u0343\u0357\u0369\u0371\u0381\u0393\u03a3\u03ad\u03b7', '\u03cb\u03dd\u03e7\u03f3\u03fb\u0405\u0413\u0421\u042b\u0445\u045f\u0483', '\u0497\u04b5\u04c5\u04cf\u04d9\u04e3\u04ed\u04f5\u04ff\u050b\u0517\u0523', '\u052d\u0539\u0543\u0553\u055f\u0565\u0573\u057d\u0591\u059d\u05a7\u05bb', '\u05cf\u05e3\u05f3\u05fb\u0605\u0619\u0627\u0635\u0643\u064f\u0659\u0669', '\u0677\u0685\u068f\u06a5\u06b7\u06c3\u06d1\u06e7\u06f5\u0703\u0713\u0723', '\u0731\u073b\u0745\u0757\u0767\u077f\u0789\u079b\u07a5\u07b3\u07c3\u07d5', '\u07e5\u07f3\u07fb\u0811\u0825\u082f\u083b\u0849\u085d\u0863\u0871\u0885', '\u089d\u08b5\u08c1\u08cf\u08dd\u08f3\u08ff\u0907\u090f\u091b\u092b\u0935', '\u0941\u0959\u0967\u0979\u0983\u0997\u09a3\u09bd\u09d3\u09e7\u09ff\u0a09', '\u0a15\u0a1f\u0a29\u0a39\u0a4f\u0a5f\u0a6b\u0a79\u0a89\u0a9b\u0aaf\u0ac3', '\u0ad9\u0aed\u0af7\u0b01\u0b0d\u0b19\u0b1f\u0b2d\u0b3f\u0b47\u0b64\u0b66', '\u0b71\u0b79\u0b7e\u0b84\u0b8b\u0b90\u0b96\u0b99\u0ba1\u0ba5\u0ba9\u0bae', '\u0bb0\u0bb7\u0bb9\u0bbf\u0bc1\u0bca\u0bcc\u0c18\u0c1d\u0c22\u0c2a\u0c2e', '\u0c31\u0c3b\u0c46\u0003\u0002\u0003\u0002', ].join(''); const atn = new _atn.ATNDeserializer().deserialize(serializedATN); const decisionsToDFA = atn.decisionToState.map(function(ds, index) { return new dfa.DFA(ds, index); }); export const SqlBaseLexer = function(input) { Lexer.call(this, input); this._interp = new _atn.LexerATNSimulator( this, atn, decisionsToDFA, new PredictionContextCache() ); return this; } as any; SqlBaseLexer.prototype = Object.create(Lexer.prototype); SqlBaseLexer.prototype.constructor = SqlBaseLexer; SqlBaseLexer.EOF = Token.EOF; SqlBaseLexer.T__0 = 1; SqlBaseLexer.T__1 = 2; SqlBaseLexer.T__2 = 3; SqlBaseLexer.T__3 = 4; SqlBaseLexer.T__4 = 5; SqlBaseLexer.T__5 = 6; SqlBaseLexer.T__6 = 7; SqlBaseLexer.T__7 = 8; SqlBaseLexer.T__8 = 9; SqlBaseLexer.SELECT = 10; SqlBaseLexer.FROM = 11; SqlBaseLexer.ADD = 12; SqlBaseLexer.AS = 13; SqlBaseLexer.ALL = 14; SqlBaseLexer.SOME = 15; SqlBaseLexer.ANY = 16; SqlBaseLexer.DISTINCT = 17; SqlBaseLexer.WHERE = 18; SqlBaseLexer.GROUP = 19; SqlBaseLexer.BY = 20; SqlBaseLexer.GROUPING = 21; SqlBaseLexer.SETS = 22; SqlBaseLexer.CUBE = 23; SqlBaseLexer.ROLLUP = 24; SqlBaseLexer.ORDER = 25; SqlBaseLexer.HAVING = 26; SqlBaseLexer.LIMIT = 27; SqlBaseLexer.AT = 28; SqlBaseLexer.OR = 29; SqlBaseLexer.AND = 30; SqlBaseLexer.IN = 31; SqlBaseLexer.NOT = 32; SqlBaseLexer.NO = 33; SqlBaseLexer.EXISTS = 34; SqlBaseLexer.BETWEEN = 35; SqlBaseLexer.LIKE = 36; SqlBaseLexer.IS = 37; SqlBaseLexer.NULL = 38; SqlBaseLexer.TRUE = 39; SqlBaseLexer.FALSE = 40; SqlBaseLexer.NULLS = 41; SqlBaseLexer.FIRST = 42; SqlBaseLexer.LAST = 43; SqlBaseLexer.ESCAPE = 44; SqlBaseLexer.ASC = 45; SqlBaseLexer.DESC = 46; SqlBaseLexer.SUBSTRING = 47; SqlBaseLexer.POSITION = 48; SqlBaseLexer.FOR = 49; SqlBaseLexer.TINYINT = 50; SqlBaseLexer.SMALLINT = 51; SqlBaseLexer.INTEGER = 52; SqlBaseLexer.DATE = 53; SqlBaseLexer.TIME = 54; SqlBaseLexer.TIMESTAMP = 55; SqlBaseLexer.INTERVAL = 56; SqlBaseLexer.YEAR = 57; SqlBaseLexer.MONTH = 58; SqlBaseLexer.DAY = 59; SqlBaseLexer.HOUR = 60; SqlBaseLexer.MINUTE = 61; SqlBaseLexer.SECOND = 62; SqlBaseLexer.ZONE = 63; SqlBaseLexer.CURRENT_DATE = 64; SqlBaseLexer.CURRENT_TIME = 65; SqlBaseLexer.CURRENT_TIMESTAMP = 66; SqlBaseLexer.LOCALTIME = 67; SqlBaseLexer.LOCALTIMESTAMP = 68; SqlBaseLexer.EXTRACT = 69; SqlBaseLexer.CASE = 70; SqlBaseLexer.WHEN = 71; SqlBaseLexer.THEN = 72; SqlBaseLexer.ELSE = 73; SqlBaseLexer.END = 74; SqlBaseLexer.JOIN = 75; SqlBaseLexer.CROSS = 76; SqlBaseLexer.OUTER = 77; SqlBaseLexer.INNER = 78; SqlBaseLexer.LEFT = 79; SqlBaseLexer.RIGHT = 80; SqlBaseLexer.FULL = 81; SqlBaseLexer.NATURAL = 82; SqlBaseLexer.USING = 83; SqlBaseLexer.ON = 84; SqlBaseLexer.FILTER = 85; SqlBaseLexer.OVER = 86; SqlBaseLexer.PARTITION = 87; SqlBaseLexer.RANGE = 88; SqlBaseLexer.ROWS = 89; SqlBaseLexer.UNBOUNDED = 90; SqlBaseLexer.PRECEDING = 91; SqlBaseLexer.FOLLOWING = 92; SqlBaseLexer.CURRENT = 93; SqlBaseLexer.ROW = 94; SqlBaseLexer.WITH = 95; SqlBaseLexer.RECURSIVE = 96; SqlBaseLexer.VALUES = 97; SqlBaseLexer.CREATE = 98; SqlBaseLexer.SCHEMA = 99; SqlBaseLexer.TABLE = 100; SqlBaseLexer.VIEW = 101; SqlBaseLexer.REPLACE = 102; SqlBaseLexer.INSERT = 103; SqlBaseLexer.DELETE = 104; SqlBaseLexer.INTO = 105; SqlBaseLexer.CONSTRAINT = 106; SqlBaseLexer.DESCRIBE = 107; SqlBaseLexer.GRANT = 108; SqlBaseLexer.REVOKE = 109; SqlBaseLexer.PRIVILEGES = 110; SqlBaseLexer.PUBLIC = 111; SqlBaseLexer.OPTION = 112; SqlBaseLexer.EXPLAIN = 113; SqlBaseLexer.ANALYZE = 114; SqlBaseLexer.FORMAT = 115; SqlBaseLexer.TYPE = 116; SqlBaseLexer.TEXT = 117; SqlBaseLexer.GRAPHVIZ = 118; SqlBaseLexer.LOGICAL = 119; SqlBaseLexer.DISTRIBUTED = 120; SqlBaseLexer.CAST = 121; SqlBaseLexer.TRY_CAST = 122; SqlBaseLexer.SHOW = 123; SqlBaseLexer.TABLES = 124; SqlBaseLexer.SCHEMAS = 125; SqlBaseLexer.CATALOGS = 126; SqlBaseLexer.COLUMNS = 127; SqlBaseLexer.COLUMN = 128; SqlBaseLexer.USE = 129; SqlBaseLexer.PARTITIONS = 130; SqlBaseLexer.FUNCTIONS = 131; SqlBaseLexer.DROP = 132; SqlBaseLexer.UNION = 133; SqlBaseLexer.EXCEPT = 134; SqlBaseLexer.INTERSECT = 135; SqlBaseLexer.TO = 136; SqlBaseLexer.SYSTEM = 137; SqlBaseLexer.BERNOULLI = 138; SqlBaseLexer.POISSONIZED = 139; SqlBaseLexer.TABLESAMPLE = 140; SqlBaseLexer.ALTER = 141; SqlBaseLexer.RENAME = 142; SqlBaseLexer.UNNEST = 143; SqlBaseLexer.ORDINALITY = 144; SqlBaseLexer.ARRAY = 145; SqlBaseLexer.MAP = 146; SqlBaseLexer.SET = 147; SqlBaseLexer.RESET = 148; SqlBaseLexer.SESSION = 149; SqlBaseLexer.DATA = 150; SqlBaseLexer.START = 151; SqlBaseLexer.TRANSACTION = 152; SqlBaseLexer.COMMIT = 153; SqlBaseLexer.ROLLBACK = 154; SqlBaseLexer.WORK = 155; SqlBaseLexer.ISOLATION = 156; SqlBaseLexer.LEVEL = 157; SqlBaseLexer.SERIALIZABLE = 158; SqlBaseLexer.REPEATABLE = 159; SqlBaseLexer.COMMITTED = 160; SqlBaseLexer.UNCOMMITTED = 161; SqlBaseLexer.READ = 162; SqlBaseLexer.WRITE = 163; SqlBaseLexer.ONLY = 164; SqlBaseLexer.CALL = 165; SqlBaseLexer.PREPARE = 166; SqlBaseLexer.DEALLOCATE = 167; SqlBaseLexer.EXECUTE = 168; SqlBaseLexer.INPUT = 169; SqlBaseLexer.OUTPUT = 170; SqlBaseLexer.CASCADE = 171; SqlBaseLexer.RESTRICT = 172; SqlBaseLexer.INCLUDING = 173; SqlBaseLexer.EXCLUDING = 174; SqlBaseLexer.PROPERTIES = 175; SqlBaseLexer.NORMALIZE = 176; SqlBaseLexer.NFD = 177; SqlBaseLexer.NFC = 178; SqlBaseLexer.NFKD = 179; SqlBaseLexer.NFKC = 180; SqlBaseLexer.IF = 181; SqlBaseLexer.NULLIF = 182; SqlBaseLexer.COALESCE = 183; SqlBaseLexer.EQ = 184; SqlBaseLexer.NEQ = 185; SqlBaseLexer.LT = 186; SqlBaseLexer.LTE = 187; SqlBaseLexer.GT = 188; SqlBaseLexer.GTE = 189; SqlBaseLexer.PLUS = 190; SqlBaseLexer.MINUS = 191; SqlBaseLexer.ASTERISK = 192; SqlBaseLexer.SLASH = 193; SqlBaseLexer.PERCENT = 194; SqlBaseLexer.CONCAT = 195; SqlBaseLexer.STRING = 196; SqlBaseLexer.BINARY_LITERAL = 197; SqlBaseLexer.INTEGER_VALUE = 198; SqlBaseLexer.DECIMAL_VALUE = 199; SqlBaseLexer.IDENTIFIER = 200; SqlBaseLexer.DIGIT_IDENTIFIER = 201; SqlBaseLexer.QUOTED_IDENTIFIER = 202; SqlBaseLexer.BACKQUOTED_IDENTIFIER = 203; SqlBaseLexer.TIME_WITH_TIME_ZONE = 204; SqlBaseLexer.TIMESTAMP_WITH_TIME_ZONE = 205; SqlBaseLexer.DOUBLE_PRECISION = 206; SqlBaseLexer.SIMPLE_COMMENT = 207; SqlBaseLexer.BRACKETED_COMMENT = 208; SqlBaseLexer.WS = 209; SqlBaseLexer.SEMICOLON = 210; SqlBaseLexer.UNRECOGNIZED = 211; SqlBaseLexer.prototype.channelNames = ['DEFAULT_TOKEN_CHANNEL', 'HIDDEN']; SqlBaseLexer.prototype.modeNames = ['DEFAULT_MODE']; SqlBaseLexer.prototype.literalNames = [ null, "'.'", "'('", "','", "')'", "'?'", "'->'", "'['", "']'", "'=>'", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "'='", null, "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", "'||'", null, null, null, null, null, null, null, null, null, null, null, null, null, null, "';'", ]; SqlBaseLexer.prototype.symbolicNames = [ null, null, null, null, null, null, null, null, null, null, 'SELECT', 'FROM', 'ADD', 'AS', 'ALL', 'SOME', 'ANY', 'DISTINCT', 'WHERE', 'GROUP', 'BY', 'GROUPING', 'SETS', 'CUBE', 'ROLLUP', 'ORDER', 'HAVING', 'LIMIT', 'AT', 'OR', 'AND', 'IN', 'NOT', 'NO', 'EXISTS', 'BETWEEN', 'LIKE', 'IS', 'NULL', 'TRUE', 'FALSE', 'NULLS', 'FIRST', 'LAST', 'ESCAPE', 'ASC', 'DESC', 'SUBSTRING', 'POSITION', 'FOR', 'TINYINT', 'SMALLINT', 'INTEGER', 'DATE', 'TIME', 'TIMESTAMP', 'INTERVAL', 'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND', 'ZONE', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'LOCALTIME', 'LOCALTIMESTAMP', 'EXTRACT', 'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'JOIN', 'CROSS', 'OUTER', 'INNER', 'LEFT', 'RIGHT', 'FULL', 'NATURAL', 'USING', 'ON', 'FILTER', 'OVER', 'PARTITION', 'RANGE', 'ROWS', 'UNBOUNDED', 'PRECEDING', 'FOLLOWING', 'CURRENT', 'ROW', 'WITH', 'RECURSIVE', 'VALUES', 'CREATE', 'SCHEMA', 'TABLE', 'VIEW', 'REPLACE', 'INSERT', 'DELETE', 'INTO', 'CONSTRAINT', 'DESCRIBE', 'GRANT', 'REVOKE', 'PRIVILEGES', 'PUBLIC', 'OPTION', 'EXPLAIN', 'ANALYZE', 'FORMAT', 'TYPE', 'TEXT', 'GRAPHVIZ', 'LOGICAL', 'DISTRIBUTED', 'CAST', 'TRY_CAST', 'SHOW', 'TABLES', 'SCHEMAS', 'CATALOGS', 'COLUMNS', 'COLUMN', 'USE', 'PARTITIONS', 'FUNCTIONS', 'DROP', 'UNION', 'EXCEPT', 'INTERSECT', 'TO', 'SYSTEM', 'BERNOULLI', 'POISSONIZED', 'TABLESAMPLE', 'ALTER', 'RENAME', 'UNNEST', 'ORDINALITY', 'ARRAY', 'MAP', 'SET', 'RESET', 'SESSION', 'DATA', 'START', 'TRANSACTION', 'COMMIT', 'ROLLBACK', 'WORK', 'ISOLATION', 'LEVEL', 'SERIALIZABLE', 'REPEATABLE', 'COMMITTED', 'UNCOMMITTED', 'READ', 'WRITE', 'ONLY', 'CALL', 'PREPARE', 'DEALLOCATE', 'EXECUTE', 'INPUT', 'OUTPUT', 'CASCADE', 'RESTRICT', 'INCLUDING', 'EXCLUDING', 'PROPERTIES', 'NORMALIZE', 'NFD', 'NFC', 'NFKD', 'NFKC', 'IF', 'NULLIF', 'COALESCE', 'EQ', 'NEQ', 'LT', 'LTE', 'GT', 'GTE', 'PLUS', 'MINUS', 'ASTERISK', 'SLASH', 'PERCENT', 'CONCAT', 'STRING', 'BINARY_LITERAL', 'INTEGER_VALUE', 'DECIMAL_VALUE', 'IDENTIFIER', 'DIGIT_IDENTIFIER', 'QUOTED_IDENTIFIER', 'BACKQUOTED_IDENTIFIER', 'TIME_WITH_TIME_ZONE', 'TIMESTAMP_WITH_TIME_ZONE', 'DOUBLE_PRECISION', 'SIMPLE_COMMENT', 'BRACKETED_COMMENT', 'WS', 'SEMICOLON', 'UNRECOGNIZED', ]; SqlBaseLexer.prototype.ruleNames = [ 'T__0', 'T__1', 'T__2', 'T__3', 'T__4', 'T__5', 'T__6', 'T__7', 'T__8', 'SELECT', 'FROM', 'ADD', 'AS', 'ALL', 'SOME', 'ANY', 'DISTINCT', 'WHERE', 'GROUP', 'BY', 'GROUPING', 'SETS', 'CUBE', 'ROLLUP', 'ORDER', 'HAVING', 'LIMIT', 'AT', 'OR', 'AND', 'IN', 'NOT', 'NO', 'EXISTS', 'BETWEEN', 'LIKE', 'IS', 'NULL', 'TRUE', 'FALSE', 'NULLS', 'FIRST', 'LAST', 'ESCAPE', 'ASC', 'DESC', 'SUBSTRING', 'POSITION', 'FOR', 'TINYINT', 'SMALLINT', 'INTEGER', 'DATE', 'TIME', 'TIMESTAMP', 'INTERVAL', 'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND', 'ZONE', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'LOCALTIME', 'LOCALTIMESTAMP', 'EXTRACT', 'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'JOIN', 'CROSS', 'OUTER', 'INNER', 'LEFT', 'RIGHT', 'FULL', 'NATURAL', 'USING', 'ON', 'FILTER', 'OVER', 'PARTITION', 'RANGE', 'ROWS', 'UNBOUNDED', 'PRECEDING', 'FOLLOWING', 'CURRENT', 'ROW', 'WITH', 'RECURSIVE', 'VALUES', 'CREATE', 'SCHEMA', 'TABLE', 'VIEW', 'REPLACE', 'INSERT', 'DELETE', 'INTO', 'CONSTRAINT', 'DESCRIBE', 'GRANT', 'REVOKE', 'PRIVILEGES', 'PUBLIC', 'OPTION', 'EXPLAIN', 'ANALYZE', 'FORMAT', 'TYPE', 'TEXT', 'GRAPHVIZ', 'LOGICAL', 'DISTRIBUTED', 'CAST', 'TRY_CAST', 'SHOW', 'TABLES', 'SCHEMAS', 'CATALOGS', 'COLUMNS', 'COLUMN', 'USE', 'PARTITIONS', 'FUNCTIONS', 'DROP', 'UNION', 'EXCEPT', 'INTERSECT', 'TO', 'SYSTEM', 'BERNOULLI', 'POISSONIZED', 'TABLESAMPLE', 'ALTER', 'RENAME', 'UNNEST', 'ORDINALITY', 'ARRAY', 'MAP', 'SET', 'RESET', 'SESSION', 'DATA', 'START', 'TRANSACTION', 'COMMIT', 'ROLLBACK', 'WORK', 'ISOLATION', 'LEVEL', 'SERIALIZABLE', 'REPEATABLE', 'COMMITTED', 'UNCOMMITTED', 'READ', 'WRITE', 'ONLY', 'CALL', 'PREPARE', 'DEALLOCATE', 'EXECUTE', 'INPUT', 'OUTPUT', 'CASCADE', 'RESTRICT', 'INCLUDING', 'EXCLUDING', 'PROPERTIES', 'NORMALIZE', 'NFD', 'NFC', 'NFKD', 'NFKC', 'IF', 'NULLIF', 'COALESCE', 'EQ', 'NEQ', 'LT', 'LTE', 'GT', 'GTE', 'PLUS', 'MINUS', 'ASTERISK', 'SLASH', 'PERCENT', 'CONCAT', 'STRING', 'BINARY_LITERAL', 'INTEGER_VALUE', 'DECIMAL_VALUE', 'IDENTIFIER', 'DIGIT_IDENTIFIER', 'QUOTED_IDENTIFIER', 'BACKQUOTED_IDENTIFIER', 'TIME_WITH_TIME_ZONE', 'TIMESTAMP_WITH_TIME_ZONE', 'DOUBLE_PRECISION', 'EXPONENT', 'DIGIT', 'LETTER', 'SIMPLE_COMMENT', 'BRACKETED_COMMENT', 'WS', 'SEMICOLON', 'UNRECOGNIZED', ]; SqlBaseLexer.prototype.grammarFileName = 'SqlBase.g4'; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseListener.ts ================================================ // Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7 // jshint ignore: start import { tree } from 'antlr4'; // This class defines a complete listener for a parse tree produced by SqlBaseParser. export const SqlBaseListener = function() { tree.ParseTreeListener.call(this); return this; } as any; SqlBaseListener.prototype = Object.create(tree.ParseTreeListener.prototype); SqlBaseListener.prototype.constructor = SqlBaseListener; // Enter a parse tree produced by SqlBaseParser#multiStatement. SqlBaseListener.prototype.enterMultiStatement = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#multiStatement. SqlBaseListener.prototype.exitMultiStatement = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#singleStatement. SqlBaseListener.prototype.enterSingleStatement = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#singleStatement. SqlBaseListener.prototype.exitSingleStatement = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#singleExpression. SqlBaseListener.prototype.enterSingleExpression = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#singleExpression. SqlBaseListener.prototype.exitSingleExpression = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#statementDefault. SqlBaseListener.prototype.enterStatementDefault = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#statementDefault. SqlBaseListener.prototype.exitStatementDefault = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#use. SqlBaseListener.prototype.enterUse = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#use. SqlBaseListener.prototype.exitUse = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#createSchema. SqlBaseListener.prototype.enterCreateSchema = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#createSchema. SqlBaseListener.prototype.exitCreateSchema = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#dropSchema. SqlBaseListener.prototype.enterDropSchema = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#dropSchema. SqlBaseListener.prototype.exitDropSchema = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#renameSchema. SqlBaseListener.prototype.enterRenameSchema = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#renameSchema. SqlBaseListener.prototype.exitRenameSchema = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#createTableAsSelect. SqlBaseListener.prototype.enterCreateTableAsSelect = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#createTableAsSelect. SqlBaseListener.prototype.exitCreateTableAsSelect = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#createTable. SqlBaseListener.prototype.enterCreateTable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#createTable. SqlBaseListener.prototype.exitCreateTable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#dropTable. SqlBaseListener.prototype.enterDropTable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#dropTable. SqlBaseListener.prototype.exitDropTable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#insertInto. SqlBaseListener.prototype.enterInsertInto = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#insertInto. SqlBaseListener.prototype.exitInsertInto = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#delete. SqlBaseListener.prototype.enterDelete = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#delete. SqlBaseListener.prototype.exitDelete = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#renameTable. SqlBaseListener.prototype.enterRenameTable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#renameTable. SqlBaseListener.prototype.exitRenameTable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#renameColumn. SqlBaseListener.prototype.enterRenameColumn = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#renameColumn. SqlBaseListener.prototype.exitRenameColumn = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#addColumn. SqlBaseListener.prototype.enterAddColumn = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#addColumn. SqlBaseListener.prototype.exitAddColumn = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#createView. SqlBaseListener.prototype.enterCreateView = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#createView. SqlBaseListener.prototype.exitCreateView = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#dropView. SqlBaseListener.prototype.enterDropView = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#dropView. SqlBaseListener.prototype.exitDropView = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#call. SqlBaseListener.prototype.enterCall = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#call. SqlBaseListener.prototype.exitCall = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#grant. SqlBaseListener.prototype.enterGrant = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#grant. SqlBaseListener.prototype.exitGrant = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#revoke. SqlBaseListener.prototype.enterRevoke = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#revoke. SqlBaseListener.prototype.exitRevoke = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#explain. SqlBaseListener.prototype.enterExplain = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#explain. SqlBaseListener.prototype.exitExplain = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showCreateTable. SqlBaseListener.prototype.enterShowCreateTable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showCreateTable. SqlBaseListener.prototype.exitShowCreateTable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showCreateView. SqlBaseListener.prototype.enterShowCreateView = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showCreateView. SqlBaseListener.prototype.exitShowCreateView = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showTables. SqlBaseListener.prototype.enterShowTables = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showTables. SqlBaseListener.prototype.exitShowTables = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showSchemas. SqlBaseListener.prototype.enterShowSchemas = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showSchemas. SqlBaseListener.prototype.exitShowSchemas = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showCatalogs. SqlBaseListener.prototype.enterShowCatalogs = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showCatalogs. SqlBaseListener.prototype.exitShowCatalogs = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showColumns. SqlBaseListener.prototype.enterShowColumns = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showColumns. SqlBaseListener.prototype.exitShowColumns = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showFunctions. SqlBaseListener.prototype.enterShowFunctions = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showFunctions. SqlBaseListener.prototype.exitShowFunctions = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showSession. SqlBaseListener.prototype.enterShowSession = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showSession. SqlBaseListener.prototype.exitShowSession = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#setSession. SqlBaseListener.prototype.enterSetSession = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#setSession. SqlBaseListener.prototype.exitSetSession = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#resetSession. SqlBaseListener.prototype.enterResetSession = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#resetSession. SqlBaseListener.prototype.exitResetSession = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#startTransaction. SqlBaseListener.prototype.enterStartTransaction = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#startTransaction. SqlBaseListener.prototype.exitStartTransaction = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#commit. SqlBaseListener.prototype.enterCommit = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#commit. SqlBaseListener.prototype.exitCommit = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#rollback. SqlBaseListener.prototype.enterRollback = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#rollback. SqlBaseListener.prototype.exitRollback = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#showPartitions. SqlBaseListener.prototype.enterShowPartitions = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#showPartitions. SqlBaseListener.prototype.exitShowPartitions = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#prepare. SqlBaseListener.prototype.enterPrepare = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#prepare. SqlBaseListener.prototype.exitPrepare = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#deallocate. SqlBaseListener.prototype.enterDeallocate = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#deallocate. SqlBaseListener.prototype.exitDeallocate = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#execute. SqlBaseListener.prototype.enterExecute = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#execute. SqlBaseListener.prototype.exitExecute = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#describeInput. SqlBaseListener.prototype.enterDescribeInput = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#describeInput. SqlBaseListener.prototype.exitDescribeInput = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#describeOutput. SqlBaseListener.prototype.enterDescribeOutput = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#describeOutput. SqlBaseListener.prototype.exitDescribeOutput = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#query. SqlBaseListener.prototype.enterQuery = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#query. SqlBaseListener.prototype.exitQuery = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#presto_with. SqlBaseListener.prototype.enterPresto_with = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#presto_with. SqlBaseListener.prototype.exitPresto_with = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#tableElement. SqlBaseListener.prototype.enterTableElement = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#tableElement. SqlBaseListener.prototype.exitTableElement = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#columnDefinition. SqlBaseListener.prototype.enterColumnDefinition = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#columnDefinition. SqlBaseListener.prototype.exitColumnDefinition = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#likeClause. SqlBaseListener.prototype.enterLikeClause = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#likeClause. SqlBaseListener.prototype.exitLikeClause = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#tableProperties. SqlBaseListener.prototype.enterTableProperties = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#tableProperties. SqlBaseListener.prototype.exitTableProperties = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#tableProperty. SqlBaseListener.prototype.enterTableProperty = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#tableProperty. SqlBaseListener.prototype.exitTableProperty = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#queryNoWith. SqlBaseListener.prototype.enterQueryNoWith = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#queryNoWith. SqlBaseListener.prototype.exitQueryNoWith = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#queryTermDefault. SqlBaseListener.prototype.enterQueryTermDefault = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#queryTermDefault. SqlBaseListener.prototype.exitQueryTermDefault = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#setOperation. SqlBaseListener.prototype.enterSetOperation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#setOperation. SqlBaseListener.prototype.exitSetOperation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#queryPrimaryDefault. SqlBaseListener.prototype.enterQueryPrimaryDefault = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#queryPrimaryDefault. SqlBaseListener.prototype.exitQueryPrimaryDefault = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#table. SqlBaseListener.prototype.enterTable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#table. SqlBaseListener.prototype.exitTable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#inlineTable. SqlBaseListener.prototype.enterInlineTable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#inlineTable. SqlBaseListener.prototype.exitInlineTable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#subquery. SqlBaseListener.prototype.enterSubquery = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#subquery. SqlBaseListener.prototype.exitSubquery = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#sortItem. SqlBaseListener.prototype.enterSortItem = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#sortItem. SqlBaseListener.prototype.exitSortItem = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#querySpecification. SqlBaseListener.prototype.enterQuerySpecification = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#querySpecification. SqlBaseListener.prototype.exitQuerySpecification = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#groupBy. SqlBaseListener.prototype.enterGroupBy = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#groupBy. SqlBaseListener.prototype.exitGroupBy = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#singleGroupingSet. SqlBaseListener.prototype.enterSingleGroupingSet = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#singleGroupingSet. SqlBaseListener.prototype.exitSingleGroupingSet = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#rollup. SqlBaseListener.prototype.enterRollup = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#rollup. SqlBaseListener.prototype.exitRollup = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#cube. SqlBaseListener.prototype.enterCube = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#cube. SqlBaseListener.prototype.exitCube = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#multipleGroupingSets. SqlBaseListener.prototype.enterMultipleGroupingSets = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#multipleGroupingSets. SqlBaseListener.prototype.exitMultipleGroupingSets = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#groupingExpressions. SqlBaseListener.prototype.enterGroupingExpressions = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#groupingExpressions. SqlBaseListener.prototype.exitGroupingExpressions = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#groupingSet. SqlBaseListener.prototype.enterGroupingSet = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#groupingSet. SqlBaseListener.prototype.exitGroupingSet = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#namedQuery. SqlBaseListener.prototype.enterNamedQuery = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#namedQuery. SqlBaseListener.prototype.exitNamedQuery = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#setQuantifier. SqlBaseListener.prototype.enterSetQuantifier = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#setQuantifier. SqlBaseListener.prototype.exitSetQuantifier = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#selectSingle. SqlBaseListener.prototype.enterSelectSingle = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#selectSingle. SqlBaseListener.prototype.exitSelectSingle = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#selectAll. SqlBaseListener.prototype.enterSelectAll = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#selectAll. SqlBaseListener.prototype.exitSelectAll = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#relationDefault. SqlBaseListener.prototype.enterRelationDefault = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#relationDefault. SqlBaseListener.prototype.exitRelationDefault = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#joinRelation. SqlBaseListener.prototype.enterJoinRelation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#joinRelation. SqlBaseListener.prototype.exitJoinRelation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#joinType. SqlBaseListener.prototype.enterJoinType = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#joinType. SqlBaseListener.prototype.exitJoinType = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#joinCriteria. SqlBaseListener.prototype.enterJoinCriteria = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#joinCriteria. SqlBaseListener.prototype.exitJoinCriteria = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#sampledRelation. SqlBaseListener.prototype.enterSampledRelation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#sampledRelation. SqlBaseListener.prototype.exitSampledRelation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#sampleType. SqlBaseListener.prototype.enterSampleType = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#sampleType. SqlBaseListener.prototype.exitSampleType = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#aliasedRelation. SqlBaseListener.prototype.enterAliasedRelation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#aliasedRelation. SqlBaseListener.prototype.exitAliasedRelation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#columnAliases. SqlBaseListener.prototype.enterColumnAliases = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#columnAliases. SqlBaseListener.prototype.exitColumnAliases = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#tableName. SqlBaseListener.prototype.enterTableName = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#tableName. SqlBaseListener.prototype.exitTableName = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#subqueryRelation. SqlBaseListener.prototype.enterSubqueryRelation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#subqueryRelation. SqlBaseListener.prototype.exitSubqueryRelation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#unnest. SqlBaseListener.prototype.enterUnnest = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#unnest. SqlBaseListener.prototype.exitUnnest = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#parenthesizedRelation. SqlBaseListener.prototype.enterParenthesizedRelation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#parenthesizedRelation. SqlBaseListener.prototype.exitParenthesizedRelation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#expression. SqlBaseListener.prototype.enterExpression = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#expression. SqlBaseListener.prototype.exitExpression = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#logicalNot. SqlBaseListener.prototype.enterLogicalNot = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#logicalNot. SqlBaseListener.prototype.exitLogicalNot = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#booleanDefault. SqlBaseListener.prototype.enterBooleanDefault = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#booleanDefault. SqlBaseListener.prototype.exitBooleanDefault = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#logicalBinary. SqlBaseListener.prototype.enterLogicalBinary = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#logicalBinary. SqlBaseListener.prototype.exitLogicalBinary = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#predicated. SqlBaseListener.prototype.enterPredicated = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#predicated. SqlBaseListener.prototype.exitPredicated = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#comparison. SqlBaseListener.prototype.enterComparison = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#comparison. SqlBaseListener.prototype.exitComparison = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#quantifiedComparison. SqlBaseListener.prototype.enterQuantifiedComparison = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#quantifiedComparison. SqlBaseListener.prototype.exitQuantifiedComparison = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#between. SqlBaseListener.prototype.enterBetween = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#between. SqlBaseListener.prototype.exitBetween = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#inList. SqlBaseListener.prototype.enterInList = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#inList. SqlBaseListener.prototype.exitInList = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#inSubquery. SqlBaseListener.prototype.enterInSubquery = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#inSubquery. SqlBaseListener.prototype.exitInSubquery = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#like. SqlBaseListener.prototype.enterLike = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#like. SqlBaseListener.prototype.exitLike = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#nullPredicate. SqlBaseListener.prototype.enterNullPredicate = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#nullPredicate. SqlBaseListener.prototype.exitNullPredicate = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#distinctFrom. SqlBaseListener.prototype.enterDistinctFrom = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#distinctFrom. SqlBaseListener.prototype.exitDistinctFrom = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#valueExpressionDefault. SqlBaseListener.prototype.enterValueExpressionDefault = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#valueExpressionDefault. SqlBaseListener.prototype.exitValueExpressionDefault = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#concatenation. SqlBaseListener.prototype.enterConcatenation = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#concatenation. SqlBaseListener.prototype.exitConcatenation = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#arithmeticBinary. SqlBaseListener.prototype.enterArithmeticBinary = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#arithmeticBinary. SqlBaseListener.prototype.exitArithmeticBinary = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#arithmeticUnary. SqlBaseListener.prototype.enterArithmeticUnary = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#arithmeticUnary. SqlBaseListener.prototype.exitArithmeticUnary = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#atTimeZone. SqlBaseListener.prototype.enterAtTimeZone = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#atTimeZone. SqlBaseListener.prototype.exitAtTimeZone = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#dereference. SqlBaseListener.prototype.enterDereference = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#dereference. SqlBaseListener.prototype.exitDereference = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#typeConstructor. SqlBaseListener.prototype.enterTypeConstructor = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#typeConstructor. SqlBaseListener.prototype.exitTypeConstructor = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#specialDateTimeFunction. SqlBaseListener.prototype.enterSpecialDateTimeFunction = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#specialDateTimeFunction. SqlBaseListener.prototype.exitSpecialDateTimeFunction = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#substring. SqlBaseListener.prototype.enterSubstring = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#substring. SqlBaseListener.prototype.exitSubstring = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#cast. SqlBaseListener.prototype.enterCast = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#cast. SqlBaseListener.prototype.exitCast = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#lambda. SqlBaseListener.prototype.enterLambda = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#lambda. SqlBaseListener.prototype.exitLambda = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#parameter. SqlBaseListener.prototype.enterParameter = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#parameter. SqlBaseListener.prototype.exitParameter = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#normalize. SqlBaseListener.prototype.enterNormalize = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#normalize. SqlBaseListener.prototype.exitNormalize = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#intervalLiteral. SqlBaseListener.prototype.enterIntervalLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#intervalLiteral. SqlBaseListener.prototype.exitIntervalLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#numericLiteral. SqlBaseListener.prototype.enterNumericLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#numericLiteral. SqlBaseListener.prototype.exitNumericLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#booleanLiteral. SqlBaseListener.prototype.enterBooleanLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#booleanLiteral. SqlBaseListener.prototype.exitBooleanLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#implicitRowConstructor. SqlBaseListener.prototype.enterImplicitRowConstructor = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#implicitRowConstructor. SqlBaseListener.prototype.exitImplicitRowConstructor = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#simpleCase. SqlBaseListener.prototype.enterSimpleCase = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#simpleCase. SqlBaseListener.prototype.exitSimpleCase = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#columnReference. SqlBaseListener.prototype.enterColumnReference = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#columnReference. SqlBaseListener.prototype.exitColumnReference = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#nullLiteral. SqlBaseListener.prototype.enterNullLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#nullLiteral. SqlBaseListener.prototype.exitNullLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#rowConstructor. SqlBaseListener.prototype.enterRowConstructor = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#rowConstructor. SqlBaseListener.prototype.exitRowConstructor = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#subscript. SqlBaseListener.prototype.enterSubscript = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#subscript. SqlBaseListener.prototype.exitSubscript = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#subqueryExpression. SqlBaseListener.prototype.enterSubqueryExpression = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#subqueryExpression. SqlBaseListener.prototype.exitSubqueryExpression = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#binaryLiteral. SqlBaseListener.prototype.enterBinaryLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#binaryLiteral. SqlBaseListener.prototype.exitBinaryLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#extract. SqlBaseListener.prototype.enterExtract = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#extract. SqlBaseListener.prototype.exitExtract = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#stringLiteral. SqlBaseListener.prototype.enterStringLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#stringLiteral. SqlBaseListener.prototype.exitStringLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#arrayConstructor. SqlBaseListener.prototype.enterArrayConstructor = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#arrayConstructor. SqlBaseListener.prototype.exitArrayConstructor = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#functionCall. SqlBaseListener.prototype.enterFunctionCall = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#functionCall. SqlBaseListener.prototype.exitFunctionCall = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#exists. SqlBaseListener.prototype.enterExists = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#exists. SqlBaseListener.prototype.exitExists = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#position. SqlBaseListener.prototype.enterPosition = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#position. SqlBaseListener.prototype.exitPosition = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#searchedCase. SqlBaseListener.prototype.enterSearchedCase = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#searchedCase. SqlBaseListener.prototype.exitSearchedCase = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#timeZoneInterval. SqlBaseListener.prototype.enterTimeZoneInterval = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#timeZoneInterval. SqlBaseListener.prototype.exitTimeZoneInterval = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#timeZoneString. SqlBaseListener.prototype.enterTimeZoneString = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#timeZoneString. SqlBaseListener.prototype.exitTimeZoneString = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#comparisonOperator. SqlBaseListener.prototype.enterComparisonOperator = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#comparisonOperator. SqlBaseListener.prototype.exitComparisonOperator = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#comparisonQuantifier. SqlBaseListener.prototype.enterComparisonQuantifier = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#comparisonQuantifier. SqlBaseListener.prototype.exitComparisonQuantifier = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#booleanValue. SqlBaseListener.prototype.enterBooleanValue = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#booleanValue. SqlBaseListener.prototype.exitBooleanValue = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#interval. SqlBaseListener.prototype.enterInterval = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#interval. SqlBaseListener.prototype.exitInterval = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#intervalField. SqlBaseListener.prototype.enterIntervalField = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#intervalField. SqlBaseListener.prototype.exitIntervalField = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#type. SqlBaseListener.prototype.enterType = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#type. SqlBaseListener.prototype.exitType = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#typeParameter. SqlBaseListener.prototype.enterTypeParameter = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#typeParameter. SqlBaseListener.prototype.exitTypeParameter = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#baseType. SqlBaseListener.prototype.enterBaseType = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#baseType. SqlBaseListener.prototype.exitBaseType = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#whenClause. SqlBaseListener.prototype.enterWhenClause = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#whenClause. SqlBaseListener.prototype.exitWhenClause = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#filter. SqlBaseListener.prototype.enterFilter = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#filter. SqlBaseListener.prototype.exitFilter = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#over. SqlBaseListener.prototype.enterOver = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#over. SqlBaseListener.prototype.exitOver = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#windowFrame. SqlBaseListener.prototype.enterWindowFrame = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#windowFrame. SqlBaseListener.prototype.exitWindowFrame = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#unboundedFrame. SqlBaseListener.prototype.enterUnboundedFrame = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#unboundedFrame. SqlBaseListener.prototype.exitUnboundedFrame = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#currentRowBound. SqlBaseListener.prototype.enterCurrentRowBound = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#currentRowBound. SqlBaseListener.prototype.exitCurrentRowBound = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#boundedFrame. SqlBaseListener.prototype.enterBoundedFrame = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#boundedFrame. SqlBaseListener.prototype.exitBoundedFrame = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#explainFormat. SqlBaseListener.prototype.enterExplainFormat = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#explainFormat. SqlBaseListener.prototype.exitExplainFormat = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#explainType. SqlBaseListener.prototype.enterExplainType = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#explainType. SqlBaseListener.prototype.exitExplainType = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#isolationLevel. SqlBaseListener.prototype.enterIsolationLevel = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#isolationLevel. SqlBaseListener.prototype.exitIsolationLevel = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#transactionAccessMode. SqlBaseListener.prototype.enterTransactionAccessMode = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#transactionAccessMode. SqlBaseListener.prototype.exitTransactionAccessMode = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#readUncommitted. SqlBaseListener.prototype.enterReadUncommitted = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#readUncommitted. SqlBaseListener.prototype.exitReadUncommitted = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#readCommitted. SqlBaseListener.prototype.enterReadCommitted = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#readCommitted. SqlBaseListener.prototype.exitReadCommitted = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#repeatableRead. SqlBaseListener.prototype.enterRepeatableRead = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#repeatableRead. SqlBaseListener.prototype.exitRepeatableRead = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#serializable. SqlBaseListener.prototype.enterSerializable = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#serializable. SqlBaseListener.prototype.exitSerializable = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#positionalArgument. SqlBaseListener.prototype.enterPositionalArgument = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#positionalArgument. SqlBaseListener.prototype.exitPositionalArgument = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#namedArgument. SqlBaseListener.prototype.enterNamedArgument = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#namedArgument. SqlBaseListener.prototype.exitNamedArgument = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#privilege. SqlBaseListener.prototype.enterPrivilege = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#privilege. SqlBaseListener.prototype.exitPrivilege = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#qualifiedName. SqlBaseListener.prototype.enterQualifiedName = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#qualifiedName. SqlBaseListener.prototype.exitQualifiedName = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#unquotedIdentifier. SqlBaseListener.prototype.enterUnquotedIdentifier = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#unquotedIdentifier. SqlBaseListener.prototype.exitUnquotedIdentifier = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#quotedIdentifierAlternative. SqlBaseListener.prototype.enterQuotedIdentifierAlternative = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#quotedIdentifierAlternative. SqlBaseListener.prototype.exitQuotedIdentifierAlternative = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#backQuotedIdentifier. SqlBaseListener.prototype.enterBackQuotedIdentifier = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#backQuotedIdentifier. SqlBaseListener.prototype.exitBackQuotedIdentifier = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#digitIdentifier. SqlBaseListener.prototype.enterDigitIdentifier = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#digitIdentifier. SqlBaseListener.prototype.exitDigitIdentifier = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#quotedIdentifier. SqlBaseListener.prototype.enterQuotedIdentifier = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#quotedIdentifier. SqlBaseListener.prototype.exitQuotedIdentifier = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#decimalLiteral. SqlBaseListener.prototype.enterDecimalLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#decimalLiteral. SqlBaseListener.prototype.exitDecimalLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#integerLiteral. SqlBaseListener.prototype.enterIntegerLiteral = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#integerLiteral. SqlBaseListener.prototype.exitIntegerLiteral = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#nonReserved. SqlBaseListener.prototype.enterNonReserved = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#nonReserved. SqlBaseListener.prototype.exitNonReserved = function(ctx) {}; // Enter a parse tree produced by SqlBaseParser#normalForm. SqlBaseListener.prototype.enterNormalForm = function(ctx) {}; // Exit a parse tree produced by SqlBaseParser#normalForm. SqlBaseListener.prototype.exitNormalForm = function(ctx) {}; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseParser.ts ================================================ // Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7 // jshint ignore: start // @ts-nocheck import { atn as _atn, dfa, PredictionContextCache, Parser, Token, ParserRuleContext, error as _error } from 'antlr4'; import { SqlBaseListener } from './SqlBaseListener'; import { SqlBaseVisitor } from './SqlBaseVisitor'; var grammarFileName = "SqlBase.g4"; var serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964", "\u0003\u00d6\u05e0\u0004\u0002\t\u0002\u0004\u0003\t\u0003\u0004\u0004", "\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007\t\u0007", "\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004\f\t\f", "\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010\t\u0010", "\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013\u0004\u0014", "\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017\t\u0017", "\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a\u0004\u001b", "\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e\t\u001e", "\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#\t#\u0004", "$\t$\u0004%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004*\t*\u0004", "+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u00041\t1\u0004", "2\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u00048\t8\u0004", "9\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004?\t?\u0003", "\u0002\u0003\u0002\u0003\u0002\u0007\u0002\u0082\n\u0002\f\u0002\u000e", "\u0002\u0085\u000b\u0002\u0003\u0002\u0005\u0002\u0088\n\u0002\u0003", "\u0002\u0003\u0002\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0004\u0003", "\u0004\u0003\u0004\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u009f\n\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0005\u0005\u00a4\n\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u00aa\n\u0005\u0003\u0005", "\u0003\u0005\u0005\u0005\u00ae\n\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u00bc\n\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u00c1\n\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u00c7\n\u0005", "\u0003\u0005\u0005\u0005\u00ca\n\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u00d1\n\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0007\u0005\u00d8\n", "\u0005\f\u0005\u000e\u0005\u00db\u000b\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0005\u0005\u00e0\n\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0005\u0005\u00e6\n\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u00ed\n\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0005\u0005\u00f6\n\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005", "\u0112\n\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u011d", "\n\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0007\u0005\u0126\n\u0005\f\u0005\u000e\u0005", "\u0129\u000b\u0005\u0005\u0005\u012b\n\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0007\u0005\u0133\n", "\u0005\f\u0005\u000e\u0005\u0136\u000b\u0005\u0003\u0005\u0003\u0005", "\u0005\u0005\u013a\n\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u013e", "\n\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0005\u0005\u0146\n\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0005\u0005\u014c\n\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0007\u0005\u0151\n\u0005\f\u0005\u000e\u0005\u0154\u000b", "\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u0158\n\u0005\u0003\u0005", "\u0003\u0005\u0005\u0005\u015c\n\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u0164\n\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0007\u0005\u016a\n", "\u0005\f\u0005\u000e\u0005\u016d\u000b\u0005\u0003\u0005\u0003\u0005", "\u0005\u0005\u0171\n\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u0180\n\u0005", "\u0003\u0005\u0003\u0005\u0005\u0005\u0184\n\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u018a\n\u0005\u0003\u0005", "\u0003\u0005\u0005\u0005\u018e\n\u0005\u0003\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0005\u0005\u0194\n\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0007\u0005\u01b0\n\u0005\f\u0005\u000e\u0005\u01b3\u000b\u0005\u0005", "\u0005\u01b5\n\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u01b9\n\u0005", "\u0003\u0005\u0003\u0005\u0005\u0005\u01bd\n\u0005\u0003\u0005\u0003", "\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u01c5", "\n\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0007\u0005\u01cc\n\u0005\f\u0005\u000e\u0005\u01cf\u000b\u0005\u0005", "\u0005\u01d1\n\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u01d5\n\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0007\u0005\u01e5\n\u0005\f\u0005\u000e\u0005", "\u01e8\u000b\u0005\u0005\u0005\u01ea\n\u0005\u0003\u0005\u0003\u0005", "\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005\u0005\u01f2\n", "\u0005\u0003\u0006\u0005\u0006\u01f5\n\u0006\u0003\u0006\u0003\u0006", "\u0003\u0007\u0003\u0007\u0005\u0007\u01fb\n\u0007\u0003\u0007\u0003", "\u0007\u0003\u0007\u0007\u0007\u0200\n\u0007\f\u0007\u000e\u0007\u0203", "\u000b\u0007\u0003\b\u0003\b\u0005\b\u0207\n\b\u0003\t\u0003\t\u0003", "\t\u0003\n\u0003\n\u0003\n\u0003\n\u0005\n\u0210\n\n\u0003\u000b\u0003", "\u000b\u0003\u000b\u0003\u000b\u0007\u000b\u0216\n\u000b\f\u000b\u000e", "\u000b\u0219\u000b\u000b\u0003\u000b\u0003\u000b\u0003\f\u0003\f\u0003", "\f\u0003\f\u0003\r\u0003\r\u0003\r\u0003\r\u0003\r\u0003\r\u0007\r\u0227", "\n\r\f\r\u000e\r\u022a\u000b\r\u0005\r\u022c\n\r\u0003\r\u0003\r\u0005", "\r\u0230\n\r\u0003\u000e\u0003\u000e\u0003\u000e\u0003\u000e\u0003\u000e", "\u0003\u000e\u0005\u000e\u0238\n\u000e\u0003\u000e\u0003\u000e\u0003", "\u000e\u0003\u000e\u0005\u000e\u023e\n\u000e\u0003\u000e\u0007\u000e", "\u0241\n\u000e\f\u000e\u000e\u000e\u0244\u000b\u000e\u0003\u000f\u0003", "\u000f\u0003\u000f\u0003\u000f\u0003\u000f\u0003\u000f\u0003\u000f\u0007", "\u000f\u024d\n\u000f\f\u000f\u000e\u000f\u0250\u000b\u000f\u0003\u000f", "\u0003\u000f\u0003\u000f\u0003\u000f\u0005\u000f\u0256\n\u000f\u0003", "\u0010\u0003\u0010\u0005\u0010\u025a\n\u0010\u0003\u0010\u0003\u0010", "\u0005\u0010\u025e\n\u0010\u0003\u0011\u0003\u0011\u0005\u0011\u0262", "\n\u0011\u0003\u0011\u0003\u0011\u0003\u0011\u0007\u0011\u0267\n\u0011", "\f\u0011\u000e\u0011\u026a\u000b\u0011\u0003\u0011\u0003\u0011\u0003", "\u0011\u0003\u0011\u0007\u0011\u0270\n\u0011\f\u0011\u000e\u0011\u0273", "\u000b\u0011\u0005\u0011\u0275\n\u0011\u0003\u0011\u0003\u0011\u0005", "\u0011\u0279\n\u0011\u0003\u0011\u0003\u0011\u0003\u0011\u0005\u0011", "\u027e\n\u0011\u0003\u0011\u0003\u0011\u0005\u0011\u0282\n\u0011\u0003", "\u0012\u0005\u0012\u0285\n\u0012\u0003\u0012\u0003\u0012\u0003\u0012", "\u0007\u0012\u028a\n\u0012\f\u0012\u000e\u0012\u028d\u000b\u0012\u0003", "\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0007", "\u0013\u0295\n\u0013\f\u0013\u000e\u0013\u0298\u000b\u0013\u0005\u0013", "\u029a\n\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003", "\u0013\u0003\u0013\u0007\u0013\u02a2\n\u0013\f\u0013\u000e\u0013\u02a5", "\u000b\u0013\u0005\u0013\u02a7\n\u0013\u0003\u0013\u0003\u0013\u0003", "\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0007\u0013\u02b0", "\n\u0013\f\u0013\u000e\u0013\u02b3\u000b\u0013\u0003\u0013\u0003\u0013", "\u0005\u0013\u02b7\n\u0013\u0003\u0014\u0003\u0014\u0003\u0014\u0003", "\u0014\u0007\u0014\u02bd\n\u0014\f\u0014\u000e\u0014\u02c0\u000b\u0014", "\u0005\u0014\u02c2\n\u0014\u0003\u0014\u0003\u0014\u0005\u0014\u02c6", "\n\u0014\u0003\u0015\u0003\u0015\u0003\u0015\u0003\u0015\u0007\u0015", "\u02cc\n\u0015\f\u0015\u000e\u0015\u02cf\u000b\u0015\u0005\u0015\u02d1", "\n\u0015\u0003\u0015\u0003\u0015\u0005\u0015\u02d5\n\u0015\u0003\u0016", "\u0003\u0016\u0005\u0016\u02d9\n\u0016\u0003\u0016\u0003\u0016\u0003", "\u0016\u0003\u0016\u0003\u0016\u0003\u0017\u0003\u0017\u0003\u0018\u0003", "\u0018\u0005\u0018\u02e4\n\u0018\u0003\u0018\u0005\u0018\u02e7\n\u0018", "\u0003\u0018\u0003\u0018\u0003\u0018\u0003\u0018\u0003\u0018\u0005\u0018", "\u02ee\n\u0018\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003", "\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003", "\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u0019\u0003", "\u0019\u0005\u0019\u0301\n\u0019\u0007\u0019\u0303\n\u0019\f\u0019\u000e", "\u0019\u0306\u000b\u0019\u0003\u001a\u0005\u001a\u0309\n\u001a\u0003", "\u001a\u0003\u001a\u0005\u001a\u030d\n\u001a\u0003\u001a\u0003\u001a", "\u0005\u001a\u0311\n\u001a\u0003\u001a\u0003\u001a\u0005\u001a\u0315", "\n\u001a\u0005\u001a\u0317\n\u001a\u0003\u001b\u0003\u001b\u0003\u001b", "\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b\u0007\u001b\u0320\n", "\u001b\f\u001b\u000e\u001b\u0323\u000b\u001b\u0003\u001b\u0003\u001b", "\u0005\u001b\u0327\n\u001b\u0003\u001c\u0003\u001c\u0003\u001c\u0003", "\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0005\u001c\u0330\n\u001c", "\u0003\u001d\u0003\u001d\u0003\u001e\u0003\u001e\u0005\u001e\u0336\n", "\u001e\u0003\u001e\u0003\u001e\u0005\u001e\u033a\n\u001e\u0005\u001e", "\u033c\n\u001e\u0003\u001f\u0003\u001f\u0003\u001f\u0003\u001f\u0007", "\u001f\u0342\n\u001f\f\u001f\u000e\u001f\u0345\u000b\u001f\u0003\u001f", "\u0003\u001f\u0003 \u0003 \u0003 \u0003 \u0003 \u0003 \u0003 \u0003", " \u0003 \u0003 \u0007 \u0353\n \f \u000e \u0356\u000b \u0003 \u0003", " \u0003 \u0005 \u035b\n \u0003 \u0003 \u0003 \u0003 \u0005 \u0361\n", " \u0003!\u0003!\u0003\"\u0003\"\u0003\"\u0003\"\u0005\"\u0369\n\"\u0003", "\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0007\"\u0371\n\"\f\"\u000e", "\"\u0374\u000b\"\u0003#\u0003#\u0005#\u0378\n#\u0003$\u0003$\u0003$", "\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0005$\u0384\n$\u0003", "$\u0003$\u0003$\u0003$\u0003$\u0003$\u0005$\u038c\n$\u0003$\u0003$\u0003", "$\u0003$\u0003$\u0007$\u0393\n$\f$\u000e$\u0396\u000b$\u0003$\u0003", "$\u0003$\u0005$\u039b\n$\u0003$\u0003$\u0003$\u0003$\u0003$\u0003$\u0005", "$\u03a3\n$\u0003$\u0003$\u0003$\u0003$\u0005$\u03a9\n$\u0003$\u0003", "$\u0005$\u03ad\n$\u0003$\u0003$\u0003$\u0005$\u03b2\n$\u0003$\u0003", "$\u0003$\u0005$\u03b7\n$\u0003%\u0003%\u0003%\u0003%\u0005%\u03bd\n", "%\u0003%\u0003%\u0003%\u0003%\u0003%\u0003%\u0003%\u0003%\u0003%\u0003", "%\u0003%\u0003%\u0007%\u03cb\n%\f%\u000e%\u03ce\u000b%\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0007&\u03e8\n&\f&\u000e&\u03eb\u000b&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0007&\u03f4\n&\f&\u000e&\u03f7", "\u000b&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0005&\u0400", "\n&\u0003&\u0005&\u0403\n&\u0003&\u0003&\u0003&\u0005&\u0408\n&\u0003", "&\u0003&\u0003&\u0007&\u040d\n&\f&\u000e&\u0410\u000b&\u0005&\u0412", "\n&\u0003&\u0003&\u0005&\u0416\n&\u0003&\u0005&\u0419\n&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0007&\u0423\n&\f&\u000e", "&\u0426\u000b&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0006&\u0438", "\n&\r&\u000e&\u0439\u0003&\u0003&\u0005&\u043e\n&\u0003&\u0003&\u0003", "&\u0003&\u0006&\u0444\n&\r&\u000e&\u0445\u0003&\u0003&\u0005&\u044a", "\n&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0007&\u0461\n&\f&\u000e&\u0464\u000b&\u0005&\u0466\n&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0003&\u0003&\u0005&\u046f\n&\u0003&\u0003", "&\u0003&\u0003&\u0005&\u0475\n&\u0003&\u0003&\u0003&\u0003&\u0005&\u047b", "\n&\u0003&\u0003&\u0003&\u0003&\u0005&\u0481\n&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0005&\u048a\n&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0005&\u0493\n&\u0003&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0005&\u049e\n&\u0003&\u0003&\u0003&\u0003", "&\u0003&\u0003&\u0003&\u0003&\u0007&\u04a8\n&\f&\u000e&\u04ab\u000b", "&\u0003\'\u0003\'\u0003\'\u0003\'\u0003\'\u0003\'\u0005\'\u04b3\n\'", "\u0003(\u0003(\u0003)\u0003)\u0003*\u0003*\u0003+\u0003+\u0005+\u04bd", "\n+\u0003+\u0003+\u0003+\u0003+\u0005+\u04c3\n+\u0003,\u0003,\u0003", "-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003", "-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003-\u0003", "-\u0007-\u04dc\n-\f-\u000e-\u04df\u000b-\u0003-\u0003-\u0003-\u0003", "-\u0003-\u0003-\u0003-\u0007-\u04e8\n-\f-\u000e-\u04eb\u000b-\u0003", "-\u0003-\u0005-\u04ef\n-\u0005-\u04f1\n-\u0003-\u0003-\u0007-\u04f5", "\n-\f-\u000e-\u04f8\u000b-\u0003.\u0003.\u0005.\u04fc\n.\u0003/\u0003", "/\u0003/\u0003/\u0005/\u0502\n/\u00030\u00030\u00030\u00030\u00030\u0003", "1\u00031\u00031\u00031\u00031\u00031\u00032\u00032\u00032\u00032\u0003", "2\u00032\u00032\u00072\u0516\n2\f2\u000e2\u0519\u000b2\u00052\u051b", "\n2\u00032\u00032\u00032\u00032\u00032\u00072\u0522\n2\f2\u000e2\u0525", "\u000b2\u00052\u0527\n2\u00032\u00052\u052a\n2\u00032\u00032\u00033", "\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u00033\u0003", "3\u00033\u00033\u00033\u00033\u00033\u00053\u053e\n3\u00034\u00034\u0003", "4\u00034\u00034\u00034\u00034\u00034\u00034\u00054\u0549\n4\u00035\u0003", "5\u00035\u00035\u00055\u054f\n5\u00036\u00036\u00036\u00036\u00036\u0005", "6\u0556\n6\u00037\u00037\u00037\u00037\u00037\u00037\u00037\u00057\u055f", "\n7\u00038\u00038\u00038\u00038\u00038\u00058\u0566\n8\u00039\u0003", "9\u00039\u00039\u00059\u056c\n9\u0003:\u0003:\u0003:\u0007:\u0571\n", ":\f:\u000e:\u0574\u000b:\u0003;\u0003;\u0003;\u0003;\u0003;\u0005;\u057b", "\n;\u0003<\u0003<\u0003=\u0003=\u0005=\u0581\n=\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0003", ">\u0003>\u0003>\u0003>\u0003>\u0003>\u0003>\u0005>\u05dc\n>\u0003?\u0003", "?\u0003?\u0002\b\u001a0BHJX@\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012", "\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPRTVXZ", "\\^`bdfhjlnprtvxz|\u0002\u0016\u0003\u0002\u00ad\u00ae\u0004\u0002\r", "\r!!\u0004\u0002\u0010\u0010\u00c8\u00c8\u0003\u0002\u00af\u00b0\u0003", "\u0002\u0087\u0088\u0003\u0002/0\u0003\u0002,-\u0004\u0002\u0010\u0010", "\u0013\u0013\u0003\u0002\u008b\u008d\u0003\u0002\u00c0\u00c1\u0003\u0002", "\u00c2\u00c4\u0003\u0002\u00ba\u00bf\u0003\u0002\u0010\u0012\u0003\u0002", ")*\u0003\u0002;@\u0003\u0002]^\u0003\u0002wx\u0003\u0002yz\u0003\u0002", "\u00a5\u00a6\u0003\u0002\u00b3\u00b6\u0002\u070b\u0002~\u0003\u0002", "\u0002\u0002\u0004\u008b\u0003\u0002\u0002\u0002\u0006\u008e\u0003\u0002", "\u0002\u0002\b\u01f1\u0003\u0002\u0002\u0002\n\u01f4\u0003\u0002\u0002", "\u0002\f\u01f8\u0003\u0002\u0002\u0002\u000e\u0206\u0003\u0002\u0002", "\u0002\u0010\u0208\u0003\u0002\u0002\u0002\u0012\u020b\u0003\u0002\u0002", "\u0002\u0014\u0211\u0003\u0002\u0002\u0002\u0016\u021c\u0003\u0002\u0002", "\u0002\u0018\u0220\u0003\u0002\u0002\u0002\u001a\u0231\u0003\u0002\u0002", "\u0002\u001c\u0255\u0003\u0002\u0002\u0002\u001e\u0257\u0003\u0002\u0002", "\u0002 \u025f\u0003\u0002\u0002\u0002\"\u0284\u0003\u0002\u0002\u0002", "$\u02b6\u0003\u0002\u0002\u0002&\u02c5\u0003\u0002\u0002\u0002(\u02d4", "\u0003\u0002\u0002\u0002*\u02d6\u0003\u0002\u0002\u0002,\u02df\u0003", "\u0002\u0002\u0002.\u02ed\u0003\u0002\u0002\u00020\u02ef\u0003\u0002", "\u0002\u00022\u0316\u0003\u0002\u0002\u00024\u0326\u0003\u0002\u0002", "\u00026\u0328\u0003\u0002\u0002\u00028\u0331\u0003\u0002\u0002\u0002", ":\u0333\u0003\u0002\u0002\u0002<\u033d\u0003\u0002\u0002\u0002>\u0360", "\u0003\u0002\u0002\u0002@\u0362\u0003\u0002\u0002\u0002B\u0368\u0003", "\u0002\u0002\u0002D\u0375\u0003\u0002\u0002\u0002F\u03b6\u0003\u0002", "\u0002\u0002H\u03bc\u0003\u0002\u0002\u0002J\u049d\u0003\u0002\u0002", "\u0002L\u04b2\u0003\u0002\u0002\u0002N\u04b4\u0003\u0002\u0002\u0002", "P\u04b6\u0003\u0002\u0002\u0002R\u04b8\u0003\u0002\u0002\u0002T\u04ba", "\u0003\u0002\u0002\u0002V\u04c4\u0003\u0002\u0002\u0002X\u04f0\u0003", "\u0002\u0002\u0002Z\u04fb\u0003\u0002\u0002\u0002\\\u0501\u0003\u0002", "\u0002\u0002^\u0503\u0003\u0002\u0002\u0002`\u0508\u0003\u0002\u0002", "\u0002b\u050e\u0003\u0002\u0002\u0002d\u053d\u0003\u0002\u0002\u0002", "f\u0548\u0003\u0002\u0002\u0002h\u054e\u0003\u0002\u0002\u0002j\u0555", "\u0003\u0002\u0002\u0002l\u055e\u0003\u0002\u0002\u0002n\u0565\u0003", "\u0002\u0002\u0002p\u056b\u0003\u0002\u0002\u0002r\u056d\u0003\u0002", "\u0002\u0002t\u057a\u0003\u0002\u0002\u0002v\u057c\u0003\u0002\u0002", "\u0002x\u0580\u0003\u0002\u0002\u0002z\u05db\u0003\u0002\u0002\u0002", "|\u05dd\u0003\u0002\u0002\u0002~\u0083\u0005\b\u0005\u0002\u007f\u0080", "\u0007\u00d4\u0002\u0002\u0080\u0082\u0005\b\u0005\u0002\u0081\u007f", "\u0003\u0002\u0002\u0002\u0082\u0085\u0003\u0002\u0002\u0002\u0083\u0081", "\u0003\u0002\u0002\u0002\u0083\u0084\u0003\u0002\u0002\u0002\u0084\u0087", "\u0003\u0002\u0002\u0002\u0085\u0083\u0003\u0002\u0002\u0002\u0086\u0088", "\u0007\u00d4\u0002\u0002\u0087\u0086\u0003\u0002\u0002\u0002\u0087\u0088", "\u0003\u0002\u0002\u0002\u0088\u0089\u0003\u0002\u0002\u0002\u0089\u008a", "\u0007\u0002\u0002\u0003\u008a\u0003\u0003\u0002\u0002\u0002\u008b\u008c", "\u0005\b\u0005\u0002\u008c\u008d\u0007\u0002\u0002\u0003\u008d\u0005", "\u0003\u0002\u0002\u0002\u008e\u008f\u0005@!\u0002\u008f\u0090\u0007", "\u0002\u0002\u0003\u0090\u0007\u0003\u0002\u0002\u0002\u0091\u01f2\u0005", "\n\u0006\u0002\u0092\u0093\u0007\u0083\u0002\u0002\u0093\u01f2\u0005", "t;\u0002\u0094\u0095\u0007\u0083\u0002\u0002\u0095\u0096\u0005t;\u0002", "\u0096\u0097\u0007\u0003\u0002\u0002\u0097\u0098\u0005t;\u0002\u0098", "\u01f2\u0003\u0002\u0002\u0002\u0099\u009a\u0007d\u0002\u0002\u009a", "\u009e\u0007e\u0002\u0002\u009b\u009c\u0007\u00b7\u0002\u0002\u009c", "\u009d\u0007\"\u0002\u0002\u009d\u009f\u0007$\u0002\u0002\u009e\u009b", "\u0003\u0002\u0002\u0002\u009e\u009f\u0003\u0002\u0002\u0002\u009f\u00a0", "\u0003\u0002\u0002\u0002\u00a0\u00a3\u0005r:\u0002\u00a1\u00a2\u0007", "a\u0002\u0002\u00a2\u00a4\u0005\u0014\u000b\u0002\u00a3\u00a1\u0003", "\u0002\u0002\u0002\u00a3\u00a4\u0003\u0002\u0002\u0002\u00a4\u01f2\u0003", "\u0002\u0002\u0002\u00a5\u00a6\u0007\u0086\u0002\u0002\u00a6\u00a9\u0007", "e\u0002\u0002\u00a7\u00a8\u0007\u00b7\u0002\u0002\u00a8\u00aa\u0007", "$\u0002\u0002\u00a9\u00a7\u0003\u0002\u0002\u0002\u00a9\u00aa\u0003", "\u0002\u0002\u0002\u00aa\u00ab\u0003\u0002\u0002\u0002\u00ab\u00ad\u0005", "r:\u0002\u00ac\u00ae\t\u0002\u0002\u0002\u00ad\u00ac\u0003\u0002\u0002", "\u0002\u00ad\u00ae\u0003\u0002\u0002\u0002\u00ae\u01f2\u0003\u0002\u0002", "\u0002\u00af\u00b0\u0007\u008f\u0002\u0002\u00b0\u00b1\u0007e\u0002", "\u0002\u00b1\u00b2\u0005r:\u0002\u00b2\u00b3\u0007\u0090\u0002\u0002", "\u00b3\u00b4\u0007\u008a\u0002\u0002\u00b4\u00b5\u0005t;\u0002\u00b5", "\u01f2\u0003\u0002\u0002\u0002\u00b6\u00b7\u0007d\u0002\u0002\u00b7", "\u00bb\u0007f\u0002\u0002\u00b8\u00b9\u0007\u00b7\u0002\u0002\u00b9", "\u00ba\u0007\"\u0002\u0002\u00ba\u00bc\u0007$\u0002\u0002\u00bb\u00b8", "\u0003\u0002\u0002\u0002\u00bb\u00bc\u0003\u0002\u0002\u0002\u00bc\u00bd", "\u0003\u0002\u0002\u0002\u00bd\u00c0\u0005r:\u0002\u00be\u00bf\u0007", "a\u0002\u0002\u00bf\u00c1\u0005\u0014\u000b\u0002\u00c0\u00be\u0003", "\u0002\u0002\u0002\u00c0\u00c1\u0003\u0002\u0002\u0002\u00c1\u00c2\u0003", "\u0002\u0002\u0002\u00c2\u00c3\u0007\u000f\u0002\u0002\u00c3\u00c9\u0005", "\n\u0006\u0002\u00c4\u00c6\u0007a\u0002\u0002\u00c5\u00c7\u0007#\u0002", "\u0002\u00c6\u00c5\u0003\u0002\u0002\u0002\u00c6\u00c7\u0003\u0002\u0002", "\u0002\u00c7\u00c8\u0003\u0002\u0002\u0002\u00c8\u00ca\u0007\u0098\u0002", "\u0002\u00c9\u00c4\u0003\u0002\u0002\u0002\u00c9\u00ca\u0003\u0002\u0002", "\u0002\u00ca\u01f2\u0003\u0002\u0002\u0002\u00cb\u00cc\u0007d\u0002", "\u0002\u00cc\u00d0\u0007f\u0002\u0002\u00cd\u00ce\u0007\u00b7\u0002", "\u0002\u00ce\u00cf\u0007\"\u0002\u0002\u00cf\u00d1\u0007$\u0002\u0002", "\u00d0\u00cd\u0003\u0002\u0002\u0002\u00d0\u00d1\u0003\u0002\u0002\u0002", "\u00d1\u00d2\u0003\u0002\u0002\u0002\u00d2\u00d3\u0005r:\u0002\u00d3", "\u00d4\u0007\u0004\u0002\u0002\u00d4\u00d9\u0005\u000e\b\u0002\u00d5", "\u00d6\u0007\u0005\u0002\u0002\u00d6\u00d8\u0005\u000e\b\u0002\u00d7", "\u00d5\u0003\u0002\u0002\u0002\u00d8\u00db\u0003\u0002\u0002\u0002\u00d9", "\u00d7\u0003\u0002\u0002\u0002\u00d9\u00da\u0003\u0002\u0002\u0002\u00da", "\u00dc\u0003\u0002\u0002\u0002\u00db\u00d9\u0003\u0002\u0002\u0002\u00dc", "\u00df\u0007\u0006\u0002\u0002\u00dd\u00de\u0007a\u0002\u0002\u00de", "\u00e0\u0005\u0014\u000b\u0002\u00df\u00dd\u0003\u0002\u0002\u0002\u00df", "\u00e0\u0003\u0002\u0002\u0002\u00e0\u01f2\u0003\u0002\u0002\u0002\u00e1", "\u00e2\u0007\u0086\u0002\u0002\u00e2\u00e5\u0007f\u0002\u0002\u00e3", "\u00e4\u0007\u00b7\u0002\u0002\u00e4\u00e6\u0007$\u0002\u0002\u00e5", "\u00e3\u0003\u0002\u0002\u0002\u00e5\u00e6\u0003\u0002\u0002\u0002\u00e6", "\u00e7\u0003\u0002\u0002\u0002\u00e7\u01f2\u0005r:\u0002\u00e8\u00e9", "\u0007i\u0002\u0002\u00e9\u00ea\u0007k\u0002\u0002\u00ea\u00ec\u0005", "r:\u0002\u00eb\u00ed\u0005<\u001f\u0002\u00ec\u00eb\u0003\u0002\u0002", "\u0002\u00ec\u00ed\u0003\u0002\u0002\u0002\u00ed\u00ee\u0003\u0002\u0002", "\u0002\u00ee\u00ef\u0005\n\u0006\u0002\u00ef\u01f2\u0003\u0002\u0002", "\u0002\u00f0\u00f1\u0007j\u0002\u0002\u00f1\u00f2\u0007\r\u0002\u0002", "\u00f2\u00f5\u0005r:\u0002\u00f3\u00f4\u0007\u0014\u0002\u0002\u00f4", "\u00f6\u0005B\"\u0002\u00f5\u00f3\u0003\u0002\u0002\u0002\u00f5\u00f6", "\u0003\u0002\u0002\u0002\u00f6\u01f2\u0003\u0002\u0002\u0002\u00f7\u00f8", "\u0007\u008f\u0002\u0002\u00f8\u00f9\u0007f\u0002\u0002\u00f9\u00fa", "\u0005r:\u0002\u00fa\u00fb\u0007\u0090\u0002\u0002\u00fb\u00fc\u0007", "\u008a\u0002\u0002\u00fc\u00fd\u0005r:\u0002\u00fd\u01f2\u0003\u0002", "\u0002\u0002\u00fe\u00ff\u0007\u008f\u0002\u0002\u00ff\u0100\u0007f", "\u0002\u0002\u0100\u0101\u0005r:\u0002\u0101\u0102\u0007\u0090\u0002", "\u0002\u0102\u0103\u0007\u0082\u0002\u0002\u0103\u0104\u0005t;\u0002", "\u0104\u0105\u0007\u008a\u0002\u0002\u0105\u0106\u0005t;\u0002\u0106", "\u01f2\u0003\u0002\u0002\u0002\u0107\u0108\u0007\u008f\u0002\u0002\u0108", "\u0109\u0007f\u0002\u0002\u0109\u010a\u0005r:\u0002\u010a\u010b\u0007", "\u000e\u0002\u0002\u010b\u010c\u0007\u0082\u0002\u0002\u010c\u010d\u0005", "\u0010\t\u0002\u010d\u01f2\u0003\u0002\u0002\u0002\u010e\u0111\u0007", "d\u0002\u0002\u010f\u0110\u0007\u001f\u0002\u0002\u0110\u0112\u0007", "h\u0002\u0002\u0111\u010f\u0003\u0002\u0002\u0002\u0111\u0112\u0003", "\u0002\u0002\u0002\u0112\u0113\u0003\u0002\u0002\u0002\u0113\u0114\u0007", "g\u0002\u0002\u0114\u0115\u0005r:\u0002\u0115\u0116\u0007\u000f\u0002", "\u0002\u0116\u0117\u0005\n\u0006\u0002\u0117\u01f2\u0003\u0002\u0002", "\u0002\u0118\u0119\u0007\u0086\u0002\u0002\u0119\u011c\u0007g\u0002", "\u0002\u011a\u011b\u0007\u00b7\u0002\u0002\u011b\u011d\u0007$\u0002", "\u0002\u011c\u011a\u0003\u0002\u0002\u0002\u011c\u011d\u0003\u0002\u0002", "\u0002\u011d\u011e\u0003\u0002\u0002\u0002\u011e\u01f2\u0005r:\u0002", "\u011f\u0120\u0007\u00a7\u0002\u0002\u0120\u0121\u0005r:\u0002\u0121", "\u012a\u0007\u0004\u0002\u0002\u0122\u0127\u0005n8\u0002\u0123\u0124", "\u0007\u0005\u0002\u0002\u0124\u0126\u0005n8\u0002\u0125\u0123\u0003", "\u0002\u0002\u0002\u0126\u0129\u0003\u0002\u0002\u0002\u0127\u0125\u0003", "\u0002\u0002\u0002\u0127\u0128\u0003\u0002\u0002\u0002\u0128\u012b\u0003", "\u0002\u0002\u0002\u0129\u0127\u0003\u0002\u0002\u0002\u012a\u0122\u0003", "\u0002\u0002\u0002\u012a\u012b\u0003\u0002\u0002\u0002\u012b\u012c\u0003", "\u0002\u0002\u0002\u012c\u012d\u0007\u0006\u0002\u0002\u012d\u01f2\u0003", "\u0002\u0002\u0002\u012e\u0139\u0007n\u0002\u0002\u012f\u0134\u0005", "p9\u0002\u0130\u0131\u0007\u0005\u0002\u0002\u0131\u0133\u0005p9\u0002", "\u0132\u0130\u0003\u0002\u0002\u0002\u0133\u0136\u0003\u0002\u0002\u0002", "\u0134\u0132\u0003\u0002\u0002\u0002\u0134\u0135\u0003\u0002\u0002\u0002", "\u0135\u013a\u0003\u0002\u0002\u0002\u0136\u0134\u0003\u0002\u0002\u0002", "\u0137\u0138\u0007\u0010\u0002\u0002\u0138\u013a\u0007p\u0002\u0002", "\u0139\u012f\u0003\u0002\u0002\u0002\u0139\u0137\u0003\u0002\u0002\u0002", "\u013a\u013b\u0003\u0002\u0002\u0002\u013b\u013d\u0007V\u0002\u0002", "\u013c\u013e\u0007f\u0002\u0002\u013d\u013c\u0003\u0002\u0002\u0002", "\u013d\u013e\u0003\u0002\u0002\u0002\u013e\u013f\u0003\u0002\u0002\u0002", "\u013f\u0140\u0005r:\u0002\u0140\u0141\u0007\u008a\u0002\u0002\u0141", "\u0145\u0005t;\u0002\u0142\u0143\u0007a\u0002\u0002\u0143\u0144\u0007", "n\u0002\u0002\u0144\u0146\u0007r\u0002\u0002\u0145\u0142\u0003\u0002", "\u0002\u0002\u0145\u0146\u0003\u0002\u0002\u0002\u0146\u01f2\u0003\u0002", "\u0002\u0002\u0147\u014b\u0007o\u0002\u0002\u0148\u0149\u0007n\u0002", "\u0002\u0149\u014a\u0007r\u0002\u0002\u014a\u014c\u00073\u0002\u0002", "\u014b\u0148\u0003\u0002\u0002\u0002\u014b\u014c\u0003\u0002\u0002\u0002", "\u014c\u0157\u0003\u0002\u0002\u0002\u014d\u0152\u0005p9\u0002\u014e", "\u014f\u0007\u0005\u0002\u0002\u014f\u0151\u0005p9\u0002\u0150\u014e", "\u0003\u0002\u0002\u0002\u0151\u0154\u0003\u0002\u0002\u0002\u0152\u0150", "\u0003\u0002\u0002\u0002\u0152\u0153\u0003\u0002\u0002\u0002\u0153\u0158", "\u0003\u0002\u0002\u0002\u0154\u0152\u0003\u0002\u0002\u0002\u0155\u0156", "\u0007\u0010\u0002\u0002\u0156\u0158\u0007p\u0002\u0002\u0157\u014d", "\u0003\u0002\u0002\u0002\u0157\u0155\u0003\u0002\u0002\u0002\u0158\u0159", "\u0003\u0002\u0002\u0002\u0159\u015b\u0007V\u0002\u0002\u015a\u015c", "\u0007f\u0002\u0002\u015b\u015a\u0003\u0002\u0002\u0002\u015b\u015c", "\u0003\u0002\u0002\u0002\u015c\u015d\u0003\u0002\u0002\u0002\u015d\u015e", "\u0005r:\u0002\u015e\u015f\u0007\r\u0002\u0002\u015f\u0160\u0005t;\u0002", "\u0160\u01f2\u0003\u0002\u0002\u0002\u0161\u0163\u0007s\u0002\u0002", "\u0162\u0164\u0007t\u0002\u0002\u0163\u0162\u0003\u0002\u0002\u0002", "\u0163\u0164\u0003\u0002\u0002\u0002\u0164\u0170\u0003\u0002\u0002\u0002", "\u0165\u0166\u0007\u0004\u0002\u0002\u0166\u016b\u0005h5\u0002\u0167", "\u0168\u0007\u0005\u0002\u0002\u0168\u016a\u0005h5\u0002\u0169\u0167", "\u0003\u0002\u0002\u0002\u016a\u016d\u0003\u0002\u0002\u0002\u016b\u0169", "\u0003\u0002\u0002\u0002\u016b\u016c\u0003\u0002\u0002\u0002\u016c\u016e", "\u0003\u0002\u0002\u0002\u016d\u016b\u0003\u0002\u0002\u0002\u016e\u016f", "\u0007\u0006\u0002\u0002\u016f\u0171\u0003\u0002\u0002\u0002\u0170\u0165", "\u0003\u0002\u0002\u0002\u0170\u0171\u0003\u0002\u0002\u0002\u0171\u0172", "\u0003\u0002\u0002\u0002\u0172\u01f2\u0005\b\u0005\u0002\u0173\u0174", "\u0007}\u0002\u0002\u0174\u0175\u0007d\u0002\u0002\u0175\u0176\u0007", "f\u0002\u0002\u0176\u01f2\u0005r:\u0002\u0177\u0178\u0007}\u0002\u0002", "\u0178\u0179\u0007d\u0002\u0002\u0179\u017a\u0007g\u0002\u0002\u017a", "\u01f2\u0005r:\u0002\u017b\u017c\u0007}\u0002\u0002\u017c\u017f\u0007", "~\u0002\u0002\u017d\u017e\t\u0003\u0002\u0002\u017e\u0180\u0005r:\u0002", "\u017f\u017d\u0003\u0002\u0002\u0002\u017f\u0180\u0003\u0002\u0002\u0002", "\u0180\u0183\u0003\u0002\u0002\u0002\u0181\u0182\u0007&\u0002\u0002", "\u0182\u0184\u0007\u00c6\u0002\u0002\u0183\u0181\u0003\u0002\u0002\u0002", "\u0183\u0184\u0003\u0002\u0002\u0002\u0184\u01f2\u0003\u0002\u0002\u0002", "\u0185\u0186\u0007}\u0002\u0002\u0186\u0189\u0007\u007f\u0002\u0002", "\u0187\u0188\t\u0003\u0002\u0002\u0188\u018a\u0005t;\u0002\u0189\u0187", "\u0003\u0002\u0002\u0002\u0189\u018a\u0003\u0002\u0002\u0002\u018a\u018d", "\u0003\u0002\u0002\u0002\u018b\u018c\u0007&\u0002\u0002\u018c\u018e", "\u0007\u00c6\u0002\u0002\u018d\u018b\u0003\u0002\u0002\u0002\u018d\u018e", "\u0003\u0002\u0002\u0002\u018e\u01f2\u0003\u0002\u0002\u0002\u018f\u0190", "\u0007}\u0002\u0002\u0190\u0193\u0007\u0080\u0002\u0002\u0191\u0192", "\u0007&\u0002\u0002\u0192\u0194\u0007\u00c6\u0002\u0002\u0193\u0191", "\u0003\u0002\u0002\u0002\u0193\u0194\u0003\u0002\u0002\u0002\u0194\u01f2", "\u0003\u0002\u0002\u0002\u0195\u0196\u0007}\u0002\u0002\u0196\u0197", "\u0007\u0081\u0002\u0002\u0197\u0198\t\u0003\u0002\u0002\u0198\u01f2", "\u0005r:\u0002\u0199\u019a\u0007m\u0002\u0002\u019a\u01f2\u0005r:\u0002", "\u019b\u019c\u00070\u0002\u0002\u019c\u01f2\u0005r:\u0002\u019d\u019e", "\u0007}\u0002\u0002\u019e\u01f2\u0007\u0085\u0002\u0002\u019f\u01a0", "\u0007}\u0002\u0002\u01a0\u01f2\u0007\u0097\u0002\u0002\u01a1\u01a2", "\u0007\u0095\u0002\u0002\u01a2\u01a3\u0007\u0097\u0002\u0002\u01a3\u01a4", "\u0005r:\u0002\u01a4\u01a5\u0007\u00ba\u0002\u0002\u01a5\u01a6\u0005", "@!\u0002\u01a6\u01f2\u0003\u0002\u0002\u0002\u01a7\u01a8\u0007\u0096", "\u0002\u0002\u01a8\u01a9\u0007\u0097\u0002\u0002\u01a9\u01f2\u0005r", ":\u0002\u01aa\u01ab\u0007\u0099\u0002\u0002\u01ab\u01b4\u0007\u009a", "\u0002\u0002\u01ac\u01b1\u0005j6\u0002\u01ad\u01ae\u0007\u0005\u0002", "\u0002\u01ae\u01b0\u0005j6\u0002\u01af\u01ad\u0003\u0002\u0002\u0002", "\u01b0\u01b3\u0003\u0002\u0002\u0002\u01b1\u01af\u0003\u0002\u0002\u0002", "\u01b1\u01b2\u0003\u0002\u0002\u0002\u01b2\u01b5\u0003\u0002\u0002\u0002", "\u01b3\u01b1\u0003\u0002\u0002\u0002\u01b4\u01ac\u0003\u0002\u0002\u0002", "\u01b4\u01b5\u0003\u0002\u0002\u0002\u01b5\u01f2\u0003\u0002\u0002\u0002", "\u01b6\u01b8\u0007\u009b\u0002\u0002\u01b7\u01b9\u0007\u009d\u0002\u0002", "\u01b8\u01b7\u0003\u0002\u0002\u0002\u01b8\u01b9\u0003\u0002\u0002\u0002", "\u01b9\u01f2\u0003\u0002\u0002\u0002\u01ba\u01bc\u0007\u009c\u0002\u0002", "\u01bb\u01bd\u0007\u009d\u0002\u0002\u01bc\u01bb\u0003\u0002\u0002\u0002", "\u01bc\u01bd\u0003\u0002\u0002\u0002\u01bd\u01f2\u0003\u0002\u0002\u0002", "\u01be\u01bf\u0007}\u0002\u0002\u01bf\u01c0\u0007\u0084\u0002\u0002", "\u01c0\u01c1\t\u0003\u0002\u0002\u01c1\u01c4\u0005r:\u0002\u01c2\u01c3", "\u0007\u0014\u0002\u0002\u01c3\u01c5\u0005B\"\u0002\u01c4\u01c2\u0003", "\u0002\u0002\u0002\u01c4\u01c5\u0003\u0002\u0002\u0002\u01c5\u01d0\u0003", "\u0002\u0002\u0002\u01c6\u01c7\u0007\u001b\u0002\u0002\u01c7\u01c8\u0007", "\u0016\u0002\u0002\u01c8\u01cd\u0005\u001e\u0010\u0002\u01c9\u01ca\u0007", "\u0005\u0002\u0002\u01ca\u01cc\u0005\u001e\u0010\u0002\u01cb\u01c9\u0003", "\u0002\u0002\u0002\u01cc\u01cf\u0003\u0002\u0002\u0002\u01cd\u01cb\u0003", "\u0002\u0002\u0002\u01cd\u01ce\u0003\u0002\u0002\u0002\u01ce\u01d1\u0003", "\u0002\u0002\u0002\u01cf\u01cd\u0003\u0002\u0002\u0002\u01d0\u01c6\u0003", "\u0002\u0002\u0002\u01d0\u01d1\u0003\u0002\u0002\u0002\u01d1\u01d4\u0003", "\u0002\u0002\u0002\u01d2\u01d3\u0007\u001d\u0002\u0002\u01d3\u01d5\t", "\u0004\u0002\u0002\u01d4\u01d2\u0003\u0002\u0002\u0002\u01d4\u01d5\u0003", "\u0002\u0002\u0002\u01d5\u01f2\u0003\u0002\u0002\u0002\u01d6\u01d7\u0007", "\u00a8\u0002\u0002\u01d7\u01d8\u0005t;\u0002\u01d8\u01d9\u0007\r\u0002", "\u0002\u01d9\u01da\u0005\b\u0005\u0002\u01da\u01f2\u0003\u0002\u0002", "\u0002\u01db\u01dc\u0007\u00a9\u0002\u0002\u01dc\u01dd\u0007\u00a8\u0002", "\u0002\u01dd\u01f2\u0005t;\u0002\u01de\u01df\u0007\u00aa\u0002\u0002", "\u01df\u01e9\u0005t;\u0002\u01e0\u01e1\u0007U\u0002\u0002\u01e1\u01e6", "\u0005@!\u0002\u01e2\u01e3\u0007\u0005\u0002\u0002\u01e3\u01e5\u0005", "@!\u0002\u01e4\u01e2\u0003\u0002\u0002\u0002\u01e5\u01e8\u0003\u0002", "\u0002\u0002\u01e6\u01e4\u0003\u0002\u0002\u0002\u01e6\u01e7\u0003\u0002", "\u0002\u0002\u01e7\u01ea\u0003\u0002\u0002\u0002\u01e8\u01e6\u0003\u0002", "\u0002\u0002\u01e9\u01e0\u0003\u0002\u0002\u0002\u01e9\u01ea\u0003\u0002", "\u0002\u0002\u01ea\u01f2\u0003\u0002\u0002\u0002\u01eb\u01ec\u0007m", "\u0002\u0002\u01ec\u01ed\u0007\u00ab\u0002\u0002\u01ed\u01f2\u0005t", ";\u0002\u01ee\u01ef\u0007m\u0002\u0002\u01ef\u01f0\u0007\u00ac\u0002", "\u0002\u01f0\u01f2\u0005t;\u0002\u01f1\u0091\u0003\u0002\u0002\u0002", "\u01f1\u0092\u0003\u0002\u0002\u0002\u01f1\u0094\u0003\u0002\u0002\u0002", "\u01f1\u0099\u0003\u0002\u0002\u0002\u01f1\u00a5\u0003\u0002\u0002\u0002", "\u01f1\u00af\u0003\u0002\u0002\u0002\u01f1\u00b6\u0003\u0002\u0002\u0002", "\u01f1\u00cb\u0003\u0002\u0002\u0002\u01f1\u00e1\u0003\u0002\u0002\u0002", "\u01f1\u00e8\u0003\u0002\u0002\u0002\u01f1\u00f0\u0003\u0002\u0002\u0002", "\u01f1\u00f7\u0003\u0002\u0002\u0002\u01f1\u00fe\u0003\u0002\u0002\u0002", "\u01f1\u0107\u0003\u0002\u0002\u0002\u01f1\u010e\u0003\u0002\u0002\u0002", "\u01f1\u0118\u0003\u0002\u0002\u0002\u01f1\u011f\u0003\u0002\u0002\u0002", "\u01f1\u012e\u0003\u0002\u0002\u0002\u01f1\u0147\u0003\u0002\u0002\u0002", "\u01f1\u0161\u0003\u0002\u0002\u0002\u01f1\u0173\u0003\u0002\u0002\u0002", "\u01f1\u0177\u0003\u0002\u0002\u0002\u01f1\u017b\u0003\u0002\u0002\u0002", "\u01f1\u0185\u0003\u0002\u0002\u0002\u01f1\u018f\u0003\u0002\u0002\u0002", "\u01f1\u0195\u0003\u0002\u0002\u0002\u01f1\u0199\u0003\u0002\u0002\u0002", "\u01f1\u019b\u0003\u0002\u0002\u0002\u01f1\u019d\u0003\u0002\u0002\u0002", "\u01f1\u019f\u0003\u0002\u0002\u0002\u01f1\u01a1\u0003\u0002\u0002\u0002", "\u01f1\u01a7\u0003\u0002\u0002\u0002\u01f1\u01aa\u0003\u0002\u0002\u0002", "\u01f1\u01b6\u0003\u0002\u0002\u0002\u01f1\u01ba\u0003\u0002\u0002\u0002", "\u01f1\u01be\u0003\u0002\u0002\u0002\u01f1\u01d6\u0003\u0002\u0002\u0002", "\u01f1\u01db\u0003\u0002\u0002\u0002\u01f1\u01de\u0003\u0002\u0002\u0002", "\u01f1\u01eb\u0003\u0002\u0002\u0002\u01f1\u01ee\u0003\u0002\u0002\u0002", "\u01f2\t\u0003\u0002\u0002\u0002\u01f3\u01f5\u0005\f\u0007\u0002\u01f4", "\u01f3\u0003\u0002\u0002\u0002\u01f4\u01f5\u0003\u0002\u0002\u0002\u01f5", "\u01f6\u0003\u0002\u0002\u0002\u01f6\u01f7\u0005\u0018\r\u0002\u01f7", "\u000b\u0003\u0002\u0002\u0002\u01f8\u01fa\u0007a\u0002\u0002\u01f9", "\u01fb\u0007b\u0002\u0002\u01fa\u01f9\u0003\u0002\u0002\u0002\u01fa", "\u01fb\u0003\u0002\u0002\u0002\u01fb\u01fc\u0003\u0002\u0002\u0002\u01fc", "\u0201\u0005*\u0016\u0002\u01fd\u01fe\u0007\u0005\u0002\u0002\u01fe", "\u0200\u0005*\u0016\u0002\u01ff\u01fd\u0003\u0002\u0002\u0002\u0200", "\u0203\u0003\u0002\u0002\u0002\u0201\u01ff\u0003\u0002\u0002\u0002\u0201", "\u0202\u0003\u0002\u0002\u0002\u0202\r\u0003\u0002\u0002\u0002\u0203", "\u0201\u0003\u0002\u0002\u0002\u0204\u0207\u0005\u0010\t\u0002\u0205", "\u0207\u0005\u0012\n\u0002\u0206\u0204\u0003\u0002\u0002\u0002\u0206", "\u0205\u0003\u0002\u0002\u0002\u0207\u000f\u0003\u0002\u0002\u0002\u0208", "\u0209\u0005t;\u0002\u0209\u020a\u0005X-\u0002\u020a\u0011\u0003\u0002", "\u0002\u0002\u020b\u020c\u0007&\u0002\u0002\u020c\u020f\u0005r:\u0002", "\u020d\u020e\t\u0005\u0002\u0002\u020e\u0210\u0007\u00b1\u0002\u0002", "\u020f\u020d\u0003\u0002\u0002\u0002\u020f\u0210\u0003\u0002\u0002\u0002", "\u0210\u0013\u0003\u0002\u0002\u0002\u0211\u0212\u0007\u0004\u0002\u0002", "\u0212\u0217\u0005\u0016\f\u0002\u0213\u0214\u0007\u0005\u0002\u0002", "\u0214\u0216\u0005\u0016\f\u0002\u0215\u0213\u0003\u0002\u0002\u0002", "\u0216\u0219\u0003\u0002\u0002\u0002\u0217\u0215\u0003\u0002\u0002\u0002", "\u0217\u0218\u0003\u0002\u0002\u0002\u0218\u021a\u0003\u0002\u0002\u0002", "\u0219\u0217\u0003\u0002\u0002\u0002\u021a\u021b\u0007\u0006\u0002\u0002", "\u021b\u0015\u0003\u0002\u0002\u0002\u021c\u021d\u0005t;\u0002\u021d", "\u021e\u0007\u00ba\u0002\u0002\u021e\u021f\u0005@!\u0002\u021f\u0017", "\u0003\u0002\u0002\u0002\u0220\u022b\u0005\u001a\u000e\u0002\u0221\u0222", "\u0007\u001b\u0002\u0002\u0222\u0223\u0007\u0016\u0002\u0002\u0223\u0228", "\u0005\u001e\u0010\u0002\u0224\u0225\u0007\u0005\u0002\u0002\u0225\u0227", "\u0005\u001e\u0010\u0002\u0226\u0224\u0003\u0002\u0002\u0002\u0227\u022a", "\u0003\u0002\u0002\u0002\u0228\u0226\u0003\u0002\u0002\u0002\u0228\u0229", "\u0003\u0002\u0002\u0002\u0229\u022c\u0003\u0002\u0002\u0002\u022a\u0228", "\u0003\u0002\u0002\u0002\u022b\u0221\u0003\u0002\u0002\u0002\u022b\u022c", "\u0003\u0002\u0002\u0002\u022c\u022f\u0003\u0002\u0002\u0002\u022d\u022e", "\u0007\u001d\u0002\u0002\u022e\u0230\t\u0004\u0002\u0002\u022f\u022d", "\u0003\u0002\u0002\u0002\u022f\u0230\u0003\u0002\u0002\u0002\u0230\u0019", "\u0003\u0002\u0002\u0002\u0231\u0232\b\u000e\u0001\u0002\u0232\u0233", "\u0005\u001c\u000f\u0002\u0233\u0242\u0003\u0002\u0002\u0002\u0234\u0235", "\f\u0004\u0002\u0002\u0235\u0237\u0007\u0089\u0002\u0002\u0236\u0238", "\u0005,\u0017\u0002\u0237\u0236\u0003\u0002\u0002\u0002\u0237\u0238", "\u0003\u0002\u0002\u0002\u0238\u0239\u0003\u0002\u0002\u0002\u0239\u0241", "\u0005\u001a\u000e\u0005\u023a\u023b\f\u0003\u0002\u0002\u023b\u023d", "\t\u0006\u0002\u0002\u023c\u023e\u0005,\u0017\u0002\u023d\u023c\u0003", "\u0002\u0002\u0002\u023d\u023e\u0003\u0002\u0002\u0002\u023e\u023f\u0003", "\u0002\u0002\u0002\u023f\u0241\u0005\u001a\u000e\u0004\u0240\u0234\u0003", "\u0002\u0002\u0002\u0240\u023a\u0003\u0002\u0002\u0002\u0241\u0244\u0003", "\u0002\u0002\u0002\u0242\u0240\u0003\u0002\u0002\u0002\u0242\u0243\u0003", "\u0002\u0002\u0002\u0243\u001b\u0003\u0002\u0002\u0002\u0244\u0242\u0003", "\u0002\u0002\u0002\u0245\u0256\u0005 \u0011\u0002\u0246\u0247\u0007", "f\u0002\u0002\u0247\u0256\u0005r:\u0002\u0248\u0249\u0007c\u0002\u0002", "\u0249\u024e\u0005@!\u0002\u024a\u024b\u0007\u0005\u0002\u0002\u024b", "\u024d\u0005@!\u0002\u024c\u024a\u0003\u0002\u0002\u0002\u024d\u0250", "\u0003\u0002\u0002\u0002\u024e\u024c\u0003\u0002\u0002\u0002\u024e\u024f", "\u0003\u0002\u0002\u0002\u024f\u0256\u0003\u0002\u0002\u0002\u0250\u024e", "\u0003\u0002\u0002\u0002\u0251\u0252\u0007\u0004\u0002\u0002\u0252\u0253", "\u0005\u0018\r\u0002\u0253\u0254\u0007\u0006\u0002\u0002\u0254\u0256", "\u0003\u0002\u0002\u0002\u0255\u0245\u0003\u0002\u0002\u0002\u0255\u0246", "\u0003\u0002\u0002\u0002\u0255\u0248\u0003\u0002\u0002\u0002\u0255\u0251", "\u0003\u0002\u0002\u0002\u0256\u001d\u0003\u0002\u0002\u0002\u0257\u0259", "\u0005@!\u0002\u0258\u025a\t\u0007\u0002\u0002\u0259\u0258\u0003\u0002", "\u0002\u0002\u0259\u025a\u0003\u0002\u0002\u0002\u025a\u025d\u0003\u0002", "\u0002\u0002\u025b\u025c\u0007+\u0002\u0002\u025c\u025e\t\b\u0002\u0002", "\u025d\u025b\u0003\u0002\u0002\u0002\u025d\u025e\u0003\u0002\u0002\u0002", "\u025e\u001f\u0003\u0002\u0002\u0002\u025f\u0261\u0007\f\u0002\u0002", "\u0260\u0262\u0005,\u0017\u0002\u0261\u0260\u0003\u0002\u0002\u0002", "\u0261\u0262\u0003\u0002\u0002\u0002\u0262\u0263\u0003\u0002\u0002\u0002", "\u0263\u0268\u0005.\u0018\u0002\u0264\u0265\u0007\u0005\u0002\u0002", "\u0265\u0267\u0005.\u0018\u0002\u0266\u0264\u0003\u0002\u0002\u0002", "\u0267\u026a\u0003\u0002\u0002\u0002\u0268\u0266\u0003\u0002\u0002\u0002", "\u0268\u0269\u0003\u0002\u0002\u0002\u0269\u0274\u0003\u0002\u0002\u0002", "\u026a\u0268\u0003\u0002\u0002\u0002\u026b\u026c\u0007\r\u0002\u0002", "\u026c\u0271\u00050\u0019\u0002\u026d\u026e\u0007\u0005\u0002\u0002", "\u026e\u0270\u00050\u0019\u0002\u026f\u026d\u0003\u0002\u0002\u0002", "\u0270\u0273\u0003\u0002\u0002\u0002\u0271\u026f\u0003\u0002\u0002\u0002", "\u0271\u0272\u0003\u0002\u0002\u0002\u0272\u0275\u0003\u0002\u0002\u0002", "\u0273\u0271\u0003\u0002\u0002\u0002\u0274\u026b\u0003\u0002\u0002\u0002", "\u0274\u0275\u0003\u0002\u0002\u0002\u0275\u0278\u0003\u0002\u0002\u0002", "\u0276\u0277\u0007\u0014\u0002\u0002\u0277\u0279\u0005B\"\u0002\u0278", "\u0276\u0003\u0002\u0002\u0002\u0278\u0279\u0003\u0002\u0002\u0002\u0279", "\u027d\u0003\u0002\u0002\u0002\u027a\u027b\u0007\u0015\u0002\u0002\u027b", "\u027c\u0007\u0016\u0002\u0002\u027c\u027e\u0005\"\u0012\u0002\u027d", "\u027a\u0003\u0002\u0002\u0002\u027d\u027e\u0003\u0002\u0002\u0002\u027e", "\u0281\u0003\u0002\u0002\u0002\u027f\u0280\u0007\u001c\u0002\u0002\u0280", "\u0282\u0005B\"\u0002\u0281\u027f\u0003\u0002\u0002\u0002\u0281\u0282", "\u0003\u0002\u0002\u0002\u0282!\u0003\u0002\u0002\u0002\u0283\u0285", "\u0005,\u0017\u0002\u0284\u0283\u0003\u0002\u0002\u0002\u0284\u0285", "\u0003\u0002\u0002\u0002\u0285\u0286\u0003\u0002\u0002\u0002\u0286\u028b", "\u0005$\u0013\u0002\u0287\u0288\u0007\u0005\u0002\u0002\u0288\u028a", "\u0005$\u0013\u0002\u0289\u0287\u0003\u0002\u0002\u0002\u028a\u028d", "\u0003\u0002\u0002\u0002\u028b\u0289\u0003\u0002\u0002\u0002\u028b\u028c", "\u0003\u0002\u0002\u0002\u028c#\u0003\u0002\u0002\u0002\u028d\u028b", "\u0003\u0002\u0002\u0002\u028e\u02b7\u0005&\u0014\u0002\u028f\u0290", "\u0007\u001a\u0002\u0002\u0290\u0299\u0007\u0004\u0002\u0002\u0291\u0296", "\u0005r:\u0002\u0292\u0293\u0007\u0005\u0002\u0002\u0293\u0295\u0005", "r:\u0002\u0294\u0292\u0003\u0002\u0002\u0002\u0295\u0298\u0003\u0002", "\u0002\u0002\u0296\u0294\u0003\u0002\u0002\u0002\u0296\u0297\u0003\u0002", "\u0002\u0002\u0297\u029a\u0003\u0002\u0002\u0002\u0298\u0296\u0003\u0002", "\u0002\u0002\u0299\u0291\u0003\u0002\u0002\u0002\u0299\u029a\u0003\u0002", "\u0002\u0002\u029a\u029b\u0003\u0002\u0002\u0002\u029b\u02b7\u0007\u0006", "\u0002\u0002\u029c\u029d\u0007\u0019\u0002\u0002\u029d\u02a6\u0007\u0004", "\u0002\u0002\u029e\u02a3\u0005r:\u0002\u029f\u02a0\u0007\u0005\u0002", "\u0002\u02a0\u02a2\u0005r:\u0002\u02a1\u029f\u0003\u0002\u0002\u0002", "\u02a2\u02a5\u0003\u0002\u0002\u0002\u02a3\u02a1\u0003\u0002\u0002\u0002", "\u02a3\u02a4\u0003\u0002\u0002\u0002\u02a4\u02a7\u0003\u0002\u0002\u0002", "\u02a5\u02a3\u0003\u0002\u0002\u0002\u02a6\u029e\u0003\u0002\u0002\u0002", "\u02a6\u02a7\u0003\u0002\u0002\u0002\u02a7\u02a8\u0003\u0002\u0002\u0002", "\u02a8\u02b7\u0007\u0006\u0002\u0002\u02a9\u02aa\u0007\u0017\u0002\u0002", "\u02aa\u02ab\u0007\u0018\u0002\u0002\u02ab\u02ac\u0007\u0004\u0002\u0002", "\u02ac\u02b1\u0005(\u0015\u0002\u02ad\u02ae\u0007\u0005\u0002\u0002", "\u02ae\u02b0\u0005(\u0015\u0002\u02af\u02ad\u0003\u0002\u0002\u0002", "\u02b0\u02b3\u0003\u0002\u0002\u0002\u02b1\u02af\u0003\u0002\u0002\u0002", "\u02b1\u02b2\u0003\u0002\u0002\u0002\u02b2\u02b4\u0003\u0002\u0002\u0002", "\u02b3\u02b1\u0003\u0002\u0002\u0002\u02b4\u02b5\u0007\u0006\u0002\u0002", "\u02b5\u02b7\u0003\u0002\u0002\u0002\u02b6\u028e\u0003\u0002\u0002\u0002", "\u02b6\u028f\u0003\u0002\u0002\u0002\u02b6\u029c\u0003\u0002\u0002\u0002", "\u02b6\u02a9\u0003\u0002\u0002\u0002\u02b7%\u0003\u0002\u0002\u0002", "\u02b8\u02c1\u0007\u0004\u0002\u0002\u02b9\u02be\u0005@!\u0002\u02ba", "\u02bb\u0007\u0005\u0002\u0002\u02bb\u02bd\u0005@!\u0002\u02bc\u02ba", "\u0003\u0002\u0002\u0002\u02bd\u02c0\u0003\u0002\u0002\u0002\u02be\u02bc", "\u0003\u0002\u0002\u0002\u02be\u02bf\u0003\u0002\u0002\u0002\u02bf\u02c2", "\u0003\u0002\u0002\u0002\u02c0\u02be\u0003\u0002\u0002\u0002\u02c1\u02b9", "\u0003\u0002\u0002\u0002\u02c1\u02c2\u0003\u0002\u0002\u0002\u02c2\u02c3", "\u0003\u0002\u0002\u0002\u02c3\u02c6\u0007\u0006\u0002\u0002\u02c4\u02c6", "\u0005@!\u0002\u02c5\u02b8\u0003\u0002\u0002\u0002\u02c5\u02c4\u0003", "\u0002\u0002\u0002\u02c6\'\u0003\u0002\u0002\u0002\u02c7\u02d0\u0007", "\u0004\u0002\u0002\u02c8\u02cd\u0005r:\u0002\u02c9\u02ca\u0007\u0005", "\u0002\u0002\u02ca\u02cc\u0005r:\u0002\u02cb\u02c9\u0003\u0002\u0002", "\u0002\u02cc\u02cf\u0003\u0002\u0002\u0002\u02cd\u02cb\u0003\u0002\u0002", "\u0002\u02cd\u02ce\u0003\u0002\u0002\u0002\u02ce\u02d1\u0003\u0002\u0002", "\u0002\u02cf\u02cd\u0003\u0002\u0002\u0002\u02d0\u02c8\u0003\u0002\u0002", "\u0002\u02d0\u02d1\u0003\u0002\u0002\u0002\u02d1\u02d2\u0003\u0002\u0002", "\u0002\u02d2\u02d5\u0007\u0006\u0002\u0002\u02d3\u02d5\u0005r:\u0002", "\u02d4\u02c7\u0003\u0002\u0002\u0002\u02d4\u02d3\u0003\u0002\u0002\u0002", "\u02d5)\u0003\u0002\u0002\u0002\u02d6\u02d8\u0005t;\u0002\u02d7\u02d9", "\u0005<\u001f\u0002\u02d8\u02d7\u0003\u0002\u0002\u0002\u02d8\u02d9", "\u0003\u0002\u0002\u0002\u02d9\u02da\u0003\u0002\u0002\u0002\u02da\u02db", "\u0007\u000f\u0002\u0002\u02db\u02dc\u0007\u0004\u0002\u0002\u02dc\u02dd", "\u0005\n\u0006\u0002\u02dd\u02de\u0007\u0006\u0002\u0002\u02de+\u0003", "\u0002\u0002\u0002\u02df\u02e0\t\t\u0002\u0002\u02e0-\u0003\u0002\u0002", "\u0002\u02e1\u02e6\u0005@!\u0002\u02e2\u02e4\u0007\u000f\u0002\u0002", "\u02e3\u02e2\u0003\u0002\u0002\u0002\u02e3\u02e4\u0003\u0002\u0002\u0002", "\u02e4\u02e5\u0003\u0002\u0002\u0002\u02e5\u02e7\u0005t;\u0002\u02e6", "\u02e3\u0003\u0002\u0002\u0002\u02e6\u02e7\u0003\u0002\u0002\u0002\u02e7", "\u02ee\u0003\u0002\u0002\u0002\u02e8\u02e9\u0005r:\u0002\u02e9\u02ea", "\u0007\u0003\u0002\u0002\u02ea\u02eb\u0007\u00c2\u0002\u0002\u02eb\u02ee", "\u0003\u0002\u0002\u0002\u02ec\u02ee\u0007\u00c2\u0002\u0002\u02ed\u02e1", "\u0003\u0002\u0002\u0002\u02ed\u02e8\u0003\u0002\u0002\u0002\u02ed\u02ec", "\u0003\u0002\u0002\u0002\u02ee/\u0003\u0002\u0002\u0002\u02ef\u02f0", "\b\u0019\u0001\u0002\u02f0\u02f1\u00056\u001c\u0002\u02f1\u0304\u0003", "\u0002\u0002\u0002\u02f2\u0300\f\u0004\u0002\u0002\u02f3\u02f4\u0007", "N\u0002\u0002\u02f4\u02f5\u0007M\u0002\u0002\u02f5\u0301\u00056\u001c", "\u0002\u02f6\u02f7\u00052\u001a\u0002\u02f7\u02f8\u0007M\u0002\u0002", "\u02f8\u02f9\u00050\u0019\u0002\u02f9\u02fa\u00054\u001b\u0002\u02fa", "\u0301\u0003\u0002\u0002\u0002\u02fb\u02fc\u0007T\u0002\u0002\u02fc", "\u02fd\u00052\u001a\u0002\u02fd\u02fe\u0007M\u0002\u0002\u02fe\u02ff", "\u00056\u001c\u0002\u02ff\u0301\u0003\u0002\u0002\u0002\u0300\u02f3", "\u0003\u0002\u0002\u0002\u0300\u02f6\u0003\u0002\u0002\u0002\u0300\u02fb", "\u0003\u0002\u0002\u0002\u0301\u0303\u0003\u0002\u0002\u0002\u0302\u02f2", "\u0003\u0002\u0002\u0002\u0303\u0306\u0003\u0002\u0002\u0002\u0304\u0302", "\u0003\u0002\u0002\u0002\u0304\u0305\u0003\u0002\u0002\u0002\u03051", "\u0003\u0002\u0002\u0002\u0306\u0304\u0003\u0002\u0002\u0002\u0307\u0309", "\u0007P\u0002\u0002\u0308\u0307\u0003\u0002\u0002\u0002\u0308\u0309", "\u0003\u0002\u0002\u0002\u0309\u0317\u0003\u0002\u0002\u0002\u030a\u030c", "\u0007Q\u0002\u0002\u030b\u030d\u0007O\u0002\u0002\u030c\u030b\u0003", "\u0002\u0002\u0002\u030c\u030d\u0003\u0002\u0002\u0002\u030d\u0317\u0003", "\u0002\u0002\u0002\u030e\u0310\u0007R\u0002\u0002\u030f\u0311\u0007", "O\u0002\u0002\u0310\u030f\u0003\u0002\u0002\u0002\u0310\u0311\u0003", "\u0002\u0002\u0002\u0311\u0317\u0003\u0002\u0002\u0002\u0312\u0314\u0007", "S\u0002\u0002\u0313\u0315\u0007O\u0002\u0002\u0314\u0313\u0003\u0002", "\u0002\u0002\u0314\u0315\u0003\u0002\u0002\u0002\u0315\u0317\u0003\u0002", "\u0002\u0002\u0316\u0308\u0003\u0002\u0002\u0002\u0316\u030a\u0003\u0002", "\u0002\u0002\u0316\u030e\u0003\u0002\u0002\u0002\u0316\u0312\u0003\u0002", "\u0002\u0002\u03173\u0003\u0002\u0002\u0002\u0318\u0319\u0007V\u0002", "\u0002\u0319\u0327\u0005B\"\u0002\u031a\u031b\u0007U\u0002\u0002\u031b", "\u031c\u0007\u0004\u0002\u0002\u031c\u0321\u0005t;\u0002\u031d\u031e", "\u0007\u0005\u0002\u0002\u031e\u0320\u0005t;\u0002\u031f\u031d\u0003", "\u0002\u0002\u0002\u0320\u0323\u0003\u0002\u0002\u0002\u0321\u031f\u0003", "\u0002\u0002\u0002\u0321\u0322\u0003\u0002\u0002\u0002\u0322\u0324\u0003", "\u0002\u0002\u0002\u0323\u0321\u0003\u0002\u0002\u0002\u0324\u0325\u0007", "\u0006\u0002\u0002\u0325\u0327\u0003\u0002\u0002\u0002\u0326\u0318\u0003", "\u0002\u0002\u0002\u0326\u031a\u0003\u0002\u0002\u0002\u03275\u0003", "\u0002\u0002\u0002\u0328\u032f\u0005:\u001e\u0002\u0329\u032a\u0007", "\u008e\u0002\u0002\u032a\u032b\u00058\u001d\u0002\u032b\u032c\u0007", "\u0004\u0002\u0002\u032c\u032d\u0005@!\u0002\u032d\u032e\u0007\u0006", "\u0002\u0002\u032e\u0330\u0003\u0002\u0002\u0002\u032f\u0329\u0003\u0002", "\u0002\u0002\u032f\u0330\u0003\u0002\u0002\u0002\u03307\u0003\u0002", "\u0002\u0002\u0331\u0332\t\n\u0002\u0002\u03329\u0003\u0002\u0002\u0002", "\u0333\u033b\u0005> \u0002\u0334\u0336\u0007\u000f\u0002\u0002\u0335", "\u0334\u0003\u0002\u0002\u0002\u0335\u0336\u0003\u0002\u0002\u0002\u0336", "\u0337\u0003\u0002\u0002\u0002\u0337\u0339\u0005t;\u0002\u0338\u033a", "\u0005<\u001f\u0002\u0339\u0338\u0003\u0002\u0002\u0002\u0339\u033a", "\u0003\u0002\u0002\u0002\u033a\u033c\u0003\u0002\u0002\u0002\u033b\u0335", "\u0003\u0002\u0002\u0002\u033b\u033c\u0003\u0002\u0002\u0002\u033c;", "\u0003\u0002\u0002\u0002\u033d\u033e\u0007\u0004\u0002\u0002\u033e\u0343", "\u0005t;\u0002\u033f\u0340\u0007\u0005\u0002\u0002\u0340\u0342\u0005", "t;\u0002\u0341\u033f\u0003\u0002\u0002\u0002\u0342\u0345\u0003\u0002", "\u0002\u0002\u0343\u0341\u0003\u0002\u0002\u0002\u0343\u0344\u0003\u0002", "\u0002\u0002\u0344\u0346\u0003\u0002\u0002\u0002\u0345\u0343\u0003\u0002", "\u0002\u0002\u0346\u0347\u0007\u0006\u0002\u0002\u0347=\u0003\u0002", "\u0002\u0002\u0348\u0361\u0005r:\u0002\u0349\u034a\u0007\u0004\u0002", "\u0002\u034a\u034b\u0005\n\u0006\u0002\u034b\u034c\u0007\u0006\u0002", "\u0002\u034c\u0361\u0003\u0002\u0002\u0002\u034d\u034e\u0007\u0091\u0002", "\u0002\u034e\u034f\u0007\u0004\u0002\u0002\u034f\u0354\u0005@!\u0002", "\u0350\u0351\u0007\u0005\u0002\u0002\u0351\u0353\u0005@!\u0002\u0352", "\u0350\u0003\u0002\u0002\u0002\u0353\u0356\u0003\u0002\u0002\u0002\u0354", "\u0352\u0003\u0002\u0002\u0002\u0354\u0355\u0003\u0002\u0002\u0002\u0355", "\u0357\u0003\u0002\u0002\u0002\u0356\u0354\u0003\u0002\u0002\u0002\u0357", "\u035a\u0007\u0006\u0002\u0002\u0358\u0359\u0007a\u0002\u0002\u0359", "\u035b\u0007\u0092\u0002\u0002\u035a\u0358\u0003\u0002\u0002\u0002\u035a", "\u035b\u0003\u0002\u0002\u0002\u035b\u0361\u0003\u0002\u0002\u0002\u035c", "\u035d\u0007\u0004\u0002\u0002\u035d\u035e\u00050\u0019\u0002\u035e", "\u035f\u0007\u0006\u0002\u0002\u035f\u0361\u0003\u0002\u0002\u0002\u0360", "\u0348\u0003\u0002\u0002\u0002\u0360\u0349\u0003\u0002\u0002\u0002\u0360", "\u034d\u0003\u0002\u0002\u0002\u0360\u035c\u0003\u0002\u0002\u0002\u0361", "?\u0003\u0002\u0002\u0002\u0362\u0363\u0005B\"\u0002\u0363A\u0003\u0002", "\u0002\u0002\u0364\u0365\b\"\u0001\u0002\u0365\u0369\u0005D#\u0002\u0366", "\u0367\u0007\"\u0002\u0002\u0367\u0369\u0005B\"\u0005\u0368\u0364\u0003", "\u0002\u0002\u0002\u0368\u0366\u0003\u0002\u0002\u0002\u0369\u0372\u0003", "\u0002\u0002\u0002\u036a\u036b\f\u0004\u0002\u0002\u036b\u036c\u0007", " \u0002\u0002\u036c\u0371\u0005B\"\u0005\u036d\u036e\f\u0003\u0002\u0002", "\u036e\u036f\u0007\u001f\u0002\u0002\u036f\u0371\u0005B\"\u0004\u0370", "\u036a\u0003\u0002\u0002\u0002\u0370\u036d\u0003\u0002\u0002\u0002\u0371", "\u0374\u0003\u0002\u0002\u0002\u0372\u0370\u0003\u0002\u0002\u0002\u0372", "\u0373\u0003\u0002\u0002\u0002\u0373C\u0003\u0002\u0002\u0002\u0374", "\u0372\u0003\u0002\u0002\u0002\u0375\u0377\u0005H%\u0002\u0376\u0378", "\u0005F$\u0002\u0377\u0376\u0003\u0002\u0002\u0002\u0377\u0378\u0003", "\u0002\u0002\u0002\u0378E\u0003\u0002\u0002\u0002\u0379\u037a\u0005", "N(\u0002\u037a\u037b\u0005H%\u0002\u037b\u03b7\u0003\u0002\u0002\u0002", "\u037c\u037d\u0005N(\u0002\u037d\u037e\u0005P)\u0002\u037e\u037f\u0007", "\u0004\u0002\u0002\u037f\u0380\u0005\n\u0006\u0002\u0380\u0381\u0007", "\u0006\u0002\u0002\u0381\u03b7\u0003\u0002\u0002\u0002\u0382\u0384\u0007", "\"\u0002\u0002\u0383\u0382\u0003\u0002\u0002\u0002\u0383\u0384\u0003", "\u0002\u0002\u0002\u0384\u0385\u0003\u0002\u0002\u0002\u0385\u0386\u0007", "%\u0002\u0002\u0386\u0387\u0005H%\u0002\u0387\u0388\u0007 \u0002\u0002", "\u0388\u0389\u0005H%\u0002\u0389\u03b7\u0003\u0002\u0002\u0002\u038a", "\u038c\u0007\"\u0002\u0002\u038b\u038a\u0003\u0002\u0002\u0002\u038b", "\u038c\u0003\u0002\u0002\u0002\u038c\u038d\u0003\u0002\u0002\u0002\u038d", "\u038e\u0007!\u0002\u0002\u038e\u038f\u0007\u0004\u0002\u0002\u038f", "\u0394\u0005@!\u0002\u0390\u0391\u0007\u0005\u0002\u0002\u0391\u0393", "\u0005@!\u0002\u0392\u0390\u0003\u0002\u0002\u0002\u0393\u0396\u0003", "\u0002\u0002\u0002\u0394\u0392\u0003\u0002\u0002\u0002\u0394\u0395\u0003", "\u0002\u0002\u0002\u0395\u0397\u0003\u0002\u0002\u0002\u0396\u0394\u0003", "\u0002\u0002\u0002\u0397\u0398\u0007\u0006\u0002\u0002\u0398\u03b7\u0003", "\u0002\u0002\u0002\u0399\u039b\u0007\"\u0002\u0002\u039a\u0399\u0003", "\u0002\u0002\u0002\u039a\u039b\u0003\u0002\u0002\u0002\u039b\u039c\u0003", "\u0002\u0002\u0002\u039c\u039d\u0007!\u0002\u0002\u039d\u039e\u0007", "\u0004\u0002\u0002\u039e\u039f\u0005\n\u0006\u0002\u039f\u03a0\u0007", "\u0006\u0002\u0002\u03a0\u03b7\u0003\u0002\u0002\u0002\u03a1\u03a3\u0007", "\"\u0002\u0002\u03a2\u03a1\u0003\u0002\u0002\u0002\u03a2\u03a3\u0003", "\u0002\u0002\u0002\u03a3\u03a4\u0003\u0002\u0002\u0002\u03a4\u03a5\u0007", "&\u0002\u0002\u03a5\u03a8\u0005H%\u0002\u03a6\u03a7\u0007.\u0002\u0002", "\u03a7\u03a9\u0005H%\u0002\u03a8\u03a6\u0003\u0002\u0002\u0002\u03a8", "\u03a9\u0003\u0002\u0002\u0002\u03a9\u03b7\u0003\u0002\u0002\u0002\u03aa", "\u03ac\u0007\'\u0002\u0002\u03ab\u03ad\u0007\"\u0002\u0002\u03ac\u03ab", "\u0003\u0002\u0002\u0002\u03ac\u03ad\u0003\u0002\u0002\u0002\u03ad\u03ae", "\u0003\u0002\u0002\u0002\u03ae\u03b7\u0007(\u0002\u0002\u03af\u03b1", "\u0007\'\u0002\u0002\u03b0\u03b2\u0007\"\u0002\u0002\u03b1\u03b0\u0003", "\u0002\u0002\u0002\u03b1\u03b2\u0003\u0002\u0002\u0002\u03b2\u03b3\u0003", "\u0002\u0002\u0002\u03b3\u03b4\u0007\u0013\u0002\u0002\u03b4\u03b5\u0007", "\r\u0002\u0002\u03b5\u03b7\u0005H%\u0002\u03b6\u0379\u0003\u0002\u0002", "\u0002\u03b6\u037c\u0003\u0002\u0002\u0002\u03b6\u0383\u0003\u0002\u0002", "\u0002\u03b6\u038b\u0003\u0002\u0002\u0002\u03b6\u039a\u0003\u0002\u0002", "\u0002\u03b6\u03a2\u0003\u0002\u0002\u0002\u03b6\u03aa\u0003\u0002\u0002", "\u0002\u03b6\u03af\u0003\u0002\u0002\u0002\u03b7G\u0003\u0002\u0002", "\u0002\u03b8\u03b9\b%\u0001\u0002\u03b9\u03bd\u0005J&\u0002\u03ba\u03bb", "\t\u000b\u0002\u0002\u03bb\u03bd\u0005H%\u0006\u03bc\u03b8\u0003\u0002", "\u0002\u0002\u03bc\u03ba\u0003\u0002\u0002\u0002\u03bd\u03cc\u0003\u0002", "\u0002\u0002\u03be\u03bf\f\u0005\u0002\u0002\u03bf\u03c0\t\f\u0002\u0002", "\u03c0\u03cb\u0005H%\u0006\u03c1\u03c2\f\u0004\u0002\u0002\u03c2\u03c3", "\t\u000b\u0002\u0002\u03c3\u03cb\u0005H%\u0005\u03c4\u03c5\f\u0003\u0002", "\u0002\u03c5\u03c6\u0007\u00c5\u0002\u0002\u03c6\u03cb\u0005H%\u0004", "\u03c7\u03c8\f\u0007\u0002\u0002\u03c8\u03c9\u0007\u001e\u0002\u0002", "\u03c9\u03cb\u0005L\'\u0002\u03ca\u03be\u0003\u0002\u0002\u0002\u03ca", "\u03c1\u0003\u0002\u0002\u0002\u03ca\u03c4\u0003\u0002\u0002\u0002\u03ca", "\u03c7\u0003\u0002\u0002\u0002\u03cb\u03ce\u0003\u0002\u0002\u0002\u03cc", "\u03ca\u0003\u0002\u0002\u0002\u03cc\u03cd\u0003\u0002\u0002\u0002\u03cd", "I\u0003\u0002\u0002\u0002\u03ce\u03cc\u0003\u0002\u0002\u0002\u03cf", "\u03d0\b&\u0001\u0002\u03d0\u049e\u0007(\u0002\u0002\u03d1\u049e\u0005", "T+\u0002\u03d2\u03d3\u0005t;\u0002\u03d3\u03d4\u0007\u00c6\u0002\u0002", "\u03d4\u049e\u0003\u0002\u0002\u0002\u03d5\u03d6\u0007\u00d0\u0002\u0002", "\u03d6\u049e\u0007\u00c6\u0002\u0002\u03d7\u049e\u0005x=\u0002\u03d8", "\u049e\u0005R*\u0002\u03d9\u049e\u0007\u00c6\u0002\u0002\u03da\u049e", "\u0007\u00c7\u0002\u0002\u03db\u049e\u0007\u0007\u0002\u0002\u03dc\u03dd", "\u00072\u0002\u0002\u03dd\u03de\u0007\u0004\u0002\u0002\u03de\u03df", "\u0005H%\u0002\u03df\u03e0\u0007!\u0002\u0002\u03e0\u03e1\u0005H%\u0002", "\u03e1\u03e2\u0007\u0006\u0002\u0002\u03e2\u049e\u0003\u0002\u0002\u0002", "\u03e3\u03e4\u0007\u0004\u0002\u0002\u03e4\u03e9\u0005@!\u0002\u03e5", "\u03e6\u0007\u0005\u0002\u0002\u03e6\u03e8\u0005@!\u0002\u03e7\u03e5", "\u0003\u0002\u0002\u0002\u03e8\u03eb\u0003\u0002\u0002\u0002\u03e9\u03e7", "\u0003\u0002\u0002\u0002\u03e9\u03ea\u0003\u0002\u0002\u0002\u03ea\u03ec", "\u0003\u0002\u0002\u0002\u03eb\u03e9\u0003\u0002\u0002\u0002\u03ec\u03ed", "\u0007\u0006\u0002\u0002\u03ed\u049e\u0003\u0002\u0002\u0002\u03ee\u03ef", "\u0007`\u0002\u0002\u03ef\u03f0\u0007\u0004\u0002\u0002\u03f0\u03f5", "\u0005@!\u0002\u03f1\u03f2\u0007\u0005\u0002\u0002\u03f2\u03f4\u0005", "@!\u0002\u03f3\u03f1\u0003\u0002\u0002\u0002\u03f4\u03f7\u0003\u0002", "\u0002\u0002\u03f5\u03f3\u0003\u0002\u0002\u0002\u03f5\u03f6\u0003\u0002", "\u0002\u0002\u03f6\u03f8\u0003\u0002\u0002\u0002\u03f7\u03f5\u0003\u0002", "\u0002\u0002\u03f8\u03f9\u0007\u0006\u0002\u0002\u03f9\u049e\u0003\u0002", "\u0002\u0002\u03fa\u03fb\u0005r:\u0002\u03fb\u03fc\u0007\u0004\u0002", "\u0002\u03fc\u03fd\u0007\u00c2\u0002\u0002\u03fd\u03ff\u0007\u0006\u0002", "\u0002\u03fe\u0400\u0005`1\u0002\u03ff\u03fe\u0003\u0002\u0002\u0002", "\u03ff\u0400\u0003\u0002\u0002\u0002\u0400\u0402\u0003\u0002\u0002\u0002", "\u0401\u0403\u0005b2\u0002\u0402\u0401\u0003\u0002\u0002\u0002\u0402", "\u0403\u0003\u0002\u0002\u0002\u0403\u049e\u0003\u0002\u0002\u0002\u0404", "\u0405\u0005r:\u0002\u0405\u0411\u0007\u0004\u0002\u0002\u0406\u0408", "\u0005,\u0017\u0002\u0407\u0406\u0003\u0002\u0002\u0002\u0407\u0408", "\u0003\u0002\u0002\u0002\u0408\u0409\u0003\u0002\u0002\u0002\u0409\u040e", "\u0005@!\u0002\u040a\u040b\u0007\u0005\u0002\u0002\u040b\u040d\u0005", "@!\u0002\u040c\u040a\u0003\u0002\u0002\u0002\u040d\u0410\u0003\u0002", "\u0002\u0002\u040e\u040c\u0003\u0002\u0002\u0002\u040e\u040f\u0003\u0002", "\u0002\u0002\u040f\u0412\u0003\u0002\u0002\u0002\u0410\u040e\u0003\u0002", "\u0002\u0002\u0411\u0407\u0003\u0002\u0002\u0002\u0411\u0412\u0003\u0002", "\u0002\u0002\u0412\u0413\u0003\u0002\u0002\u0002\u0413\u0415\u0007\u0006", "\u0002\u0002\u0414\u0416\u0005`1\u0002\u0415\u0414\u0003\u0002\u0002", "\u0002\u0415\u0416\u0003\u0002\u0002\u0002\u0416\u0418\u0003\u0002\u0002", "\u0002\u0417\u0419\u0005b2\u0002\u0418\u0417\u0003\u0002\u0002\u0002", "\u0418\u0419\u0003\u0002\u0002\u0002\u0419\u049e\u0003\u0002\u0002\u0002", "\u041a\u041b\u0005t;\u0002\u041b\u041c\u0007\b\u0002\u0002\u041c\u041d", "\u0005@!\u0002\u041d\u049e\u0003\u0002\u0002\u0002\u041e\u041f\u0007", "\u0004\u0002\u0002\u041f\u0424\u0005t;\u0002\u0420\u0421\u0007\u0005", "\u0002\u0002\u0421\u0423\u0005t;\u0002\u0422\u0420\u0003\u0002\u0002", "\u0002\u0423\u0426\u0003\u0002\u0002\u0002\u0424\u0422\u0003\u0002\u0002", "\u0002\u0424\u0425\u0003\u0002\u0002\u0002\u0425\u0427\u0003\u0002\u0002", "\u0002\u0426\u0424\u0003\u0002\u0002\u0002\u0427\u0428\u0007\u0006\u0002", "\u0002\u0428\u0429\u0007\b\u0002\u0002\u0429\u042a\u0005@!\u0002\u042a", "\u049e\u0003\u0002\u0002\u0002\u042b\u042c\u0007\u0004\u0002\u0002\u042c", "\u042d\u0005\n\u0006\u0002\u042d\u042e\u0007\u0006\u0002\u0002\u042e", "\u049e\u0003\u0002\u0002\u0002\u042f\u0430\u0007$\u0002\u0002\u0430", "\u0431\u0007\u0004\u0002\u0002\u0431\u0432\u0005\n\u0006\u0002\u0432", "\u0433\u0007\u0006\u0002\u0002\u0433\u049e\u0003\u0002\u0002\u0002\u0434", "\u0435\u0007H\u0002\u0002\u0435\u0437\u0005H%\u0002\u0436\u0438\u0005", "^0\u0002\u0437\u0436\u0003\u0002\u0002\u0002\u0438\u0439\u0003\u0002", "\u0002\u0002\u0439\u0437\u0003\u0002\u0002\u0002\u0439\u043a\u0003\u0002", "\u0002\u0002\u043a\u043d\u0003\u0002\u0002\u0002\u043b\u043c\u0007K", "\u0002\u0002\u043c\u043e\u0005@!\u0002\u043d\u043b\u0003\u0002\u0002", "\u0002\u043d\u043e\u0003\u0002\u0002\u0002\u043e\u043f\u0003\u0002\u0002", "\u0002\u043f\u0440\u0007L\u0002\u0002\u0440\u049e\u0003\u0002\u0002", "\u0002\u0441\u0443\u0007H\u0002\u0002\u0442\u0444\u0005^0\u0002\u0443", "\u0442\u0003\u0002\u0002\u0002\u0444\u0445\u0003\u0002\u0002\u0002\u0445", "\u0443\u0003\u0002\u0002\u0002\u0445\u0446\u0003\u0002\u0002\u0002\u0446", "\u0449\u0003\u0002\u0002\u0002\u0447\u0448\u0007K\u0002\u0002\u0448", "\u044a\u0005@!\u0002\u0449\u0447\u0003\u0002\u0002\u0002\u0449\u044a", "\u0003\u0002\u0002\u0002\u044a\u044b\u0003\u0002\u0002\u0002\u044b\u044c", "\u0007L\u0002\u0002\u044c\u049e\u0003\u0002\u0002\u0002\u044d\u044e", "\u0007{\u0002\u0002\u044e\u044f\u0007\u0004\u0002\u0002\u044f\u0450", "\u0005@!\u0002\u0450\u0451\u0007\u000f\u0002\u0002\u0451\u0452\u0005", "X-\u0002\u0452\u0453\u0007\u0006\u0002\u0002\u0453\u049e\u0003\u0002", "\u0002\u0002\u0454\u0455\u0007|\u0002\u0002\u0455\u0456\u0007\u0004", "\u0002\u0002\u0456\u0457\u0005@!\u0002\u0457\u0458\u0007\u000f\u0002", "\u0002\u0458\u0459\u0005X-\u0002\u0459\u045a\u0007\u0006\u0002\u0002", "\u045a\u049e\u0003\u0002\u0002\u0002\u045b\u045c\u0007\u0093\u0002\u0002", "\u045c\u0465\u0007\t\u0002\u0002\u045d\u0462\u0005@!\u0002\u045e\u045f", "\u0007\u0005\u0002\u0002\u045f\u0461\u0005@!\u0002\u0460\u045e\u0003", "\u0002\u0002\u0002\u0461\u0464\u0003\u0002\u0002\u0002\u0462\u0460\u0003", "\u0002\u0002\u0002\u0462\u0463\u0003\u0002\u0002\u0002\u0463\u0466\u0003", "\u0002\u0002\u0002\u0464\u0462\u0003\u0002\u0002\u0002\u0465\u045d\u0003", "\u0002\u0002\u0002\u0465\u0466\u0003\u0002\u0002\u0002\u0466\u0467\u0003", "\u0002\u0002\u0002\u0467\u049e\u0007\n\u0002\u0002\u0468\u049e\u0005", "t;\u0002\u0469\u049e\u0007B\u0002\u0002\u046a\u046e\u0007C\u0002\u0002", "\u046b\u046c\u0007\u0004\u0002\u0002\u046c\u046d\u0007\u00c8\u0002\u0002", "\u046d\u046f\u0007\u0006\u0002\u0002\u046e\u046b\u0003\u0002\u0002\u0002", "\u046e\u046f\u0003\u0002\u0002\u0002\u046f\u049e\u0003\u0002\u0002\u0002", "\u0470\u0474\u0007D\u0002\u0002\u0471\u0472\u0007\u0004\u0002\u0002", "\u0472\u0473\u0007\u00c8\u0002\u0002\u0473\u0475\u0007\u0006\u0002\u0002", "\u0474\u0471\u0003\u0002\u0002\u0002\u0474\u0475\u0003\u0002\u0002\u0002", "\u0475\u049e\u0003\u0002\u0002\u0002\u0476\u047a\u0007E\u0002\u0002", "\u0477\u0478\u0007\u0004\u0002\u0002\u0478\u0479\u0007\u00c8\u0002\u0002", "\u0479\u047b\u0007\u0006\u0002\u0002\u047a\u0477\u0003\u0002\u0002\u0002", "\u047a\u047b\u0003\u0002\u0002\u0002\u047b\u049e\u0003\u0002\u0002\u0002", "\u047c\u0480\u0007F\u0002\u0002\u047d\u047e\u0007\u0004\u0002\u0002", "\u047e\u047f\u0007\u00c8\u0002\u0002\u047f\u0481\u0007\u0006\u0002\u0002", "\u0480\u047d\u0003\u0002\u0002\u0002\u0480\u0481\u0003\u0002\u0002\u0002", "\u0481\u049e\u0003\u0002\u0002\u0002\u0482\u0483\u00071\u0002\u0002", "\u0483\u0484\u0007\u0004\u0002\u0002\u0484\u0485\u0005H%\u0002\u0485", "\u0486\u0007\r\u0002\u0002\u0486\u0489\u0005H%\u0002\u0487\u0488\u0007", "3\u0002\u0002\u0488\u048a\u0005H%\u0002\u0489\u0487\u0003\u0002\u0002", "\u0002\u0489\u048a\u0003\u0002\u0002\u0002\u048a\u048b\u0003\u0002\u0002", "\u0002\u048b\u048c\u0007\u0006\u0002\u0002\u048c\u049e\u0003\u0002\u0002", "\u0002\u048d\u048e\u0007\u00b2\u0002\u0002\u048e\u048f\u0007\u0004\u0002", "\u0002\u048f\u0492\u0005H%\u0002\u0490\u0491\u0007\u0005\u0002\u0002", "\u0491\u0493\u0005|?\u0002\u0492\u0490\u0003\u0002\u0002\u0002\u0492", "\u0493\u0003\u0002\u0002\u0002\u0493\u0494\u0003\u0002\u0002\u0002\u0494", "\u0495\u0007\u0006\u0002\u0002\u0495\u049e\u0003\u0002\u0002\u0002\u0496", "\u0497\u0007G\u0002\u0002\u0497\u0498\u0007\u0004\u0002\u0002\u0498", "\u0499\u0005t;\u0002\u0499\u049a\u0007\r\u0002\u0002\u049a\u049b\u0005", "H%\u0002\u049b\u049c\u0007\u0006\u0002\u0002\u049c\u049e\u0003\u0002", "\u0002\u0002\u049d\u03cf\u0003\u0002\u0002\u0002\u049d\u03d1\u0003\u0002", "\u0002\u0002\u049d\u03d2\u0003\u0002\u0002\u0002\u049d\u03d5\u0003\u0002", "\u0002\u0002\u049d\u03d7\u0003\u0002\u0002\u0002\u049d\u03d8\u0003\u0002", "\u0002\u0002\u049d\u03d9\u0003\u0002\u0002\u0002\u049d\u03da\u0003\u0002", "\u0002\u0002\u049d\u03db\u0003\u0002\u0002\u0002\u049d\u03dc\u0003\u0002", "\u0002\u0002\u049d\u03e3\u0003\u0002\u0002\u0002\u049d\u03ee\u0003\u0002", "\u0002\u0002\u049d\u03fa\u0003\u0002\u0002\u0002\u049d\u0404\u0003\u0002", "\u0002\u0002\u049d\u041a\u0003\u0002\u0002\u0002\u049d\u041e\u0003\u0002", "\u0002\u0002\u049d\u042b\u0003\u0002\u0002\u0002\u049d\u042f\u0003\u0002", "\u0002\u0002\u049d\u0434\u0003\u0002\u0002\u0002\u049d\u0441\u0003\u0002", "\u0002\u0002\u049d\u044d\u0003\u0002\u0002\u0002\u049d\u0454\u0003\u0002", "\u0002\u0002\u049d\u045b\u0003\u0002\u0002\u0002\u049d\u0468\u0003\u0002", "\u0002\u0002\u049d\u0469\u0003\u0002\u0002\u0002\u049d\u046a\u0003\u0002", "\u0002\u0002\u049d\u0470\u0003\u0002\u0002\u0002\u049d\u0476\u0003\u0002", "\u0002\u0002\u049d\u047c\u0003\u0002\u0002\u0002\u049d\u0482\u0003\u0002", "\u0002\u0002\u049d\u048d\u0003\u0002\u0002\u0002\u049d\u0496\u0003\u0002", "\u0002\u0002\u049e\u04a9\u0003\u0002\u0002\u0002\u049f\u04a0\f\r\u0002", "\u0002\u04a0\u04a1\u0007\t\u0002\u0002\u04a1\u04a2\u0005H%\u0002\u04a2", "\u04a3\u0007\n\u0002\u0002\u04a3\u04a8\u0003\u0002\u0002\u0002\u04a4", "\u04a5\f\u000b\u0002\u0002\u04a5\u04a6\u0007\u0003\u0002\u0002\u04a6", "\u04a8\u0005t;\u0002\u04a7\u049f\u0003\u0002\u0002\u0002\u04a7\u04a4", "\u0003\u0002\u0002\u0002\u04a8\u04ab\u0003\u0002\u0002\u0002\u04a9\u04a7", "\u0003\u0002\u0002\u0002\u04a9\u04aa\u0003\u0002\u0002\u0002\u04aaK", "\u0003\u0002\u0002\u0002\u04ab\u04a9\u0003\u0002\u0002\u0002\u04ac\u04ad", "\u00078\u0002\u0002\u04ad\u04ae\u0007A\u0002\u0002\u04ae\u04b3\u0005", "T+\u0002\u04af\u04b0\u00078\u0002\u0002\u04b0\u04b1\u0007A\u0002\u0002", "\u04b1\u04b3\u0007\u00c6\u0002\u0002\u04b2\u04ac\u0003\u0002\u0002\u0002", "\u04b2\u04af\u0003\u0002\u0002\u0002\u04b3M\u0003\u0002\u0002\u0002", "\u04b4\u04b5\t\r\u0002\u0002\u04b5O\u0003\u0002\u0002\u0002\u04b6\u04b7", "\t\u000e\u0002\u0002\u04b7Q\u0003\u0002\u0002\u0002\u04b8\u04b9\t\u000f", "\u0002\u0002\u04b9S\u0003\u0002\u0002\u0002\u04ba\u04bc\u0007:\u0002", "\u0002\u04bb\u04bd\t\u000b\u0002\u0002\u04bc\u04bb\u0003\u0002\u0002", "\u0002\u04bc\u04bd\u0003\u0002\u0002\u0002\u04bd\u04be\u0003\u0002\u0002", "\u0002\u04be\u04bf\u0007\u00c6\u0002\u0002\u04bf\u04c2\u0005V,\u0002", "\u04c0\u04c1\u0007\u008a\u0002\u0002\u04c1\u04c3\u0005V,\u0002\u04c2", "\u04c0\u0003\u0002\u0002\u0002\u04c2\u04c3\u0003\u0002\u0002\u0002\u04c3", "U\u0003\u0002\u0002\u0002\u04c4\u04c5\t\u0010\u0002\u0002\u04c5W\u0003", "\u0002\u0002\u0002\u04c6\u04c7\b-\u0001\u0002\u04c7\u04c8\u0007\u0093", "\u0002\u0002\u04c8\u04c9\u0007\u00bc\u0002\u0002\u04c9\u04ca\u0005X", "-\u0002\u04ca\u04cb\u0007\u00be\u0002\u0002\u04cb\u04f1\u0003\u0002", "\u0002\u0002\u04cc\u04cd\u0007\u0094\u0002\u0002\u04cd\u04ce\u0007\u00bc", "\u0002\u0002\u04ce\u04cf\u0005X-\u0002\u04cf\u04d0\u0007\u0005\u0002", "\u0002\u04d0\u04d1\u0005X-\u0002\u04d1\u04d2\u0007\u00be\u0002\u0002", "\u04d2\u04f1\u0003\u0002\u0002\u0002\u04d3\u04d4\u0007`\u0002\u0002", "\u04d4\u04d5\u0007\u0004\u0002\u0002\u04d5\u04d6\u0005t;\u0002\u04d6", "\u04dd\u0005X-\u0002\u04d7\u04d8\u0007\u0005\u0002\u0002\u04d8\u04d9", "\u0005t;\u0002\u04d9\u04da\u0005X-\u0002\u04da\u04dc\u0003\u0002\u0002", "\u0002\u04db\u04d7\u0003\u0002\u0002\u0002\u04dc\u04df\u0003\u0002\u0002", "\u0002\u04dd\u04db\u0003\u0002\u0002\u0002\u04dd\u04de\u0003\u0002\u0002", "\u0002\u04de\u04e0\u0003\u0002\u0002\u0002\u04df\u04dd\u0003\u0002\u0002", "\u0002\u04e0\u04e1\u0007\u0006\u0002\u0002\u04e1\u04f1\u0003\u0002\u0002", "\u0002\u04e2\u04ee\u0005\\/\u0002\u04e3\u04e4\u0007\u0004\u0002\u0002", "\u04e4\u04e9\u0005Z.\u0002\u04e5\u04e6\u0007\u0005\u0002\u0002\u04e6", "\u04e8\u0005Z.\u0002\u04e7\u04e5\u0003\u0002\u0002\u0002\u04e8\u04eb", "\u0003\u0002\u0002\u0002\u04e9\u04e7\u0003\u0002\u0002\u0002\u04e9\u04ea", "\u0003\u0002\u0002\u0002\u04ea\u04ec\u0003\u0002\u0002\u0002\u04eb\u04e9", "\u0003\u0002\u0002\u0002\u04ec\u04ed\u0007\u0006\u0002\u0002\u04ed\u04ef", "\u0003\u0002\u0002\u0002\u04ee\u04e3\u0003\u0002\u0002\u0002\u04ee\u04ef", "\u0003\u0002\u0002\u0002\u04ef\u04f1\u0003\u0002\u0002\u0002\u04f0\u04c6", "\u0003\u0002\u0002\u0002\u04f0\u04cc\u0003\u0002\u0002\u0002\u04f0\u04d3", "\u0003\u0002\u0002\u0002\u04f0\u04e2\u0003\u0002\u0002\u0002\u04f1\u04f6", "\u0003\u0002\u0002\u0002\u04f2\u04f3\f\u0007\u0002\u0002\u04f3\u04f5", "\u0007\u0093\u0002\u0002\u04f4\u04f2\u0003\u0002\u0002\u0002\u04f5\u04f8", "\u0003\u0002\u0002\u0002\u04f6\u04f4\u0003\u0002\u0002\u0002\u04f6\u04f7", "\u0003\u0002\u0002\u0002\u04f7Y\u0003\u0002\u0002\u0002\u04f8\u04f6", "\u0003\u0002\u0002\u0002\u04f9\u04fc\u0007\u00c8\u0002\u0002\u04fa\u04fc", "\u0005X-\u0002\u04fb\u04f9\u0003\u0002\u0002\u0002\u04fb\u04fa\u0003", "\u0002\u0002\u0002\u04fc[\u0003\u0002\u0002\u0002\u04fd\u0502\u0007", "\u00ce\u0002\u0002\u04fe\u0502\u0007\u00cf\u0002\u0002\u04ff\u0502\u0007", "\u00d0\u0002\u0002\u0500\u0502\u0005t;\u0002\u0501\u04fd\u0003\u0002", "\u0002\u0002\u0501\u04fe\u0003\u0002\u0002\u0002\u0501\u04ff\u0003\u0002", "\u0002\u0002\u0501\u0500\u0003\u0002\u0002\u0002\u0502]\u0003\u0002", "\u0002\u0002\u0503\u0504\u0007I\u0002\u0002\u0504\u0505\u0005@!\u0002", "\u0505\u0506\u0007J\u0002\u0002\u0506\u0507\u0005@!\u0002\u0507_\u0003", "\u0002\u0002\u0002\u0508\u0509\u0007W\u0002\u0002\u0509\u050a\u0007", "\u0004\u0002\u0002\u050a\u050b\u0007\u0014\u0002\u0002\u050b\u050c\u0005", "B\"\u0002\u050c\u050d\u0007\u0006\u0002\u0002\u050da\u0003\u0002\u0002", "\u0002\u050e\u050f\u0007X\u0002\u0002\u050f\u051a\u0007\u0004\u0002", "\u0002\u0510\u0511\u0007Y\u0002\u0002\u0511\u0512\u0007\u0016\u0002", "\u0002\u0512\u0517\u0005@!\u0002\u0513\u0514\u0007\u0005\u0002\u0002", "\u0514\u0516\u0005@!\u0002\u0515\u0513\u0003\u0002\u0002\u0002\u0516", "\u0519\u0003\u0002\u0002\u0002\u0517\u0515\u0003\u0002\u0002\u0002\u0517", "\u0518\u0003\u0002\u0002\u0002\u0518\u051b\u0003\u0002\u0002\u0002\u0519", "\u0517\u0003\u0002\u0002\u0002\u051a\u0510\u0003\u0002\u0002\u0002\u051a", "\u051b\u0003\u0002\u0002\u0002\u051b\u0526\u0003\u0002\u0002\u0002\u051c", "\u051d\u0007\u001b\u0002\u0002\u051d\u051e\u0007\u0016\u0002\u0002\u051e", "\u0523\u0005\u001e\u0010\u0002\u051f\u0520\u0007\u0005\u0002\u0002\u0520", "\u0522\u0005\u001e\u0010\u0002\u0521\u051f\u0003\u0002\u0002\u0002\u0522", "\u0525\u0003\u0002\u0002\u0002\u0523\u0521\u0003\u0002\u0002\u0002\u0523", "\u0524\u0003\u0002\u0002\u0002\u0524\u0527\u0003\u0002\u0002\u0002\u0525", "\u0523\u0003\u0002\u0002\u0002\u0526\u051c\u0003\u0002\u0002\u0002\u0526", "\u0527\u0003\u0002\u0002\u0002\u0527\u0529\u0003\u0002\u0002\u0002\u0528", "\u052a\u0005d3\u0002\u0529\u0528\u0003\u0002\u0002\u0002\u0529\u052a", "\u0003\u0002\u0002\u0002\u052a\u052b\u0003\u0002\u0002\u0002\u052b\u052c", "\u0007\u0006\u0002\u0002\u052cc\u0003\u0002\u0002\u0002\u052d\u052e", "\u0007Z\u0002\u0002\u052e\u053e\u0005f4\u0002\u052f\u0530\u0007[\u0002", "\u0002\u0530\u053e\u0005f4\u0002\u0531\u0532\u0007Z\u0002\u0002\u0532", "\u0533\u0007%\u0002\u0002\u0533\u0534\u0005f4\u0002\u0534\u0535\u0007", " \u0002\u0002\u0535\u0536\u0005f4\u0002\u0536\u053e\u0003\u0002\u0002", "\u0002\u0537\u0538\u0007[\u0002\u0002\u0538\u0539\u0007%\u0002\u0002", "\u0539\u053a\u0005f4\u0002\u053a\u053b\u0007 \u0002\u0002\u053b\u053c", "\u0005f4\u0002\u053c\u053e\u0003\u0002\u0002\u0002\u053d\u052d\u0003", "\u0002\u0002\u0002\u053d\u052f\u0003\u0002\u0002\u0002\u053d\u0531\u0003", "\u0002\u0002\u0002\u053d\u0537\u0003\u0002\u0002\u0002\u053ee\u0003", "\u0002\u0002\u0002\u053f\u0540\u0007\\\u0002\u0002\u0540\u0549\u0007", "]\u0002\u0002\u0541\u0542\u0007\\\u0002\u0002\u0542\u0549\u0007^\u0002", "\u0002\u0543\u0544\u0007_\u0002\u0002\u0544\u0549\u0007`\u0002\u0002", "\u0545\u0546\u0005@!\u0002\u0546\u0547\t\u0011\u0002\u0002\u0547\u0549", "\u0003\u0002\u0002\u0002\u0548\u053f\u0003\u0002\u0002\u0002\u0548\u0541", "\u0003\u0002\u0002\u0002\u0548\u0543\u0003\u0002\u0002\u0002\u0548\u0545", "\u0003\u0002\u0002\u0002\u0549g\u0003\u0002\u0002\u0002\u054a\u054b", "\u0007u\u0002\u0002\u054b\u054f\t\u0012\u0002\u0002\u054c\u054d\u0007", "v\u0002\u0002\u054d\u054f\t\u0013\u0002\u0002\u054e\u054a\u0003\u0002", "\u0002\u0002\u054e\u054c\u0003\u0002\u0002\u0002\u054fi\u0003\u0002", "\u0002\u0002\u0550\u0551\u0007\u009e\u0002\u0002\u0551\u0552\u0007\u009f", "\u0002\u0002\u0552\u0556\u0005l7\u0002\u0553\u0554\u0007\u00a4\u0002", "\u0002\u0554\u0556\t\u0014\u0002\u0002\u0555\u0550\u0003\u0002\u0002", "\u0002\u0555\u0553\u0003\u0002\u0002\u0002\u0556k\u0003\u0002\u0002", "\u0002\u0557\u0558\u0007\u00a4\u0002\u0002\u0558\u055f\u0007\u00a3\u0002", "\u0002\u0559\u055a\u0007\u00a4\u0002\u0002\u055a\u055f\u0007\u00a2\u0002", "\u0002\u055b\u055c\u0007\u00a1\u0002\u0002\u055c\u055f\u0007\u00a4\u0002", "\u0002\u055d\u055f\u0007\u00a0\u0002\u0002\u055e\u0557\u0003\u0002\u0002", "\u0002\u055e\u0559\u0003\u0002\u0002\u0002\u055e\u055b\u0003\u0002\u0002", "\u0002\u055e\u055d\u0003\u0002\u0002\u0002\u055fm\u0003\u0002\u0002", "\u0002\u0560\u0566\u0005@!\u0002\u0561\u0562\u0005t;\u0002\u0562\u0563", "\u0007\u000b\u0002\u0002\u0563\u0564\u0005@!\u0002\u0564\u0566\u0003", "\u0002\u0002\u0002\u0565\u0560\u0003\u0002\u0002\u0002\u0565\u0561\u0003", "\u0002\u0002\u0002\u0566o\u0003\u0002\u0002\u0002\u0567\u056c\u0007", "\f\u0002\u0002\u0568\u056c\u0007j\u0002\u0002\u0569\u056c\u0007i\u0002", "\u0002\u056a\u056c\u0005t;\u0002\u056b\u0567\u0003\u0002\u0002\u0002", "\u056b\u0568\u0003\u0002\u0002\u0002\u056b\u0569\u0003\u0002\u0002\u0002", "\u056b\u056a\u0003\u0002\u0002\u0002\u056cq\u0003\u0002\u0002\u0002", "\u056d\u0572\u0005t;\u0002\u056e\u056f\u0007\u0003\u0002\u0002\u056f", "\u0571\u0005t;\u0002\u0570\u056e\u0003\u0002\u0002\u0002\u0571\u0574", "\u0003\u0002\u0002\u0002\u0572\u0570\u0003\u0002\u0002\u0002\u0572\u0573", "\u0003\u0002\u0002\u0002\u0573s\u0003\u0002\u0002\u0002\u0574\u0572", "\u0003\u0002\u0002\u0002\u0575\u057b\u0007\u00ca\u0002\u0002\u0576\u057b", "\u0005v<\u0002\u0577\u057b\u0005z>\u0002\u0578\u057b\u0007\u00cd\u0002", "\u0002\u0579\u057b\u0007\u00cb\u0002\u0002\u057a\u0575\u0003\u0002\u0002", "\u0002\u057a\u0576\u0003\u0002\u0002\u0002\u057a\u0577\u0003\u0002\u0002", "\u0002\u057a\u0578\u0003\u0002\u0002\u0002\u057a\u0579\u0003\u0002\u0002", "\u0002\u057bu\u0003\u0002\u0002\u0002\u057c\u057d\u0007\u00cc\u0002", "\u0002\u057dw\u0003\u0002\u0002\u0002\u057e\u0581\u0007\u00c9\u0002", "\u0002\u057f\u0581\u0007\u00c8\u0002\u0002\u0580\u057e\u0003\u0002\u0002", "\u0002\u0580\u057f\u0003\u0002\u0002\u0002\u0581y\u0003\u0002\u0002", "\u0002\u0582\u05dc\u0007}\u0002\u0002\u0583\u05dc\u0007~\u0002\u0002", "\u0584\u05dc\u0007\u0081\u0002\u0002\u0585\u05dc\u0007\u0082\u0002\u0002", "\u0586\u05dc\u0007\u0084\u0002\u0002\u0587\u05dc\u0007\u0085\u0002\u0002", "\u0588\u05dc\u0007\u007f\u0002\u0002\u0589\u05dc\u0007\u0080\u0002\u0002", "\u058a\u05dc\u0007\u0097\u0002\u0002\u058b\u05dc\u0007\u000e\u0002\u0002", "\u058c\u05dc\u0007W\u0002\u0002\u058d\u05dc\u0007X\u0002\u0002\u058e", "\u05dc\u0007Y\u0002\u0002\u058f\u05dc\u0007Z\u0002\u0002\u0590\u05dc", "\u0007[\u0002\u0002\u0591\u05dc\u0007]\u0002\u0002\u0592\u05dc\u0007", "^\u0002\u0002\u0593\u05dc\u0007_\u0002\u0002\u0594\u05dc\u0007`\u0002", "\u0002\u0595\u05dc\u0007\u0094\u0002\u0002\u0596\u05dc\u0007\u0093\u0002", "\u0002\u0597\u05dc\u00074\u0002\u0002\u0598\u05dc\u00075\u0002\u0002", "\u0599\u05dc\u00076\u0002\u0002\u059a\u05dc\u00077\u0002\u0002\u059b", "\u05dc\u00078\u0002\u0002\u059c\u05dc\u00079\u0002\u0002\u059d\u05dc", "\u0007:\u0002\u0002\u059e\u05dc\u0007A\u0002\u0002\u059f\u05dc\u0007", ";\u0002\u0002\u05a0\u05dc\u0007<\u0002\u0002\u05a1\u05dc\u0007=\u0002", "\u0002\u05a2\u05dc\u0007>\u0002\u0002\u05a3\u05dc\u0007?\u0002\u0002", "\u05a4\u05dc\u0007@\u0002\u0002\u05a5\u05dc\u0007s\u0002\u0002\u05a6", "\u05dc\u0007t\u0002\u0002\u05a7\u05dc\u0007u\u0002\u0002\u05a8\u05dc", "\u0007v\u0002\u0002\u05a9\u05dc\u0007w\u0002\u0002\u05aa\u05dc\u0007", "x\u0002\u0002\u05ab\u05dc\u0007y\u0002\u0002\u05ac\u05dc\u0007z\u0002", "\u0002\u05ad\u05dc\u0007\u008e\u0002\u0002\u05ae\u05dc\u0007\u008b\u0002", "\u0002\u05af\u05dc\u0007\u008c\u0002\u0002\u05b0\u05dc\u0007\u008d\u0002", "\u0002\u05b1\u05dc\u0007\u0083\u0002\u0002\u05b2\u05dc\u0007\u008a\u0002", "\u0002\u05b3\u05dc\u0007\u0095\u0002\u0002\u05b4\u05dc\u0007\u0096\u0002", "\u0002\u05b5\u05dc\u0007g\u0002\u0002\u05b6\u05dc\u0007h\u0002\u0002", "\u05b7\u05dc\u0007\u00b7\u0002\u0002\u05b8\u05dc\u0007\u00b8\u0002\u0002", "\u05b9\u05dc\u0007\u00b9\u0002\u0002\u05ba\u05dc\u0005|?\u0002\u05bb", "\u05dc\u00072\u0002\u0002\u05bc\u05dc\u0007#\u0002\u0002\u05bd\u05dc", "\u0007\u0098\u0002\u0002\u05be\u05dc\u0007\u0099\u0002\u0002\u05bf\u05dc", "\u0007\u009a\u0002\u0002\u05c0\u05dc\u0007\u009b\u0002\u0002\u05c1\u05dc", "\u0007\u009c\u0002\u0002\u05c2\u05dc\u0007\u009d\u0002\u0002\u05c3\u05dc", "\u0007\u009e\u0002\u0002\u05c4\u05dc\u0007\u009f\u0002\u0002\u05c5\u05dc", "\u0007\u00a0\u0002\u0002\u05c6\u05dc\u0007\u00a1\u0002\u0002\u05c7\u05dc", "\u0007\u00a2\u0002\u0002\u05c8\u05dc\u0007\u00a3\u0002\u0002\u05c9\u05dc", "\u0007\u00a4\u0002\u0002\u05ca\u05dc\u0007\u00a5\u0002\u0002\u05cb\u05dc", "\u0007\u00a6\u0002\u0002\u05cc\u05dc\u0007\u00a7\u0002\u0002\u05cd\u05dc", "\u0007n\u0002\u0002\u05ce\u05dc\u0007o\u0002\u0002\u05cf\u05dc\u0007", "p\u0002\u0002\u05d0\u05dc\u0007q\u0002\u0002\u05d1\u05dc\u0007r\u0002", "\u0002\u05d2\u05dc\u00071\u0002\u0002\u05d3\u05dc\u0007e\u0002\u0002", "\u05d4\u05dc\u0007\u00ad\u0002\u0002\u05d5\u05dc\u0007\u00ae\u0002\u0002", "\u05d6\u05dc\u0007\u00ab\u0002\u0002\u05d7\u05dc\u0007\u00ac\u0002\u0002", "\u05d8\u05dc\u0007\u00af\u0002\u0002\u05d9\u05dc\u0007\u00b0\u0002\u0002", "\u05da\u05dc\u0007\u00b1\u0002\u0002\u05db\u0582\u0003\u0002\u0002\u0002", "\u05db\u0583\u0003\u0002\u0002\u0002\u05db\u0584\u0003\u0002\u0002\u0002", "\u05db\u0585\u0003\u0002\u0002\u0002\u05db\u0586\u0003\u0002\u0002\u0002", "\u05db\u0587\u0003\u0002\u0002\u0002\u05db\u0588\u0003\u0002\u0002\u0002", "\u05db\u0589\u0003\u0002\u0002\u0002\u05db\u058a\u0003\u0002\u0002\u0002", "\u05db\u058b\u0003\u0002\u0002\u0002\u05db\u058c\u0003\u0002\u0002\u0002", "\u05db\u058d\u0003\u0002\u0002\u0002\u05db\u058e\u0003\u0002\u0002\u0002", "\u05db\u058f\u0003\u0002\u0002\u0002\u05db\u0590\u0003\u0002\u0002\u0002", "\u05db\u0591\u0003\u0002\u0002\u0002\u05db\u0592\u0003\u0002\u0002\u0002", "\u05db\u0593\u0003\u0002\u0002\u0002\u05db\u0594\u0003\u0002\u0002\u0002", "\u05db\u0595\u0003\u0002\u0002\u0002\u05db\u0596\u0003\u0002\u0002\u0002", "\u05db\u0597\u0003\u0002\u0002\u0002\u05db\u0598\u0003\u0002\u0002\u0002", "\u05db\u0599\u0003\u0002\u0002\u0002\u05db\u059a\u0003\u0002\u0002\u0002", "\u05db\u059b\u0003\u0002\u0002\u0002\u05db\u059c\u0003\u0002\u0002\u0002", "\u05db\u059d\u0003\u0002\u0002\u0002\u05db\u059e\u0003\u0002\u0002\u0002", "\u05db\u059f\u0003\u0002\u0002\u0002\u05db\u05a0\u0003\u0002\u0002\u0002", "\u05db\u05a1\u0003\u0002\u0002\u0002\u05db\u05a2\u0003\u0002\u0002\u0002", "\u05db\u05a3\u0003\u0002\u0002\u0002\u05db\u05a4\u0003\u0002\u0002\u0002", "\u05db\u05a5\u0003\u0002\u0002\u0002\u05db\u05a6\u0003\u0002\u0002\u0002", "\u05db\u05a7\u0003\u0002\u0002\u0002\u05db\u05a8\u0003\u0002\u0002\u0002", "\u05db\u05a9\u0003\u0002\u0002\u0002\u05db\u05aa\u0003\u0002\u0002\u0002", "\u05db\u05ab\u0003\u0002\u0002\u0002\u05db\u05ac\u0003\u0002\u0002\u0002", "\u05db\u05ad\u0003\u0002\u0002\u0002\u05db\u05ae\u0003\u0002\u0002\u0002", "\u05db\u05af\u0003\u0002\u0002\u0002\u05db\u05b0\u0003\u0002\u0002\u0002", "\u05db\u05b1\u0003\u0002\u0002\u0002\u05db\u05b2\u0003\u0002\u0002\u0002", "\u05db\u05b3\u0003\u0002\u0002\u0002\u05db\u05b4\u0003\u0002\u0002\u0002", "\u05db\u05b5\u0003\u0002\u0002\u0002\u05db\u05b6\u0003\u0002\u0002\u0002", "\u05db\u05b7\u0003\u0002\u0002\u0002\u05db\u05b8\u0003\u0002\u0002\u0002", "\u05db\u05b9\u0003\u0002\u0002\u0002\u05db\u05ba\u0003\u0002\u0002\u0002", "\u05db\u05bb\u0003\u0002\u0002\u0002\u05db\u05bc\u0003\u0002\u0002\u0002", "\u05db\u05bd\u0003\u0002\u0002\u0002\u05db\u05be\u0003\u0002\u0002\u0002", "\u05db\u05bf\u0003\u0002\u0002\u0002\u05db\u05c0\u0003\u0002\u0002\u0002", "\u05db\u05c1\u0003\u0002\u0002\u0002\u05db\u05c2\u0003\u0002\u0002\u0002", "\u05db\u05c3\u0003\u0002\u0002\u0002\u05db\u05c4\u0003\u0002\u0002\u0002", "\u05db\u05c5\u0003\u0002\u0002\u0002\u05db\u05c6\u0003\u0002\u0002\u0002", "\u05db\u05c7\u0003\u0002\u0002\u0002\u05db\u05c8\u0003\u0002\u0002\u0002", "\u05db\u05c9\u0003\u0002\u0002\u0002\u05db\u05ca\u0003\u0002\u0002\u0002", "\u05db\u05cb\u0003\u0002\u0002\u0002\u05db\u05cc\u0003\u0002\u0002\u0002", "\u05db\u05cd\u0003\u0002\u0002\u0002\u05db\u05ce\u0003\u0002\u0002\u0002", "\u05db\u05cf\u0003\u0002\u0002\u0002\u05db\u05d0\u0003\u0002\u0002\u0002", "\u05db\u05d1\u0003\u0002\u0002\u0002\u05db\u05d2\u0003\u0002\u0002\u0002", "\u05db\u05d3\u0003\u0002\u0002\u0002\u05db\u05d4\u0003\u0002\u0002\u0002", "\u05db\u05d5\u0003\u0002\u0002\u0002\u05db\u05d6\u0003\u0002\u0002\u0002", "\u05db\u05d7\u0003\u0002\u0002\u0002\u05db\u05d8\u0003\u0002\u0002\u0002", "\u05db\u05d9\u0003\u0002\u0002\u0002\u05db\u05da\u0003\u0002\u0002\u0002", "\u05dc{\u0003\u0002\u0002\u0002\u05dd\u05de\t\u0015\u0002\u0002\u05de", "}\u0003\u0002\u0002\u0002\u00af\u0083\u0087\u009e\u00a3\u00a9\u00ad", "\u00bb\u00c0\u00c6\u00c9\u00d0\u00d9\u00df\u00e5\u00ec\u00f5\u0111\u011c", "\u0127\u012a\u0134\u0139\u013d\u0145\u014b\u0152\u0157\u015b\u0163\u016b", "\u0170\u017f\u0183\u0189\u018d\u0193\u01b1\u01b4\u01b8\u01bc\u01c4\u01cd", "\u01d0\u01d4\u01e6\u01e9\u01f1\u01f4\u01fa\u0201\u0206\u020f\u0217\u0228", "\u022b\u022f\u0237\u023d\u0240\u0242\u024e\u0255\u0259\u025d\u0261\u0268", "\u0271\u0274\u0278\u027d\u0281\u0284\u028b\u0296\u0299\u02a3\u02a6\u02b1", "\u02b6\u02be\u02c1\u02c5\u02cd\u02d0\u02d4\u02d8\u02e3\u02e6\u02ed\u0300", "\u0304\u0308\u030c\u0310\u0314\u0316\u0321\u0326\u032f\u0335\u0339\u033b", "\u0343\u0354\u035a\u0360\u0368\u0370\u0372\u0377\u0383\u038b\u0394\u039a", "\u03a2\u03a8\u03ac\u03b1\u03b6\u03bc\u03ca\u03cc\u03e9\u03f5\u03ff\u0402", "\u0407\u040e\u0411\u0415\u0418\u0424\u0439\u043d\u0445\u0449\u0462\u0465", "\u046e\u0474\u047a\u0480\u0489\u0492\u049d\u04a7\u04a9\u04b2\u04bc\u04c2", "\u04dd\u04e9\u04ee\u04f0\u04f6\u04fb\u0501\u0517\u051a\u0523\u0526\u0529", "\u053d\u0548\u054e\u0555\u055e\u0565\u056b\u0572\u057a\u0580\u05db"].join(""); var atn = new _atn.ATNDeserializer().deserialize(serializedATN); var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new dfa.DFA(ds, index); }); var sharedContextCache = new PredictionContextCache(); var literalNames = [ null, "'.'", "'('", "','", "')'", "'?'", "'->'", "'['", "']'", "'=>'", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "'='", null, "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", "'||'", null, null, null, null, null, null, null, null, null, null, null, null, null, null, "';'" ]; var symbolicNames = [ null, null, null, null, null, null, null, null, null, null, "SELECT", "FROM", "ADD", "AS", "ALL", "SOME", "ANY", "DISTINCT", "WHERE", "GROUP", "BY", "GROUPING", "SETS", "CUBE", "ROLLUP", "ORDER", "HAVING", "LIMIT", "AT", "OR", "AND", "IN", "NOT", "NO", "EXISTS", "BETWEEN", "LIKE", "IS", "NULL", "TRUE", "FALSE", "NULLS", "FIRST", "LAST", "ESCAPE", "ASC", "DESC", "SUBSTRING", "POSITION", "FOR", "TINYINT", "SMALLINT", "INTEGER", "DATE", "TIME", "TIMESTAMP", "INTERVAL", "YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND", "ZONE", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "LOCALTIME", "LOCALTIMESTAMP", "EXTRACT", "CASE", "WHEN", "THEN", "ELSE", "END", "JOIN", "CROSS", "OUTER", "INNER", "LEFT", "RIGHT", "FULL", "NATURAL", "USING", "ON", "FILTER", "OVER", "PARTITION", "RANGE", "ROWS", "UNBOUNDED", "PRECEDING", "FOLLOWING", "CURRENT", "ROW", "WITH", "RECURSIVE", "VALUES", "CREATE", "SCHEMA", "TABLE", "VIEW", "REPLACE", "INSERT", "DELETE", "INTO", "CONSTRAINT", "DESCRIBE", "GRANT", "REVOKE", "PRIVILEGES", "PUBLIC", "OPTION", "EXPLAIN", "ANALYZE", "FORMAT", "TYPE", "TEXT", "GRAPHVIZ", "LOGICAL", "DISTRIBUTED", "CAST", "TRY_CAST", "SHOW", "TABLES", "SCHEMAS", "CATALOGS", "COLUMNS", "COLUMN", "USE", "PARTITIONS", "FUNCTIONS", "DROP", "UNION", "EXCEPT", "INTERSECT", "TO", "SYSTEM", "BERNOULLI", "POISSONIZED", "TABLESAMPLE", "ALTER", "RENAME", "UNNEST", "ORDINALITY", "ARRAY", "MAP", "SET", "RESET", "SESSION", "DATA", "START", "TRANSACTION", "COMMIT", "ROLLBACK", "WORK", "ISOLATION", "LEVEL", "SERIALIZABLE", "REPEATABLE", "COMMITTED", "UNCOMMITTED", "READ", "WRITE", "ONLY", "CALL", "PREPARE", "DEALLOCATE", "EXECUTE", "INPUT", "OUTPUT", "CASCADE", "RESTRICT", "INCLUDING", "EXCLUDING", "PROPERTIES", "NORMALIZE", "NFD", "NFC", "NFKD", "NFKC", "IF", "NULLIF", "COALESCE", "EQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "CONCAT", "STRING", "BINARY_LITERAL", "INTEGER_VALUE", "DECIMAL_VALUE", "IDENTIFIER", "DIGIT_IDENTIFIER", "QUOTED_IDENTIFIER", "BACKQUOTED_IDENTIFIER", "TIME_WITH_TIME_ZONE", "TIMESTAMP_WITH_TIME_ZONE", "DOUBLE_PRECISION", "SIMPLE_COMMENT", "BRACKETED_COMMENT", "WS", "SEMICOLON", "UNRECOGNIZED", "DELIMITER" ]; var ruleNames = [ "multiStatement", "singleStatement", "singleExpression", "statement", "query", "presto_with", "tableElement", "columnDefinition", "likeClause", "tableProperties", "tableProperty", "queryNoWith", "queryTerm", "queryPrimary", "sortItem", "querySpecification", "groupBy", "groupingElement", "groupingExpressions", "groupingSet", "namedQuery", "setQuantifier", "selectItem", "relation", "joinType", "joinCriteria", "sampledRelation", "sampleType", "aliasedRelation", "columnAliases", "relationPrimary", "expression", "booleanExpression", "predicated", "predicate", "valueExpression", "primaryExpression", "timeZoneSpecifier", "comparisonOperator", "comparisonQuantifier", "booleanValue", "interval", "intervalField", "type", "typeParameter", "baseType", "whenClause", "filter", "over", "windowFrame", "frameBound", "explainOption", "transactionMode", "levelOfIsolation", "callArgument", "privilege", "qualifiedName", "identifier", "quotedIdentifier", "number", "nonReserved", "normalForm" ]; export const SqlBaseParser = function(input){ Parser.call(this, input); this._interp = new _atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache); this.ruleNames = ruleNames; this.literalNames = literalNames; this.symbolicNames = symbolicNames; // return this; } as any; SqlBaseParser.prototype = Object.create(Parser.prototype); SqlBaseParser.prototype.constructor = SqlBaseParser; Object.defineProperty(SqlBaseParser.prototype, "atn", { get : function() { return atn; } }); SqlBaseParser.EOF = Token.EOF; SqlBaseParser.T__0 = 1; SqlBaseParser.T__1 = 2; SqlBaseParser.T__2 = 3; SqlBaseParser.T__3 = 4; SqlBaseParser.T__4 = 5; SqlBaseParser.T__5 = 6; SqlBaseParser.T__6 = 7; SqlBaseParser.T__7 = 8; SqlBaseParser.T__8 = 9; SqlBaseParser.SELECT = 10; SqlBaseParser.FROM = 11; SqlBaseParser.ADD = 12; SqlBaseParser.AS = 13; SqlBaseParser.ALL = 14; SqlBaseParser.SOME = 15; SqlBaseParser.ANY = 16; SqlBaseParser.DISTINCT = 17; SqlBaseParser.WHERE = 18; SqlBaseParser.GROUP = 19; SqlBaseParser.BY = 20; SqlBaseParser.GROUPING = 21; SqlBaseParser.SETS = 22; SqlBaseParser.CUBE = 23; SqlBaseParser.ROLLUP = 24; SqlBaseParser.ORDER = 25; SqlBaseParser.HAVING = 26; SqlBaseParser.LIMIT = 27; SqlBaseParser.AT = 28; SqlBaseParser.OR = 29; SqlBaseParser.AND = 30; SqlBaseParser.IN = 31; SqlBaseParser.NOT = 32; SqlBaseParser.NO = 33; SqlBaseParser.EXISTS = 34; SqlBaseParser.BETWEEN = 35; SqlBaseParser.LIKE = 36; SqlBaseParser.IS = 37; SqlBaseParser.NULL = 38; SqlBaseParser.TRUE = 39; SqlBaseParser.FALSE = 40; SqlBaseParser.NULLS = 41; SqlBaseParser.FIRST = 42; SqlBaseParser.LAST = 43; SqlBaseParser.ESCAPE = 44; SqlBaseParser.ASC = 45; SqlBaseParser.DESC = 46; SqlBaseParser.SUBSTRING = 47; SqlBaseParser.POSITION = 48; SqlBaseParser.FOR = 49; SqlBaseParser.TINYINT = 50; SqlBaseParser.SMALLINT = 51; SqlBaseParser.INTEGER = 52; SqlBaseParser.DATE = 53; SqlBaseParser.TIME = 54; SqlBaseParser.TIMESTAMP = 55; SqlBaseParser.INTERVAL = 56; SqlBaseParser.YEAR = 57; SqlBaseParser.MONTH = 58; SqlBaseParser.DAY = 59; SqlBaseParser.HOUR = 60; SqlBaseParser.MINUTE = 61; SqlBaseParser.SECOND = 62; SqlBaseParser.ZONE = 63; SqlBaseParser.CURRENT_DATE = 64; SqlBaseParser.CURRENT_TIME = 65; SqlBaseParser.CURRENT_TIMESTAMP = 66; SqlBaseParser.LOCALTIME = 67; SqlBaseParser.LOCALTIMESTAMP = 68; SqlBaseParser.EXTRACT = 69; SqlBaseParser.CASE = 70; SqlBaseParser.WHEN = 71; SqlBaseParser.THEN = 72; SqlBaseParser.ELSE = 73; SqlBaseParser.END = 74; SqlBaseParser.JOIN = 75; SqlBaseParser.CROSS = 76; SqlBaseParser.OUTER = 77; SqlBaseParser.INNER = 78; SqlBaseParser.LEFT = 79; SqlBaseParser.RIGHT = 80; SqlBaseParser.FULL = 81; SqlBaseParser.NATURAL = 82; SqlBaseParser.USING = 83; SqlBaseParser.ON = 84; SqlBaseParser.FILTER = 85; SqlBaseParser.OVER = 86; SqlBaseParser.PARTITION = 87; SqlBaseParser.RANGE = 88; SqlBaseParser.ROWS = 89; SqlBaseParser.UNBOUNDED = 90; SqlBaseParser.PRECEDING = 91; SqlBaseParser.FOLLOWING = 92; SqlBaseParser.CURRENT = 93; SqlBaseParser.ROW = 94; SqlBaseParser.WITH = 95; SqlBaseParser.RECURSIVE = 96; SqlBaseParser.VALUES = 97; SqlBaseParser.CREATE = 98; SqlBaseParser.SCHEMA = 99; SqlBaseParser.TABLE = 100; SqlBaseParser.VIEW = 101; SqlBaseParser.REPLACE = 102; SqlBaseParser.INSERT = 103; SqlBaseParser.DELETE = 104; SqlBaseParser.INTO = 105; SqlBaseParser.CONSTRAINT = 106; SqlBaseParser.DESCRIBE = 107; SqlBaseParser.GRANT = 108; SqlBaseParser.REVOKE = 109; SqlBaseParser.PRIVILEGES = 110; SqlBaseParser.PUBLIC = 111; SqlBaseParser.OPTION = 112; SqlBaseParser.EXPLAIN = 113; SqlBaseParser.ANALYZE = 114; SqlBaseParser.FORMAT = 115; SqlBaseParser.TYPE = 116; SqlBaseParser.TEXT = 117; SqlBaseParser.GRAPHVIZ = 118; SqlBaseParser.LOGICAL = 119; SqlBaseParser.DISTRIBUTED = 120; SqlBaseParser.CAST = 121; SqlBaseParser.TRY_CAST = 122; SqlBaseParser.SHOW = 123; SqlBaseParser.TABLES = 124; SqlBaseParser.SCHEMAS = 125; SqlBaseParser.CATALOGS = 126; SqlBaseParser.COLUMNS = 127; SqlBaseParser.COLUMN = 128; SqlBaseParser.USE = 129; SqlBaseParser.PARTITIONS = 130; SqlBaseParser.FUNCTIONS = 131; SqlBaseParser.DROP = 132; SqlBaseParser.UNION = 133; SqlBaseParser.EXCEPT = 134; SqlBaseParser.INTERSECT = 135; SqlBaseParser.TO = 136; SqlBaseParser.SYSTEM = 137; SqlBaseParser.BERNOULLI = 138; SqlBaseParser.POISSONIZED = 139; SqlBaseParser.TABLESAMPLE = 140; SqlBaseParser.ALTER = 141; SqlBaseParser.RENAME = 142; SqlBaseParser.UNNEST = 143; SqlBaseParser.ORDINALITY = 144; SqlBaseParser.ARRAY = 145; SqlBaseParser.MAP = 146; SqlBaseParser.SET = 147; SqlBaseParser.RESET = 148; SqlBaseParser.SESSION = 149; SqlBaseParser.DATA = 150; SqlBaseParser.START = 151; SqlBaseParser.TRANSACTION = 152; SqlBaseParser.COMMIT = 153; SqlBaseParser.ROLLBACK = 154; SqlBaseParser.WORK = 155; SqlBaseParser.ISOLATION = 156; SqlBaseParser.LEVEL = 157; SqlBaseParser.SERIALIZABLE = 158; SqlBaseParser.REPEATABLE = 159; SqlBaseParser.COMMITTED = 160; SqlBaseParser.UNCOMMITTED = 161; SqlBaseParser.READ = 162; SqlBaseParser.WRITE = 163; SqlBaseParser.ONLY = 164; SqlBaseParser.CALL = 165; SqlBaseParser.PREPARE = 166; SqlBaseParser.DEALLOCATE = 167; SqlBaseParser.EXECUTE = 168; SqlBaseParser.INPUT = 169; SqlBaseParser.OUTPUT = 170; SqlBaseParser.CASCADE = 171; SqlBaseParser.RESTRICT = 172; SqlBaseParser.INCLUDING = 173; SqlBaseParser.EXCLUDING = 174; SqlBaseParser.PROPERTIES = 175; SqlBaseParser.NORMALIZE = 176; SqlBaseParser.NFD = 177; SqlBaseParser.NFC = 178; SqlBaseParser.NFKD = 179; SqlBaseParser.NFKC = 180; SqlBaseParser.IF = 181; SqlBaseParser.NULLIF = 182; SqlBaseParser.COALESCE = 183; SqlBaseParser.EQ = 184; SqlBaseParser.NEQ = 185; SqlBaseParser.LT = 186; SqlBaseParser.LTE = 187; SqlBaseParser.GT = 188; SqlBaseParser.GTE = 189; SqlBaseParser.PLUS = 190; SqlBaseParser.MINUS = 191; SqlBaseParser.ASTERISK = 192; SqlBaseParser.SLASH = 193; SqlBaseParser.PERCENT = 194; SqlBaseParser.CONCAT = 195; SqlBaseParser.STRING = 196; SqlBaseParser.BINARY_LITERAL = 197; SqlBaseParser.INTEGER_VALUE = 198; SqlBaseParser.DECIMAL_VALUE = 199; SqlBaseParser.IDENTIFIER = 200; SqlBaseParser.DIGIT_IDENTIFIER = 201; SqlBaseParser.QUOTED_IDENTIFIER = 202; SqlBaseParser.BACKQUOTED_IDENTIFIER = 203; SqlBaseParser.TIME_WITH_TIME_ZONE = 204; SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE = 205; SqlBaseParser.DOUBLE_PRECISION = 206; SqlBaseParser.SIMPLE_COMMENT = 207; SqlBaseParser.BRACKETED_COMMENT = 208; SqlBaseParser.WS = 209; SqlBaseParser.SEMICOLON = 210; SqlBaseParser.UNRECOGNIZED = 211; SqlBaseParser.DELIMITER = 212; SqlBaseParser.RULE_multiStatement = 0; SqlBaseParser.RULE_singleStatement = 1; SqlBaseParser.RULE_singleExpression = 2; SqlBaseParser.RULE_statement = 3; SqlBaseParser.RULE_query = 4; SqlBaseParser.RULE_presto_with = 5; SqlBaseParser.RULE_tableElement = 6; SqlBaseParser.RULE_columnDefinition = 7; SqlBaseParser.RULE_likeClause = 8; SqlBaseParser.RULE_tableProperties = 9; SqlBaseParser.RULE_tableProperty = 10; SqlBaseParser.RULE_queryNoWith = 11; SqlBaseParser.RULE_queryTerm = 12; SqlBaseParser.RULE_queryPrimary = 13; SqlBaseParser.RULE_sortItem = 14; SqlBaseParser.RULE_querySpecification = 15; SqlBaseParser.RULE_groupBy = 16; SqlBaseParser.RULE_groupingElement = 17; SqlBaseParser.RULE_groupingExpressions = 18; SqlBaseParser.RULE_groupingSet = 19; SqlBaseParser.RULE_namedQuery = 20; SqlBaseParser.RULE_setQuantifier = 21; SqlBaseParser.RULE_selectItem = 22; SqlBaseParser.RULE_relation = 23; SqlBaseParser.RULE_joinType = 24; SqlBaseParser.RULE_joinCriteria = 25; SqlBaseParser.RULE_sampledRelation = 26; SqlBaseParser.RULE_sampleType = 27; SqlBaseParser.RULE_aliasedRelation = 28; SqlBaseParser.RULE_columnAliases = 29; SqlBaseParser.RULE_relationPrimary = 30; SqlBaseParser.RULE_expression = 31; SqlBaseParser.RULE_booleanExpression = 32; SqlBaseParser.RULE_predicated = 33; SqlBaseParser.RULE_predicate = 34; SqlBaseParser.RULE_valueExpression = 35; SqlBaseParser.RULE_primaryExpression = 36; SqlBaseParser.RULE_timeZoneSpecifier = 37; SqlBaseParser.RULE_comparisonOperator = 38; SqlBaseParser.RULE_comparisonQuantifier = 39; SqlBaseParser.RULE_booleanValue = 40; SqlBaseParser.RULE_interval = 41; SqlBaseParser.RULE_intervalField = 42; SqlBaseParser.RULE_type = 43; SqlBaseParser.RULE_typeParameter = 44; SqlBaseParser.RULE_baseType = 45; SqlBaseParser.RULE_whenClause = 46; SqlBaseParser.RULE_filter = 47; SqlBaseParser.RULE_over = 48; SqlBaseParser.RULE_windowFrame = 49; SqlBaseParser.RULE_frameBound = 50; SqlBaseParser.RULE_explainOption = 51; SqlBaseParser.RULE_transactionMode = 52; SqlBaseParser.RULE_levelOfIsolation = 53; SqlBaseParser.RULE_callArgument = 54; SqlBaseParser.RULE_privilege = 55; SqlBaseParser.RULE_qualifiedName = 56; SqlBaseParser.RULE_identifier = 57; SqlBaseParser.RULE_quotedIdentifier = 58; SqlBaseParser.RULE_number = 59; SqlBaseParser.RULE_nonReserved = 60; SqlBaseParser.RULE_normalForm = 61; function MultiStatementContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_multiStatement; // return this; } MultiStatementContext.prototype = Object.create(ParserRuleContext.prototype); MultiStatementContext.prototype.constructor = MultiStatementContext; MultiStatementContext.prototype.statement = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(StatementContext); } else { return this.getTypedRuleContext(StatementContext,i); } }; MultiStatementContext.prototype.EOF = function() { return this.getToken(SqlBaseParser.EOF, 0); }; MultiStatementContext.prototype.SEMICOLON = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(SqlBaseParser.SEMICOLON); } else { return this.getToken(SqlBaseParser.SEMICOLON, i); } }; MultiStatementContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterMultiStatement(this); } }; MultiStatementContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitMultiStatement(this); } }; MultiStatementContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitMultiStatement(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.MultiStatementContext = MultiStatementContext; SqlBaseParser.prototype.multiStatement = function() { var localctx = new MultiStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 0, SqlBaseParser.RULE_multiStatement); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 124; this.statement(); this.state = 129; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,0,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 125; this.match(SqlBaseParser.SEMICOLON); this.state = 126; this.statement(); } this.state = 131; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,0,this._ctx); } this.state = 133; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.SEMICOLON) { this.state = 132; this.match(SqlBaseParser.SEMICOLON); } this.state = 135; this.match(SqlBaseParser.EOF); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SingleStatementContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_singleStatement; // return this; } SingleStatementContext.prototype = Object.create(ParserRuleContext.prototype); SingleStatementContext.prototype.constructor = SingleStatementContext; SingleStatementContext.prototype.statement = function() { return this.getTypedRuleContext(StatementContext,0); }; SingleStatementContext.prototype.EOF = function() { return this.getToken(SqlBaseParser.EOF, 0); }; SingleStatementContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSingleStatement(this); } }; SingleStatementContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSingleStatement(this); } }; SingleStatementContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSingleStatement(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SingleStatementContext = SingleStatementContext; SqlBaseParser.prototype.singleStatement = function() { var localctx = new SingleStatementContext(this, this._ctx, this.state); this.enterRule(localctx, 2, SqlBaseParser.RULE_singleStatement); try { this.enterOuterAlt(localctx, 1); this.state = 137; this.statement(); this.state = 138; this.match(SqlBaseParser.EOF); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SingleExpressionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_singleExpression; // return this; } SingleExpressionContext.prototype = Object.create(ParserRuleContext.prototype); SingleExpressionContext.prototype.constructor = SingleExpressionContext; SingleExpressionContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SingleExpressionContext.prototype.EOF = function() { return this.getToken(SqlBaseParser.EOF, 0); }; SingleExpressionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSingleExpression(this); } }; SingleExpressionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSingleExpression(this); } }; SingleExpressionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSingleExpression(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SingleExpressionContext = SingleExpressionContext; SqlBaseParser.prototype.singleExpression = function() { var localctx = new (SingleExpressionContext as any)(this, this._ctx, this.state); this.enterRule(localctx, 4, SqlBaseParser.RULE_singleExpression); try { this.enterOuterAlt(localctx, 1); this.state = 140; this.expression(); this.state = 141; this.match(SqlBaseParser.EOF); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function StatementContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_statement; // return this; } StatementContext.prototype = Object.create(ParserRuleContext.prototype); StatementContext.prototype.constructor = StatementContext; StatementContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function ExplainContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ExplainContext.prototype = Object.create(StatementContext.prototype); ExplainContext.prototype.constructor = ExplainContext; SqlBaseParser.ExplainContext = ExplainContext; ExplainContext.prototype.EXPLAIN = function() { return this.getToken(SqlBaseParser.EXPLAIN, 0); }; ExplainContext.prototype.statement = function() { return this.getTypedRuleContext(StatementContext,0); }; ExplainContext.prototype.ANALYZE = function() { return this.getToken(SqlBaseParser.ANALYZE, 0); }; ExplainContext.prototype.explainOption = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExplainOptionContext); } else { return this.getTypedRuleContext(ExplainOptionContext,i); } }; ExplainContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExplain(this); } }; ExplainContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExplain(this); } }; ExplainContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExplain(this); } else { return (visitor as any).visitChildren(this); } }; function PrepareContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } PrepareContext.prototype = Object.create(StatementContext.prototype); PrepareContext.prototype.constructor = PrepareContext; SqlBaseParser.PrepareContext = PrepareContext; PrepareContext.prototype.PREPARE = function() { return this.getToken(SqlBaseParser.PREPARE, 0); }; PrepareContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; PrepareContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; PrepareContext.prototype.statement = function() { return this.getTypedRuleContext(StatementContext,0); }; PrepareContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterPrepare(this); } }; PrepareContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitPrepare(this); } }; PrepareContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitPrepare(this); } else { return (visitor as any).visitChildren(this); } }; function CreateTableContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } CreateTableContext.prototype = Object.create(StatementContext.prototype); CreateTableContext.prototype.constructor = CreateTableContext; SqlBaseParser.CreateTableContext = CreateTableContext; CreateTableContext.prototype.CREATE = function() { return this.getToken(SqlBaseParser.CREATE, 0); }; CreateTableContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; CreateTableContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; CreateTableContext.prototype.tableElement = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TableElementContext); } else { return this.getTypedRuleContext(TableElementContext,i); } }; CreateTableContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; CreateTableContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; CreateTableContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; CreateTableContext.prototype.WITH = function() { return this.getToken(SqlBaseParser.WITH, 0); }; CreateTableContext.prototype.tableProperties = function() { return this.getTypedRuleContext(TablePropertiesContext,0); }; CreateTableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCreateTable(this); } }; CreateTableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCreateTable(this); } }; CreateTableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCreateTable(this); } else { return (visitor as any).visitChildren(this); } }; function StartTransactionContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } StartTransactionContext.prototype = Object.create(StatementContext.prototype); StartTransactionContext.prototype.constructor = StartTransactionContext; SqlBaseParser.StartTransactionContext = StartTransactionContext; StartTransactionContext.prototype.START = function() { return this.getToken(SqlBaseParser.START, 0); }; StartTransactionContext.prototype.TRANSACTION = function() { return this.getToken(SqlBaseParser.TRANSACTION, 0); }; StartTransactionContext.prototype.transactionMode = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TransactionModeContext); } else { return this.getTypedRuleContext(TransactionModeContext,i); } }; StartTransactionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterStartTransaction(this); } }; StartTransactionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitStartTransaction(this); } }; StartTransactionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitStartTransaction(this); } else { return (visitor as any).visitChildren(this); } }; function CreateTableAsSelectContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } CreateTableAsSelectContext.prototype = Object.create(StatementContext.prototype); CreateTableAsSelectContext.prototype.constructor = CreateTableAsSelectContext; SqlBaseParser.CreateTableAsSelectContext = CreateTableAsSelectContext; CreateTableAsSelectContext.prototype.CREATE = function() { return this.getToken(SqlBaseParser.CREATE, 0); }; CreateTableAsSelectContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; CreateTableAsSelectContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; CreateTableAsSelectContext.prototype.AS = function() { return this.getToken(SqlBaseParser.AS, 0); }; CreateTableAsSelectContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; CreateTableAsSelectContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; CreateTableAsSelectContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; CreateTableAsSelectContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; CreateTableAsSelectContext.prototype.WITH = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(SqlBaseParser.WITH); } else { return this.getToken(SqlBaseParser.WITH, i); } }; CreateTableAsSelectContext.prototype.tableProperties = function() { return this.getTypedRuleContext(TablePropertiesContext,0); }; CreateTableAsSelectContext.prototype.DATA = function() { return this.getToken(SqlBaseParser.DATA, 0); }; CreateTableAsSelectContext.prototype.NO = function() { return this.getToken(SqlBaseParser.NO, 0); }; CreateTableAsSelectContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCreateTableAsSelect(this); } }; CreateTableAsSelectContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCreateTableAsSelect(this); } }; CreateTableAsSelectContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCreateTableAsSelect(this); } else { return (visitor as any).visitChildren(this); } }; function UseContext(parser, ctx) { StatementContext.call(this, parser); this.schema = null; // IdentifierContext; this.catalog = null; // IdentifierContext; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } UseContext.prototype = Object.create(StatementContext.prototype); UseContext.prototype.constructor = UseContext; SqlBaseParser.UseContext = UseContext; UseContext.prototype.USE = function() { return this.getToken(SqlBaseParser.USE, 0); }; UseContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; UseContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterUse(this); } }; UseContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitUse(this); } }; UseContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitUse(this); } else { return (visitor as any).visitChildren(this); } }; function DeallocateContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DeallocateContext.prototype = Object.create(StatementContext.prototype); DeallocateContext.prototype.constructor = DeallocateContext; SqlBaseParser.DeallocateContext = DeallocateContext; DeallocateContext.prototype.DEALLOCATE = function() { return this.getToken(SqlBaseParser.DEALLOCATE, 0); }; DeallocateContext.prototype.PREPARE = function() { return this.getToken(SqlBaseParser.PREPARE, 0); }; DeallocateContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; DeallocateContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDeallocate(this); } }; DeallocateContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDeallocate(this); } }; DeallocateContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDeallocate(this); } else { return (visitor as any).visitChildren(this); } }; function RenameTableContext(parser, ctx) { StatementContext.call(this, parser); this.from = null; // QualifiedNameContext; this.to = null; // QualifiedNameContext; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } RenameTableContext.prototype = Object.create(StatementContext.prototype); RenameTableContext.prototype.constructor = RenameTableContext; SqlBaseParser.RenameTableContext = RenameTableContext; RenameTableContext.prototype.ALTER = function() { return this.getToken(SqlBaseParser.ALTER, 0); }; RenameTableContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; RenameTableContext.prototype.RENAME = function() { return this.getToken(SqlBaseParser.RENAME, 0); }; RenameTableContext.prototype.TO = function() { return this.getToken(SqlBaseParser.TO, 0); }; RenameTableContext.prototype.qualifiedName = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(QualifiedNameContext); } else { return this.getTypedRuleContext(QualifiedNameContext,i); } }; RenameTableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRenameTable(this); } }; RenameTableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRenameTable(this); } }; RenameTableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRenameTable(this); } else { return (visitor as any).visitChildren(this); } }; function CommitContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } CommitContext.prototype = Object.create(StatementContext.prototype); CommitContext.prototype.constructor = CommitContext; SqlBaseParser.CommitContext = CommitContext; CommitContext.prototype.COMMIT = function() { return this.getToken(SqlBaseParser.COMMIT, 0); }; CommitContext.prototype.WORK = function() { return this.getToken(SqlBaseParser.WORK, 0); }; CommitContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCommit(this); } }; CommitContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCommit(this); } }; CommitContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCommit(this); } else { return (visitor as any).visitChildren(this); } }; function RevokeContext(parser, ctx) { StatementContext.call(this, parser); this.grantee = null; // IdentifierContext; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } RevokeContext.prototype = Object.create(StatementContext.prototype); RevokeContext.prototype.constructor = RevokeContext; SqlBaseParser.RevokeContext = RevokeContext; RevokeContext.prototype.REVOKE = function() { return this.getToken(SqlBaseParser.REVOKE, 0); }; RevokeContext.prototype.ON = function() { return this.getToken(SqlBaseParser.ON, 0); }; RevokeContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; RevokeContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; RevokeContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; RevokeContext.prototype.privilege = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(PrivilegeContext); } else { return this.getTypedRuleContext(PrivilegeContext,i); } }; RevokeContext.prototype.ALL = function() { return this.getToken(SqlBaseParser.ALL, 0); }; RevokeContext.prototype.PRIVILEGES = function() { return this.getToken(SqlBaseParser.PRIVILEGES, 0); }; RevokeContext.prototype.GRANT = function() { return this.getToken(SqlBaseParser.GRANT, 0); }; RevokeContext.prototype.OPTION = function() { return this.getToken(SqlBaseParser.OPTION, 0); }; RevokeContext.prototype.FOR = function() { return this.getToken(SqlBaseParser.FOR, 0); }; RevokeContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; RevokeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRevoke(this); } }; RevokeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRevoke(this); } }; RevokeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRevoke(this); } else { return (visitor as any).visitChildren(this); } }; function ShowPartitionsContext(parser, ctx) { StatementContext.call(this, parser); this.limit = null; // Token; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowPartitionsContext.prototype = Object.create(StatementContext.prototype); ShowPartitionsContext.prototype.constructor = ShowPartitionsContext; SqlBaseParser.ShowPartitionsContext = ShowPartitionsContext; ShowPartitionsContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowPartitionsContext.prototype.PARTITIONS = function() { return this.getToken(SqlBaseParser.PARTITIONS, 0); }; ShowPartitionsContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; ShowPartitionsContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; ShowPartitionsContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; ShowPartitionsContext.prototype.WHERE = function() { return this.getToken(SqlBaseParser.WHERE, 0); }; ShowPartitionsContext.prototype.booleanExpression = function() { return this.getTypedRuleContext(BooleanExpressionContext,0); }; ShowPartitionsContext.prototype.ORDER = function() { return this.getToken(SqlBaseParser.ORDER, 0); }; ShowPartitionsContext.prototype.BY = function() { return this.getToken(SqlBaseParser.BY, 0); }; ShowPartitionsContext.prototype.sortItem = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SortItemContext); } else { return this.getTypedRuleContext(SortItemContext,i); } }; ShowPartitionsContext.prototype.LIMIT = function() { return this.getToken(SqlBaseParser.LIMIT, 0); }; ShowPartitionsContext.prototype.INTEGER_VALUE = function() { return this.getToken(SqlBaseParser.INTEGER_VALUE, 0); }; ShowPartitionsContext.prototype.ALL = function() { return this.getToken(SqlBaseParser.ALL, 0); }; ShowPartitionsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowPartitions(this); } }; ShowPartitionsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowPartitions(this); } }; ShowPartitionsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowPartitions(this); } else { return (visitor as any).visitChildren(this); } }; function DropViewContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DropViewContext.prototype = Object.create(StatementContext.prototype); DropViewContext.prototype.constructor = DropViewContext; SqlBaseParser.DropViewContext = DropViewContext; DropViewContext.prototype.DROP = function() { return this.getToken(SqlBaseParser.DROP, 0); }; DropViewContext.prototype.VIEW = function() { return this.getToken(SqlBaseParser.VIEW, 0); }; DropViewContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; DropViewContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; DropViewContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; DropViewContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDropView(this); } }; DropViewContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDropView(this); } }; DropViewContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDropView(this); } else { return (visitor as any).visitChildren(this); } }; function DeleteContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DeleteContext.prototype = Object.create(StatementContext.prototype); DeleteContext.prototype.constructor = DeleteContext; SqlBaseParser.DeleteContext = DeleteContext; DeleteContext.prototype.DELETE = function() { return this.getToken(SqlBaseParser.DELETE, 0); }; DeleteContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; DeleteContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; DeleteContext.prototype.WHERE = function() { return this.getToken(SqlBaseParser.WHERE, 0); }; DeleteContext.prototype.booleanExpression = function() { return this.getTypedRuleContext(BooleanExpressionContext,0); }; DeleteContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDelete(this); } }; DeleteContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDelete(this); } }; DeleteContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDelete(this); } else { return (visitor as any).visitChildren(this); } }; function ShowTablesContext(parser, ctx) { StatementContext.call(this, parser); this.pattern = null; // Token; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowTablesContext.prototype = Object.create(StatementContext.prototype); ShowTablesContext.prototype.constructor = ShowTablesContext; SqlBaseParser.ShowTablesContext = ShowTablesContext; ShowTablesContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowTablesContext.prototype.TABLES = function() { return this.getToken(SqlBaseParser.TABLES, 0); }; ShowTablesContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; ShowTablesContext.prototype.LIKE = function() { return this.getToken(SqlBaseParser.LIKE, 0); }; ShowTablesContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; ShowTablesContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; ShowTablesContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; ShowTablesContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowTables(this); } }; ShowTablesContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowTables(this); } }; ShowTablesContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowTables(this); } else { return (visitor as any).visitChildren(this); } }; function DescribeInputContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DescribeInputContext.prototype = Object.create(StatementContext.prototype); DescribeInputContext.prototype.constructor = DescribeInputContext; SqlBaseParser.DescribeInputContext = DescribeInputContext; DescribeInputContext.prototype.DESCRIBE = function() { return this.getToken(SqlBaseParser.DESCRIBE, 0); }; DescribeInputContext.prototype.INPUT = function() { return this.getToken(SqlBaseParser.INPUT, 0); }; DescribeInputContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; DescribeInputContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDescribeInput(this); } }; DescribeInputContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDescribeInput(this); } }; DescribeInputContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDescribeInput(this); } else { return (visitor as any).visitChildren(this); } }; function ShowCatalogsContext(parser, ctx) { StatementContext.call(this, parser); this.pattern = null; // Token; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowCatalogsContext.prototype = Object.create(StatementContext.prototype); ShowCatalogsContext.prototype.constructor = ShowCatalogsContext; SqlBaseParser.ShowCatalogsContext = ShowCatalogsContext; ShowCatalogsContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowCatalogsContext.prototype.CATALOGS = function() { return this.getToken(SqlBaseParser.CATALOGS, 0); }; ShowCatalogsContext.prototype.LIKE = function() { return this.getToken(SqlBaseParser.LIKE, 0); }; ShowCatalogsContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; ShowCatalogsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowCatalogs(this); } }; ShowCatalogsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowCatalogs(this); } }; ShowCatalogsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowCatalogs(this); } else { return (visitor as any).visitChildren(this); } }; function StatementDefaultContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } StatementDefaultContext.prototype = Object.create(StatementContext.prototype); StatementDefaultContext.prototype.constructor = StatementDefaultContext; SqlBaseParser.StatementDefaultContext = StatementDefaultContext; StatementDefaultContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; StatementDefaultContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterStatementDefault(this); } }; StatementDefaultContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitStatementDefault(this); } }; StatementDefaultContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitStatementDefault(this); } else { return (visitor as any).visitChildren(this); } }; function RenameColumnContext(parser, ctx) { StatementContext.call(this, parser); this.tableName = null; // QualifiedNameContext; this.from = null; // IdentifierContext; this.to = null; // IdentifierContext; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } RenameColumnContext.prototype = Object.create(StatementContext.prototype); RenameColumnContext.prototype.constructor = RenameColumnContext; SqlBaseParser.RenameColumnContext = RenameColumnContext; RenameColumnContext.prototype.ALTER = function() { return this.getToken(SqlBaseParser.ALTER, 0); }; RenameColumnContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; RenameColumnContext.prototype.RENAME = function() { return this.getToken(SqlBaseParser.RENAME, 0); }; RenameColumnContext.prototype.COLUMN = function() { return this.getToken(SqlBaseParser.COLUMN, 0); }; RenameColumnContext.prototype.TO = function() { return this.getToken(SqlBaseParser.TO, 0); }; RenameColumnContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; RenameColumnContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; RenameColumnContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRenameColumn(this); } }; RenameColumnContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRenameColumn(this); } }; RenameColumnContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRenameColumn(this); } else { return (visitor as any).visitChildren(this); } }; function SetSessionContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } SetSessionContext.prototype = Object.create(StatementContext.prototype); SetSessionContext.prototype.constructor = SetSessionContext; SqlBaseParser.SetSessionContext = SetSessionContext; SetSessionContext.prototype.SET = function() { return this.getToken(SqlBaseParser.SET, 0); }; SetSessionContext.prototype.SESSION = function() { return this.getToken(SqlBaseParser.SESSION, 0); }; SetSessionContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; SetSessionContext.prototype.EQ = function() { return this.getToken(SqlBaseParser.EQ, 0); }; SetSessionContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SetSessionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSetSession(this); } }; SetSessionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSetSession(this); } }; SetSessionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSetSession(this); } else { return (visitor as any).visitChildren(this); } }; function CreateViewContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } CreateViewContext.prototype = Object.create(StatementContext.prototype); CreateViewContext.prototype.constructor = CreateViewContext; SqlBaseParser.CreateViewContext = CreateViewContext; CreateViewContext.prototype.CREATE = function() { return this.getToken(SqlBaseParser.CREATE, 0); }; CreateViewContext.prototype.VIEW = function() { return this.getToken(SqlBaseParser.VIEW, 0); }; CreateViewContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; CreateViewContext.prototype.AS = function() { return this.getToken(SqlBaseParser.AS, 0); }; CreateViewContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; CreateViewContext.prototype.OR = function() { return this.getToken(SqlBaseParser.OR, 0); }; CreateViewContext.prototype.REPLACE = function() { return this.getToken(SqlBaseParser.REPLACE, 0); }; CreateViewContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCreateView(this); } }; CreateViewContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCreateView(this); } }; CreateViewContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCreateView(this); } else { return (visitor as any).visitChildren(this); } }; function ShowCreateTableContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowCreateTableContext.prototype = Object.create(StatementContext.prototype); ShowCreateTableContext.prototype.constructor = ShowCreateTableContext; SqlBaseParser.ShowCreateTableContext = ShowCreateTableContext; ShowCreateTableContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowCreateTableContext.prototype.CREATE = function() { return this.getToken(SqlBaseParser.CREATE, 0); }; ShowCreateTableContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; ShowCreateTableContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; ShowCreateTableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowCreateTable(this); } }; ShowCreateTableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowCreateTable(this); } }; ShowCreateTableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowCreateTable(this); } else { return (visitor as any).visitChildren(this); } }; function ShowSchemasContext(parser, ctx) { StatementContext.call(this, parser); this.pattern = null; // Token; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowSchemasContext.prototype = Object.create(StatementContext.prototype); ShowSchemasContext.prototype.constructor = ShowSchemasContext; SqlBaseParser.ShowSchemasContext = ShowSchemasContext; ShowSchemasContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowSchemasContext.prototype.SCHEMAS = function() { return this.getToken(SqlBaseParser.SCHEMAS, 0); }; ShowSchemasContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; ShowSchemasContext.prototype.LIKE = function() { return this.getToken(SqlBaseParser.LIKE, 0); }; ShowSchemasContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; ShowSchemasContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; ShowSchemasContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; ShowSchemasContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowSchemas(this); } }; ShowSchemasContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowSchemas(this); } }; ShowSchemasContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowSchemas(this); } else { return (visitor as any).visitChildren(this); } }; function DropTableContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DropTableContext.prototype = Object.create(StatementContext.prototype); DropTableContext.prototype.constructor = DropTableContext; SqlBaseParser.DropTableContext = DropTableContext; DropTableContext.prototype.DROP = function() { return this.getToken(SqlBaseParser.DROP, 0); }; DropTableContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; DropTableContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; DropTableContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; DropTableContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; DropTableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDropTable(this); } }; DropTableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDropTable(this); } }; DropTableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDropTable(this); } else { return (visitor as any).visitChildren(this); } }; function ShowColumnsContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowColumnsContext.prototype = Object.create(StatementContext.prototype); ShowColumnsContext.prototype.constructor = ShowColumnsContext; SqlBaseParser.ShowColumnsContext = ShowColumnsContext; ShowColumnsContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowColumnsContext.prototype.COLUMNS = function() { return this.getToken(SqlBaseParser.COLUMNS, 0); }; ShowColumnsContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; ShowColumnsContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; ShowColumnsContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; ShowColumnsContext.prototype.DESCRIBE = function() { return this.getToken(SqlBaseParser.DESCRIBE, 0); }; ShowColumnsContext.prototype.DESC = function() { return this.getToken(SqlBaseParser.DESC, 0); }; ShowColumnsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowColumns(this); } }; ShowColumnsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowColumns(this); } }; ShowColumnsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowColumns(this); } else { return (visitor as any).visitChildren(this); } }; function RollbackContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } RollbackContext.prototype = Object.create(StatementContext.prototype); RollbackContext.prototype.constructor = RollbackContext; SqlBaseParser.RollbackContext = RollbackContext; RollbackContext.prototype.ROLLBACK = function() { return this.getToken(SqlBaseParser.ROLLBACK, 0); }; RollbackContext.prototype.WORK = function() { return this.getToken(SqlBaseParser.WORK, 0); }; RollbackContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRollback(this); } }; RollbackContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRollback(this); } }; RollbackContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRollback(this); } else { return (visitor as any).visitChildren(this); } }; function AddColumnContext(parser, ctx) { StatementContext.call(this, parser); this.tableName = null; // QualifiedNameContext; this.column = null; // ColumnDefinitionContext; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } AddColumnContext.prototype = Object.create(StatementContext.prototype); AddColumnContext.prototype.constructor = AddColumnContext; SqlBaseParser.AddColumnContext = AddColumnContext; AddColumnContext.prototype.ALTER = function() { return this.getToken(SqlBaseParser.ALTER, 0); }; AddColumnContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; AddColumnContext.prototype.ADD = function() { return this.getToken(SqlBaseParser.ADD, 0); }; AddColumnContext.prototype.COLUMN = function() { return this.getToken(SqlBaseParser.COLUMN, 0); }; AddColumnContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; AddColumnContext.prototype.columnDefinition = function() { return this.getTypedRuleContext(ColumnDefinitionContext,0); }; AddColumnContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterAddColumn(this); } }; AddColumnContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitAddColumn(this); } }; AddColumnContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitAddColumn(this); } else { return (visitor as any).visitChildren(this); } }; function ResetSessionContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ResetSessionContext.prototype = Object.create(StatementContext.prototype); ResetSessionContext.prototype.constructor = ResetSessionContext; SqlBaseParser.ResetSessionContext = ResetSessionContext; ResetSessionContext.prototype.RESET = function() { return this.getToken(SqlBaseParser.RESET, 0); }; ResetSessionContext.prototype.SESSION = function() { return this.getToken(SqlBaseParser.SESSION, 0); }; ResetSessionContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; ResetSessionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterResetSession(this); } }; ResetSessionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitResetSession(this); } }; ResetSessionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitResetSession(this); } else { return (visitor as any).visitChildren(this); } }; function InsertIntoContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } InsertIntoContext.prototype = Object.create(StatementContext.prototype); InsertIntoContext.prototype.constructor = InsertIntoContext; SqlBaseParser.InsertIntoContext = InsertIntoContext; InsertIntoContext.prototype.INSERT = function() { return this.getToken(SqlBaseParser.INSERT, 0); }; InsertIntoContext.prototype.INTO = function() { return this.getToken(SqlBaseParser.INTO, 0); }; InsertIntoContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; InsertIntoContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; InsertIntoContext.prototype.columnAliases = function() { return this.getTypedRuleContext(ColumnAliasesContext,0); }; InsertIntoContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterInsertInto(this); } }; InsertIntoContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitInsertInto(this); } }; InsertIntoContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitInsertInto(this); } else { return (visitor as any).visitChildren(this); } }; function ShowSessionContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowSessionContext.prototype = Object.create(StatementContext.prototype); ShowSessionContext.prototype.constructor = ShowSessionContext; SqlBaseParser.ShowSessionContext = ShowSessionContext; ShowSessionContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowSessionContext.prototype.SESSION = function() { return this.getToken(SqlBaseParser.SESSION, 0); }; ShowSessionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowSession(this); } }; ShowSessionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowSession(this); } }; ShowSessionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowSession(this); } else { return (visitor as any).visitChildren(this); } }; function CreateSchemaContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } CreateSchemaContext.prototype = Object.create(StatementContext.prototype); CreateSchemaContext.prototype.constructor = CreateSchemaContext; SqlBaseParser.CreateSchemaContext = CreateSchemaContext; CreateSchemaContext.prototype.CREATE = function() { return this.getToken(SqlBaseParser.CREATE, 0); }; CreateSchemaContext.prototype.SCHEMA = function() { return this.getToken(SqlBaseParser.SCHEMA, 0); }; CreateSchemaContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; CreateSchemaContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; CreateSchemaContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; CreateSchemaContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; CreateSchemaContext.prototype.WITH = function() { return this.getToken(SqlBaseParser.WITH, 0); }; CreateSchemaContext.prototype.tableProperties = function() { return this.getTypedRuleContext(TablePropertiesContext,0); }; CreateSchemaContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCreateSchema(this); } }; CreateSchemaContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCreateSchema(this); } }; CreateSchemaContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCreateSchema(this); } else { return (visitor as any).visitChildren(this); } }; function ExecuteContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ExecuteContext.prototype = Object.create(StatementContext.prototype); ExecuteContext.prototype.constructor = ExecuteContext; SqlBaseParser.ExecuteContext = ExecuteContext; ExecuteContext.prototype.EXECUTE = function() { return this.getToken(SqlBaseParser.EXECUTE, 0); }; ExecuteContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; ExecuteContext.prototype.USING = function() { return this.getToken(SqlBaseParser.USING, 0); }; ExecuteContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; ExecuteContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExecute(this); } }; ExecuteContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExecute(this); } }; ExecuteContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExecute(this); } else { return (visitor as any).visitChildren(this); } }; function CallContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } CallContext.prototype = Object.create(StatementContext.prototype); CallContext.prototype.constructor = CallContext; SqlBaseParser.CallContext = CallContext; CallContext.prototype.CALL = function() { return this.getToken(SqlBaseParser.CALL, 0); }; CallContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; CallContext.prototype.callArgument = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(CallArgumentContext); } else { return this.getTypedRuleContext(CallArgumentContext,i); } }; CallContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCall(this); } }; CallContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCall(this); } }; CallContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCall(this); } else { return (visitor as any).visitChildren(this); } }; function RenameSchemaContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } RenameSchemaContext.prototype = Object.create(StatementContext.prototype); RenameSchemaContext.prototype.constructor = RenameSchemaContext; SqlBaseParser.RenameSchemaContext = RenameSchemaContext; RenameSchemaContext.prototype.ALTER = function() { return this.getToken(SqlBaseParser.ALTER, 0); }; RenameSchemaContext.prototype.SCHEMA = function() { return this.getToken(SqlBaseParser.SCHEMA, 0); }; RenameSchemaContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; RenameSchemaContext.prototype.RENAME = function() { return this.getToken(SqlBaseParser.RENAME, 0); }; RenameSchemaContext.prototype.TO = function() { return this.getToken(SqlBaseParser.TO, 0); }; RenameSchemaContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; RenameSchemaContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRenameSchema(this); } }; RenameSchemaContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRenameSchema(this); } }; RenameSchemaContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRenameSchema(this); } else { return (visitor as any).visitChildren(this); } }; function ShowFunctionsContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowFunctionsContext.prototype = Object.create(StatementContext.prototype); ShowFunctionsContext.prototype.constructor = ShowFunctionsContext; SqlBaseParser.ShowFunctionsContext = ShowFunctionsContext; ShowFunctionsContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowFunctionsContext.prototype.FUNCTIONS = function() { return this.getToken(SqlBaseParser.FUNCTIONS, 0); }; ShowFunctionsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowFunctions(this); } }; ShowFunctionsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowFunctions(this); } }; ShowFunctionsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowFunctions(this); } else { return (visitor as any).visitChildren(this); } }; function DescribeOutputContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DescribeOutputContext.prototype = Object.create(StatementContext.prototype); DescribeOutputContext.prototype.constructor = DescribeOutputContext; SqlBaseParser.DescribeOutputContext = DescribeOutputContext; DescribeOutputContext.prototype.DESCRIBE = function() { return this.getToken(SqlBaseParser.DESCRIBE, 0); }; DescribeOutputContext.prototype.OUTPUT = function() { return this.getToken(SqlBaseParser.OUTPUT, 0); }; DescribeOutputContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; DescribeOutputContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDescribeOutput(this); } }; DescribeOutputContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDescribeOutput(this); } }; DescribeOutputContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDescribeOutput(this); } else { return (visitor as any).visitChildren(this); } }; function DropSchemaContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } DropSchemaContext.prototype = Object.create(StatementContext.prototype); DropSchemaContext.prototype.constructor = DropSchemaContext; SqlBaseParser.DropSchemaContext = DropSchemaContext; DropSchemaContext.prototype.DROP = function() { return this.getToken(SqlBaseParser.DROP, 0); }; DropSchemaContext.prototype.SCHEMA = function() { return this.getToken(SqlBaseParser.SCHEMA, 0); }; DropSchemaContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; DropSchemaContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; DropSchemaContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; DropSchemaContext.prototype.CASCADE = function() { return this.getToken(SqlBaseParser.CASCADE, 0); }; DropSchemaContext.prototype.RESTRICT = function() { return this.getToken(SqlBaseParser.RESTRICT, 0); }; DropSchemaContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDropSchema(this); } }; DropSchemaContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDropSchema(this); } }; DropSchemaContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDropSchema(this); } else { return (visitor as any).visitChildren(this); } }; function GrantContext(parser, ctx) { StatementContext.call(this, parser); this.grantee = null; // IdentifierContext; StatementContext.prototype.copyFrom.call(this, ctx); // return this; } GrantContext.prototype = Object.create(StatementContext.prototype); GrantContext.prototype.constructor = GrantContext; SqlBaseParser.GrantContext = GrantContext; GrantContext.prototype.GRANT = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(SqlBaseParser.GRANT); } else { return this.getToken(SqlBaseParser.GRANT, i); } }; GrantContext.prototype.ON = function() { return this.getToken(SqlBaseParser.ON, 0); }; GrantContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; GrantContext.prototype.TO = function() { return this.getToken(SqlBaseParser.TO, 0); }; GrantContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; GrantContext.prototype.privilege = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(PrivilegeContext); } else { return this.getTypedRuleContext(PrivilegeContext,i); } }; GrantContext.prototype.ALL = function() { return this.getToken(SqlBaseParser.ALL, 0); }; GrantContext.prototype.PRIVILEGES = function() { return this.getToken(SqlBaseParser.PRIVILEGES, 0); }; GrantContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; GrantContext.prototype.WITH = function() { return this.getToken(SqlBaseParser.WITH, 0); }; GrantContext.prototype.OPTION = function() { return this.getToken(SqlBaseParser.OPTION, 0); }; GrantContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterGrant(this); } }; GrantContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitGrant(this); } }; GrantContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitGrant(this); } else { return (visitor as any).visitChildren(this); } }; function ShowCreateViewContext(parser, ctx) { StatementContext.call(this, parser); StatementContext.prototype.copyFrom.call(this, ctx); // return this; } ShowCreateViewContext.prototype = Object.create(StatementContext.prototype); ShowCreateViewContext.prototype.constructor = ShowCreateViewContext; SqlBaseParser.ShowCreateViewContext = ShowCreateViewContext; ShowCreateViewContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; ShowCreateViewContext.prototype.CREATE = function() { return this.getToken(SqlBaseParser.CREATE, 0); }; ShowCreateViewContext.prototype.VIEW = function() { return this.getToken(SqlBaseParser.VIEW, 0); }; ShowCreateViewContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; ShowCreateViewContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterShowCreateView(this); } }; ShowCreateViewContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitShowCreateView(this); } }; ShowCreateViewContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitShowCreateView(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.StatementContext = StatementContext; SqlBaseParser.prototype.statement = function() { var localctx = new StatementContext(this, this._ctx, this.state); this.enterRule(localctx, 6, SqlBaseParser.RULE_statement); var _la = 0; // Token type try { this.state = 495; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,46,this._ctx); switch(la_) { case 1: localctx = new StatementDefaultContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 143; this.query(); break; case 2: localctx = new UseContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 144; this.match(SqlBaseParser.USE); this.state = 145; localctx.schema = this.identifier(); break; case 3: localctx = new UseContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 146; this.match(SqlBaseParser.USE); this.state = 147; localctx.catalog = this.identifier(); this.state = 148; this.match(SqlBaseParser.T__0); this.state = 149; localctx.schema = this.identifier(); break; case 4: localctx = new CreateSchemaContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 151; this.match(SqlBaseParser.CREATE); this.state = 152; this.match(SqlBaseParser.SCHEMA); this.state = 156; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,2,this._ctx); if(la_===1) { this.state = 153; this.match(SqlBaseParser.IF); this.state = 154; this.match(SqlBaseParser.NOT); this.state = 155; this.match(SqlBaseParser.EXISTS); } this.state = 158; this.qualifiedName(); this.state = 161; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WITH) { this.state = 159; this.match(SqlBaseParser.WITH); this.state = 160; this.tableProperties(); } break; case 5: localctx = new DropSchemaContext(this, localctx); this.enterOuterAlt(localctx, 5); this.state = 163; this.match(SqlBaseParser.DROP); this.state = 164; this.match(SqlBaseParser.SCHEMA); this.state = 167; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,4,this._ctx); if(la_===1) { this.state = 165; this.match(SqlBaseParser.IF); this.state = 166; this.match(SqlBaseParser.EXISTS); } this.state = 169; this.qualifiedName(); this.state = 171; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.CASCADE || _la===SqlBaseParser.RESTRICT) { this.state = 170; _la = this._input.LA(1); if(!(_la===SqlBaseParser.CASCADE || _la===SqlBaseParser.RESTRICT)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } break; case 6: localctx = new RenameSchemaContext(this, localctx); this.enterOuterAlt(localctx, 6); this.state = 173; this.match(SqlBaseParser.ALTER); this.state = 174; this.match(SqlBaseParser.SCHEMA); this.state = 175; this.qualifiedName(); this.state = 176; this.match(SqlBaseParser.RENAME); this.state = 177; this.match(SqlBaseParser.TO); this.state = 178; this.identifier(); break; case 7: localctx = new CreateTableAsSelectContext(this, localctx); this.enterOuterAlt(localctx, 7); this.state = 180; this.match(SqlBaseParser.CREATE); this.state = 181; this.match(SqlBaseParser.TABLE); this.state = 185; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,6,this._ctx); if(la_===1) { this.state = 182; this.match(SqlBaseParser.IF); this.state = 183; this.match(SqlBaseParser.NOT); this.state = 184; this.match(SqlBaseParser.EXISTS); } this.state = 187; this.qualifiedName(); this.state = 190; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WITH) { this.state = 188; this.match(SqlBaseParser.WITH); this.state = 189; this.tableProperties(); } this.state = 192; this.match(SqlBaseParser.AS); this.state = 193; this.query(); this.state = 199; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WITH) { this.state = 194; this.match(SqlBaseParser.WITH); this.state = 196; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NO) { this.state = 195; this.match(SqlBaseParser.NO); } this.state = 198; this.match(SqlBaseParser.DATA); } break; case 8: localctx = new CreateTableContext(this, localctx); this.enterOuterAlt(localctx, 8); this.state = 201; this.match(SqlBaseParser.CREATE); this.state = 202; this.match(SqlBaseParser.TABLE); this.state = 206; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,10,this._ctx); if(la_===1) { this.state = 203; this.match(SqlBaseParser.IF); this.state = 204; this.match(SqlBaseParser.NOT); this.state = 205; this.match(SqlBaseParser.EXISTS); } this.state = 208; this.qualifiedName(); this.state = 209; this.match(SqlBaseParser.T__1); this.state = 210; this.tableElement(); this.state = 215; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 211; this.match(SqlBaseParser.T__2); this.state = 212; this.tableElement(); this.state = 217; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 218; this.match(SqlBaseParser.T__3); this.state = 221; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WITH) { this.state = 219; this.match(SqlBaseParser.WITH); this.state = 220; this.tableProperties(); } break; case 9: localctx = new DropTableContext(this, localctx); this.enterOuterAlt(localctx, 9); this.state = 223; this.match(SqlBaseParser.DROP); this.state = 224; this.match(SqlBaseParser.TABLE); this.state = 227; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,13,this._ctx); if(la_===1) { this.state = 225; this.match(SqlBaseParser.IF); this.state = 226; this.match(SqlBaseParser.EXISTS); } this.state = 229; this.qualifiedName(); break; case 10: localctx = new InsertIntoContext(this, localctx); this.enterOuterAlt(localctx, 10); this.state = 230; this.match(SqlBaseParser.INSERT); this.state = 231; this.match(SqlBaseParser.INTO); this.state = 232; this.qualifiedName(); this.state = 234; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,14,this._ctx); if(la_===1) { this.state = 233; this.columnAliases(); } this.state = 236; this.query(); break; case 11: localctx = new DeleteContext(this, localctx); this.enterOuterAlt(localctx, 11); this.state = 238; this.match(SqlBaseParser.DELETE); this.state = 239; this.match(SqlBaseParser.FROM); this.state = 240; this.qualifiedName(); this.state = 243; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WHERE) { this.state = 241; this.match(SqlBaseParser.WHERE); this.state = 242; this.booleanExpression(0); } break; case 12: localctx = new RenameTableContext(this, localctx); this.enterOuterAlt(localctx, 12); this.state = 245; this.match(SqlBaseParser.ALTER); this.state = 246; this.match(SqlBaseParser.TABLE); this.state = 247; localctx.from = this.qualifiedName(); this.state = 248; this.match(SqlBaseParser.RENAME); this.state = 249; this.match(SqlBaseParser.TO); this.state = 250; localctx.to = this.qualifiedName(); break; case 13: localctx = new RenameColumnContext(this, localctx); this.enterOuterAlt(localctx, 13); this.state = 252; this.match(SqlBaseParser.ALTER); this.state = 253; this.match(SqlBaseParser.TABLE); this.state = 254; localctx.tableName = this.qualifiedName(); this.state = 255; this.match(SqlBaseParser.RENAME); this.state = 256; this.match(SqlBaseParser.COLUMN); this.state = 257; localctx.from = this.identifier(); this.state = 258; this.match(SqlBaseParser.TO); this.state = 259; localctx.to = this.identifier(); break; case 14: localctx = new AddColumnContext(this, localctx); this.enterOuterAlt(localctx, 14); this.state = 261; this.match(SqlBaseParser.ALTER); this.state = 262; this.match(SqlBaseParser.TABLE); this.state = 263; localctx.tableName = this.qualifiedName(); this.state = 264; this.match(SqlBaseParser.ADD); this.state = 265; this.match(SqlBaseParser.COLUMN); this.state = 266; localctx.column = this.columnDefinition(); break; case 15: localctx = new CreateViewContext(this, localctx); this.enterOuterAlt(localctx, 15); this.state = 268; this.match(SqlBaseParser.CREATE); this.state = 271; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.OR) { this.state = 269; this.match(SqlBaseParser.OR); this.state = 270; this.match(SqlBaseParser.REPLACE); } this.state = 273; this.match(SqlBaseParser.VIEW); this.state = 274; this.qualifiedName(); this.state = 275; this.match(SqlBaseParser.AS); this.state = 276; this.query(); break; case 16: localctx = new DropViewContext(this, localctx); this.enterOuterAlt(localctx, 16); this.state = 278; this.match(SqlBaseParser.DROP); this.state = 279; this.match(SqlBaseParser.VIEW); this.state = 282; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,17,this._ctx); if(la_===1) { this.state = 280; this.match(SqlBaseParser.IF); this.state = 281; this.match(SqlBaseParser.EXISTS); } this.state = 284; this.qualifiedName(); break; case 17: localctx = new CallContext(this, localctx); this.enterOuterAlt(localctx, 17); this.state = 285; this.match(SqlBaseParser.CALL); this.state = 286; this.qualifiedName(); this.state = 287; this.match(SqlBaseParser.T__1); this.state = 296; this._errHandler.sync(this); _la = this._input.LA(1); if((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << SqlBaseParser.T__1) | (1 << SqlBaseParser.T__4) | (1 << SqlBaseParser.ADD))) !== 0) || ((((_la - 32)) & ~0x1f) == 0 && ((1 << (_la - 32)) & ((1 << (SqlBaseParser.NOT - 32)) | (1 << (SqlBaseParser.NO - 32)) | (1 << (SqlBaseParser.EXISTS - 32)) | (1 << (SqlBaseParser.NULL - 32)) | (1 << (SqlBaseParser.TRUE - 32)) | (1 << (SqlBaseParser.FALSE - 32)) | (1 << (SqlBaseParser.SUBSTRING - 32)) | (1 << (SqlBaseParser.POSITION - 32)) | (1 << (SqlBaseParser.TINYINT - 32)) | (1 << (SqlBaseParser.SMALLINT - 32)) | (1 << (SqlBaseParser.INTEGER - 32)) | (1 << (SqlBaseParser.DATE - 32)) | (1 << (SqlBaseParser.TIME - 32)) | (1 << (SqlBaseParser.TIMESTAMP - 32)) | (1 << (SqlBaseParser.INTERVAL - 32)) | (1 << (SqlBaseParser.YEAR - 32)) | (1 << (SqlBaseParser.MONTH - 32)) | (1 << (SqlBaseParser.DAY - 32)) | (1 << (SqlBaseParser.HOUR - 32)) | (1 << (SqlBaseParser.MINUTE - 32)) | (1 << (SqlBaseParser.SECOND - 32)) | (1 << (SqlBaseParser.ZONE - 32)))) !== 0) || ((((_la - 64)) & ~0x1f) == 0 && ((1 << (_la - 64)) & ((1 << (SqlBaseParser.CURRENT_DATE - 64)) | (1 << (SqlBaseParser.CURRENT_TIME - 64)) | (1 << (SqlBaseParser.CURRENT_TIMESTAMP - 64)) | (1 << (SqlBaseParser.LOCALTIME - 64)) | (1 << (SqlBaseParser.LOCALTIMESTAMP - 64)) | (1 << (SqlBaseParser.EXTRACT - 64)) | (1 << (SqlBaseParser.CASE - 64)) | (1 << (SqlBaseParser.FILTER - 64)) | (1 << (SqlBaseParser.OVER - 64)) | (1 << (SqlBaseParser.PARTITION - 64)) | (1 << (SqlBaseParser.RANGE - 64)) | (1 << (SqlBaseParser.ROWS - 64)) | (1 << (SqlBaseParser.PRECEDING - 64)) | (1 << (SqlBaseParser.FOLLOWING - 64)) | (1 << (SqlBaseParser.CURRENT - 64)) | (1 << (SqlBaseParser.ROW - 64)))) !== 0) || ((((_la - 99)) & ~0x1f) == 0 && ((1 << (_la - 99)) & ((1 << (SqlBaseParser.SCHEMA - 99)) | (1 << (SqlBaseParser.VIEW - 99)) | (1 << (SqlBaseParser.REPLACE - 99)) | (1 << (SqlBaseParser.GRANT - 99)) | (1 << (SqlBaseParser.REVOKE - 99)) | (1 << (SqlBaseParser.PRIVILEGES - 99)) | (1 << (SqlBaseParser.PUBLIC - 99)) | (1 << (SqlBaseParser.OPTION - 99)) | (1 << (SqlBaseParser.EXPLAIN - 99)) | (1 << (SqlBaseParser.ANALYZE - 99)) | (1 << (SqlBaseParser.FORMAT - 99)) | (1 << (SqlBaseParser.TYPE - 99)) | (1 << (SqlBaseParser.TEXT - 99)) | (1 << (SqlBaseParser.GRAPHVIZ - 99)) | (1 << (SqlBaseParser.LOGICAL - 99)) | (1 << (SqlBaseParser.DISTRIBUTED - 99)) | (1 << (SqlBaseParser.CAST - 99)) | (1 << (SqlBaseParser.TRY_CAST - 99)) | (1 << (SqlBaseParser.SHOW - 99)) | (1 << (SqlBaseParser.TABLES - 99)) | (1 << (SqlBaseParser.SCHEMAS - 99)) | (1 << (SqlBaseParser.CATALOGS - 99)) | (1 << (SqlBaseParser.COLUMNS - 99)) | (1 << (SqlBaseParser.COLUMN - 99)) | (1 << (SqlBaseParser.USE - 99)) | (1 << (SqlBaseParser.PARTITIONS - 99)))) !== 0) || ((((_la - 131)) & ~0x1f) == 0 && ((1 << (_la - 131)) & ((1 << (SqlBaseParser.FUNCTIONS - 131)) | (1 << (SqlBaseParser.TO - 131)) | (1 << (SqlBaseParser.SYSTEM - 131)) | (1 << (SqlBaseParser.BERNOULLI - 131)) | (1 << (SqlBaseParser.POISSONIZED - 131)) | (1 << (SqlBaseParser.TABLESAMPLE - 131)) | (1 << (SqlBaseParser.ARRAY - 131)) | (1 << (SqlBaseParser.MAP - 131)) | (1 << (SqlBaseParser.SET - 131)) | (1 << (SqlBaseParser.RESET - 131)) | (1 << (SqlBaseParser.SESSION - 131)) | (1 << (SqlBaseParser.DATA - 131)) | (1 << (SqlBaseParser.START - 131)) | (1 << (SqlBaseParser.TRANSACTION - 131)) | (1 << (SqlBaseParser.COMMIT - 131)) | (1 << (SqlBaseParser.ROLLBACK - 131)) | (1 << (SqlBaseParser.WORK - 131)) | (1 << (SqlBaseParser.ISOLATION - 131)) | (1 << (SqlBaseParser.LEVEL - 131)) | (1 << (SqlBaseParser.SERIALIZABLE - 131)) | (1 << (SqlBaseParser.REPEATABLE - 131)) | (1 << (SqlBaseParser.COMMITTED - 131)) | (1 << (SqlBaseParser.UNCOMMITTED - 131)) | (1 << (SqlBaseParser.READ - 131)))) !== 0) || ((((_la - 163)) & ~0x1f) == 0 && ((1 << (_la - 163)) & ((1 << (SqlBaseParser.WRITE - 163)) | (1 << (SqlBaseParser.ONLY - 163)) | (1 << (SqlBaseParser.CALL - 163)) | (1 << (SqlBaseParser.INPUT - 163)) | (1 << (SqlBaseParser.OUTPUT - 163)) | (1 << (SqlBaseParser.CASCADE - 163)) | (1 << (SqlBaseParser.RESTRICT - 163)) | (1 << (SqlBaseParser.INCLUDING - 163)) | (1 << (SqlBaseParser.EXCLUDING - 163)) | (1 << (SqlBaseParser.PROPERTIES - 163)) | (1 << (SqlBaseParser.NORMALIZE - 163)) | (1 << (SqlBaseParser.NFD - 163)) | (1 << (SqlBaseParser.NFC - 163)) | (1 << (SqlBaseParser.NFKD - 163)) | (1 << (SqlBaseParser.NFKC - 163)) | (1 << (SqlBaseParser.IF - 163)) | (1 << (SqlBaseParser.NULLIF - 163)) | (1 << (SqlBaseParser.COALESCE - 163)) | (1 << (SqlBaseParser.PLUS - 163)) | (1 << (SqlBaseParser.MINUS - 163)))) !== 0) || ((((_la - 196)) & ~0x1f) == 0 && ((1 << (_la - 196)) & ((1 << (SqlBaseParser.STRING - 196)) | (1 << (SqlBaseParser.BINARY_LITERAL - 196)) | (1 << (SqlBaseParser.INTEGER_VALUE - 196)) | (1 << (SqlBaseParser.DECIMAL_VALUE - 196)) | (1 << (SqlBaseParser.IDENTIFIER - 196)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 196)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.DOUBLE_PRECISION - 196)))) !== 0)) { this.state = 288; this.callArgument(); this.state = 293; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 289; this.match(SqlBaseParser.T__2); this.state = 290; this.callArgument(); this.state = 295; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 298; this.match(SqlBaseParser.T__3); break; case 18: localctx = new GrantContext(this, localctx); this.enterOuterAlt(localctx, 18); this.state = 300; this.match(SqlBaseParser.GRANT); this.state = 311; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.SELECT: case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.INSERT: case SqlBaseParser.DELETE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: this.state = 301; this.privilege(); this.state = 306; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 302; this.match(SqlBaseParser.T__2); this.state = 303; this.privilege(); this.state = 308; this._errHandler.sync(this); _la = this._input.LA(1); } break; case SqlBaseParser.ALL: this.state = 309; this.match(SqlBaseParser.ALL); this.state = 310; this.match(SqlBaseParser.PRIVILEGES); break; default: throw new _error.NoViableAltException(this); } this.state = 313; this.match(SqlBaseParser.ON); this.state = 315; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.TABLE) { this.state = 314; this.match(SqlBaseParser.TABLE); } this.state = 317; this.qualifiedName(); this.state = 318; this.match(SqlBaseParser.TO); this.state = 319; localctx.grantee = this.identifier(); this.state = 323; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WITH) { this.state = 320; this.match(SqlBaseParser.WITH); this.state = 321; this.match(SqlBaseParser.GRANT); this.state = 322; this.match(SqlBaseParser.OPTION); } break; case 19: localctx = new RevokeContext(this, localctx); this.enterOuterAlt(localctx, 19); this.state = 325; this.match(SqlBaseParser.REVOKE); this.state = 329; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,24,this._ctx); if(la_===1) { this.state = 326; this.match(SqlBaseParser.GRANT); this.state = 327; this.match(SqlBaseParser.OPTION); this.state = 328; this.match(SqlBaseParser.FOR); } this.state = 341; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.SELECT: case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.INSERT: case SqlBaseParser.DELETE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: this.state = 331; this.privilege(); this.state = 336; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 332; this.match(SqlBaseParser.T__2); this.state = 333; this.privilege(); this.state = 338; this._errHandler.sync(this); _la = this._input.LA(1); } break; case SqlBaseParser.ALL: this.state = 339; this.match(SqlBaseParser.ALL); this.state = 340; this.match(SqlBaseParser.PRIVILEGES); break; default: throw new _error.NoViableAltException(this); } this.state = 343; this.match(SqlBaseParser.ON); this.state = 345; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.TABLE) { this.state = 344; this.match(SqlBaseParser.TABLE); } this.state = 347; this.qualifiedName(); this.state = 348; this.match(SqlBaseParser.FROM); this.state = 349; localctx.grantee = this.identifier(); break; case 20: localctx = new ExplainContext(this, localctx); this.enterOuterAlt(localctx, 20); this.state = 351; this.match(SqlBaseParser.EXPLAIN); this.state = 353; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ANALYZE) { this.state = 352; this.match(SqlBaseParser.ANALYZE); } this.state = 366; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,30,this._ctx); if(la_===1) { this.state = 355; this.match(SqlBaseParser.T__1); this.state = 356; this.explainOption(); this.state = 361; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 357; this.match(SqlBaseParser.T__2); this.state = 358; this.explainOption(); this.state = 363; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 364; this.match(SqlBaseParser.T__3); } this.state = 368; this.statement(); break; case 21: localctx = new ShowCreateTableContext(this, localctx); this.enterOuterAlt(localctx, 21); this.state = 369; this.match(SqlBaseParser.SHOW); this.state = 370; this.match(SqlBaseParser.CREATE); this.state = 371; this.match(SqlBaseParser.TABLE); this.state = 372; this.qualifiedName(); break; case 22: localctx = new ShowCreateViewContext(this, localctx); this.enterOuterAlt(localctx, 22); this.state = 373; this.match(SqlBaseParser.SHOW); this.state = 374; this.match(SqlBaseParser.CREATE); this.state = 375; this.match(SqlBaseParser.VIEW); this.state = 376; this.qualifiedName(); break; case 23: localctx = new ShowTablesContext(this, localctx); this.enterOuterAlt(localctx, 23); this.state = 377; this.match(SqlBaseParser.SHOW); this.state = 378; this.match(SqlBaseParser.TABLES); this.state = 381; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN) { this.state = 379; _la = this._input.LA(1); if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 380; this.qualifiedName(); } this.state = 385; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.LIKE) { this.state = 383; this.match(SqlBaseParser.LIKE); this.state = 384; localctx.pattern = this.match(SqlBaseParser.STRING); } break; case 24: localctx = new ShowSchemasContext(this, localctx); this.enterOuterAlt(localctx, 24); this.state = 387; this.match(SqlBaseParser.SHOW); this.state = 388; this.match(SqlBaseParser.SCHEMAS); this.state = 391; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN) { this.state = 389; _la = this._input.LA(1); if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 390; this.identifier(); } this.state = 395; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.LIKE) { this.state = 393; this.match(SqlBaseParser.LIKE); this.state = 394; localctx.pattern = this.match(SqlBaseParser.STRING); } break; case 25: localctx = new ShowCatalogsContext(this, localctx); this.enterOuterAlt(localctx, 25); this.state = 397; this.match(SqlBaseParser.SHOW); this.state = 398; this.match(SqlBaseParser.CATALOGS); this.state = 401; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.LIKE) { this.state = 399; this.match(SqlBaseParser.LIKE); this.state = 400; localctx.pattern = this.match(SqlBaseParser.STRING); } break; case 26: localctx = new ShowColumnsContext(this, localctx); this.enterOuterAlt(localctx, 26); this.state = 403; this.match(SqlBaseParser.SHOW); this.state = 404; this.match(SqlBaseParser.COLUMNS); this.state = 405; _la = this._input.LA(1); if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 406; this.qualifiedName(); break; case 27: localctx = new ShowColumnsContext(this, localctx); this.enterOuterAlt(localctx, 27); this.state = 407; this.match(SqlBaseParser.DESCRIBE); this.state = 408; this.qualifiedName(); break; case 28: localctx = new ShowColumnsContext(this, localctx); this.enterOuterAlt(localctx, 28); this.state = 409; this.match(SqlBaseParser.DESC); this.state = 410; this.qualifiedName(); break; case 29: localctx = new ShowFunctionsContext(this, localctx); this.enterOuterAlt(localctx, 29); this.state = 411; this.match(SqlBaseParser.SHOW); this.state = 412; this.match(SqlBaseParser.FUNCTIONS); break; case 30: localctx = new ShowSessionContext(this, localctx); this.enterOuterAlt(localctx, 30); this.state = 413; this.match(SqlBaseParser.SHOW); this.state = 414; this.match(SqlBaseParser.SESSION); break; case 31: localctx = new SetSessionContext(this, localctx); this.enterOuterAlt(localctx, 31); this.state = 415; this.match(SqlBaseParser.SET); this.state = 416; this.match(SqlBaseParser.SESSION); this.state = 417; this.qualifiedName(); this.state = 418; this.match(SqlBaseParser.EQ); this.state = 419; this.expression(); break; case 32: localctx = new ResetSessionContext(this, localctx); this.enterOuterAlt(localctx, 32); this.state = 421; this.match(SqlBaseParser.RESET); this.state = 422; this.match(SqlBaseParser.SESSION); this.state = 423; this.qualifiedName(); break; case 33: localctx = new StartTransactionContext(this, localctx); this.enterOuterAlt(localctx, 33); this.state = 424; this.match(SqlBaseParser.START); this.state = 425; this.match(SqlBaseParser.TRANSACTION); this.state = 434; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ISOLATION || _la===SqlBaseParser.READ) { this.state = 426; this.transactionMode(); this.state = 431; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 427; this.match(SqlBaseParser.T__2); this.state = 428; this.transactionMode(); this.state = 433; this._errHandler.sync(this); _la = this._input.LA(1); } } break; case 34: localctx = new CommitContext(this, localctx); this.enterOuterAlt(localctx, 34); this.state = 436; this.match(SqlBaseParser.COMMIT); this.state = 438; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WORK) { this.state = 437; this.match(SqlBaseParser.WORK); } break; case 35: localctx = new RollbackContext(this, localctx); this.enterOuterAlt(localctx, 35); this.state = 440; this.match(SqlBaseParser.ROLLBACK); this.state = 442; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WORK) { this.state = 441; this.match(SqlBaseParser.WORK); } break; case 36: localctx = new ShowPartitionsContext(this, localctx); this.enterOuterAlt(localctx, 36); this.state = 444; this.match(SqlBaseParser.SHOW); this.state = 445; this.match(SqlBaseParser.PARTITIONS); this.state = 446; _la = this._input.LA(1); if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 447; this.qualifiedName(); this.state = 450; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WHERE) { this.state = 448; this.match(SqlBaseParser.WHERE); this.state = 449; this.booleanExpression(0); } this.state = 462; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ORDER) { this.state = 452; this.match(SqlBaseParser.ORDER); this.state = 453; this.match(SqlBaseParser.BY); this.state = 454; this.sortItem(); this.state = 459; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 455; this.match(SqlBaseParser.T__2); this.state = 456; this.sortItem(); this.state = 461; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 466; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.LIMIT) { this.state = 464; this.match(SqlBaseParser.LIMIT); this.state = 465; localctx.limit = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.ALL || _la===SqlBaseParser.INTEGER_VALUE)) { localctx.limit = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } break; case 37: localctx = new PrepareContext(this, localctx); this.enterOuterAlt(localctx, 37); this.state = 468; this.match(SqlBaseParser.PREPARE); this.state = 469; this.identifier(); this.state = 470; this.match(SqlBaseParser.FROM); this.state = 471; this.statement(); break; case 38: localctx = new DeallocateContext(this, localctx); this.enterOuterAlt(localctx, 38); this.state = 473; this.match(SqlBaseParser.DEALLOCATE); this.state = 474; this.match(SqlBaseParser.PREPARE); this.state = 475; this.identifier(); break; case 39: localctx = new ExecuteContext(this, localctx); this.enterOuterAlt(localctx, 39); this.state = 476; this.match(SqlBaseParser.EXECUTE); this.state = 477; this.identifier(); this.state = 487; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.USING) { this.state = 478; this.match(SqlBaseParser.USING); this.state = 479; this.expression(); this.state = 484; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 480; this.match(SqlBaseParser.T__2); this.state = 481; this.expression(); this.state = 486; this._errHandler.sync(this); _la = this._input.LA(1); } } break; case 40: localctx = new DescribeInputContext(this, localctx); this.enterOuterAlt(localctx, 40); this.state = 489; this.match(SqlBaseParser.DESCRIBE); this.state = 490; this.match(SqlBaseParser.INPUT); this.state = 491; this.identifier(); break; case 41: localctx = new DescribeOutputContext(this, localctx); this.enterOuterAlt(localctx, 41); this.state = 492; this.match(SqlBaseParser.DESCRIBE); this.state = 493; this.match(SqlBaseParser.OUTPUT); this.state = 494; this.identifier(); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function QueryContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_query; // return this; } QueryContext.prototype = Object.create(ParserRuleContext.prototype); QueryContext.prototype.constructor = QueryContext; QueryContext.prototype.queryNoWith = function() { return this.getTypedRuleContext(QueryNoWithContext,0); }; QueryContext.prototype.presto_with = function() { return this.getTypedRuleContext(Presto_withContext,0); }; QueryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQuery(this); } }; QueryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQuery(this); } }; QueryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQuery(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.QueryContext = QueryContext; SqlBaseParser.prototype.query = function() { var localctx = new QueryContext(this, this._ctx, this.state); this.enterRule(localctx, 8, SqlBaseParser.RULE_query); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 498; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.WITH) { this.state = 497; this.presto_with(); } this.state = 500; this.queryNoWith(); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Presto_withContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_presto_with; // return this; } Presto_withContext.prototype = Object.create(ParserRuleContext.prototype); Presto_withContext.prototype.constructor = Presto_withContext; Presto_withContext.prototype.WITH = function() { return this.getToken(SqlBaseParser.WITH, 0); }; Presto_withContext.prototype.namedQuery = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(NamedQueryContext); } else { return this.getTypedRuleContext(NamedQueryContext,i); } }; Presto_withContext.prototype.RECURSIVE = function() { return this.getToken(SqlBaseParser.RECURSIVE, 0); }; Presto_withContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterPresto_with(this); } }; Presto_withContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitPresto_with(this); } }; Presto_withContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitPresto_with(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.Presto_withContext = Presto_withContext; SqlBaseParser.prototype.presto_with = function() { var localctx = new Presto_withContext(this, this._ctx, this.state); this.enterRule(localctx, 10, SqlBaseParser.RULE_presto_with); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 502; this.match(SqlBaseParser.WITH); this.state = 504; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.RECURSIVE) { this.state = 503; this.match(SqlBaseParser.RECURSIVE); } this.state = 506; this.namedQuery(); this.state = 511; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 507; this.match(SqlBaseParser.T__2); this.state = 508; this.namedQuery(); this.state = 513; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TableElementContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_tableElement; // return this; } TableElementContext.prototype = Object.create(ParserRuleContext.prototype); TableElementContext.prototype.constructor = TableElementContext; TableElementContext.prototype.columnDefinition = function() { return this.getTypedRuleContext(ColumnDefinitionContext,0); }; TableElementContext.prototype.likeClause = function() { return this.getTypedRuleContext(LikeClauseContext,0); }; TableElementContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTableElement(this); } }; TableElementContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTableElement(this); } }; TableElementContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTableElement(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.TableElementContext = TableElementContext; SqlBaseParser.prototype.tableElement = function() { var localctx = new TableElementContext(this, this._ctx, this.state); this.enterRule(localctx, 12, SqlBaseParser.RULE_tableElement); try { this.state = 516; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: this.enterOuterAlt(localctx, 1); this.state = 514; this.columnDefinition(); break; case SqlBaseParser.LIKE: this.enterOuterAlt(localctx, 2); this.state = 515; this.likeClause(); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ColumnDefinitionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_columnDefinition; // return this; } ColumnDefinitionContext.prototype = Object.create(ParserRuleContext.prototype); ColumnDefinitionContext.prototype.constructor = ColumnDefinitionContext; ColumnDefinitionContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; ColumnDefinitionContext.prototype.type = function() { return this.getTypedRuleContext(TypeContext,0); }; ColumnDefinitionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterColumnDefinition(this); } }; ColumnDefinitionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitColumnDefinition(this); } }; ColumnDefinitionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitColumnDefinition(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.ColumnDefinitionContext = ColumnDefinitionContext; SqlBaseParser.prototype.columnDefinition = function() { var localctx = new ColumnDefinitionContext(this, this._ctx, this.state); this.enterRule(localctx, 14, SqlBaseParser.RULE_columnDefinition); try { this.enterOuterAlt(localctx, 1); this.state = 518; this.identifier(); this.state = 519; this.type(0); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function LikeClauseContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_likeClause; this.optionType = null; // Token // return this; } LikeClauseContext.prototype = Object.create(ParserRuleContext.prototype); LikeClauseContext.prototype.constructor = LikeClauseContext; LikeClauseContext.prototype.LIKE = function() { return this.getToken(SqlBaseParser.LIKE, 0); }; LikeClauseContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; LikeClauseContext.prototype.PROPERTIES = function() { return this.getToken(SqlBaseParser.PROPERTIES, 0); }; LikeClauseContext.prototype.INCLUDING = function() { return this.getToken(SqlBaseParser.INCLUDING, 0); }; LikeClauseContext.prototype.EXCLUDING = function() { return this.getToken(SqlBaseParser.EXCLUDING, 0); }; LikeClauseContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterLikeClause(this); } }; LikeClauseContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitLikeClause(this); } }; LikeClauseContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitLikeClause(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.LikeClauseContext = LikeClauseContext; SqlBaseParser.prototype.likeClause = function() { var localctx = new LikeClauseContext(this, this._ctx, this.state); this.enterRule(localctx, 16, SqlBaseParser.RULE_likeClause); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 521; this.match(SqlBaseParser.LIKE); this.state = 522; this.qualifiedName(); this.state = 525; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.INCLUDING || _la===SqlBaseParser.EXCLUDING) { this.state = 523; localctx.optionType = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.INCLUDING || _la===SqlBaseParser.EXCLUDING)) { localctx.optionType = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 524; this.match(SqlBaseParser.PROPERTIES); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TablePropertiesContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_tableProperties; // return this; } TablePropertiesContext.prototype = Object.create(ParserRuleContext.prototype); TablePropertiesContext.prototype.constructor = TablePropertiesContext; TablePropertiesContext.prototype.tableProperty = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TablePropertyContext); } else { return this.getTypedRuleContext(TablePropertyContext,i); } }; TablePropertiesContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTableProperties(this); } }; TablePropertiesContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTableProperties(this); } }; TablePropertiesContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTableProperties(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.TablePropertiesContext = TablePropertiesContext; SqlBaseParser.prototype.tableProperties = function() { var localctx = new TablePropertiesContext(this, this._ctx, this.state); this.enterRule(localctx, 18, SqlBaseParser.RULE_tableProperties); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 527; this.match(SqlBaseParser.T__1); this.state = 528; this.tableProperty(); this.state = 533; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 529; this.match(SqlBaseParser.T__2); this.state = 530; this.tableProperty(); this.state = 535; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 536; this.match(SqlBaseParser.T__3); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TablePropertyContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_tableProperty; // return this; } TablePropertyContext.prototype = Object.create(ParserRuleContext.prototype); TablePropertyContext.prototype.constructor = TablePropertyContext; TablePropertyContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; TablePropertyContext.prototype.EQ = function() { return this.getToken(SqlBaseParser.EQ, 0); }; TablePropertyContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; TablePropertyContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTableProperty(this); } }; TablePropertyContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTableProperty(this); } }; TablePropertyContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTableProperty(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.TablePropertyContext = TablePropertyContext; SqlBaseParser.prototype.tableProperty = function() { var localctx = new TablePropertyContext(this, this._ctx, this.state); this.enterRule(localctx, 20, SqlBaseParser.RULE_tableProperty); try { this.enterOuterAlt(localctx, 1); this.state = 538; this.identifier(); this.state = 539; this.match(SqlBaseParser.EQ); this.state = 540; this.expression(); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function QueryNoWithContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_queryNoWith; this.limit = null; // Token // return this; } QueryNoWithContext.prototype = Object.create(ParserRuleContext.prototype); QueryNoWithContext.prototype.constructor = QueryNoWithContext; QueryNoWithContext.prototype.queryTerm = function() { return this.getTypedRuleContext(QueryTermContext,0); }; QueryNoWithContext.prototype.ORDER = function() { return this.getToken(SqlBaseParser.ORDER, 0); }; QueryNoWithContext.prototype.BY = function() { return this.getToken(SqlBaseParser.BY, 0); }; QueryNoWithContext.prototype.sortItem = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SortItemContext); } else { return this.getTypedRuleContext(SortItemContext,i); } }; QueryNoWithContext.prototype.LIMIT = function() { return this.getToken(SqlBaseParser.LIMIT, 0); }; QueryNoWithContext.prototype.INTEGER_VALUE = function() { return this.getToken(SqlBaseParser.INTEGER_VALUE, 0); }; QueryNoWithContext.prototype.ALL = function() { return this.getToken(SqlBaseParser.ALL, 0); }; QueryNoWithContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQueryNoWith(this); } }; QueryNoWithContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQueryNoWith(this); } }; QueryNoWithContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQueryNoWith(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.QueryNoWithContext = QueryNoWithContext; SqlBaseParser.prototype.queryNoWith = function() { var localctx = new QueryNoWithContext(this, this._ctx, this.state); this.enterRule(localctx, 22, SqlBaseParser.RULE_queryNoWith); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 542; this.queryTerm(0); this.state = 553; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ORDER) { this.state = 543; this.match(SqlBaseParser.ORDER); this.state = 544; this.match(SqlBaseParser.BY); this.state = 545; this.sortItem(); this.state = 550; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 546; this.match(SqlBaseParser.T__2); this.state = 547; this.sortItem(); this.state = 552; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 557; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.LIMIT) { this.state = 555; this.match(SqlBaseParser.LIMIT); this.state = 556; localctx.limit = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.ALL || _la===SqlBaseParser.INTEGER_VALUE)) { localctx.limit = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function QueryTermContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_queryTerm; //return this; } QueryTermContext.prototype = Object.create(ParserRuleContext.prototype); QueryTermContext.prototype.constructor = QueryTermContext; QueryTermContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function QueryTermDefaultContext(parser, ctx) { QueryTermContext.call(this, parser); QueryTermContext.prototype.copyFrom.call(this, ctx); //return this; } QueryTermDefaultContext.prototype = Object.create(QueryTermContext.prototype); QueryTermDefaultContext.prototype.constructor = QueryTermDefaultContext; SqlBaseParser.QueryTermDefaultContext = QueryTermDefaultContext; QueryTermDefaultContext.prototype.queryPrimary = function() { return this.getTypedRuleContext(QueryPrimaryContext,0); }; QueryTermDefaultContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQueryTermDefault(this); } }; QueryTermDefaultContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQueryTermDefault(this); } }; QueryTermDefaultContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQueryTermDefault(this); } else { return (visitor as any).visitChildren(this); } }; function SetOperationContext(parser, ctx) { QueryTermContext.call(this, parser); this.left = null; // QueryTermContext; this.operator = null; // Token; this.right = null; // QueryTermContext; QueryTermContext.prototype.copyFrom.call(this, ctx); //return this; } SetOperationContext.prototype = Object.create(QueryTermContext.prototype); SetOperationContext.prototype.constructor = SetOperationContext; SqlBaseParser.SetOperationContext = SetOperationContext; SetOperationContext.prototype.queryTerm = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(QueryTermContext); } else { return this.getTypedRuleContext(QueryTermContext,i); } }; SetOperationContext.prototype.INTERSECT = function() { return this.getToken(SqlBaseParser.INTERSECT, 0); }; SetOperationContext.prototype.setQuantifier = function() { return this.getTypedRuleContext(SetQuantifierContext,0); }; SetOperationContext.prototype.UNION = function() { return this.getToken(SqlBaseParser.UNION, 0); }; SetOperationContext.prototype.EXCEPT = function() { return this.getToken(SqlBaseParser.EXCEPT, 0); }; SetOperationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSetOperation(this); } }; SetOperationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSetOperation(this); } }; SetOperationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSetOperation(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.prototype.queryTerm = function(_p) { if(_p===undefined) { _p = 0; } var _parentctx = this._ctx; var _parentState = this.state; var localctx = new QueryTermContext(this, this._ctx, _parentState); var _prevctx = localctx; var _startState = 24; this.enterRecursionRule(localctx, 24, SqlBaseParser.RULE_queryTerm, _p); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); localctx = new QueryTermDefaultContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 560; this.queryPrimary(); this._ctx.stop = this._input.LT(-1); this.state = 576; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,59,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { if(this._parseListeners!==null) { this.triggerExitRuleEvent(); } _prevctx = localctx; this.state = 574; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,58,this._ctx); switch(la_) { case 1: localctx = new SetOperationContext(this, new QueryTermContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_queryTerm); this.state = 562; if (!( this.precpred(this._ctx, 2))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 2)"); } this.state = 563; localctx.operator = this.match(SqlBaseParser.INTERSECT); this.state = 565; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) { this.state = 564; this.setQuantifier(); } this.state = 567; localctx.right = this.queryTerm(3); break; case 2: localctx = new SetOperationContext(this, new QueryTermContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_queryTerm); this.state = 568; if (!( this.precpred(this._ctx, 1))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 1)"); } this.state = 569; localctx.operator = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.UNION || _la===SqlBaseParser.EXCEPT)) { localctx.operator = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 571; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) { this.state = 570; this.setQuantifier(); } this.state = 573; localctx.right = this.queryTerm(2); break; } } this.state = 578; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,59,this._ctx); } } catch( error) { if(error instanceof _error.RecognitionException) { localctx.exception = error; this._errHandler.reportError(this, error); this._errHandler.recover(this, error); } else { throw error; } } finally { this.unrollRecursionContexts(_parentctx) } return localctx; }; function QueryPrimaryContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_queryPrimary; // return this; } QueryPrimaryContext.prototype = Object.create(ParserRuleContext.prototype); QueryPrimaryContext.prototype.constructor = QueryPrimaryContext; QueryPrimaryContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function SubqueryContext(parser, ctx) { QueryPrimaryContext.call(this, parser); QueryPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } SubqueryContext.prototype = Object.create(QueryPrimaryContext.prototype); SubqueryContext.prototype.constructor = SubqueryContext; SqlBaseParser.SubqueryContext = SubqueryContext; SubqueryContext.prototype.queryNoWith = function() { return this.getTypedRuleContext(QueryNoWithContext,0); }; SubqueryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSubquery(this); } }; SubqueryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSubquery(this); } }; SubqueryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSubquery(this); } else { return (visitor as any).visitChildren(this); } }; function QueryPrimaryDefaultContext(parser, ctx) { QueryPrimaryContext.call(this, parser); QueryPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } QueryPrimaryDefaultContext.prototype = Object.create(QueryPrimaryContext.prototype); QueryPrimaryDefaultContext.prototype.constructor = QueryPrimaryDefaultContext; SqlBaseParser.QueryPrimaryDefaultContext = QueryPrimaryDefaultContext; QueryPrimaryDefaultContext.prototype.querySpecification = function() { return this.getTypedRuleContext(QuerySpecificationContext,0); }; QueryPrimaryDefaultContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQueryPrimaryDefault(this); } }; QueryPrimaryDefaultContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQueryPrimaryDefault(this); } }; QueryPrimaryDefaultContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQueryPrimaryDefault(this); } else { return (visitor as any).visitChildren(this); } }; function TableContext(parser, ctx) { QueryPrimaryContext.call(this, parser); QueryPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } TableContext.prototype = Object.create(QueryPrimaryContext.prototype); TableContext.prototype.constructor = TableContext; SqlBaseParser.TableContext = TableContext; TableContext.prototype.TABLE = function() { return this.getToken(SqlBaseParser.TABLE, 0); }; TableContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; TableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTable(this); } }; TableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTable(this); } }; TableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTable(this); } else { return (visitor as any).visitChildren(this); } }; function InlineTableContext(parser, ctx) { QueryPrimaryContext.call(this, parser); QueryPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } InlineTableContext.prototype = Object.create(QueryPrimaryContext.prototype); InlineTableContext.prototype.constructor = InlineTableContext; SqlBaseParser.InlineTableContext = InlineTableContext; InlineTableContext.prototype.VALUES = function() { return this.getToken(SqlBaseParser.VALUES, 0); }; InlineTableContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; InlineTableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterInlineTable(this); } }; InlineTableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitInlineTable(this); } }; InlineTableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitInlineTable(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.QueryPrimaryContext = QueryPrimaryContext; SqlBaseParser.prototype.queryPrimary = function() { var localctx = new QueryPrimaryContext(this, this._ctx, this.state); this.enterRule(localctx, 26, SqlBaseParser.RULE_queryPrimary); try { this.state = 595; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.SELECT: localctx = new QueryPrimaryDefaultContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 579; this.querySpecification(); break; case SqlBaseParser.TABLE: localctx = new TableContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 580; this.match(SqlBaseParser.TABLE); this.state = 581; this.qualifiedName(); break; case SqlBaseParser.VALUES: localctx = new InlineTableContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 582; this.match(SqlBaseParser.VALUES); this.state = 583; this.expression(); this.state = 588; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,60,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 584; this.match(SqlBaseParser.T__2); this.state = 585; this.expression(); } this.state = 590; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,60,this._ctx); } break; case SqlBaseParser.T__1: localctx = new SubqueryContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 591; this.match(SqlBaseParser.T__1); this.state = 592; this.queryNoWith(); this.state = 593; this.match(SqlBaseParser.T__3); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SortItemContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_sortItem; this.ordering = null; // Token this.nullOrdering = null; // Token // return this; } SortItemContext.prototype = Object.create(ParserRuleContext.prototype); SortItemContext.prototype.constructor = SortItemContext; SortItemContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SortItemContext.prototype.NULLS = function() { return this.getToken(SqlBaseParser.NULLS, 0); }; SortItemContext.prototype.ASC = function() { return this.getToken(SqlBaseParser.ASC, 0); }; SortItemContext.prototype.DESC = function() { return this.getToken(SqlBaseParser.DESC, 0); }; SortItemContext.prototype.FIRST = function() { return this.getToken(SqlBaseParser.FIRST, 0); }; SortItemContext.prototype.LAST = function() { return this.getToken(SqlBaseParser.LAST, 0); }; SortItemContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSortItem(this); } }; SortItemContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSortItem(this); } }; SortItemContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSortItem(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SortItemContext = SortItemContext; SqlBaseParser.prototype.sortItem = function() { var localctx = new SortItemContext(this, this._ctx, this.state); this.enterRule(localctx, 28, SqlBaseParser.RULE_sortItem); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 597; this.expression(); this.state = 599; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ASC || _la===SqlBaseParser.DESC) { this.state = 598; localctx.ordering = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.ASC || _la===SqlBaseParser.DESC)) { localctx.ordering = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } this.state = 603; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NULLS) { this.state = 601; this.match(SqlBaseParser.NULLS); this.state = 602; localctx.nullOrdering = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.FIRST || _la===SqlBaseParser.LAST)) { localctx.nullOrdering = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function QuerySpecificationContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_querySpecification; this.where = null; // BooleanExpressionContext this.having = null; // BooleanExpressionContext // return this; } QuerySpecificationContext.prototype = Object.create(ParserRuleContext.prototype); QuerySpecificationContext.prototype.constructor = QuerySpecificationContext; QuerySpecificationContext.prototype.SELECT = function() { return this.getToken(SqlBaseParser.SELECT, 0); }; QuerySpecificationContext.prototype.selectItem = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SelectItemContext); } else { return this.getTypedRuleContext(SelectItemContext,i); } }; QuerySpecificationContext.prototype.setQuantifier = function() { return this.getTypedRuleContext(SetQuantifierContext,0); }; QuerySpecificationContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; QuerySpecificationContext.prototype.relation = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(RelationContext); } else { return this.getTypedRuleContext(RelationContext,i); } }; QuerySpecificationContext.prototype.WHERE = function() { return this.getToken(SqlBaseParser.WHERE, 0); }; QuerySpecificationContext.prototype.GROUP = function() { return this.getToken(SqlBaseParser.GROUP, 0); }; QuerySpecificationContext.prototype.BY = function() { return this.getToken(SqlBaseParser.BY, 0); }; QuerySpecificationContext.prototype.groupBy = function() { return this.getTypedRuleContext(GroupByContext,0); }; QuerySpecificationContext.prototype.HAVING = function() { return this.getToken(SqlBaseParser.HAVING, 0); }; QuerySpecificationContext.prototype.booleanExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(BooleanExpressionContext); } else { return this.getTypedRuleContext(BooleanExpressionContext,i); } }; QuerySpecificationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQuerySpecification(this); } }; QuerySpecificationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQuerySpecification(this); } }; QuerySpecificationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQuerySpecification(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.QuerySpecificationContext = QuerySpecificationContext; SqlBaseParser.prototype.querySpecification = function() { var localctx = new QuerySpecificationContext(this, this._ctx, this.state); this.enterRule(localctx, 30, SqlBaseParser.RULE_querySpecification); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 605; this.match(SqlBaseParser.SELECT); this.state = 607; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) { this.state = 606; this.setQuantifier(); } this.state = 609; this.selectItem(); this.state = 614; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,65,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 610; this.match(SqlBaseParser.T__2); this.state = 611; this.selectItem(); } this.state = 616; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,65,this._ctx); } this.state = 626; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,67,this._ctx); if(la_===1) { this.state = 617; this.match(SqlBaseParser.FROM); this.state = 618; this.relation(0); this.state = 623; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,66,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 619; this.match(SqlBaseParser.T__2); this.state = 620; this.relation(0); } this.state = 625; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,66,this._ctx); } } this.state = 630; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,68,this._ctx); if(la_===1) { this.state = 628; this.match(SqlBaseParser.WHERE); this.state = 629; localctx.where = this.booleanExpression(0); } this.state = 635; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,69,this._ctx); if(la_===1) { this.state = 632; this.match(SqlBaseParser.GROUP); this.state = 633; this.match(SqlBaseParser.BY); this.state = 634; this.groupBy(); } this.state = 639; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,70,this._ctx); if(la_===1) { this.state = 637; this.match(SqlBaseParser.HAVING); this.state = 638; localctx.having = this.booleanExpression(0); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function GroupByContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_groupBy; // return this; } GroupByContext.prototype = Object.create(ParserRuleContext.prototype); GroupByContext.prototype.constructor = GroupByContext; GroupByContext.prototype.groupingElement = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(GroupingElementContext); } else { return this.getTypedRuleContext(GroupingElementContext,i); } }; GroupByContext.prototype.setQuantifier = function() { return this.getTypedRuleContext(SetQuantifierContext,0); }; GroupByContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterGroupBy(this); } }; GroupByContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitGroupBy(this); } }; GroupByContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitGroupBy(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.GroupByContext = GroupByContext; SqlBaseParser.prototype.groupBy = function() { var localctx = new GroupByContext(this, this._ctx, this.state); this.enterRule(localctx, 32, SqlBaseParser.RULE_groupBy); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 642; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) { this.state = 641; this.setQuantifier(); } this.state = 644; this.groupingElement(); this.state = 649; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,72,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 645; this.match(SqlBaseParser.T__2); this.state = 646; this.groupingElement(); } this.state = 651; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,72,this._ctx); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function GroupingElementContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_groupingElement; // return this; } GroupingElementContext.prototype = Object.create(ParserRuleContext.prototype); GroupingElementContext.prototype.constructor = GroupingElementContext; GroupingElementContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function MultipleGroupingSetsContext(parser, ctx) { GroupingElementContext.call(this, parser); GroupingElementContext.prototype.copyFrom.call(this, ctx); // return this; } MultipleGroupingSetsContext.prototype = Object.create(GroupingElementContext.prototype); MultipleGroupingSetsContext.prototype.constructor = MultipleGroupingSetsContext; SqlBaseParser.MultipleGroupingSetsContext = MultipleGroupingSetsContext; MultipleGroupingSetsContext.prototype.GROUPING = function() { return this.getToken(SqlBaseParser.GROUPING, 0); }; MultipleGroupingSetsContext.prototype.SETS = function() { return this.getToken(SqlBaseParser.SETS, 0); }; MultipleGroupingSetsContext.prototype.groupingSet = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(GroupingSetContext); } else { return this.getTypedRuleContext(GroupingSetContext,i); } }; MultipleGroupingSetsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterMultipleGroupingSets(this); } }; MultipleGroupingSetsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitMultipleGroupingSets(this); } }; MultipleGroupingSetsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitMultipleGroupingSets(this); } else { return (visitor as any).visitChildren(this); } }; function SingleGroupingSetContext(parser, ctx) { GroupingElementContext.call(this, parser); GroupingElementContext.prototype.copyFrom.call(this, ctx); // return this; } SingleGroupingSetContext.prototype = Object.create(GroupingElementContext.prototype); SingleGroupingSetContext.prototype.constructor = SingleGroupingSetContext; SqlBaseParser.SingleGroupingSetContext = SingleGroupingSetContext; SingleGroupingSetContext.prototype.groupingExpressions = function() { return this.getTypedRuleContext(GroupingExpressionsContext,0); }; SingleGroupingSetContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSingleGroupingSet(this); } }; SingleGroupingSetContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSingleGroupingSet(this); } }; SingleGroupingSetContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSingleGroupingSet(this); } else { return (visitor as any).visitChildren(this); } }; function CubeContext(parser, ctx) { GroupingElementContext.call(this, parser); GroupingElementContext.prototype.copyFrom.call(this, ctx); // return this; } CubeContext.prototype = Object.create(GroupingElementContext.prototype); CubeContext.prototype.constructor = CubeContext; SqlBaseParser.CubeContext = CubeContext; CubeContext.prototype.CUBE = function() { return this.getToken(SqlBaseParser.CUBE, 0); }; CubeContext.prototype.qualifiedName = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(QualifiedNameContext); } else { return this.getTypedRuleContext(QualifiedNameContext,i); } }; CubeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCube(this); } }; CubeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCube(this); } }; CubeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCube(this); } else { return (visitor as any).visitChildren(this); } }; function RollupContext(parser, ctx) { GroupingElementContext.call(this, parser); GroupingElementContext.prototype.copyFrom.call(this, ctx); // return this; } RollupContext.prototype = Object.create(GroupingElementContext.prototype); RollupContext.prototype.constructor = RollupContext; SqlBaseParser.RollupContext = RollupContext; RollupContext.prototype.ROLLUP = function() { return this.getToken(SqlBaseParser.ROLLUP, 0); }; RollupContext.prototype.qualifiedName = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(QualifiedNameContext); } else { return this.getTypedRuleContext(QualifiedNameContext,i); } }; RollupContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRollup(this); } }; RollupContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRollup(this); } }; RollupContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRollup(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.GroupingElementContext = GroupingElementContext; SqlBaseParser.prototype.groupingElement = function() { var localctx = new GroupingElementContext(this, this._ctx, this.state); this.enterRule(localctx, 34, SqlBaseParser.RULE_groupingElement); var _la = 0; // Token type try { this.state = 692; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.T__1: case SqlBaseParser.T__4: case SqlBaseParser.ADD: case SqlBaseParser.NOT: case SqlBaseParser.NO: case SqlBaseParser.EXISTS: case SqlBaseParser.NULL: case SqlBaseParser.TRUE: case SqlBaseParser.FALSE: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.CURRENT_DATE: case SqlBaseParser.CURRENT_TIME: case SqlBaseParser.CURRENT_TIMESTAMP: case SqlBaseParser.LOCALTIME: case SqlBaseParser.LOCALTIMESTAMP: case SqlBaseParser.EXTRACT: case SqlBaseParser.CASE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.CAST: case SqlBaseParser.TRY_CAST: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NORMALIZE: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.PLUS: case SqlBaseParser.MINUS: case SqlBaseParser.STRING: case SqlBaseParser.BINARY_LITERAL: case SqlBaseParser.INTEGER_VALUE: case SqlBaseParser.DECIMAL_VALUE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: case SqlBaseParser.DOUBLE_PRECISION: localctx = new SingleGroupingSetContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 652; this.groupingExpressions(); break; case SqlBaseParser.ROLLUP: localctx = new RollupContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 653; this.match(SqlBaseParser.ROLLUP); this.state = 654; this.match(SqlBaseParser.T__1); this.state = 663; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ADD || ((((_la - 33)) & ~0x1f) == 0 && ((1 << (_la - 33)) & ((1 << (SqlBaseParser.NO - 33)) | (1 << (SqlBaseParser.SUBSTRING - 33)) | (1 << (SqlBaseParser.POSITION - 33)) | (1 << (SqlBaseParser.TINYINT - 33)) | (1 << (SqlBaseParser.SMALLINT - 33)) | (1 << (SqlBaseParser.INTEGER - 33)) | (1 << (SqlBaseParser.DATE - 33)) | (1 << (SqlBaseParser.TIME - 33)) | (1 << (SqlBaseParser.TIMESTAMP - 33)) | (1 << (SqlBaseParser.INTERVAL - 33)) | (1 << (SqlBaseParser.YEAR - 33)) | (1 << (SqlBaseParser.MONTH - 33)) | (1 << (SqlBaseParser.DAY - 33)) | (1 << (SqlBaseParser.HOUR - 33)) | (1 << (SqlBaseParser.MINUTE - 33)) | (1 << (SqlBaseParser.SECOND - 33)) | (1 << (SqlBaseParser.ZONE - 33)))) !== 0) || ((((_la - 85)) & ~0x1f) == 0 && ((1 << (_la - 85)) & ((1 << (SqlBaseParser.FILTER - 85)) | (1 << (SqlBaseParser.OVER - 85)) | (1 << (SqlBaseParser.PARTITION - 85)) | (1 << (SqlBaseParser.RANGE - 85)) | (1 << (SqlBaseParser.ROWS - 85)) | (1 << (SqlBaseParser.PRECEDING - 85)) | (1 << (SqlBaseParser.FOLLOWING - 85)) | (1 << (SqlBaseParser.CURRENT - 85)) | (1 << (SqlBaseParser.ROW - 85)) | (1 << (SqlBaseParser.SCHEMA - 85)) | (1 << (SqlBaseParser.VIEW - 85)) | (1 << (SqlBaseParser.REPLACE - 85)) | (1 << (SqlBaseParser.GRANT - 85)) | (1 << (SqlBaseParser.REVOKE - 85)) | (1 << (SqlBaseParser.PRIVILEGES - 85)) | (1 << (SqlBaseParser.PUBLIC - 85)) | (1 << (SqlBaseParser.OPTION - 85)) | (1 << (SqlBaseParser.EXPLAIN - 85)) | (1 << (SqlBaseParser.ANALYZE - 85)) | (1 << (SqlBaseParser.FORMAT - 85)) | (1 << (SqlBaseParser.TYPE - 85)))) !== 0) || ((((_la - 117)) & ~0x1f) == 0 && ((1 << (_la - 117)) & ((1 << (SqlBaseParser.TEXT - 117)) | (1 << (SqlBaseParser.GRAPHVIZ - 117)) | (1 << (SqlBaseParser.LOGICAL - 117)) | (1 << (SqlBaseParser.DISTRIBUTED - 117)) | (1 << (SqlBaseParser.SHOW - 117)) | (1 << (SqlBaseParser.TABLES - 117)) | (1 << (SqlBaseParser.SCHEMAS - 117)) | (1 << (SqlBaseParser.CATALOGS - 117)) | (1 << (SqlBaseParser.COLUMNS - 117)) | (1 << (SqlBaseParser.COLUMN - 117)) | (1 << (SqlBaseParser.USE - 117)) | (1 << (SqlBaseParser.PARTITIONS - 117)) | (1 << (SqlBaseParser.FUNCTIONS - 117)) | (1 << (SqlBaseParser.TO - 117)) | (1 << (SqlBaseParser.SYSTEM - 117)) | (1 << (SqlBaseParser.BERNOULLI - 117)) | (1 << (SqlBaseParser.POISSONIZED - 117)) | (1 << (SqlBaseParser.TABLESAMPLE - 117)) | (1 << (SqlBaseParser.ARRAY - 117)) | (1 << (SqlBaseParser.MAP - 117)) | (1 << (SqlBaseParser.SET - 117)) | (1 << (SqlBaseParser.RESET - 117)))) !== 0) || ((((_la - 149)) & ~0x1f) == 0 && ((1 << (_la - 149)) & ((1 << (SqlBaseParser.SESSION - 149)) | (1 << (SqlBaseParser.DATA - 149)) | (1 << (SqlBaseParser.START - 149)) | (1 << (SqlBaseParser.TRANSACTION - 149)) | (1 << (SqlBaseParser.COMMIT - 149)) | (1 << (SqlBaseParser.ROLLBACK - 149)) | (1 << (SqlBaseParser.WORK - 149)) | (1 << (SqlBaseParser.ISOLATION - 149)) | (1 << (SqlBaseParser.LEVEL - 149)) | (1 << (SqlBaseParser.SERIALIZABLE - 149)) | (1 << (SqlBaseParser.REPEATABLE - 149)) | (1 << (SqlBaseParser.COMMITTED - 149)) | (1 << (SqlBaseParser.UNCOMMITTED - 149)) | (1 << (SqlBaseParser.READ - 149)) | (1 << (SqlBaseParser.WRITE - 149)) | (1 << (SqlBaseParser.ONLY - 149)) | (1 << (SqlBaseParser.CALL - 149)) | (1 << (SqlBaseParser.INPUT - 149)) | (1 << (SqlBaseParser.OUTPUT - 149)) | (1 << (SqlBaseParser.CASCADE - 149)) | (1 << (SqlBaseParser.RESTRICT - 149)) | (1 << (SqlBaseParser.INCLUDING - 149)) | (1 << (SqlBaseParser.EXCLUDING - 149)) | (1 << (SqlBaseParser.PROPERTIES - 149)) | (1 << (SqlBaseParser.NFD - 149)) | (1 << (SqlBaseParser.NFC - 149)) | (1 << (SqlBaseParser.NFKD - 149)) | (1 << (SqlBaseParser.NFKC - 149)))) !== 0) || ((((_la - 181)) & ~0x1f) == 0 && ((1 << (_la - 181)) & ((1 << (SqlBaseParser.IF - 181)) | (1 << (SqlBaseParser.NULLIF - 181)) | (1 << (SqlBaseParser.COALESCE - 181)) | (1 << (SqlBaseParser.IDENTIFIER - 181)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 181)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 181)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 181)))) !== 0)) { this.state = 655; this.qualifiedName(); this.state = 660; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 656; this.match(SqlBaseParser.T__2); this.state = 657; this.qualifiedName(); this.state = 662; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 665; this.match(SqlBaseParser.T__3); break; case SqlBaseParser.CUBE: localctx = new CubeContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 666; this.match(SqlBaseParser.CUBE); this.state = 667; this.match(SqlBaseParser.T__1); this.state = 676; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ADD || ((((_la - 33)) & ~0x1f) == 0 && ((1 << (_la - 33)) & ((1 << (SqlBaseParser.NO - 33)) | (1 << (SqlBaseParser.SUBSTRING - 33)) | (1 << (SqlBaseParser.POSITION - 33)) | (1 << (SqlBaseParser.TINYINT - 33)) | (1 << (SqlBaseParser.SMALLINT - 33)) | (1 << (SqlBaseParser.INTEGER - 33)) | (1 << (SqlBaseParser.DATE - 33)) | (1 << (SqlBaseParser.TIME - 33)) | (1 << (SqlBaseParser.TIMESTAMP - 33)) | (1 << (SqlBaseParser.INTERVAL - 33)) | (1 << (SqlBaseParser.YEAR - 33)) | (1 << (SqlBaseParser.MONTH - 33)) | (1 << (SqlBaseParser.DAY - 33)) | (1 << (SqlBaseParser.HOUR - 33)) | (1 << (SqlBaseParser.MINUTE - 33)) | (1 << (SqlBaseParser.SECOND - 33)) | (1 << (SqlBaseParser.ZONE - 33)))) !== 0) || ((((_la - 85)) & ~0x1f) == 0 && ((1 << (_la - 85)) & ((1 << (SqlBaseParser.FILTER - 85)) | (1 << (SqlBaseParser.OVER - 85)) | (1 << (SqlBaseParser.PARTITION - 85)) | (1 << (SqlBaseParser.RANGE - 85)) | (1 << (SqlBaseParser.ROWS - 85)) | (1 << (SqlBaseParser.PRECEDING - 85)) | (1 << (SqlBaseParser.FOLLOWING - 85)) | (1 << (SqlBaseParser.CURRENT - 85)) | (1 << (SqlBaseParser.ROW - 85)) | (1 << (SqlBaseParser.SCHEMA - 85)) | (1 << (SqlBaseParser.VIEW - 85)) | (1 << (SqlBaseParser.REPLACE - 85)) | (1 << (SqlBaseParser.GRANT - 85)) | (1 << (SqlBaseParser.REVOKE - 85)) | (1 << (SqlBaseParser.PRIVILEGES - 85)) | (1 << (SqlBaseParser.PUBLIC - 85)) | (1 << (SqlBaseParser.OPTION - 85)) | (1 << (SqlBaseParser.EXPLAIN - 85)) | (1 << (SqlBaseParser.ANALYZE - 85)) | (1 << (SqlBaseParser.FORMAT - 85)) | (1 << (SqlBaseParser.TYPE - 85)))) !== 0) || ((((_la - 117)) & ~0x1f) == 0 && ((1 << (_la - 117)) & ((1 << (SqlBaseParser.TEXT - 117)) | (1 << (SqlBaseParser.GRAPHVIZ - 117)) | (1 << (SqlBaseParser.LOGICAL - 117)) | (1 << (SqlBaseParser.DISTRIBUTED - 117)) | (1 << (SqlBaseParser.SHOW - 117)) | (1 << (SqlBaseParser.TABLES - 117)) | (1 << (SqlBaseParser.SCHEMAS - 117)) | (1 << (SqlBaseParser.CATALOGS - 117)) | (1 << (SqlBaseParser.COLUMNS - 117)) | (1 << (SqlBaseParser.COLUMN - 117)) | (1 << (SqlBaseParser.USE - 117)) | (1 << (SqlBaseParser.PARTITIONS - 117)) | (1 << (SqlBaseParser.FUNCTIONS - 117)) | (1 << (SqlBaseParser.TO - 117)) | (1 << (SqlBaseParser.SYSTEM - 117)) | (1 << (SqlBaseParser.BERNOULLI - 117)) | (1 << (SqlBaseParser.POISSONIZED - 117)) | (1 << (SqlBaseParser.TABLESAMPLE - 117)) | (1 << (SqlBaseParser.ARRAY - 117)) | (1 << (SqlBaseParser.MAP - 117)) | (1 << (SqlBaseParser.SET - 117)) | (1 << (SqlBaseParser.RESET - 117)))) !== 0) || ((((_la - 149)) & ~0x1f) == 0 && ((1 << (_la - 149)) & ((1 << (SqlBaseParser.SESSION - 149)) | (1 << (SqlBaseParser.DATA - 149)) | (1 << (SqlBaseParser.START - 149)) | (1 << (SqlBaseParser.TRANSACTION - 149)) | (1 << (SqlBaseParser.COMMIT - 149)) | (1 << (SqlBaseParser.ROLLBACK - 149)) | (1 << (SqlBaseParser.WORK - 149)) | (1 << (SqlBaseParser.ISOLATION - 149)) | (1 << (SqlBaseParser.LEVEL - 149)) | (1 << (SqlBaseParser.SERIALIZABLE - 149)) | (1 << (SqlBaseParser.REPEATABLE - 149)) | (1 << (SqlBaseParser.COMMITTED - 149)) | (1 << (SqlBaseParser.UNCOMMITTED - 149)) | (1 << (SqlBaseParser.READ - 149)) | (1 << (SqlBaseParser.WRITE - 149)) | (1 << (SqlBaseParser.ONLY - 149)) | (1 << (SqlBaseParser.CALL - 149)) | (1 << (SqlBaseParser.INPUT - 149)) | (1 << (SqlBaseParser.OUTPUT - 149)) | (1 << (SqlBaseParser.CASCADE - 149)) | (1 << (SqlBaseParser.RESTRICT - 149)) | (1 << (SqlBaseParser.INCLUDING - 149)) | (1 << (SqlBaseParser.EXCLUDING - 149)) | (1 << (SqlBaseParser.PROPERTIES - 149)) | (1 << (SqlBaseParser.NFD - 149)) | (1 << (SqlBaseParser.NFC - 149)) | (1 << (SqlBaseParser.NFKD - 149)) | (1 << (SqlBaseParser.NFKC - 149)))) !== 0) || ((((_la - 181)) & ~0x1f) == 0 && ((1 << (_la - 181)) & ((1 << (SqlBaseParser.IF - 181)) | (1 << (SqlBaseParser.NULLIF - 181)) | (1 << (SqlBaseParser.COALESCE - 181)) | (1 << (SqlBaseParser.IDENTIFIER - 181)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 181)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 181)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 181)))) !== 0)) { this.state = 668; this.qualifiedName(); this.state = 673; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 669; this.match(SqlBaseParser.T__2); this.state = 670; this.qualifiedName(); this.state = 675; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 678; this.match(SqlBaseParser.T__3); break; case SqlBaseParser.GROUPING: localctx = new MultipleGroupingSetsContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 679; this.match(SqlBaseParser.GROUPING); this.state = 680; this.match(SqlBaseParser.SETS); this.state = 681; this.match(SqlBaseParser.T__1); this.state = 682; this.groupingSet(); this.state = 687; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 683; this.match(SqlBaseParser.T__2); this.state = 684; this.groupingSet(); this.state = 689; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 690; this.match(SqlBaseParser.T__3); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function GroupingExpressionsContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_groupingExpressions; // return this; } GroupingExpressionsContext.prototype = Object.create(ParserRuleContext.prototype); GroupingExpressionsContext.prototype.constructor = GroupingExpressionsContext; GroupingExpressionsContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; GroupingExpressionsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterGroupingExpressions(this); } }; GroupingExpressionsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitGroupingExpressions(this); } }; GroupingExpressionsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitGroupingExpressions(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.GroupingExpressionsContext = GroupingExpressionsContext; SqlBaseParser.prototype.groupingExpressions = function() { var localctx = new GroupingExpressionsContext(this, this._ctx, this.state); this.enterRule(localctx, 36, SqlBaseParser.RULE_groupingExpressions); var _la = 0; // Token type try { this.state = 707; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,81,this._ctx); switch(la_) { case 1: this.enterOuterAlt(localctx, 1); this.state = 694; this.match(SqlBaseParser.T__1); this.state = 703; this._errHandler.sync(this); _la = this._input.LA(1); if((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << SqlBaseParser.T__1) | (1 << SqlBaseParser.T__4) | (1 << SqlBaseParser.ADD))) !== 0) || ((((_la - 32)) & ~0x1f) == 0 && ((1 << (_la - 32)) & ((1 << (SqlBaseParser.NOT - 32)) | (1 << (SqlBaseParser.NO - 32)) | (1 << (SqlBaseParser.EXISTS - 32)) | (1 << (SqlBaseParser.NULL - 32)) | (1 << (SqlBaseParser.TRUE - 32)) | (1 << (SqlBaseParser.FALSE - 32)) | (1 << (SqlBaseParser.SUBSTRING - 32)) | (1 << (SqlBaseParser.POSITION - 32)) | (1 << (SqlBaseParser.TINYINT - 32)) | (1 << (SqlBaseParser.SMALLINT - 32)) | (1 << (SqlBaseParser.INTEGER - 32)) | (1 << (SqlBaseParser.DATE - 32)) | (1 << (SqlBaseParser.TIME - 32)) | (1 << (SqlBaseParser.TIMESTAMP - 32)) | (1 << (SqlBaseParser.INTERVAL - 32)) | (1 << (SqlBaseParser.YEAR - 32)) | (1 << (SqlBaseParser.MONTH - 32)) | (1 << (SqlBaseParser.DAY - 32)) | (1 << (SqlBaseParser.HOUR - 32)) | (1 << (SqlBaseParser.MINUTE - 32)) | (1 << (SqlBaseParser.SECOND - 32)) | (1 << (SqlBaseParser.ZONE - 32)))) !== 0) || ((((_la - 64)) & ~0x1f) == 0 && ((1 << (_la - 64)) & ((1 << (SqlBaseParser.CURRENT_DATE - 64)) | (1 << (SqlBaseParser.CURRENT_TIME - 64)) | (1 << (SqlBaseParser.CURRENT_TIMESTAMP - 64)) | (1 << (SqlBaseParser.LOCALTIME - 64)) | (1 << (SqlBaseParser.LOCALTIMESTAMP - 64)) | (1 << (SqlBaseParser.EXTRACT - 64)) | (1 << (SqlBaseParser.CASE - 64)) | (1 << (SqlBaseParser.FILTER - 64)) | (1 << (SqlBaseParser.OVER - 64)) | (1 << (SqlBaseParser.PARTITION - 64)) | (1 << (SqlBaseParser.RANGE - 64)) | (1 << (SqlBaseParser.ROWS - 64)) | (1 << (SqlBaseParser.PRECEDING - 64)) | (1 << (SqlBaseParser.FOLLOWING - 64)) | (1 << (SqlBaseParser.CURRENT - 64)) | (1 << (SqlBaseParser.ROW - 64)))) !== 0) || ((((_la - 99)) & ~0x1f) == 0 && ((1 << (_la - 99)) & ((1 << (SqlBaseParser.SCHEMA - 99)) | (1 << (SqlBaseParser.VIEW - 99)) | (1 << (SqlBaseParser.REPLACE - 99)) | (1 << (SqlBaseParser.GRANT - 99)) | (1 << (SqlBaseParser.REVOKE - 99)) | (1 << (SqlBaseParser.PRIVILEGES - 99)) | (1 << (SqlBaseParser.PUBLIC - 99)) | (1 << (SqlBaseParser.OPTION - 99)) | (1 << (SqlBaseParser.EXPLAIN - 99)) | (1 << (SqlBaseParser.ANALYZE - 99)) | (1 << (SqlBaseParser.FORMAT - 99)) | (1 << (SqlBaseParser.TYPE - 99)) | (1 << (SqlBaseParser.TEXT - 99)) | (1 << (SqlBaseParser.GRAPHVIZ - 99)) | (1 << (SqlBaseParser.LOGICAL - 99)) | (1 << (SqlBaseParser.DISTRIBUTED - 99)) | (1 << (SqlBaseParser.CAST - 99)) | (1 << (SqlBaseParser.TRY_CAST - 99)) | (1 << (SqlBaseParser.SHOW - 99)) | (1 << (SqlBaseParser.TABLES - 99)) | (1 << (SqlBaseParser.SCHEMAS - 99)) | (1 << (SqlBaseParser.CATALOGS - 99)) | (1 << (SqlBaseParser.COLUMNS - 99)) | (1 << (SqlBaseParser.COLUMN - 99)) | (1 << (SqlBaseParser.USE - 99)) | (1 << (SqlBaseParser.PARTITIONS - 99)))) !== 0) || ((((_la - 131)) & ~0x1f) == 0 && ((1 << (_la - 131)) & ((1 << (SqlBaseParser.FUNCTIONS - 131)) | (1 << (SqlBaseParser.TO - 131)) | (1 << (SqlBaseParser.SYSTEM - 131)) | (1 << (SqlBaseParser.BERNOULLI - 131)) | (1 << (SqlBaseParser.POISSONIZED - 131)) | (1 << (SqlBaseParser.TABLESAMPLE - 131)) | (1 << (SqlBaseParser.ARRAY - 131)) | (1 << (SqlBaseParser.MAP - 131)) | (1 << (SqlBaseParser.SET - 131)) | (1 << (SqlBaseParser.RESET - 131)) | (1 << (SqlBaseParser.SESSION - 131)) | (1 << (SqlBaseParser.DATA - 131)) | (1 << (SqlBaseParser.START - 131)) | (1 << (SqlBaseParser.TRANSACTION - 131)) | (1 << (SqlBaseParser.COMMIT - 131)) | (1 << (SqlBaseParser.ROLLBACK - 131)) | (1 << (SqlBaseParser.WORK - 131)) | (1 << (SqlBaseParser.ISOLATION - 131)) | (1 << (SqlBaseParser.LEVEL - 131)) | (1 << (SqlBaseParser.SERIALIZABLE - 131)) | (1 << (SqlBaseParser.REPEATABLE - 131)) | (1 << (SqlBaseParser.COMMITTED - 131)) | (1 << (SqlBaseParser.UNCOMMITTED - 131)) | (1 << (SqlBaseParser.READ - 131)))) !== 0) || ((((_la - 163)) & ~0x1f) == 0 && ((1 << (_la - 163)) & ((1 << (SqlBaseParser.WRITE - 163)) | (1 << (SqlBaseParser.ONLY - 163)) | (1 << (SqlBaseParser.CALL - 163)) | (1 << (SqlBaseParser.INPUT - 163)) | (1 << (SqlBaseParser.OUTPUT - 163)) | (1 << (SqlBaseParser.CASCADE - 163)) | (1 << (SqlBaseParser.RESTRICT - 163)) | (1 << (SqlBaseParser.INCLUDING - 163)) | (1 << (SqlBaseParser.EXCLUDING - 163)) | (1 << (SqlBaseParser.PROPERTIES - 163)) | (1 << (SqlBaseParser.NORMALIZE - 163)) | (1 << (SqlBaseParser.NFD - 163)) | (1 << (SqlBaseParser.NFC - 163)) | (1 << (SqlBaseParser.NFKD - 163)) | (1 << (SqlBaseParser.NFKC - 163)) | (1 << (SqlBaseParser.IF - 163)) | (1 << (SqlBaseParser.NULLIF - 163)) | (1 << (SqlBaseParser.COALESCE - 163)) | (1 << (SqlBaseParser.PLUS - 163)) | (1 << (SqlBaseParser.MINUS - 163)))) !== 0) || ((((_la - 196)) & ~0x1f) == 0 && ((1 << (_la - 196)) & ((1 << (SqlBaseParser.STRING - 196)) | (1 << (SqlBaseParser.BINARY_LITERAL - 196)) | (1 << (SqlBaseParser.INTEGER_VALUE - 196)) | (1 << (SqlBaseParser.DECIMAL_VALUE - 196)) | (1 << (SqlBaseParser.IDENTIFIER - 196)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 196)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.DOUBLE_PRECISION - 196)))) !== 0)) { this.state = 695; this.expression(); this.state = 700; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 696; this.match(SqlBaseParser.T__2); this.state = 697; this.expression(); this.state = 702; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 705; this.match(SqlBaseParser.T__3); break; case 2: this.enterOuterAlt(localctx, 2); this.state = 706; this.expression(); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function GroupingSetContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_groupingSet; // return this; } GroupingSetContext.prototype = Object.create(ParserRuleContext.prototype); GroupingSetContext.prototype.constructor = GroupingSetContext; GroupingSetContext.prototype.qualifiedName = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(QualifiedNameContext); } else { return this.getTypedRuleContext(QualifiedNameContext,i); } }; GroupingSetContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterGroupingSet(this); } }; GroupingSetContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitGroupingSet(this); } }; GroupingSetContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitGroupingSet(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.GroupingSetContext = GroupingSetContext; SqlBaseParser.prototype.groupingSet = function() { var localctx = new GroupingSetContext(this, this._ctx, this.state); this.enterRule(localctx, 38, SqlBaseParser.RULE_groupingSet); var _la = 0; // Token type try { this.state = 722; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.T__1: this.enterOuterAlt(localctx, 1); this.state = 709; this.match(SqlBaseParser.T__1); this.state = 718; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ADD || ((((_la - 33)) & ~0x1f) == 0 && ((1 << (_la - 33)) & ((1 << (SqlBaseParser.NO - 33)) | (1 << (SqlBaseParser.SUBSTRING - 33)) | (1 << (SqlBaseParser.POSITION - 33)) | (1 << (SqlBaseParser.TINYINT - 33)) | (1 << (SqlBaseParser.SMALLINT - 33)) | (1 << (SqlBaseParser.INTEGER - 33)) | (1 << (SqlBaseParser.DATE - 33)) | (1 << (SqlBaseParser.TIME - 33)) | (1 << (SqlBaseParser.TIMESTAMP - 33)) | (1 << (SqlBaseParser.INTERVAL - 33)) | (1 << (SqlBaseParser.YEAR - 33)) | (1 << (SqlBaseParser.MONTH - 33)) | (1 << (SqlBaseParser.DAY - 33)) | (1 << (SqlBaseParser.HOUR - 33)) | (1 << (SqlBaseParser.MINUTE - 33)) | (1 << (SqlBaseParser.SECOND - 33)) | (1 << (SqlBaseParser.ZONE - 33)))) !== 0) || ((((_la - 85)) & ~0x1f) == 0 && ((1 << (_la - 85)) & ((1 << (SqlBaseParser.FILTER - 85)) | (1 << (SqlBaseParser.OVER - 85)) | (1 << (SqlBaseParser.PARTITION - 85)) | (1 << (SqlBaseParser.RANGE - 85)) | (1 << (SqlBaseParser.ROWS - 85)) | (1 << (SqlBaseParser.PRECEDING - 85)) | (1 << (SqlBaseParser.FOLLOWING - 85)) | (1 << (SqlBaseParser.CURRENT - 85)) | (1 << (SqlBaseParser.ROW - 85)) | (1 << (SqlBaseParser.SCHEMA - 85)) | (1 << (SqlBaseParser.VIEW - 85)) | (1 << (SqlBaseParser.REPLACE - 85)) | (1 << (SqlBaseParser.GRANT - 85)) | (1 << (SqlBaseParser.REVOKE - 85)) | (1 << (SqlBaseParser.PRIVILEGES - 85)) | (1 << (SqlBaseParser.PUBLIC - 85)) | (1 << (SqlBaseParser.OPTION - 85)) | (1 << (SqlBaseParser.EXPLAIN - 85)) | (1 << (SqlBaseParser.ANALYZE - 85)) | (1 << (SqlBaseParser.FORMAT - 85)) | (1 << (SqlBaseParser.TYPE - 85)))) !== 0) || ((((_la - 117)) & ~0x1f) == 0 && ((1 << (_la - 117)) & ((1 << (SqlBaseParser.TEXT - 117)) | (1 << (SqlBaseParser.GRAPHVIZ - 117)) | (1 << (SqlBaseParser.LOGICAL - 117)) | (1 << (SqlBaseParser.DISTRIBUTED - 117)) | (1 << (SqlBaseParser.SHOW - 117)) | (1 << (SqlBaseParser.TABLES - 117)) | (1 << (SqlBaseParser.SCHEMAS - 117)) | (1 << (SqlBaseParser.CATALOGS - 117)) | (1 << (SqlBaseParser.COLUMNS - 117)) | (1 << (SqlBaseParser.COLUMN - 117)) | (1 << (SqlBaseParser.USE - 117)) | (1 << (SqlBaseParser.PARTITIONS - 117)) | (1 << (SqlBaseParser.FUNCTIONS - 117)) | (1 << (SqlBaseParser.TO - 117)) | (1 << (SqlBaseParser.SYSTEM - 117)) | (1 << (SqlBaseParser.BERNOULLI - 117)) | (1 << (SqlBaseParser.POISSONIZED - 117)) | (1 << (SqlBaseParser.TABLESAMPLE - 117)) | (1 << (SqlBaseParser.ARRAY - 117)) | (1 << (SqlBaseParser.MAP - 117)) | (1 << (SqlBaseParser.SET - 117)) | (1 << (SqlBaseParser.RESET - 117)))) !== 0) || ((((_la - 149)) & ~0x1f) == 0 && ((1 << (_la - 149)) & ((1 << (SqlBaseParser.SESSION - 149)) | (1 << (SqlBaseParser.DATA - 149)) | (1 << (SqlBaseParser.START - 149)) | (1 << (SqlBaseParser.TRANSACTION - 149)) | (1 << (SqlBaseParser.COMMIT - 149)) | (1 << (SqlBaseParser.ROLLBACK - 149)) | (1 << (SqlBaseParser.WORK - 149)) | (1 << (SqlBaseParser.ISOLATION - 149)) | (1 << (SqlBaseParser.LEVEL - 149)) | (1 << (SqlBaseParser.SERIALIZABLE - 149)) | (1 << (SqlBaseParser.REPEATABLE - 149)) | (1 << (SqlBaseParser.COMMITTED - 149)) | (1 << (SqlBaseParser.UNCOMMITTED - 149)) | (1 << (SqlBaseParser.READ - 149)) | (1 << (SqlBaseParser.WRITE - 149)) | (1 << (SqlBaseParser.ONLY - 149)) | (1 << (SqlBaseParser.CALL - 149)) | (1 << (SqlBaseParser.INPUT - 149)) | (1 << (SqlBaseParser.OUTPUT - 149)) | (1 << (SqlBaseParser.CASCADE - 149)) | (1 << (SqlBaseParser.RESTRICT - 149)) | (1 << (SqlBaseParser.INCLUDING - 149)) | (1 << (SqlBaseParser.EXCLUDING - 149)) | (1 << (SqlBaseParser.PROPERTIES - 149)) | (1 << (SqlBaseParser.NFD - 149)) | (1 << (SqlBaseParser.NFC - 149)) | (1 << (SqlBaseParser.NFKD - 149)) | (1 << (SqlBaseParser.NFKC - 149)))) !== 0) || ((((_la - 181)) & ~0x1f) == 0 && ((1 << (_la - 181)) & ((1 << (SqlBaseParser.IF - 181)) | (1 << (SqlBaseParser.NULLIF - 181)) | (1 << (SqlBaseParser.COALESCE - 181)) | (1 << (SqlBaseParser.IDENTIFIER - 181)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 181)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 181)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 181)))) !== 0)) { this.state = 710; this.qualifiedName(); this.state = 715; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 711; this.match(SqlBaseParser.T__2); this.state = 712; this.qualifiedName(); this.state = 717; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 720; this.match(SqlBaseParser.T__3); break; case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: this.enterOuterAlt(localctx, 2); this.state = 721; this.qualifiedName(); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function NamedQueryContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_namedQuery; this.name = null; // IdentifierContext // return this; } NamedQueryContext.prototype = Object.create(ParserRuleContext.prototype); NamedQueryContext.prototype.constructor = NamedQueryContext; NamedQueryContext.prototype.AS = function() { return this.getToken(SqlBaseParser.AS, 0); }; NamedQueryContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; NamedQueryContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; NamedQueryContext.prototype.columnAliases = function() { return this.getTypedRuleContext(ColumnAliasesContext,0); }; NamedQueryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNamedQuery(this); } }; NamedQueryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNamedQuery(this); } }; NamedQueryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNamedQuery(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.NamedQueryContext = NamedQueryContext; SqlBaseParser.prototype.namedQuery = function() { var localctx = new NamedQueryContext(this, this._ctx, this.state); this.enterRule(localctx, 40, SqlBaseParser.RULE_namedQuery); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 724; localctx.name = this.identifier(); this.state = 726; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.T__1) { this.state = 725; this.columnAliases(); } this.state = 728; this.match(SqlBaseParser.AS); this.state = 729; this.match(SqlBaseParser.T__1); this.state = 730; this.query(); this.state = 731; this.match(SqlBaseParser.T__3); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SetQuantifierContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_setQuantifier; // return this; } SetQuantifierContext.prototype = Object.create(ParserRuleContext.prototype); SetQuantifierContext.prototype.constructor = SetQuantifierContext; SetQuantifierContext.prototype.DISTINCT = function() { return this.getToken(SqlBaseParser.DISTINCT, 0); }; SetQuantifierContext.prototype.ALL = function() { return this.getToken(SqlBaseParser.ALL, 0); }; SetQuantifierContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSetQuantifier(this); } }; SetQuantifierContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSetQuantifier(this); } }; SetQuantifierContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSetQuantifier(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SetQuantifierContext = SetQuantifierContext; SqlBaseParser.prototype.setQuantifier = function() { var localctx = new SetQuantifierContext(this, this._ctx, this.state); this.enterRule(localctx, 42, SqlBaseParser.RULE_setQuantifier); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 733; _la = this._input.LA(1); if(!(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SelectItemContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_selectItem; // return this; } SelectItemContext.prototype = Object.create(ParserRuleContext.prototype); SelectItemContext.prototype.constructor = SelectItemContext; SelectItemContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function SelectAllContext(parser, ctx) { SelectItemContext.call(this, parser); SelectItemContext.prototype.copyFrom.call(this, ctx); // return this; } SelectAllContext.prototype = Object.create(SelectItemContext.prototype); SelectAllContext.prototype.constructor = SelectAllContext; SqlBaseParser.SelectAllContext = SelectAllContext; SelectAllContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; SelectAllContext.prototype.ASTERISK = function() { return this.getToken(SqlBaseParser.ASTERISK, 0); }; SelectAllContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSelectAll(this); } }; SelectAllContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSelectAll(this); } }; SelectAllContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSelectAll(this); } else { return (visitor as any).visitChildren(this); } }; function SelectSingleContext(parser, ctx) { SelectItemContext.call(this, parser); SelectItemContext.prototype.copyFrom.call(this, ctx); // return this; } SelectSingleContext.prototype = Object.create(SelectItemContext.prototype); SelectSingleContext.prototype.constructor = SelectSingleContext; SqlBaseParser.SelectSingleContext = SelectSingleContext; SelectSingleContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SelectSingleContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; SelectSingleContext.prototype.AS = function() { return this.getToken(SqlBaseParser.AS, 0); }; SelectSingleContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSelectSingle(this); } }; SelectSingleContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSelectSingle(this); } }; SelectSingleContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSelectSingle(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SelectItemContext = SelectItemContext; SqlBaseParser.prototype.selectItem = function() { var localctx = new SelectItemContext(this, this._ctx, this.state); this.enterRule(localctx, 44, SqlBaseParser.RULE_selectItem); var _la = 0; // Token type try { this.state = 747; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,88,this._ctx); switch(la_) { case 1: localctx = new SelectSingleContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 735; this.expression(); this.state = 740; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,87,this._ctx); if(la_===1) { this.state = 737; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.AS) { this.state = 736; this.match(SqlBaseParser.AS); } this.state = 739; this.identifier(); } break; case 2: localctx = new SelectAllContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 742; this.qualifiedName(); this.state = 743; this.match(SqlBaseParser.T__0); this.state = 744; this.match(SqlBaseParser.ASTERISK); break; case 3: localctx = new SelectAllContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 746; this.match(SqlBaseParser.ASTERISK); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function RelationContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_relation; // return this; } RelationContext.prototype = Object.create(ParserRuleContext.prototype); RelationContext.prototype.constructor = RelationContext; RelationContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function RelationDefaultContext(parser, ctx) { RelationContext.call(this, parser); RelationContext.prototype.copyFrom.call(this, ctx); // return this; } RelationDefaultContext.prototype = Object.create(RelationContext.prototype); RelationDefaultContext.prototype.constructor = RelationDefaultContext; SqlBaseParser.RelationDefaultContext = RelationDefaultContext; RelationDefaultContext.prototype.sampledRelation = function() { return this.getTypedRuleContext(SampledRelationContext,0); }; RelationDefaultContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRelationDefault(this); } }; RelationDefaultContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRelationDefault(this); } }; RelationDefaultContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRelationDefault(this); } else { return (visitor as any).visitChildren(this); } }; function JoinRelationContext(parser, ctx) { RelationContext.call(this, parser); this.left = null; // RelationContext; this.right = null; // SampledRelationContext; this.rightRelation = null; // RelationContext; RelationContext.prototype.copyFrom.call(this, ctx); // return this; } JoinRelationContext.prototype = Object.create(RelationContext.prototype); JoinRelationContext.prototype.constructor = JoinRelationContext; SqlBaseParser.JoinRelationContext = JoinRelationContext; JoinRelationContext.prototype.relation = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(RelationContext); } else { return this.getTypedRuleContext(RelationContext,i); } }; JoinRelationContext.prototype.CROSS = function() { return this.getToken(SqlBaseParser.CROSS, 0); }; JoinRelationContext.prototype.JOIN = function() { return this.getToken(SqlBaseParser.JOIN, 0); }; JoinRelationContext.prototype.joinType = function() { return this.getTypedRuleContext(JoinTypeContext,0); }; JoinRelationContext.prototype.joinCriteria = function() { return this.getTypedRuleContext(JoinCriteriaContext,0); }; JoinRelationContext.prototype.NATURAL = function() { return this.getToken(SqlBaseParser.NATURAL, 0); }; JoinRelationContext.prototype.sampledRelation = function() { return this.getTypedRuleContext(SampledRelationContext,0); }; JoinRelationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterJoinRelation(this); } }; JoinRelationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitJoinRelation(this); } }; JoinRelationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitJoinRelation(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.prototype.relation = function(_p) { if(_p===undefined) { _p = 0; } var _parentctx = this._ctx; var _parentState = this.state; var localctx = new RelationContext(this, this._ctx, _parentState); var _prevctx = localctx; var _startState = 46; this.enterRecursionRule(localctx, 46, SqlBaseParser.RULE_relation, _p); try { this.enterOuterAlt(localctx, 1); localctx = new RelationDefaultContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 750; this.sampledRelation(); this._ctx.stop = this._input.LT(-1); this.state = 770; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,90,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { if(this._parseListeners!==null) { this.triggerExitRuleEvent(); } _prevctx = localctx; localctx = new JoinRelationContext(this, new RelationContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_relation); this.state = 752; if (!( this.precpred(this._ctx, 2))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 2)"); } this.state = 766; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.CROSS: this.state = 753; this.match(SqlBaseParser.CROSS); this.state = 754; this.match(SqlBaseParser.JOIN); this.state = 755; localctx.right = this.sampledRelation(); break; case SqlBaseParser.JOIN: case SqlBaseParser.INNER: case SqlBaseParser.LEFT: case SqlBaseParser.RIGHT: case SqlBaseParser.FULL: this.state = 756; this.joinType(); this.state = 757; this.match(SqlBaseParser.JOIN); this.state = 758; localctx.rightRelation = this.relation(0); this.state = 759; this.joinCriteria(); break; case SqlBaseParser.NATURAL: this.state = 761; this.match(SqlBaseParser.NATURAL); this.state = 762; this.joinType(); this.state = 763; this.match(SqlBaseParser.JOIN); this.state = 764; localctx.right = this.sampledRelation(); break; default: throw new _error.NoViableAltException(this); } } this.state = 772; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,90,this._ctx); } } catch( error) { if(error instanceof _error.RecognitionException) { localctx.exception = error; this._errHandler.reportError(this, error); this._errHandler.recover(this, error); } else { throw error; } } finally { this.unrollRecursionContexts(_parentctx) } return localctx; }; function JoinTypeContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_joinType; // return this; } JoinTypeContext.prototype = Object.create(ParserRuleContext.prototype); JoinTypeContext.prototype.constructor = JoinTypeContext; JoinTypeContext.prototype.INNER = function() { return this.getToken(SqlBaseParser.INNER, 0); }; JoinTypeContext.prototype.LEFT = function() { return this.getToken(SqlBaseParser.LEFT, 0); }; JoinTypeContext.prototype.OUTER = function() { return this.getToken(SqlBaseParser.OUTER, 0); }; JoinTypeContext.prototype.RIGHT = function() { return this.getToken(SqlBaseParser.RIGHT, 0); }; JoinTypeContext.prototype.FULL = function() { return this.getToken(SqlBaseParser.FULL, 0); }; JoinTypeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterJoinType(this); } }; JoinTypeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitJoinType(this); } }; JoinTypeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitJoinType(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.JoinTypeContext = JoinTypeContext; SqlBaseParser.prototype.joinType = function() { var localctx = new JoinTypeContext(this, this._ctx, this.state); this.enterRule(localctx, 48, SqlBaseParser.RULE_joinType); var _la = 0; // Token type try { this.state = 788; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.JOIN: case SqlBaseParser.INNER: this.enterOuterAlt(localctx, 1); this.state = 774; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.INNER) { this.state = 773; this.match(SqlBaseParser.INNER); } break; case SqlBaseParser.LEFT: this.enterOuterAlt(localctx, 2); this.state = 776; this.match(SqlBaseParser.LEFT); this.state = 778; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.OUTER) { this.state = 777; this.match(SqlBaseParser.OUTER); } break; case SqlBaseParser.RIGHT: this.enterOuterAlt(localctx, 3); this.state = 780; this.match(SqlBaseParser.RIGHT); this.state = 782; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.OUTER) { this.state = 781; this.match(SqlBaseParser.OUTER); } break; case SqlBaseParser.FULL: this.enterOuterAlt(localctx, 4); this.state = 784; this.match(SqlBaseParser.FULL); this.state = 786; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.OUTER) { this.state = 785; this.match(SqlBaseParser.OUTER); } break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function JoinCriteriaContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_joinCriteria; // return this; } JoinCriteriaContext.prototype = Object.create(ParserRuleContext.prototype); JoinCriteriaContext.prototype.constructor = JoinCriteriaContext; JoinCriteriaContext.prototype.ON = function() { return this.getToken(SqlBaseParser.ON, 0); }; JoinCriteriaContext.prototype.booleanExpression = function() { return this.getTypedRuleContext(BooleanExpressionContext,0); }; JoinCriteriaContext.prototype.USING = function() { return this.getToken(SqlBaseParser.USING, 0); }; JoinCriteriaContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; JoinCriteriaContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterJoinCriteria(this); } }; JoinCriteriaContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitJoinCriteria(this); } }; JoinCriteriaContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitJoinCriteria(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.JoinCriteriaContext = JoinCriteriaContext; SqlBaseParser.prototype.joinCriteria = function() { var localctx = new JoinCriteriaContext(this, this._ctx, this.state); this.enterRule(localctx, 50, SqlBaseParser.RULE_joinCriteria); var _la = 0; // Token type try { this.state = 804; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.ON: this.enterOuterAlt(localctx, 1); this.state = 790; this.match(SqlBaseParser.ON); this.state = 791; this.booleanExpression(0); break; case SqlBaseParser.USING: this.enterOuterAlt(localctx, 2); this.state = 792; this.match(SqlBaseParser.USING); this.state = 793; this.match(SqlBaseParser.T__1); this.state = 794; this.identifier(); this.state = 799; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 795; this.match(SqlBaseParser.T__2); this.state = 796; this.identifier(); this.state = 801; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 802; this.match(SqlBaseParser.T__3); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SampledRelationContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_sampledRelation; this.percentage = null; // ExpressionContext // return this; } SampledRelationContext.prototype = Object.create(ParserRuleContext.prototype); SampledRelationContext.prototype.constructor = SampledRelationContext; SampledRelationContext.prototype.aliasedRelation = function() { return this.getTypedRuleContext(AliasedRelationContext,0); }; SampledRelationContext.prototype.TABLESAMPLE = function() { return this.getToken(SqlBaseParser.TABLESAMPLE, 0); }; SampledRelationContext.prototype.sampleType = function() { return this.getTypedRuleContext(SampleTypeContext,0); }; SampledRelationContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SampledRelationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSampledRelation(this); } }; SampledRelationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSampledRelation(this); } }; SampledRelationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSampledRelation(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SampledRelationContext = SampledRelationContext; SqlBaseParser.prototype.sampledRelation = function() { var localctx = new SampledRelationContext(this, this._ctx, this.state); this.enterRule(localctx, 52, SqlBaseParser.RULE_sampledRelation); try { this.enterOuterAlt(localctx, 1); this.state = 806; this.aliasedRelation(); this.state = 813; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,98,this._ctx); if(la_===1) { this.state = 807; this.match(SqlBaseParser.TABLESAMPLE); this.state = 808; this.sampleType(); this.state = 809; this.match(SqlBaseParser.T__1); this.state = 810; localctx.percentage = this.expression(); this.state = 811; this.match(SqlBaseParser.T__3); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SampleTypeContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_sampleType; // return this; } SampleTypeContext.prototype = Object.create(ParserRuleContext.prototype); SampleTypeContext.prototype.constructor = SampleTypeContext; SampleTypeContext.prototype.BERNOULLI = function() { return this.getToken(SqlBaseParser.BERNOULLI, 0); }; SampleTypeContext.prototype.SYSTEM = function() { return this.getToken(SqlBaseParser.SYSTEM, 0); }; SampleTypeContext.prototype.POISSONIZED = function() { return this.getToken(SqlBaseParser.POISSONIZED, 0); }; SampleTypeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSampleType(this); } }; SampleTypeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSampleType(this); } }; SampleTypeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSampleType(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.SampleTypeContext = SampleTypeContext; SqlBaseParser.prototype.sampleType = function() { var localctx = new SampleTypeContext(this, this._ctx, this.state); this.enterRule(localctx, 54, SqlBaseParser.RULE_sampleType); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 815; _la = this._input.LA(1); if(!(((((_la - 137)) & ~0x1f) == 0 && ((1 << (_la - 137)) & ((1 << (SqlBaseParser.SYSTEM - 137)) | (1 << (SqlBaseParser.BERNOULLI - 137)) | (1 << (SqlBaseParser.POISSONIZED - 137)))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function AliasedRelationContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_aliasedRelation; this.relationP = null; // RelationPrimaryContext this.as = null; // Token this.alias = null; // IdentifierContext // return this; } AliasedRelationContext.prototype = Object.create(ParserRuleContext.prototype); AliasedRelationContext.prototype.constructor = AliasedRelationContext; AliasedRelationContext.prototype.relationPrimary = function() { return this.getTypedRuleContext(RelationPrimaryContext,0); }; AliasedRelationContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; AliasedRelationContext.prototype.columnAliases = function() { return this.getTypedRuleContext(ColumnAliasesContext,0); }; AliasedRelationContext.prototype.AS = function() { return this.getToken(SqlBaseParser.AS, 0); }; AliasedRelationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterAliasedRelation(this); } }; AliasedRelationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitAliasedRelation(this); } }; AliasedRelationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitAliasedRelation(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.AliasedRelationContext = AliasedRelationContext; SqlBaseParser.prototype.aliasedRelation = function() { var localctx = new AliasedRelationContext(this, this._ctx, this.state); this.enterRule(localctx, 56, SqlBaseParser.RULE_aliasedRelation); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 817; localctx.relationP = this.relationPrimary(); this.state = 825; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,101,this._ctx); if(la_===1) { this.state = 819; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.AS) { this.state = 818; localctx.as = this.match(SqlBaseParser.AS); } this.state = 821; localctx.alias = this.identifier(); this.state = 823; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,100,this._ctx); if(la_===1) { this.state = 822; this.columnAliases(); } } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ColumnAliasesContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_columnAliases; // return this; } ColumnAliasesContext.prototype = Object.create(ParserRuleContext.prototype); ColumnAliasesContext.prototype.constructor = ColumnAliasesContext; ColumnAliasesContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; ColumnAliasesContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterColumnAliases(this); } }; ColumnAliasesContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitColumnAliases(this); } }; ColumnAliasesContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitColumnAliases(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.ColumnAliasesContext = ColumnAliasesContext; SqlBaseParser.prototype.columnAliases = function() { var localctx = new ColumnAliasesContext(this, this._ctx, this.state); this.enterRule(localctx, 58, SqlBaseParser.RULE_columnAliases); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 827; this.match(SqlBaseParser.T__1); this.state = 828; this.identifier(); this.state = 833; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 829; this.match(SqlBaseParser.T__2); this.state = 830; this.identifier(); this.state = 835; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 836; this.match(SqlBaseParser.T__3); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function RelationPrimaryContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_relationPrimary; // return this; } RelationPrimaryContext.prototype = Object.create(ParserRuleContext.prototype); RelationPrimaryContext.prototype.constructor = RelationPrimaryContext; RelationPrimaryContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function SubqueryRelationContext(parser, ctx) { RelationPrimaryContext.call(this, parser); RelationPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } SubqueryRelationContext.prototype = Object.create(RelationPrimaryContext.prototype); SubqueryRelationContext.prototype.constructor = SubqueryRelationContext; SqlBaseParser.SubqueryRelationContext = SubqueryRelationContext; SubqueryRelationContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; SubqueryRelationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSubqueryRelation(this); } }; SubqueryRelationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSubqueryRelation(this); } }; SubqueryRelationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSubqueryRelation(this); } else { return (visitor as any).visitChildren(this); } }; function ParenthesizedRelationContext(parser, ctx) { RelationPrimaryContext.call(this, parser); RelationPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } ParenthesizedRelationContext.prototype = Object.create(RelationPrimaryContext.prototype); ParenthesizedRelationContext.prototype.constructor = ParenthesizedRelationContext; SqlBaseParser.ParenthesizedRelationContext = ParenthesizedRelationContext; ParenthesizedRelationContext.prototype.relation = function() { return this.getTypedRuleContext(RelationContext,0); }; ParenthesizedRelationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterParenthesizedRelation(this); } }; ParenthesizedRelationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitParenthesizedRelation(this); } }; ParenthesizedRelationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitParenthesizedRelation(this); } else { return (visitor as any).visitChildren(this); } }; function UnnestContext(parser, ctx) { RelationPrimaryContext.call(this, parser); RelationPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } UnnestContext.prototype = Object.create(RelationPrimaryContext.prototype); UnnestContext.prototype.constructor = UnnestContext; SqlBaseParser.UnnestContext = UnnestContext; UnnestContext.prototype.UNNEST = function() { return this.getToken(SqlBaseParser.UNNEST, 0); }; UnnestContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; UnnestContext.prototype.WITH = function() { return this.getToken(SqlBaseParser.WITH, 0); }; UnnestContext.prototype.ORDINALITY = function() { return this.getToken(SqlBaseParser.ORDINALITY, 0); }; UnnestContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterUnnest(this); } }; UnnestContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitUnnest(this); } }; UnnestContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitUnnest(this); } else { return (visitor as any).visitChildren(this); } }; function TableNameContext(parser, ctx) { RelationPrimaryContext.call(this, parser); RelationPrimaryContext.prototype.copyFrom.call(this, ctx); // return this; } TableNameContext.prototype = Object.create(RelationPrimaryContext.prototype); TableNameContext.prototype.constructor = TableNameContext; SqlBaseParser.TableNameContext = TableNameContext; TableNameContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; TableNameContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTableName(this); } }; TableNameContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTableName(this); } }; TableNameContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTableName(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.RelationPrimaryContext = RelationPrimaryContext; SqlBaseParser.prototype.relationPrimary = function() { var localctx = new RelationPrimaryContext(this, this._ctx, this.state); this.enterRule(localctx, 60, SqlBaseParser.RULE_relationPrimary); var _la = 0; // Token type try { this.state = 862; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,105,this._ctx); switch(la_) { case 1: localctx = new TableNameContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 838; this.qualifiedName(); break; case 2: localctx = new SubqueryRelationContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 839; this.match(SqlBaseParser.T__1); this.state = 840; this.query(); this.state = 841; this.match(SqlBaseParser.T__3); break; case 3: localctx = new UnnestContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 843; this.match(SqlBaseParser.UNNEST); this.state = 844; this.match(SqlBaseParser.T__1); this.state = 845; this.expression(); this.state = 850; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 846; this.match(SqlBaseParser.T__2); this.state = 847; this.expression(); this.state = 852; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 853; this.match(SqlBaseParser.T__3); this.state = 856; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,104,this._ctx); if(la_===1) { this.state = 854; this.match(SqlBaseParser.WITH); this.state = 855; this.match(SqlBaseParser.ORDINALITY); } break; case 4: localctx = new ParenthesizedRelationContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 858; this.match(SqlBaseParser.T__1); this.state = 859; this.relation(0); this.state = 860; this.match(SqlBaseParser.T__3); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ExpressionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_expression; // return this; } ExpressionContext.prototype = Object.create(ParserRuleContext.prototype); ExpressionContext.prototype.constructor = ExpressionContext; ExpressionContext.prototype.booleanExpression = function() { return this.getTypedRuleContext(BooleanExpressionContext,0); }; ExpressionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExpression(this); } }; ExpressionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExpression(this); } }; ExpressionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExpression(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.ExpressionContext = ExpressionContext; SqlBaseParser.prototype.expression = function() { var localctx = new ExpressionContext(this, this._ctx, this.state); this.enterRule(localctx, 62, SqlBaseParser.RULE_expression); try { this.enterOuterAlt(localctx, 1); this.state = 864; this.booleanExpression(0); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function BooleanExpressionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_booleanExpression; // return this; } BooleanExpressionContext.prototype = Object.create(ParserRuleContext.prototype); BooleanExpressionContext.prototype.constructor = BooleanExpressionContext; BooleanExpressionContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function LogicalNotContext(parser, ctx) { BooleanExpressionContext.call(this, parser); BooleanExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } LogicalNotContext.prototype = Object.create(BooleanExpressionContext.prototype); LogicalNotContext.prototype.constructor = LogicalNotContext; SqlBaseParser.LogicalNotContext = LogicalNotContext; LogicalNotContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; LogicalNotContext.prototype.booleanExpression = function() { return this.getTypedRuleContext(BooleanExpressionContext,0); }; LogicalNotContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterLogicalNot(this); } }; LogicalNotContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitLogicalNot(this); } }; LogicalNotContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitLogicalNot(this); } else { return (visitor as any).visitChildren(this); } }; function BooleanDefaultContext(parser, ctx) { BooleanExpressionContext.call(this, parser); BooleanExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } BooleanDefaultContext.prototype = Object.create(BooleanExpressionContext.prototype); BooleanDefaultContext.prototype.constructor = BooleanDefaultContext; SqlBaseParser.BooleanDefaultContext = BooleanDefaultContext; BooleanDefaultContext.prototype.predicated = function() { return this.getTypedRuleContext(PredicatedContext,0); }; BooleanDefaultContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBooleanDefault(this); } }; BooleanDefaultContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBooleanDefault(this); } }; BooleanDefaultContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBooleanDefault(this); } else { return (visitor as any).visitChildren(this); } }; function LogicalBinaryContext(parser, ctx) { BooleanExpressionContext.call(this, parser); this.left = null; // BooleanExpressionContext; this.operator = null; // Token; this.right = null; // BooleanExpressionContext; BooleanExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } LogicalBinaryContext.prototype = Object.create(BooleanExpressionContext.prototype); LogicalBinaryContext.prototype.constructor = LogicalBinaryContext; SqlBaseParser.LogicalBinaryContext = LogicalBinaryContext; LogicalBinaryContext.prototype.booleanExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(BooleanExpressionContext); } else { return this.getTypedRuleContext(BooleanExpressionContext,i); } }; LogicalBinaryContext.prototype.AND = function() { return this.getToken(SqlBaseParser.AND, 0); }; LogicalBinaryContext.prototype.OR = function() { return this.getToken(SqlBaseParser.OR, 0); }; LogicalBinaryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterLogicalBinary(this); } }; LogicalBinaryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitLogicalBinary(this); } }; LogicalBinaryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitLogicalBinary(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.prototype.booleanExpression = function(_p) { if(_p===undefined) { _p = 0; } var _parentctx = this._ctx; var _parentState = this.state; var localctx = new BooleanExpressionContext(this, this._ctx, _parentState); var _prevctx = localctx; var _startState = 64; this.enterRecursionRule(localctx, 64, SqlBaseParser.RULE_booleanExpression, _p); try { this.enterOuterAlt(localctx, 1); this.state = 870; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.T__1: case SqlBaseParser.T__4: case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.EXISTS: case SqlBaseParser.NULL: case SqlBaseParser.TRUE: case SqlBaseParser.FALSE: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.CURRENT_DATE: case SqlBaseParser.CURRENT_TIME: case SqlBaseParser.CURRENT_TIMESTAMP: case SqlBaseParser.LOCALTIME: case SqlBaseParser.LOCALTIMESTAMP: case SqlBaseParser.EXTRACT: case SqlBaseParser.CASE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.CAST: case SqlBaseParser.TRY_CAST: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NORMALIZE: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.PLUS: case SqlBaseParser.MINUS: case SqlBaseParser.STRING: case SqlBaseParser.BINARY_LITERAL: case SqlBaseParser.INTEGER_VALUE: case SqlBaseParser.DECIMAL_VALUE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: case SqlBaseParser.DOUBLE_PRECISION: localctx = new BooleanDefaultContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 867; this.predicated(); break; case SqlBaseParser.NOT: localctx = new LogicalNotContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 868; this.match(SqlBaseParser.NOT); this.state = 869; this.booleanExpression(3); break; default: throw new _error.NoViableAltException(this); } this._ctx.stop = this._input.LT(-1); this.state = 880; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,108,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { if(this._parseListeners!==null) { this.triggerExitRuleEvent(); } _prevctx = localctx; this.state = 878; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,107,this._ctx); switch(la_) { case 1: localctx = new LogicalBinaryContext(this, new BooleanExpressionContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_booleanExpression); this.state = 872; if (!( this.precpred(this._ctx, 2))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 2)"); } this.state = 873; localctx.operator = this.match(SqlBaseParser.AND); this.state = 874; localctx.right = this.booleanExpression(3); break; case 2: localctx = new LogicalBinaryContext(this, new BooleanExpressionContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_booleanExpression); this.state = 875; if (!( this.precpred(this._ctx, 1))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 1)"); } this.state = 876; localctx.operator = this.match(SqlBaseParser.OR); this.state = 877; localctx.right = this.booleanExpression(2); break; } } this.state = 882; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,108,this._ctx); } } catch( error) { if(error instanceof _error.RecognitionException) { localctx.exception = error; this._errHandler.reportError(this, error); this._errHandler.recover(this, error); } else { throw error; } } finally { this.unrollRecursionContexts(_parentctx) } return localctx; }; function PredicatedContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_predicated; this._valueExpression = null; // ValueExpressionContext // return this; } PredicatedContext.prototype = Object.create(ParserRuleContext.prototype); PredicatedContext.prototype.constructor = PredicatedContext; PredicatedContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; PredicatedContext.prototype.predicate = function() { return this.getTypedRuleContext(PredicateContext,0); }; PredicatedContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterPredicated(this); } }; PredicatedContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitPredicated(this); } }; PredicatedContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitPredicated(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.PredicatedContext = PredicatedContext; SqlBaseParser.prototype.predicated = function() { var localctx = new PredicatedContext(this, this._ctx, this.state); this.enterRule(localctx, 66, SqlBaseParser.RULE_predicated); try { this.enterOuterAlt(localctx, 1); this.state = 883; localctx._valueExpression = this.valueExpression(0); this.state = 885; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,109,this._ctx); if(la_===1) { this.state = 884; this.predicate(localctx._valueExpression); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function PredicateContext(parser, parent, invokingState, value) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_predicate; this.value = null this.value = value || null; // return this; } PredicateContext.prototype = Object.create(ParserRuleContext.prototype); PredicateContext.prototype.constructor = PredicateContext; PredicateContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); this.value = ctx.value; }; function ComparisonContext(parser, ctx) { PredicateContext.call(this, parser); this.right = null; // ValueExpressionContext; PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } ComparisonContext.prototype = Object.create(PredicateContext.prototype); ComparisonContext.prototype.constructor = ComparisonContext; SqlBaseParser.ComparisonContext = ComparisonContext; ComparisonContext.prototype.comparisonOperator = function() { return this.getTypedRuleContext(ComparisonOperatorContext,0); }; ComparisonContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; ComparisonContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterComparison(this); } }; ComparisonContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitComparison(this); } }; ComparisonContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitComparison(this); } else { return (visitor as any).visitChildren(this); } }; function LikeContext(parser, ctx) { PredicateContext.call(this, parser); this.pattern = null; // ValueExpressionContext; this.escape = null; // ValueExpressionContext; PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } LikeContext.prototype = Object.create(PredicateContext.prototype); LikeContext.prototype.constructor = LikeContext; SqlBaseParser.LikeContext = LikeContext; LikeContext.prototype.LIKE = function() { return this.getToken(SqlBaseParser.LIKE, 0); }; LikeContext.prototype.valueExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ValueExpressionContext); } else { return this.getTypedRuleContext(ValueExpressionContext,i); } }; LikeContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; LikeContext.prototype.ESCAPE = function() { return this.getToken(SqlBaseParser.ESCAPE, 0); }; LikeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterLike(this); } }; LikeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitLike(this); } }; LikeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitLike(this); } else { return (visitor as any).visitChildren(this); } }; function InSubqueryContext(parser, ctx) { PredicateContext.call(this, parser); PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } InSubqueryContext.prototype = Object.create(PredicateContext.prototype); InSubqueryContext.prototype.constructor = InSubqueryContext; SqlBaseParser.InSubqueryContext = InSubqueryContext; InSubqueryContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; InSubqueryContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; InSubqueryContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; InSubqueryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterInSubquery(this); } }; InSubqueryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitInSubquery(this); } }; InSubqueryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitInSubquery(this); } else { return (visitor as any).visitChildren(this); } }; function DistinctFromContext(parser, ctx) { PredicateContext.call(this, parser); this.right = null; // ValueExpressionContext; PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } DistinctFromContext.prototype = Object.create(PredicateContext.prototype); DistinctFromContext.prototype.constructor = DistinctFromContext; SqlBaseParser.DistinctFromContext = DistinctFromContext; DistinctFromContext.prototype.IS = function() { return this.getToken(SqlBaseParser.IS, 0); }; DistinctFromContext.prototype.DISTINCT = function() { return this.getToken(SqlBaseParser.DISTINCT, 0); }; DistinctFromContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; DistinctFromContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; DistinctFromContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; DistinctFromContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDistinctFrom(this); } }; DistinctFromContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDistinctFrom(this); } }; DistinctFromContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDistinctFrom(this); } else { return (visitor as any).visitChildren(this); } }; function InListContext(parser, ctx) { PredicateContext.call(this, parser); PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } InListContext.prototype = Object.create(PredicateContext.prototype); InListContext.prototype.constructor = InListContext; SqlBaseParser.InListContext = InListContext; InListContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; InListContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; InListContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; InListContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterInList(this); } }; InListContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitInList(this); } }; InListContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitInList(this); } else { return (visitor as any).visitChildren(this); } }; function NullPredicateContext(parser, ctx) { PredicateContext.call(this, parser); PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } NullPredicateContext.prototype = Object.create(PredicateContext.prototype); NullPredicateContext.prototype.constructor = NullPredicateContext; SqlBaseParser.NullPredicateContext = NullPredicateContext; NullPredicateContext.prototype.IS = function() { return this.getToken(SqlBaseParser.IS, 0); }; NullPredicateContext.prototype.NULL = function() { return this.getToken(SqlBaseParser.NULL, 0); }; NullPredicateContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; NullPredicateContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNullPredicate(this); } }; NullPredicateContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNullPredicate(this); } }; NullPredicateContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNullPredicate(this); } else { return (visitor as any).visitChildren(this); } }; function BetweenContext(parser, ctx) { PredicateContext.call(this, parser); this.lower = null; // ValueExpressionContext; this.upper = null; // ValueExpressionContext; PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } BetweenContext.prototype = Object.create(PredicateContext.prototype); BetweenContext.prototype.constructor = BetweenContext; SqlBaseParser.BetweenContext = BetweenContext; BetweenContext.prototype.BETWEEN = function() { return this.getToken(SqlBaseParser.BETWEEN, 0); }; BetweenContext.prototype.AND = function() { return this.getToken(SqlBaseParser.AND, 0); }; BetweenContext.prototype.valueExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ValueExpressionContext); } else { return this.getTypedRuleContext(ValueExpressionContext,i); } }; BetweenContext.prototype.NOT = function() { return this.getToken(SqlBaseParser.NOT, 0); }; BetweenContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBetween(this); } }; BetweenContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBetween(this); } }; BetweenContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBetween(this); } else { return (visitor as any).visitChildren(this); } }; function QuantifiedComparisonContext(parser, ctx) { PredicateContext.call(this, parser); PredicateContext.prototype.copyFrom.call(this, ctx); // return this; } QuantifiedComparisonContext.prototype = Object.create(PredicateContext.prototype); QuantifiedComparisonContext.prototype.constructor = QuantifiedComparisonContext; SqlBaseParser.QuantifiedComparisonContext = QuantifiedComparisonContext; QuantifiedComparisonContext.prototype.comparisonOperator = function() { return this.getTypedRuleContext(ComparisonOperatorContext,0); }; QuantifiedComparisonContext.prototype.comparisonQuantifier = function() { return this.getTypedRuleContext(ComparisonQuantifierContext,0); }; QuantifiedComparisonContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; QuantifiedComparisonContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQuantifiedComparison(this); } }; QuantifiedComparisonContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQuantifiedComparison(this); } }; QuantifiedComparisonContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQuantifiedComparison(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.PredicateContext = PredicateContext; SqlBaseParser.prototype.predicate = function(value) { var localctx = new PredicateContext(this, this._ctx, this.state, value); this.enterRule(localctx, 68, SqlBaseParser.RULE_predicate); var _la = 0; // Token type try { this.state = 948; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,118,this._ctx); switch(la_) { case 1: localctx = new ComparisonContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 887; this.comparisonOperator(); this.state = 888; localctx.right = this.valueExpression(0); break; case 2: localctx = new QuantifiedComparisonContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 890; this.comparisonOperator(); this.state = 891; this.comparisonQuantifier(); this.state = 892; this.match(SqlBaseParser.T__1); this.state = 893; this.query(); this.state = 894; this.match(SqlBaseParser.T__3); break; case 3: localctx = new BetweenContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 897; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NOT) { this.state = 896; this.match(SqlBaseParser.NOT); } this.state = 899; this.match(SqlBaseParser.BETWEEN); this.state = 900; localctx.lower = this.valueExpression(0); this.state = 901; this.match(SqlBaseParser.AND); this.state = 902; localctx.upper = this.valueExpression(0); break; case 4: localctx = new InListContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 905; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NOT) { this.state = 904; this.match(SqlBaseParser.NOT); } this.state = 907; this.match(SqlBaseParser.IN); this.state = 908; this.match(SqlBaseParser.T__1); this.state = 909; this.expression(); this.state = 914; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 910; this.match(SqlBaseParser.T__2); this.state = 911; this.expression(); this.state = 916; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 917; this.match(SqlBaseParser.T__3); break; case 5: localctx = new InSubqueryContext(this, localctx); this.enterOuterAlt(localctx, 5); this.state = 920; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NOT) { this.state = 919; this.match(SqlBaseParser.NOT); } this.state = 922; this.match(SqlBaseParser.IN); this.state = 923; this.match(SqlBaseParser.T__1); this.state = 924; this.query(); this.state = 925; this.match(SqlBaseParser.T__3); break; case 6: localctx = new LikeContext(this, localctx); this.enterOuterAlt(localctx, 6); this.state = 928; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NOT) { this.state = 927; this.match(SqlBaseParser.NOT); } this.state = 930; this.match(SqlBaseParser.LIKE); this.state = 931; localctx.pattern = this.valueExpression(0); this.state = 934; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,115,this._ctx); if(la_===1) { this.state = 932; this.match(SqlBaseParser.ESCAPE); this.state = 933; localctx.escape = this.valueExpression(0); } break; case 7: localctx = new NullPredicateContext(this, localctx); this.enterOuterAlt(localctx, 7); this.state = 936; this.match(SqlBaseParser.IS); this.state = 938; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NOT) { this.state = 937; this.match(SqlBaseParser.NOT); } this.state = 940; this.match(SqlBaseParser.NULL); break; case 8: localctx = new DistinctFromContext(this, localctx); this.enterOuterAlt(localctx, 8); this.state = 941; this.match(SqlBaseParser.IS); this.state = 943; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.NOT) { this.state = 942; this.match(SqlBaseParser.NOT); } this.state = 945; this.match(SqlBaseParser.DISTINCT); this.state = 946; this.match(SqlBaseParser.FROM); this.state = 947; localctx.right = this.valueExpression(0); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ValueExpressionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_valueExpression; // return this; } ValueExpressionContext.prototype = Object.create(ParserRuleContext.prototype); ValueExpressionContext.prototype.constructor = ValueExpressionContext; ValueExpressionContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function ValueExpressionDefaultContext(parser, ctx) { ValueExpressionContext.call(this, parser); ValueExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ValueExpressionDefaultContext.prototype = Object.create(ValueExpressionContext.prototype); ValueExpressionDefaultContext.prototype.constructor = ValueExpressionDefaultContext; SqlBaseParser.ValueExpressionDefaultContext = ValueExpressionDefaultContext; ValueExpressionDefaultContext.prototype.primaryExpression = function() { return this.getTypedRuleContext(PrimaryExpressionContext,0); }; ValueExpressionDefaultContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterValueExpressionDefault(this); } }; ValueExpressionDefaultContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitValueExpressionDefault(this); } }; ValueExpressionDefaultContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitValueExpressionDefault(this); } else { return (visitor as any).visitChildren(this); } }; function ConcatenationContext(parser, ctx) { ValueExpressionContext.call(this, parser); this.left = null; // ValueExpressionContext; this.right = null; // ValueExpressionContext; ValueExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ConcatenationContext.prototype = Object.create(ValueExpressionContext.prototype); ConcatenationContext.prototype.constructor = ConcatenationContext; SqlBaseParser.ConcatenationContext = ConcatenationContext; ConcatenationContext.prototype.CONCAT = function() { return this.getToken(SqlBaseParser.CONCAT, 0); }; ConcatenationContext.prototype.valueExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ValueExpressionContext); } else { return this.getTypedRuleContext(ValueExpressionContext,i); } }; ConcatenationContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterConcatenation(this); } }; ConcatenationContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitConcatenation(this); } }; ConcatenationContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitConcatenation(this); } else { return (visitor as any).visitChildren(this); } }; function ArithmeticBinaryContext(parser, ctx) { ValueExpressionContext.call(this, parser); this.left = null; // ValueExpressionContext; this.operator = null; // Token; this.right = null; // ValueExpressionContext; ValueExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ArithmeticBinaryContext.prototype = Object.create(ValueExpressionContext.prototype); ArithmeticBinaryContext.prototype.constructor = ArithmeticBinaryContext; SqlBaseParser.ArithmeticBinaryContext = ArithmeticBinaryContext; ArithmeticBinaryContext.prototype.valueExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ValueExpressionContext); } else { return this.getTypedRuleContext(ValueExpressionContext,i); } }; ArithmeticBinaryContext.prototype.ASTERISK = function() { return this.getToken(SqlBaseParser.ASTERISK, 0); }; ArithmeticBinaryContext.prototype.SLASH = function() { return this.getToken(SqlBaseParser.SLASH, 0); }; ArithmeticBinaryContext.prototype.PERCENT = function() { return this.getToken(SqlBaseParser.PERCENT, 0); }; ArithmeticBinaryContext.prototype.PLUS = function() { return this.getToken(SqlBaseParser.PLUS, 0); }; ArithmeticBinaryContext.prototype.MINUS = function() { return this.getToken(SqlBaseParser.MINUS, 0); }; ArithmeticBinaryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterArithmeticBinary(this); } }; ArithmeticBinaryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitArithmeticBinary(this); } }; ArithmeticBinaryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitArithmeticBinary(this); } else { return (visitor as any).visitChildren(this); } }; function ArithmeticUnaryContext(parser, ctx) { ValueExpressionContext.call(this, parser); this.operator = null; // Token; ValueExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ArithmeticUnaryContext.prototype = Object.create(ValueExpressionContext.prototype); ArithmeticUnaryContext.prototype.constructor = ArithmeticUnaryContext; SqlBaseParser.ArithmeticUnaryContext = ArithmeticUnaryContext; ArithmeticUnaryContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; ArithmeticUnaryContext.prototype.MINUS = function() { return this.getToken(SqlBaseParser.MINUS, 0); }; ArithmeticUnaryContext.prototype.PLUS = function() { return this.getToken(SqlBaseParser.PLUS, 0); }; ArithmeticUnaryContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterArithmeticUnary(this); } }; ArithmeticUnaryContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitArithmeticUnary(this); } }; ArithmeticUnaryContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitArithmeticUnary(this); } else { return (visitor as any).visitChildren(this); } }; function AtTimeZoneContext(parser, ctx) { ValueExpressionContext.call(this, parser); ValueExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } AtTimeZoneContext.prototype = Object.create(ValueExpressionContext.prototype); AtTimeZoneContext.prototype.constructor = AtTimeZoneContext; SqlBaseParser.AtTimeZoneContext = AtTimeZoneContext; AtTimeZoneContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; AtTimeZoneContext.prototype.AT = function() { return this.getToken(SqlBaseParser.AT, 0); }; AtTimeZoneContext.prototype.timeZoneSpecifier = function() { return this.getTypedRuleContext(TimeZoneSpecifierContext,0); }; AtTimeZoneContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterAtTimeZone(this); } }; AtTimeZoneContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitAtTimeZone(this); } }; AtTimeZoneContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitAtTimeZone(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.prototype.valueExpression = function(_p) { if(_p===undefined) { _p = 0; } var _parentctx = this._ctx; var _parentState = this.state; var localctx = new ValueExpressionContext(this, this._ctx, _parentState); var _prevctx = localctx; var _startState = 70; this.enterRecursionRule(localctx, 70, SqlBaseParser.RULE_valueExpression, _p); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 954; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.T__1: case SqlBaseParser.T__4: case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.EXISTS: case SqlBaseParser.NULL: case SqlBaseParser.TRUE: case SqlBaseParser.FALSE: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.CURRENT_DATE: case SqlBaseParser.CURRENT_TIME: case SqlBaseParser.CURRENT_TIMESTAMP: case SqlBaseParser.LOCALTIME: case SqlBaseParser.LOCALTIMESTAMP: case SqlBaseParser.EXTRACT: case SqlBaseParser.CASE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.CAST: case SqlBaseParser.TRY_CAST: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NORMALIZE: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.STRING: case SqlBaseParser.BINARY_LITERAL: case SqlBaseParser.INTEGER_VALUE: case SqlBaseParser.DECIMAL_VALUE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: case SqlBaseParser.DOUBLE_PRECISION: localctx = new ValueExpressionDefaultContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 951; this.primaryExpression(0); break; case SqlBaseParser.PLUS: case SqlBaseParser.MINUS: localctx = new ArithmeticUnaryContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 952; localctx.operator = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS)) { localctx.operator = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 953; this.valueExpression(4); break; default: throw new _error.NoViableAltException(this); } this._ctx.stop = this._input.LT(-1); this.state = 970; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,121,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { if(this._parseListeners!==null) { this.triggerExitRuleEvent(); } _prevctx = localctx; this.state = 968; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,120,this._ctx); switch(la_) { case 1: localctx = new ArithmeticBinaryContext(this, new ValueExpressionContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression); this.state = 956; if (!( this.precpred(this._ctx, 3))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 3)"); } this.state = 957; localctx.operator = this._input.LT(1); _la = this._input.LA(1); if(!(((((_la - 192)) & ~0x1f) == 0 && ((1 << (_la - 192)) & ((1 << (SqlBaseParser.ASTERISK - 192)) | (1 << (SqlBaseParser.SLASH - 192)) | (1 << (SqlBaseParser.PERCENT - 192)))) !== 0))) { localctx.operator = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 958; localctx.right = this.valueExpression(4); break; case 2: localctx = new ArithmeticBinaryContext(this, new ValueExpressionContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression); this.state = 959; if (!( this.precpred(this._ctx, 2))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 2)"); } this.state = 960; localctx.operator = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS)) { localctx.operator = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 961; localctx.right = this.valueExpression(3); break; case 3: localctx = new ConcatenationContext(this, new ValueExpressionContext(this, _parentctx, _parentState)); localctx.left = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression); this.state = 962; if (!( this.precpred(this._ctx, 1))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 1)"); } this.state = 963; this.match(SqlBaseParser.CONCAT); this.state = 964; localctx.right = this.valueExpression(2); break; case 4: localctx = new AtTimeZoneContext(this, new ValueExpressionContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression); this.state = 965; if (!( this.precpred(this._ctx, 5))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 5)"); } this.state = 966; this.match(SqlBaseParser.AT); this.state = 967; this.timeZoneSpecifier(); break; } } this.state = 972; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,121,this._ctx); } } catch( error) { if(error instanceof _error.RecognitionException) { localctx.exception = error; this._errHandler.reportError(this, error); this._errHandler.recover(this, error); } else { throw error; } } finally { this.unrollRecursionContexts(_parentctx) } return localctx; }; function PrimaryExpressionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_primaryExpression; // return this; } PrimaryExpressionContext.prototype = Object.create(ParserRuleContext.prototype); PrimaryExpressionContext.prototype.constructor = PrimaryExpressionContext; PrimaryExpressionContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function DereferenceContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); this.base = null; // PrimaryExpressionContext; this.fieldName = null; // IdentifierContext; PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } DereferenceContext.prototype = Object.create(PrimaryExpressionContext.prototype); DereferenceContext.prototype.constructor = DereferenceContext; SqlBaseParser.DereferenceContext = DereferenceContext; DereferenceContext.prototype.primaryExpression = function() { return this.getTypedRuleContext(PrimaryExpressionContext,0); }; DereferenceContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; DereferenceContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDereference(this); } }; DereferenceContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDereference(this); } }; DereferenceContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDereference(this); } else { return (visitor as any).visitChildren(this); } }; function TypeConstructorContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } TypeConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype); TypeConstructorContext.prototype.constructor = TypeConstructorContext; SqlBaseParser.TypeConstructorContext = TypeConstructorContext; TypeConstructorContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; TypeConstructorContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; TypeConstructorContext.prototype.DOUBLE_PRECISION = function() { return this.getToken(SqlBaseParser.DOUBLE_PRECISION, 0); }; TypeConstructorContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTypeConstructor(this); } }; TypeConstructorContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTypeConstructor(this); } }; TypeConstructorContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTypeConstructor(this); } else { return (visitor as any).visitChildren(this); } }; function SpecialDateTimeFunctionContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); this.name = null; // Token; this.precision = null; // Token; PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } SpecialDateTimeFunctionContext.prototype = Object.create(PrimaryExpressionContext.prototype); SpecialDateTimeFunctionContext.prototype.constructor = SpecialDateTimeFunctionContext; SqlBaseParser.SpecialDateTimeFunctionContext = SpecialDateTimeFunctionContext; SpecialDateTimeFunctionContext.prototype.CURRENT_DATE = function() { return this.getToken(SqlBaseParser.CURRENT_DATE, 0); }; SpecialDateTimeFunctionContext.prototype.CURRENT_TIME = function() { return this.getToken(SqlBaseParser.CURRENT_TIME, 0); }; SpecialDateTimeFunctionContext.prototype.INTEGER_VALUE = function() { return this.getToken(SqlBaseParser.INTEGER_VALUE, 0); }; SpecialDateTimeFunctionContext.prototype.CURRENT_TIMESTAMP = function() { return this.getToken(SqlBaseParser.CURRENT_TIMESTAMP, 0); }; SpecialDateTimeFunctionContext.prototype.LOCALTIME = function() { return this.getToken(SqlBaseParser.LOCALTIME, 0); }; SpecialDateTimeFunctionContext.prototype.LOCALTIMESTAMP = function() { return this.getToken(SqlBaseParser.LOCALTIMESTAMP, 0); }; SpecialDateTimeFunctionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSpecialDateTimeFunction(this); } }; SpecialDateTimeFunctionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSpecialDateTimeFunction(this); } }; SpecialDateTimeFunctionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSpecialDateTimeFunction(this); } else { return (visitor as any).visitChildren(this); } }; function SubstringContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } SubstringContext.prototype = Object.create(PrimaryExpressionContext.prototype); SubstringContext.prototype.constructor = SubstringContext; SqlBaseParser.SubstringContext = SubstringContext; SubstringContext.prototype.SUBSTRING = function() { return this.getToken(SqlBaseParser.SUBSTRING, 0); }; SubstringContext.prototype.valueExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ValueExpressionContext); } else { return this.getTypedRuleContext(ValueExpressionContext,i); } }; SubstringContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; SubstringContext.prototype.FOR = function() { return this.getToken(SqlBaseParser.FOR, 0); }; SubstringContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSubstring(this); } }; SubstringContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSubstring(this); } }; SubstringContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSubstring(this); } else { return (visitor as any).visitChildren(this); } }; function CastContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } CastContext.prototype = Object.create(PrimaryExpressionContext.prototype); CastContext.prototype.constructor = CastContext; SqlBaseParser.CastContext = CastContext; CastContext.prototype.CAST = function() { return this.getToken(SqlBaseParser.CAST, 0); }; CastContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; CastContext.prototype.AS = function() { return this.getToken(SqlBaseParser.AS, 0); }; CastContext.prototype.type = function() { return this.getTypedRuleContext(TypeContext,0); }; CastContext.prototype.TRY_CAST = function() { return this.getToken(SqlBaseParser.TRY_CAST, 0); }; CastContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCast(this); } }; CastContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCast(this); } }; CastContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCast(this); } else { return (visitor as any).visitChildren(this); } }; function LambdaContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } LambdaContext.prototype = Object.create(PrimaryExpressionContext.prototype); LambdaContext.prototype.constructor = LambdaContext; SqlBaseParser.LambdaContext = LambdaContext; LambdaContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; LambdaContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; LambdaContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterLambda(this); } }; LambdaContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitLambda(this); } }; LambdaContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitLambda(this); } else { return (visitor as any).visitChildren(this); } }; function ParameterContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ParameterContext.prototype = Object.create(PrimaryExpressionContext.prototype); ParameterContext.prototype.constructor = ParameterContext; SqlBaseParser.ParameterContext = ParameterContext; ParameterContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterParameter(this); } }; ParameterContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitParameter(this); } }; ParameterContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitParameter(this); } else { return (visitor as any).visitChildren(this); } }; function NormalizeContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } NormalizeContext.prototype = Object.create(PrimaryExpressionContext.prototype); NormalizeContext.prototype.constructor = NormalizeContext; SqlBaseParser.NormalizeContext = NormalizeContext; NormalizeContext.prototype.NORMALIZE = function() { return this.getToken(SqlBaseParser.NORMALIZE, 0); }; NormalizeContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; NormalizeContext.prototype.normalForm = function() { return this.getTypedRuleContext(NormalFormContext,0); }; NormalizeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNormalize(this); } }; NormalizeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNormalize(this); } }; NormalizeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNormalize(this); } else { return (visitor as any).visitChildren(this); } }; function IntervalLiteralContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } IntervalLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype); IntervalLiteralContext.prototype.constructor = IntervalLiteralContext; SqlBaseParser.IntervalLiteralContext = IntervalLiteralContext; IntervalLiteralContext.prototype.interval = function() { return this.getTypedRuleContext(IntervalContext,0); }; IntervalLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterIntervalLiteral(this); } }; IntervalLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitIntervalLiteral(this); } }; IntervalLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitIntervalLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function NumericLiteralContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } NumericLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype); NumericLiteralContext.prototype.constructor = NumericLiteralContext; SqlBaseParser.NumericLiteralContext = NumericLiteralContext; NumericLiteralContext.prototype.number = function() { return this.getTypedRuleContext(NumberContext,0); }; NumericLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNumericLiteral(this); } }; NumericLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNumericLiteral(this); } }; NumericLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNumericLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function BooleanLiteralContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } BooleanLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype); BooleanLiteralContext.prototype.constructor = BooleanLiteralContext; SqlBaseParser.BooleanLiteralContext = BooleanLiteralContext; BooleanLiteralContext.prototype.booleanValue = function() { return this.getTypedRuleContext(BooleanValueContext,0); }; BooleanLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBooleanLiteral(this); } }; BooleanLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBooleanLiteral(this); } }; BooleanLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBooleanLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function ImplicitRowConstructorContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ImplicitRowConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype); ImplicitRowConstructorContext.prototype.constructor = ImplicitRowConstructorContext; SqlBaseParser.ImplicitRowConstructorContext = ImplicitRowConstructorContext; ImplicitRowConstructorContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; ImplicitRowConstructorContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterImplicitRowConstructor(this); } }; ImplicitRowConstructorContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitImplicitRowConstructor(this); } }; ImplicitRowConstructorContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitImplicitRowConstructor(this); } else { return (visitor as any).visitChildren(this); } }; function SimpleCaseContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); this.elseExpression = null; // ExpressionContext; PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } SimpleCaseContext.prototype = Object.create(PrimaryExpressionContext.prototype); SimpleCaseContext.prototype.constructor = SimpleCaseContext; SqlBaseParser.SimpleCaseContext = SimpleCaseContext; SimpleCaseContext.prototype.CASE = function() { return this.getToken(SqlBaseParser.CASE, 0); }; SimpleCaseContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; SimpleCaseContext.prototype.END = function() { return this.getToken(SqlBaseParser.END, 0); }; SimpleCaseContext.prototype.whenClause = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(WhenClauseContext); } else { return this.getTypedRuleContext(WhenClauseContext,i); } }; SimpleCaseContext.prototype.ELSE = function() { return this.getToken(SqlBaseParser.ELSE, 0); }; SimpleCaseContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SimpleCaseContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSimpleCase(this); } }; SimpleCaseContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSimpleCase(this); } }; SimpleCaseContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSimpleCase(this); } else { return (visitor as any).visitChildren(this); } }; function ColumnReferenceContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ColumnReferenceContext.prototype = Object.create(PrimaryExpressionContext.prototype); ColumnReferenceContext.prototype.constructor = ColumnReferenceContext; SqlBaseParser.ColumnReferenceContext = ColumnReferenceContext; ColumnReferenceContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; ColumnReferenceContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterColumnReference(this); } }; ColumnReferenceContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitColumnReference(this); } }; ColumnReferenceContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitColumnReference(this); } else { return (visitor as any).visitChildren(this); } }; function NullLiteralContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } NullLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype); NullLiteralContext.prototype.constructor = NullLiteralContext; SqlBaseParser.NullLiteralContext = NullLiteralContext; NullLiteralContext.prototype.NULL = function() { return this.getToken(SqlBaseParser.NULL, 0); }; NullLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNullLiteral(this); } }; NullLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNullLiteral(this); } }; NullLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNullLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function RowConstructorContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } RowConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype); RowConstructorContext.prototype.constructor = RowConstructorContext; SqlBaseParser.RowConstructorContext = RowConstructorContext; RowConstructorContext.prototype.ROW = function() { return this.getToken(SqlBaseParser.ROW, 0); }; RowConstructorContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; RowConstructorContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRowConstructor(this); } }; RowConstructorContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRowConstructor(this); } }; RowConstructorContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRowConstructor(this); } else { return (visitor as any).visitChildren(this); } }; function SubscriptContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); this.value = null; // PrimaryExpressionContext; this.index = null; // ValueExpressionContext; PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } SubscriptContext.prototype = Object.create(PrimaryExpressionContext.prototype); SubscriptContext.prototype.constructor = SubscriptContext; SqlBaseParser.SubscriptContext = SubscriptContext; SubscriptContext.prototype.primaryExpression = function() { return this.getTypedRuleContext(PrimaryExpressionContext,0); }; SubscriptContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; SubscriptContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSubscript(this); } }; SubscriptContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSubscript(this); } }; SubscriptContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSubscript(this); } else { return (visitor as any).visitChildren(this); } }; function SubqueryExpressionContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } SubqueryExpressionContext.prototype = Object.create(PrimaryExpressionContext.prototype); SubqueryExpressionContext.prototype.constructor = SubqueryExpressionContext; SqlBaseParser.SubqueryExpressionContext = SubqueryExpressionContext; SubqueryExpressionContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; SubqueryExpressionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSubqueryExpression(this); } }; SubqueryExpressionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSubqueryExpression(this); } }; SubqueryExpressionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSubqueryExpression(this); } else { return (visitor as any).visitChildren(this); } }; function BinaryLiteralContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } BinaryLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype); BinaryLiteralContext.prototype.constructor = BinaryLiteralContext; SqlBaseParser.BinaryLiteralContext = BinaryLiteralContext; BinaryLiteralContext.prototype.BINARY_LITERAL = function() { return this.getToken(SqlBaseParser.BINARY_LITERAL, 0); }; BinaryLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBinaryLiteral(this); } }; BinaryLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBinaryLiteral(this); } }; BinaryLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBinaryLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function ExtractContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ExtractContext.prototype = Object.create(PrimaryExpressionContext.prototype); ExtractContext.prototype.constructor = ExtractContext; SqlBaseParser.ExtractContext = ExtractContext; ExtractContext.prototype.EXTRACT = function() { return this.getToken(SqlBaseParser.EXTRACT, 0); }; ExtractContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; ExtractContext.prototype.FROM = function() { return this.getToken(SqlBaseParser.FROM, 0); }; ExtractContext.prototype.valueExpression = function() { return this.getTypedRuleContext(ValueExpressionContext,0); }; ExtractContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExtract(this); } }; ExtractContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExtract(this); } }; ExtractContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExtract(this); } else { return (visitor as any).visitChildren(this); } }; function StringLiteralContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } StringLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype); StringLiteralContext.prototype.constructor = StringLiteralContext; SqlBaseParser.StringLiteralContext = StringLiteralContext; StringLiteralContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; StringLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterStringLiteral(this); } }; StringLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitStringLiteral(this); } }; StringLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitStringLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function ArrayConstructorContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ArrayConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype); ArrayConstructorContext.prototype.constructor = ArrayConstructorContext; SqlBaseParser.ArrayConstructorContext = ArrayConstructorContext; ArrayConstructorContext.prototype.ARRAY = function() { return this.getToken(SqlBaseParser.ARRAY, 0); }; ArrayConstructorContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; ArrayConstructorContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterArrayConstructor(this); } }; ArrayConstructorContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitArrayConstructor(this); } }; ArrayConstructorContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitArrayConstructor(this); } else { return (visitor as any).visitChildren(this); } }; function FunctionCallContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } FunctionCallContext.prototype = Object.create(PrimaryExpressionContext.prototype); FunctionCallContext.prototype.constructor = FunctionCallContext; SqlBaseParser.FunctionCallContext = FunctionCallContext; FunctionCallContext.prototype.qualifiedName = function() { return this.getTypedRuleContext(QualifiedNameContext,0); }; FunctionCallContext.prototype.ASTERISK = function() { return this.getToken(SqlBaseParser.ASTERISK, 0); }; FunctionCallContext.prototype.filter = function() { return this.getTypedRuleContext(FilterContext,0); }; FunctionCallContext.prototype.over = function() { return this.getTypedRuleContext(OverContext,0); }; FunctionCallContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; FunctionCallContext.prototype.setQuantifier = function() { return this.getTypedRuleContext(SetQuantifierContext,0); }; FunctionCallContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterFunctionCall(this); } }; FunctionCallContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitFunctionCall(this); } }; FunctionCallContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitFunctionCall(this); } else { return (visitor as any).visitChildren(this); } }; function ExistsContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } ExistsContext.prototype = Object.create(PrimaryExpressionContext.prototype); ExistsContext.prototype.constructor = ExistsContext; SqlBaseParser.ExistsContext = ExistsContext; ExistsContext.prototype.EXISTS = function() { return this.getToken(SqlBaseParser.EXISTS, 0); }; ExistsContext.prototype.query = function() { return this.getTypedRuleContext(QueryContext,0); }; ExistsContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExists(this); } }; ExistsContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExists(this); } }; ExistsContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExists(this); } else { return (visitor as any).visitChildren(this); } }; function PositionContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } PositionContext.prototype = Object.create(PrimaryExpressionContext.prototype); PositionContext.prototype.constructor = PositionContext; SqlBaseParser.PositionContext = PositionContext; PositionContext.prototype.POSITION = function() { return this.getToken(SqlBaseParser.POSITION, 0); }; PositionContext.prototype.valueExpression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ValueExpressionContext); } else { return this.getTypedRuleContext(ValueExpressionContext,i); } }; PositionContext.prototype.IN = function() { return this.getToken(SqlBaseParser.IN, 0); }; PositionContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterPosition(this); } }; PositionContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitPosition(this); } }; PositionContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitPosition(this); } else { return (visitor as any).visitChildren(this); } }; function SearchedCaseContext(parser, ctx) { PrimaryExpressionContext.call(this, parser); this.elseExpression = null; // ExpressionContext; PrimaryExpressionContext.prototype.copyFrom.call(this, ctx); // return this; } SearchedCaseContext.prototype = Object.create(PrimaryExpressionContext.prototype); SearchedCaseContext.prototype.constructor = SearchedCaseContext; SqlBaseParser.SearchedCaseContext = SearchedCaseContext; SearchedCaseContext.prototype.CASE = function() { return this.getToken(SqlBaseParser.CASE, 0); }; SearchedCaseContext.prototype.END = function() { return this.getToken(SqlBaseParser.END, 0); }; SearchedCaseContext.prototype.whenClause = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(WhenClauseContext); } else { return this.getTypedRuleContext(WhenClauseContext,i); } }; SearchedCaseContext.prototype.ELSE = function() { return this.getToken(SqlBaseParser.ELSE, 0); }; SearchedCaseContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; SearchedCaseContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSearchedCase(this); } }; SearchedCaseContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSearchedCase(this); } }; SearchedCaseContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSearchedCase(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.prototype.primaryExpression = function(_p) { if(_p===undefined) { _p = 0; } var _parentctx = this._ctx; var _parentState = this.state; var localctx = new PrimaryExpressionContext(this, this._ctx, _parentState); var _prevctx = localctx; var _startState = 72; this.enterRecursionRule(localctx, 72, SqlBaseParser.RULE_primaryExpression, _p); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1179; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,144,this._ctx); switch(la_) { case 1: localctx = new NullLiteralContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 974; this.match(SqlBaseParser.NULL); break; case 2: localctx = new IntervalLiteralContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 975; this.interval(); break; case 3: localctx = new TypeConstructorContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 976; this.identifier(); this.state = 977; this.match(SqlBaseParser.STRING); break; case 4: localctx = new TypeConstructorContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 979; this.match(SqlBaseParser.DOUBLE_PRECISION); this.state = 980; this.match(SqlBaseParser.STRING); break; case 5: localctx = new NumericLiteralContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 981; this.number(); break; case 6: localctx = new BooleanLiteralContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 982; this.booleanValue(); break; case 7: localctx = new StringLiteralContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 983; this.match(SqlBaseParser.STRING); break; case 8: localctx = new BinaryLiteralContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 984; this.match(SqlBaseParser.BINARY_LITERAL); break; case 9: localctx = new ParameterContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 985; this.match(SqlBaseParser.T__4); break; case 10: localctx = new PositionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 986; this.match(SqlBaseParser.POSITION); this.state = 987; this.match(SqlBaseParser.T__1); this.state = 988; this.valueExpression(0); this.state = 989; this.match(SqlBaseParser.IN); this.state = 990; this.valueExpression(0); this.state = 991; this.match(SqlBaseParser.T__3); break; case 11: localctx = new ImplicitRowConstructorContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 993; this.match(SqlBaseParser.T__1); this.state = 994; this.expression(); this.state = 999; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 995; this.match(SqlBaseParser.T__2); this.state = 996; this.expression(); this.state = 1001; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 1002; this.match(SqlBaseParser.T__3); break; case 12: localctx = new RowConstructorContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1004; this.match(SqlBaseParser.ROW); this.state = 1005; this.match(SqlBaseParser.T__1); this.state = 1006; this.expression(); this.state = 1011; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1007; this.match(SqlBaseParser.T__2); this.state = 1008; this.expression(); this.state = 1013; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 1014; this.match(SqlBaseParser.T__3); break; case 13: localctx = new FunctionCallContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1016; this.qualifiedName(); this.state = 1017; this.match(SqlBaseParser.T__1); this.state = 1018; this.match(SqlBaseParser.ASTERISK); this.state = 1019; this.match(SqlBaseParser.T__3); this.state = 1021; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,124,this._ctx); if(la_===1) { this.state = 1020; this.filter(); } this.state = 1024; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,125,this._ctx); if(la_===1) { this.state = 1023; this.over(); } break; case 14: localctx = new FunctionCallContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1026; this.qualifiedName(); this.state = 1027; this.match(SqlBaseParser.T__1); this.state = 1039; this._errHandler.sync(this); _la = this._input.LA(1); if((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << SqlBaseParser.T__1) | (1 << SqlBaseParser.T__4) | (1 << SqlBaseParser.ADD) | (1 << SqlBaseParser.ALL) | (1 << SqlBaseParser.DISTINCT))) !== 0) || ((((_la - 32)) & ~0x1f) == 0 && ((1 << (_la - 32)) & ((1 << (SqlBaseParser.NOT - 32)) | (1 << (SqlBaseParser.NO - 32)) | (1 << (SqlBaseParser.EXISTS - 32)) | (1 << (SqlBaseParser.NULL - 32)) | (1 << (SqlBaseParser.TRUE - 32)) | (1 << (SqlBaseParser.FALSE - 32)) | (1 << (SqlBaseParser.SUBSTRING - 32)) | (1 << (SqlBaseParser.POSITION - 32)) | (1 << (SqlBaseParser.TINYINT - 32)) | (1 << (SqlBaseParser.SMALLINT - 32)) | (1 << (SqlBaseParser.INTEGER - 32)) | (1 << (SqlBaseParser.DATE - 32)) | (1 << (SqlBaseParser.TIME - 32)) | (1 << (SqlBaseParser.TIMESTAMP - 32)) | (1 << (SqlBaseParser.INTERVAL - 32)) | (1 << (SqlBaseParser.YEAR - 32)) | (1 << (SqlBaseParser.MONTH - 32)) | (1 << (SqlBaseParser.DAY - 32)) | (1 << (SqlBaseParser.HOUR - 32)) | (1 << (SqlBaseParser.MINUTE - 32)) | (1 << (SqlBaseParser.SECOND - 32)) | (1 << (SqlBaseParser.ZONE - 32)))) !== 0) || ((((_la - 64)) & ~0x1f) == 0 && ((1 << (_la - 64)) & ((1 << (SqlBaseParser.CURRENT_DATE - 64)) | (1 << (SqlBaseParser.CURRENT_TIME - 64)) | (1 << (SqlBaseParser.CURRENT_TIMESTAMP - 64)) | (1 << (SqlBaseParser.LOCALTIME - 64)) | (1 << (SqlBaseParser.LOCALTIMESTAMP - 64)) | (1 << (SqlBaseParser.EXTRACT - 64)) | (1 << (SqlBaseParser.CASE - 64)) | (1 << (SqlBaseParser.FILTER - 64)) | (1 << (SqlBaseParser.OVER - 64)) | (1 << (SqlBaseParser.PARTITION - 64)) | (1 << (SqlBaseParser.RANGE - 64)) | (1 << (SqlBaseParser.ROWS - 64)) | (1 << (SqlBaseParser.PRECEDING - 64)) | (1 << (SqlBaseParser.FOLLOWING - 64)) | (1 << (SqlBaseParser.CURRENT - 64)) | (1 << (SqlBaseParser.ROW - 64)))) !== 0) || ((((_la - 99)) & ~0x1f) == 0 && ((1 << (_la - 99)) & ((1 << (SqlBaseParser.SCHEMA - 99)) | (1 << (SqlBaseParser.VIEW - 99)) | (1 << (SqlBaseParser.REPLACE - 99)) | (1 << (SqlBaseParser.GRANT - 99)) | (1 << (SqlBaseParser.REVOKE - 99)) | (1 << (SqlBaseParser.PRIVILEGES - 99)) | (1 << (SqlBaseParser.PUBLIC - 99)) | (1 << (SqlBaseParser.OPTION - 99)) | (1 << (SqlBaseParser.EXPLAIN - 99)) | (1 << (SqlBaseParser.ANALYZE - 99)) | (1 << (SqlBaseParser.FORMAT - 99)) | (1 << (SqlBaseParser.TYPE - 99)) | (1 << (SqlBaseParser.TEXT - 99)) | (1 << (SqlBaseParser.GRAPHVIZ - 99)) | (1 << (SqlBaseParser.LOGICAL - 99)) | (1 << (SqlBaseParser.DISTRIBUTED - 99)) | (1 << (SqlBaseParser.CAST - 99)) | (1 << (SqlBaseParser.TRY_CAST - 99)) | (1 << (SqlBaseParser.SHOW - 99)) | (1 << (SqlBaseParser.TABLES - 99)) | (1 << (SqlBaseParser.SCHEMAS - 99)) | (1 << (SqlBaseParser.CATALOGS - 99)) | (1 << (SqlBaseParser.COLUMNS - 99)) | (1 << (SqlBaseParser.COLUMN - 99)) | (1 << (SqlBaseParser.USE - 99)) | (1 << (SqlBaseParser.PARTITIONS - 99)))) !== 0) || ((((_la - 131)) & ~0x1f) == 0 && ((1 << (_la - 131)) & ((1 << (SqlBaseParser.FUNCTIONS - 131)) | (1 << (SqlBaseParser.TO - 131)) | (1 << (SqlBaseParser.SYSTEM - 131)) | (1 << (SqlBaseParser.BERNOULLI - 131)) | (1 << (SqlBaseParser.POISSONIZED - 131)) | (1 << (SqlBaseParser.TABLESAMPLE - 131)) | (1 << (SqlBaseParser.ARRAY - 131)) | (1 << (SqlBaseParser.MAP - 131)) | (1 << (SqlBaseParser.SET - 131)) | (1 << (SqlBaseParser.RESET - 131)) | (1 << (SqlBaseParser.SESSION - 131)) | (1 << (SqlBaseParser.DATA - 131)) | (1 << (SqlBaseParser.START - 131)) | (1 << (SqlBaseParser.TRANSACTION - 131)) | (1 << (SqlBaseParser.COMMIT - 131)) | (1 << (SqlBaseParser.ROLLBACK - 131)) | (1 << (SqlBaseParser.WORK - 131)) | (1 << (SqlBaseParser.ISOLATION - 131)) | (1 << (SqlBaseParser.LEVEL - 131)) | (1 << (SqlBaseParser.SERIALIZABLE - 131)) | (1 << (SqlBaseParser.REPEATABLE - 131)) | (1 << (SqlBaseParser.COMMITTED - 131)) | (1 << (SqlBaseParser.UNCOMMITTED - 131)) | (1 << (SqlBaseParser.READ - 131)))) !== 0) || ((((_la - 163)) & ~0x1f) == 0 && ((1 << (_la - 163)) & ((1 << (SqlBaseParser.WRITE - 163)) | (1 << (SqlBaseParser.ONLY - 163)) | (1 << (SqlBaseParser.CALL - 163)) | (1 << (SqlBaseParser.INPUT - 163)) | (1 << (SqlBaseParser.OUTPUT - 163)) | (1 << (SqlBaseParser.CASCADE - 163)) | (1 << (SqlBaseParser.RESTRICT - 163)) | (1 << (SqlBaseParser.INCLUDING - 163)) | (1 << (SqlBaseParser.EXCLUDING - 163)) | (1 << (SqlBaseParser.PROPERTIES - 163)) | (1 << (SqlBaseParser.NORMALIZE - 163)) | (1 << (SqlBaseParser.NFD - 163)) | (1 << (SqlBaseParser.NFC - 163)) | (1 << (SqlBaseParser.NFKD - 163)) | (1 << (SqlBaseParser.NFKC - 163)) | (1 << (SqlBaseParser.IF - 163)) | (1 << (SqlBaseParser.NULLIF - 163)) | (1 << (SqlBaseParser.COALESCE - 163)) | (1 << (SqlBaseParser.PLUS - 163)) | (1 << (SqlBaseParser.MINUS - 163)))) !== 0) || ((((_la - 196)) & ~0x1f) == 0 && ((1 << (_la - 196)) & ((1 << (SqlBaseParser.STRING - 196)) | (1 << (SqlBaseParser.BINARY_LITERAL - 196)) | (1 << (SqlBaseParser.INTEGER_VALUE - 196)) | (1 << (SqlBaseParser.DECIMAL_VALUE - 196)) | (1 << (SqlBaseParser.IDENTIFIER - 196)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 196)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.DOUBLE_PRECISION - 196)))) !== 0)) { this.state = 1029; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) { this.state = 1028; this.setQuantifier(); } this.state = 1031; this.expression(); this.state = 1036; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1032; this.match(SqlBaseParser.T__2); this.state = 1033; this.expression(); this.state = 1038; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 1041; this.match(SqlBaseParser.T__3); this.state = 1043; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,129,this._ctx); if(la_===1) { this.state = 1042; this.filter(); } this.state = 1046; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,130,this._ctx); if(la_===1) { this.state = 1045; this.over(); } break; case 15: localctx = new LambdaContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1048; this.identifier(); this.state = 1049; this.match(SqlBaseParser.T__5); this.state = 1050; this.expression(); break; case 16: localctx = new LambdaContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1052; this.match(SqlBaseParser.T__1); this.state = 1053; this.identifier(); this.state = 1058; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1054; this.match(SqlBaseParser.T__2); this.state = 1055; this.identifier(); this.state = 1060; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 1061; this.match(SqlBaseParser.T__3); this.state = 1062; this.match(SqlBaseParser.T__5); this.state = 1063; this.expression(); break; case 17: localctx = new SubqueryExpressionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1065; this.match(SqlBaseParser.T__1); this.state = 1066; this.query(); this.state = 1067; this.match(SqlBaseParser.T__3); break; case 18: localctx = new ExistsContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1069; this.match(SqlBaseParser.EXISTS); this.state = 1070; this.match(SqlBaseParser.T__1); this.state = 1071; this.query(); this.state = 1072; this.match(SqlBaseParser.T__3); break; case 19: localctx = new SimpleCaseContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1074; this.match(SqlBaseParser.CASE); this.state = 1075; this.valueExpression(0); this.state = 1077; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 1076; this.whenClause(); this.state = 1079; this._errHandler.sync(this); _la = this._input.LA(1); } while(_la===SqlBaseParser.WHEN); this.state = 1083; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ELSE) { this.state = 1081; this.match(SqlBaseParser.ELSE); this.state = 1082; localctx.elseExpression = this.expression(); } this.state = 1085; this.match(SqlBaseParser.END); break; case 20: localctx = new SearchedCaseContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1087; this.match(SqlBaseParser.CASE); this.state = 1089; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 1088; this.whenClause(); this.state = 1091; this._errHandler.sync(this); _la = this._input.LA(1); } while(_la===SqlBaseParser.WHEN); this.state = 1095; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ELSE) { this.state = 1093; this.match(SqlBaseParser.ELSE); this.state = 1094; localctx.elseExpression = this.expression(); } this.state = 1097; this.match(SqlBaseParser.END); break; case 21: localctx = new CastContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1099; this.match(SqlBaseParser.CAST); this.state = 1100; this.match(SqlBaseParser.T__1); this.state = 1101; this.expression(); this.state = 1102; this.match(SqlBaseParser.AS); this.state = 1103; this.type(0); this.state = 1104; this.match(SqlBaseParser.T__3); break; case 22: localctx = new CastContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1106; this.match(SqlBaseParser.TRY_CAST); this.state = 1107; this.match(SqlBaseParser.T__1); this.state = 1108; this.expression(); this.state = 1109; this.match(SqlBaseParser.AS); this.state = 1110; this.type(0); this.state = 1111; this.match(SqlBaseParser.T__3); break; case 23: localctx = new ArrayConstructorContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1113; this.match(SqlBaseParser.ARRAY); this.state = 1114; this.match(SqlBaseParser.T__6); this.state = 1123; this._errHandler.sync(this); _la = this._input.LA(1); if((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << SqlBaseParser.T__1) | (1 << SqlBaseParser.T__4) | (1 << SqlBaseParser.ADD))) !== 0) || ((((_la - 32)) & ~0x1f) == 0 && ((1 << (_la - 32)) & ((1 << (SqlBaseParser.NOT - 32)) | (1 << (SqlBaseParser.NO - 32)) | (1 << (SqlBaseParser.EXISTS - 32)) | (1 << (SqlBaseParser.NULL - 32)) | (1 << (SqlBaseParser.TRUE - 32)) | (1 << (SqlBaseParser.FALSE - 32)) | (1 << (SqlBaseParser.SUBSTRING - 32)) | (1 << (SqlBaseParser.POSITION - 32)) | (1 << (SqlBaseParser.TINYINT - 32)) | (1 << (SqlBaseParser.SMALLINT - 32)) | (1 << (SqlBaseParser.INTEGER - 32)) | (1 << (SqlBaseParser.DATE - 32)) | (1 << (SqlBaseParser.TIME - 32)) | (1 << (SqlBaseParser.TIMESTAMP - 32)) | (1 << (SqlBaseParser.INTERVAL - 32)) | (1 << (SqlBaseParser.YEAR - 32)) | (1 << (SqlBaseParser.MONTH - 32)) | (1 << (SqlBaseParser.DAY - 32)) | (1 << (SqlBaseParser.HOUR - 32)) | (1 << (SqlBaseParser.MINUTE - 32)) | (1 << (SqlBaseParser.SECOND - 32)) | (1 << (SqlBaseParser.ZONE - 32)))) !== 0) || ((((_la - 64)) & ~0x1f) == 0 && ((1 << (_la - 64)) & ((1 << (SqlBaseParser.CURRENT_DATE - 64)) | (1 << (SqlBaseParser.CURRENT_TIME - 64)) | (1 << (SqlBaseParser.CURRENT_TIMESTAMP - 64)) | (1 << (SqlBaseParser.LOCALTIME - 64)) | (1 << (SqlBaseParser.LOCALTIMESTAMP - 64)) | (1 << (SqlBaseParser.EXTRACT - 64)) | (1 << (SqlBaseParser.CASE - 64)) | (1 << (SqlBaseParser.FILTER - 64)) | (1 << (SqlBaseParser.OVER - 64)) | (1 << (SqlBaseParser.PARTITION - 64)) | (1 << (SqlBaseParser.RANGE - 64)) | (1 << (SqlBaseParser.ROWS - 64)) | (1 << (SqlBaseParser.PRECEDING - 64)) | (1 << (SqlBaseParser.FOLLOWING - 64)) | (1 << (SqlBaseParser.CURRENT - 64)) | (1 << (SqlBaseParser.ROW - 64)))) !== 0) || ((((_la - 99)) & ~0x1f) == 0 && ((1 << (_la - 99)) & ((1 << (SqlBaseParser.SCHEMA - 99)) | (1 << (SqlBaseParser.VIEW - 99)) | (1 << (SqlBaseParser.REPLACE - 99)) | (1 << (SqlBaseParser.GRANT - 99)) | (1 << (SqlBaseParser.REVOKE - 99)) | (1 << (SqlBaseParser.PRIVILEGES - 99)) | (1 << (SqlBaseParser.PUBLIC - 99)) | (1 << (SqlBaseParser.OPTION - 99)) | (1 << (SqlBaseParser.EXPLAIN - 99)) | (1 << (SqlBaseParser.ANALYZE - 99)) | (1 << (SqlBaseParser.FORMAT - 99)) | (1 << (SqlBaseParser.TYPE - 99)) | (1 << (SqlBaseParser.TEXT - 99)) | (1 << (SqlBaseParser.GRAPHVIZ - 99)) | (1 << (SqlBaseParser.LOGICAL - 99)) | (1 << (SqlBaseParser.DISTRIBUTED - 99)) | (1 << (SqlBaseParser.CAST - 99)) | (1 << (SqlBaseParser.TRY_CAST - 99)) | (1 << (SqlBaseParser.SHOW - 99)) | (1 << (SqlBaseParser.TABLES - 99)) | (1 << (SqlBaseParser.SCHEMAS - 99)) | (1 << (SqlBaseParser.CATALOGS - 99)) | (1 << (SqlBaseParser.COLUMNS - 99)) | (1 << (SqlBaseParser.COLUMN - 99)) | (1 << (SqlBaseParser.USE - 99)) | (1 << (SqlBaseParser.PARTITIONS - 99)))) !== 0) || ((((_la - 131)) & ~0x1f) == 0 && ((1 << (_la - 131)) & ((1 << (SqlBaseParser.FUNCTIONS - 131)) | (1 << (SqlBaseParser.TO - 131)) | (1 << (SqlBaseParser.SYSTEM - 131)) | (1 << (SqlBaseParser.BERNOULLI - 131)) | (1 << (SqlBaseParser.POISSONIZED - 131)) | (1 << (SqlBaseParser.TABLESAMPLE - 131)) | (1 << (SqlBaseParser.ARRAY - 131)) | (1 << (SqlBaseParser.MAP - 131)) | (1 << (SqlBaseParser.SET - 131)) | (1 << (SqlBaseParser.RESET - 131)) | (1 << (SqlBaseParser.SESSION - 131)) | (1 << (SqlBaseParser.DATA - 131)) | (1 << (SqlBaseParser.START - 131)) | (1 << (SqlBaseParser.TRANSACTION - 131)) | (1 << (SqlBaseParser.COMMIT - 131)) | (1 << (SqlBaseParser.ROLLBACK - 131)) | (1 << (SqlBaseParser.WORK - 131)) | (1 << (SqlBaseParser.ISOLATION - 131)) | (1 << (SqlBaseParser.LEVEL - 131)) | (1 << (SqlBaseParser.SERIALIZABLE - 131)) | (1 << (SqlBaseParser.REPEATABLE - 131)) | (1 << (SqlBaseParser.COMMITTED - 131)) | (1 << (SqlBaseParser.UNCOMMITTED - 131)) | (1 << (SqlBaseParser.READ - 131)))) !== 0) || ((((_la - 163)) & ~0x1f) == 0 && ((1 << (_la - 163)) & ((1 << (SqlBaseParser.WRITE - 163)) | (1 << (SqlBaseParser.ONLY - 163)) | (1 << (SqlBaseParser.CALL - 163)) | (1 << (SqlBaseParser.INPUT - 163)) | (1 << (SqlBaseParser.OUTPUT - 163)) | (1 << (SqlBaseParser.CASCADE - 163)) | (1 << (SqlBaseParser.RESTRICT - 163)) | (1 << (SqlBaseParser.INCLUDING - 163)) | (1 << (SqlBaseParser.EXCLUDING - 163)) | (1 << (SqlBaseParser.PROPERTIES - 163)) | (1 << (SqlBaseParser.NORMALIZE - 163)) | (1 << (SqlBaseParser.NFD - 163)) | (1 << (SqlBaseParser.NFC - 163)) | (1 << (SqlBaseParser.NFKD - 163)) | (1 << (SqlBaseParser.NFKC - 163)) | (1 << (SqlBaseParser.IF - 163)) | (1 << (SqlBaseParser.NULLIF - 163)) | (1 << (SqlBaseParser.COALESCE - 163)) | (1 << (SqlBaseParser.PLUS - 163)) | (1 << (SqlBaseParser.MINUS - 163)))) !== 0) || ((((_la - 196)) & ~0x1f) == 0 && ((1 << (_la - 196)) & ((1 << (SqlBaseParser.STRING - 196)) | (1 << (SqlBaseParser.BINARY_LITERAL - 196)) | (1 << (SqlBaseParser.INTEGER_VALUE - 196)) | (1 << (SqlBaseParser.DECIMAL_VALUE - 196)) | (1 << (SqlBaseParser.IDENTIFIER - 196)) | (1 << (SqlBaseParser.DIGIT_IDENTIFIER - 196)) | (1 << (SqlBaseParser.QUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.BACKQUOTED_IDENTIFIER - 196)) | (1 << (SqlBaseParser.DOUBLE_PRECISION - 196)))) !== 0)) { this.state = 1115; this.expression(); this.state = 1120; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1116; this.match(SqlBaseParser.T__2); this.state = 1117; this.expression(); this.state = 1122; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 1125; this.match(SqlBaseParser.T__7); break; case 24: localctx = new ColumnReferenceContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1126; this.identifier(); break; case 25: localctx = new SpecialDateTimeFunctionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1127; localctx.name = this.match(SqlBaseParser.CURRENT_DATE); break; case 26: localctx = new SpecialDateTimeFunctionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1128; localctx.name = this.match(SqlBaseParser.CURRENT_TIME); this.state = 1132; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,138,this._ctx); if(la_===1) { this.state = 1129; this.match(SqlBaseParser.T__1); this.state = 1130; localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE); this.state = 1131; this.match(SqlBaseParser.T__3); } break; case 27: localctx = new SpecialDateTimeFunctionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1134; localctx.name = this.match(SqlBaseParser.CURRENT_TIMESTAMP); this.state = 1138; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,139,this._ctx); if(la_===1) { this.state = 1135; this.match(SqlBaseParser.T__1); this.state = 1136; localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE); this.state = 1137; this.match(SqlBaseParser.T__3); } break; case 28: localctx = new SpecialDateTimeFunctionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1140; localctx.name = this.match(SqlBaseParser.LOCALTIME); this.state = 1144; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,140,this._ctx); if(la_===1) { this.state = 1141; this.match(SqlBaseParser.T__1); this.state = 1142; localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE); this.state = 1143; this.match(SqlBaseParser.T__3); } break; case 29: localctx = new SpecialDateTimeFunctionContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1146; localctx.name = this.match(SqlBaseParser.LOCALTIMESTAMP); this.state = 1150; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,141,this._ctx); if(la_===1) { this.state = 1147; this.match(SqlBaseParser.T__1); this.state = 1148; localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE); this.state = 1149; this.match(SqlBaseParser.T__3); } break; case 30: localctx = new SubstringContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1152; this.match(SqlBaseParser.SUBSTRING); this.state = 1153; this.match(SqlBaseParser.T__1); this.state = 1154; this.valueExpression(0); this.state = 1155; this.match(SqlBaseParser.FROM); this.state = 1156; this.valueExpression(0); this.state = 1159; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.FOR) { this.state = 1157; this.match(SqlBaseParser.FOR); this.state = 1158; this.valueExpression(0); } this.state = 1161; this.match(SqlBaseParser.T__3); break; case 31: localctx = new NormalizeContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1163; this.match(SqlBaseParser.NORMALIZE); this.state = 1164; this.match(SqlBaseParser.T__1); this.state = 1165; this.valueExpression(0); this.state = 1168; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.T__2) { this.state = 1166; this.match(SqlBaseParser.T__2); this.state = 1167; this.normalForm(); } this.state = 1170; this.match(SqlBaseParser.T__3); break; case 32: localctx = new ExtractContext(this, localctx); this._ctx = localctx; _prevctx = localctx; this.state = 1172; this.match(SqlBaseParser.EXTRACT); this.state = 1173; this.match(SqlBaseParser.T__1); this.state = 1174; this.identifier(); this.state = 1175; this.match(SqlBaseParser.FROM); this.state = 1176; this.valueExpression(0); this.state = 1177; this.match(SqlBaseParser.T__3); break; } this._ctx.stop = this._input.LT(-1); this.state = 1191; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,146,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { if(this._parseListeners!==null) { this.triggerExitRuleEvent(); } _prevctx = localctx; this.state = 1189; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,145,this._ctx); switch(la_) { case 1: localctx = new SubscriptContext(this, new PrimaryExpressionContext(this, _parentctx, _parentState)); localctx.value = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_primaryExpression); this.state = 1181; if (!( this.precpred(this._ctx, 11))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 11)"); } this.state = 1182; this.match(SqlBaseParser.T__6); this.state = 1183; localctx.index = this.valueExpression(0); this.state = 1184; this.match(SqlBaseParser.T__7); break; case 2: localctx = new DereferenceContext(this, new PrimaryExpressionContext(this, _parentctx, _parentState)); localctx.base = _prevctx; this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_primaryExpression); this.state = 1186; if (!( this.precpred(this._ctx, 9))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 9)"); } this.state = 1187; this.match(SqlBaseParser.T__0); this.state = 1188; localctx.fieldName = this.identifier(); break; } } this.state = 1193; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,146,this._ctx); } } catch( error) { if(error instanceof _error.RecognitionException) { localctx.exception = error; this._errHandler.reportError(this, error); this._errHandler.recover(this, error); } else { throw error; } } finally { this.unrollRecursionContexts(_parentctx) } return localctx; }; function TimeZoneSpecifierContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_timeZoneSpecifier; // return this; } TimeZoneSpecifierContext.prototype = Object.create(ParserRuleContext.prototype); TimeZoneSpecifierContext.prototype.constructor = TimeZoneSpecifierContext; TimeZoneSpecifierContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function TimeZoneIntervalContext(parser, ctx) { TimeZoneSpecifierContext.call(this, parser); TimeZoneSpecifierContext.prototype.copyFrom.call(this, ctx); // return this; } TimeZoneIntervalContext.prototype = Object.create(TimeZoneSpecifierContext.prototype); TimeZoneIntervalContext.prototype.constructor = TimeZoneIntervalContext; SqlBaseParser.TimeZoneIntervalContext = TimeZoneIntervalContext; TimeZoneIntervalContext.prototype.TIME = function() { return this.getToken(SqlBaseParser.TIME, 0); }; TimeZoneIntervalContext.prototype.ZONE = function() { return this.getToken(SqlBaseParser.ZONE, 0); }; TimeZoneIntervalContext.prototype.interval = function() { return this.getTypedRuleContext(IntervalContext,0); }; TimeZoneIntervalContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTimeZoneInterval(this); } }; TimeZoneIntervalContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTimeZoneInterval(this); } }; TimeZoneIntervalContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTimeZoneInterval(this); } else { return (visitor as any).visitChildren(this); } }; function TimeZoneStringContext(parser, ctx) { TimeZoneSpecifierContext.call(this, parser); TimeZoneSpecifierContext.prototype.copyFrom.call(this, ctx); // return this; } TimeZoneStringContext.prototype = Object.create(TimeZoneSpecifierContext.prototype); TimeZoneStringContext.prototype.constructor = TimeZoneStringContext; SqlBaseParser.TimeZoneStringContext = TimeZoneStringContext; TimeZoneStringContext.prototype.TIME = function() { return this.getToken(SqlBaseParser.TIME, 0); }; TimeZoneStringContext.prototype.ZONE = function() { return this.getToken(SqlBaseParser.ZONE, 0); }; TimeZoneStringContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; TimeZoneStringContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTimeZoneString(this); } }; TimeZoneStringContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTimeZoneString(this); } }; TimeZoneStringContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTimeZoneString(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.TimeZoneSpecifierContext = TimeZoneSpecifierContext; SqlBaseParser.prototype.timeZoneSpecifier = function() { var localctx = new TimeZoneSpecifierContext(this, this._ctx, this.state); this.enterRule(localctx, 74, SqlBaseParser.RULE_timeZoneSpecifier); try { this.state = 1200; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,147,this._ctx); switch(la_) { case 1: localctx = new TimeZoneIntervalContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1194; this.match(SqlBaseParser.TIME); this.state = 1195; this.match(SqlBaseParser.ZONE); this.state = 1196; this.interval(); break; case 2: localctx = new TimeZoneStringContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1197; this.match(SqlBaseParser.TIME); this.state = 1198; this.match(SqlBaseParser.ZONE); this.state = 1199; this.match(SqlBaseParser.STRING); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ComparisonOperatorContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_comparisonOperator; // return this; } ComparisonOperatorContext.prototype = Object.create(ParserRuleContext.prototype); ComparisonOperatorContext.prototype.constructor = ComparisonOperatorContext; ComparisonOperatorContext.prototype.EQ = function() { return this.getToken(SqlBaseParser.EQ, 0); }; ComparisonOperatorContext.prototype.NEQ = function() { return this.getToken(SqlBaseParser.NEQ, 0); }; ComparisonOperatorContext.prototype.LT = function() { return this.getToken(SqlBaseParser.LT, 0); }; ComparisonOperatorContext.prototype.LTE = function() { return this.getToken(SqlBaseParser.LTE, 0); }; ComparisonOperatorContext.prototype.GT = function() { return this.getToken(SqlBaseParser.GT, 0); }; ComparisonOperatorContext.prototype.GTE = function() { return this.getToken(SqlBaseParser.GTE, 0); }; ComparisonOperatorContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterComparisonOperator(this); } }; ComparisonOperatorContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitComparisonOperator(this); } }; ComparisonOperatorContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitComparisonOperator(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.ComparisonOperatorContext = ComparisonOperatorContext; SqlBaseParser.prototype.comparisonOperator = function() { var localctx = new ComparisonOperatorContext(this, this._ctx, this.state); this.enterRule(localctx, 76, SqlBaseParser.RULE_comparisonOperator); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1202; _la = this._input.LA(1); if(!(((((_la - 184)) & ~0x1f) == 0 && ((1 << (_la - 184)) & ((1 << (SqlBaseParser.EQ - 184)) | (1 << (SqlBaseParser.NEQ - 184)) | (1 << (SqlBaseParser.LT - 184)) | (1 << (SqlBaseParser.LTE - 184)) | (1 << (SqlBaseParser.GT - 184)) | (1 << (SqlBaseParser.GTE - 184)))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ComparisonQuantifierContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_comparisonQuantifier; // return this; } ComparisonQuantifierContext.prototype = Object.create(ParserRuleContext.prototype); ComparisonQuantifierContext.prototype.constructor = ComparisonQuantifierContext; ComparisonQuantifierContext.prototype.ALL = function() { return this.getToken(SqlBaseParser.ALL, 0); }; ComparisonQuantifierContext.prototype.SOME = function() { return this.getToken(SqlBaseParser.SOME, 0); }; ComparisonQuantifierContext.prototype.ANY = function() { return this.getToken(SqlBaseParser.ANY, 0); }; ComparisonQuantifierContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterComparisonQuantifier(this); } }; ComparisonQuantifierContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitComparisonQuantifier(this); } }; ComparisonQuantifierContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitComparisonQuantifier(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.ComparisonQuantifierContext = ComparisonQuantifierContext; SqlBaseParser.prototype.comparisonQuantifier = function() { var localctx = new ComparisonQuantifierContext(this, this._ctx, this.state); this.enterRule(localctx, 78, SqlBaseParser.RULE_comparisonQuantifier); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1204; _la = this._input.LA(1); if(!((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << SqlBaseParser.ALL) | (1 << SqlBaseParser.SOME) | (1 << SqlBaseParser.ANY))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function BooleanValueContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_booleanValue; // return this; } BooleanValueContext.prototype = Object.create(ParserRuleContext.prototype); BooleanValueContext.prototype.constructor = BooleanValueContext; BooleanValueContext.prototype.TRUE = function() { return this.getToken(SqlBaseParser.TRUE, 0); }; BooleanValueContext.prototype.FALSE = function() { return this.getToken(SqlBaseParser.FALSE, 0); }; BooleanValueContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBooleanValue(this); } }; BooleanValueContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBooleanValue(this); } }; BooleanValueContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBooleanValue(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.BooleanValueContext = BooleanValueContext; SqlBaseParser.prototype.booleanValue = function() { var localctx = new BooleanValueContext(this, this._ctx, this.state); this.enterRule(localctx, 80, SqlBaseParser.RULE_booleanValue); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1206; _la = this._input.LA(1); if(!(_la===SqlBaseParser.TRUE || _la===SqlBaseParser.FALSE)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function IntervalContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_interval; this.sign = null; // Token this.from = null; // IntervalFieldContext this.to = null; // IntervalFieldContext // return this; } IntervalContext.prototype = Object.create(ParserRuleContext.prototype); IntervalContext.prototype.constructor = IntervalContext; IntervalContext.prototype.INTERVAL = function() { return this.getToken(SqlBaseParser.INTERVAL, 0); }; IntervalContext.prototype.STRING = function() { return this.getToken(SqlBaseParser.STRING, 0); }; IntervalContext.prototype.intervalField = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IntervalFieldContext); } else { return this.getTypedRuleContext(IntervalFieldContext,i); } }; IntervalContext.prototype.TO = function() { return this.getToken(SqlBaseParser.TO, 0); }; IntervalContext.prototype.PLUS = function() { return this.getToken(SqlBaseParser.PLUS, 0); }; IntervalContext.prototype.MINUS = function() { return this.getToken(SqlBaseParser.MINUS, 0); }; IntervalContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterInterval(this); } }; IntervalContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitInterval(this); } }; IntervalContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitInterval(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.IntervalContext = IntervalContext; SqlBaseParser.prototype.interval = function() { var localctx = new IntervalContext(this, this._ctx, this.state); this.enterRule(localctx, 82, SqlBaseParser.RULE_interval); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1208; this.match(SqlBaseParser.INTERVAL); this.state = 1210; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS) { this.state = 1209; localctx.sign = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS)) { localctx.sign = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } this.state = 1212; this.match(SqlBaseParser.STRING); this.state = 1213; localctx.from = this.intervalField(); this.state = 1216; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,149,this._ctx); if(la_===1) { this.state = 1214; this.match(SqlBaseParser.TO); this.state = 1215; localctx.to = this.intervalField(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function IntervalFieldContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_intervalField; // return this; } IntervalFieldContext.prototype = Object.create(ParserRuleContext.prototype); IntervalFieldContext.prototype.constructor = IntervalFieldContext; IntervalFieldContext.prototype.YEAR = function() { return this.getToken(SqlBaseParser.YEAR, 0); }; IntervalFieldContext.prototype.MONTH = function() { return this.getToken(SqlBaseParser.MONTH, 0); }; IntervalFieldContext.prototype.DAY = function() { return this.getToken(SqlBaseParser.DAY, 0); }; IntervalFieldContext.prototype.HOUR = function() { return this.getToken(SqlBaseParser.HOUR, 0); }; IntervalFieldContext.prototype.MINUTE = function() { return this.getToken(SqlBaseParser.MINUTE, 0); }; IntervalFieldContext.prototype.SECOND = function() { return this.getToken(SqlBaseParser.SECOND, 0); }; IntervalFieldContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterIntervalField(this); } }; IntervalFieldContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitIntervalField(this); } }; IntervalFieldContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitIntervalField(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.IntervalFieldContext = IntervalFieldContext; SqlBaseParser.prototype.intervalField = function() { var localctx = new IntervalFieldContext(this, this._ctx, this.state); this.enterRule(localctx, 84, SqlBaseParser.RULE_intervalField); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1218; _la = this._input.LA(1); if(!(((((_la - 57)) & ~0x1f) == 0 && ((1 << (_la - 57)) & ((1 << (SqlBaseParser.YEAR - 57)) | (1 << (SqlBaseParser.MONTH - 57)) | (1 << (SqlBaseParser.DAY - 57)) | (1 << (SqlBaseParser.HOUR - 57)) | (1 << (SqlBaseParser.MINUTE - 57)) | (1 << (SqlBaseParser.SECOND - 57)))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TypeContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_type; // return this; } TypeContext.prototype = Object.create(ParserRuleContext.prototype); TypeContext.prototype.constructor = TypeContext; TypeContext.prototype.ARRAY = function() { return this.getToken(SqlBaseParser.ARRAY, 0); }; TypeContext.prototype.type = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TypeContext); } else { return this.getTypedRuleContext(TypeContext,i); } }; TypeContext.prototype.MAP = function() { return this.getToken(SqlBaseParser.MAP, 0); }; TypeContext.prototype.ROW = function() { return this.getToken(SqlBaseParser.ROW, 0); }; TypeContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; TypeContext.prototype.baseType = function() { return this.getTypedRuleContext(BaseTypeContext,0); }; TypeContext.prototype.typeParameter = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TypeParameterContext); } else { return this.getTypedRuleContext(TypeParameterContext,i); } }; TypeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterType(this); } }; TypeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitType(this); } }; TypeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitType(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.prototype.type = function(_p) { if(_p===undefined) { _p = 0; } var _parentctx = this._ctx; var _parentState = this.state; var localctx = new TypeContext(this, this._ctx, _parentState); var _prevctx = localctx; var _startState = 86; this.enterRecursionRule(localctx, 86, SqlBaseParser.RULE_type, _p); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1262; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,153,this._ctx); switch(la_) { case 1: this.state = 1221; this.match(SqlBaseParser.ARRAY); this.state = 1222; this.match(SqlBaseParser.LT); this.state = 1223; this.type(0); this.state = 1224; this.match(SqlBaseParser.GT); break; case 2: this.state = 1226; this.match(SqlBaseParser.MAP); this.state = 1227; this.match(SqlBaseParser.LT); this.state = 1228; this.type(0); this.state = 1229; this.match(SqlBaseParser.T__2); this.state = 1230; this.type(0); this.state = 1231; this.match(SqlBaseParser.GT); break; case 3: this.state = 1233; this.match(SqlBaseParser.ROW); this.state = 1234; this.match(SqlBaseParser.T__1); this.state = 1235; this.identifier(); this.state = 1236; this.type(0); this.state = 1243; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1237; this.match(SqlBaseParser.T__2); this.state = 1238; this.identifier(); this.state = 1239; this.type(0); this.state = 1245; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 1246; this.match(SqlBaseParser.T__3); break; case 4: this.state = 1248; this.baseType(); this.state = 1260; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,152,this._ctx); if(la_===1) { this.state = 1249; this.match(SqlBaseParser.T__1); this.state = 1250; this.typeParameter(); this.state = 1255; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1251; this.match(SqlBaseParser.T__2); this.state = 1252; this.typeParameter(); this.state = 1257; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 1258; this.match(SqlBaseParser.T__3); } break; } this._ctx.stop = this._input.LT(-1); this.state = 1268; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,154,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { if(this._parseListeners!==null) { this.triggerExitRuleEvent(); } _prevctx = localctx; localctx = new TypeContext(this, _parentctx, _parentState); this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_type); this.state = 1264; if (!( this.precpred(this._ctx, 5))) { throw new _error.FailedPredicateException(this, "this.precpred(this._ctx, 5)"); } this.state = 1265; this.match(SqlBaseParser.ARRAY); } this.state = 1270; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,154,this._ctx); } } catch( error) { if(error instanceof _error.RecognitionException) { localctx.exception = error; this._errHandler.reportError(this, error); this._errHandler.recover(this, error); } else { throw error; } } finally { this.unrollRecursionContexts(_parentctx) } return localctx; }; function TypeParameterContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_typeParameter; // return this; } TypeParameterContext.prototype = Object.create(ParserRuleContext.prototype); TypeParameterContext.prototype.constructor = TypeParameterContext; TypeParameterContext.prototype.INTEGER_VALUE = function() { return this.getToken(SqlBaseParser.INTEGER_VALUE, 0); }; TypeParameterContext.prototype.type = function() { return this.getTypedRuleContext(TypeContext,0); }; TypeParameterContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTypeParameter(this); } }; TypeParameterContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTypeParameter(this); } }; TypeParameterContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTypeParameter(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.TypeParameterContext = TypeParameterContext; SqlBaseParser.prototype.typeParameter = function() { var localctx = new TypeParameterContext(this, this._ctx, this.state); this.enterRule(localctx, 88, SqlBaseParser.RULE_typeParameter); try { this.state = 1273; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.INTEGER_VALUE: this.enterOuterAlt(localctx, 1); this.state = 1271; this.match(SqlBaseParser.INTEGER_VALUE); break; case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: case SqlBaseParser.TIME_WITH_TIME_ZONE: case SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE: case SqlBaseParser.DOUBLE_PRECISION: this.enterOuterAlt(localctx, 2); this.state = 1272; this.type(0); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function BaseTypeContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_baseType; // return this; } BaseTypeContext.prototype = Object.create(ParserRuleContext.prototype); BaseTypeContext.prototype.constructor = BaseTypeContext; BaseTypeContext.prototype.TIME_WITH_TIME_ZONE = function() { return this.getToken(SqlBaseParser.TIME_WITH_TIME_ZONE, 0); }; BaseTypeContext.prototype.TIMESTAMP_WITH_TIME_ZONE = function() { return this.getToken(SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE, 0); }; BaseTypeContext.prototype.DOUBLE_PRECISION = function() { return this.getToken(SqlBaseParser.DOUBLE_PRECISION, 0); }; BaseTypeContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; BaseTypeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBaseType(this); } }; BaseTypeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBaseType(this); } }; BaseTypeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBaseType(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.BaseTypeContext = BaseTypeContext; SqlBaseParser.prototype.baseType = function() { var localctx = new BaseTypeContext(this, this._ctx, this.state); this.enterRule(localctx, 90, SqlBaseParser.RULE_baseType); try { this.state = 1279; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.TIME_WITH_TIME_ZONE: this.enterOuterAlt(localctx, 1); this.state = 1275; this.match(SqlBaseParser.TIME_WITH_TIME_ZONE); break; case SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE: this.enterOuterAlt(localctx, 2); this.state = 1276; this.match(SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE); break; case SqlBaseParser.DOUBLE_PRECISION: this.enterOuterAlt(localctx, 3); this.state = 1277; this.match(SqlBaseParser.DOUBLE_PRECISION); break; case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: this.enterOuterAlt(localctx, 4); this.state = 1278; this.identifier(); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function WhenClauseContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_whenClause; this.condition = null; // ExpressionContext this.result = null; // ExpressionContext // return this; } WhenClauseContext.prototype = Object.create(ParserRuleContext.prototype); WhenClauseContext.prototype.constructor = WhenClauseContext; WhenClauseContext.prototype.WHEN = function() { return this.getToken(SqlBaseParser.WHEN, 0); }; WhenClauseContext.prototype.THEN = function() { return this.getToken(SqlBaseParser.THEN, 0); }; WhenClauseContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; WhenClauseContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterWhenClause(this); } }; WhenClauseContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitWhenClause(this); } }; WhenClauseContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitWhenClause(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.WhenClauseContext = WhenClauseContext; SqlBaseParser.prototype.whenClause = function() { var localctx = new WhenClauseContext(this, this._ctx, this.state); this.enterRule(localctx, 92, SqlBaseParser.RULE_whenClause); try { this.enterOuterAlt(localctx, 1); this.state = 1281; this.match(SqlBaseParser.WHEN); this.state = 1282; localctx.condition = this.expression(); this.state = 1283; this.match(SqlBaseParser.THEN); this.state = 1284; localctx.result = this.expression(); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function FilterContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_filter; // return this; } FilterContext.prototype = Object.create(ParserRuleContext.prototype); FilterContext.prototype.constructor = FilterContext; FilterContext.prototype.FILTER = function() { return this.getToken(SqlBaseParser.FILTER, 0); }; FilterContext.prototype.WHERE = function() { return this.getToken(SqlBaseParser.WHERE, 0); }; FilterContext.prototype.booleanExpression = function() { return this.getTypedRuleContext(BooleanExpressionContext,0); }; FilterContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterFilter(this); } }; FilterContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitFilter(this); } }; FilterContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitFilter(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.FilterContext = FilterContext; SqlBaseParser.prototype.filter = function() { var localctx = new FilterContext(this, this._ctx, this.state); this.enterRule(localctx, 94, SqlBaseParser.RULE_filter); try { this.enterOuterAlt(localctx, 1); this.state = 1286; this.match(SqlBaseParser.FILTER); this.state = 1287; this.match(SqlBaseParser.T__1); this.state = 1288; this.match(SqlBaseParser.WHERE); this.state = 1289; this.booleanExpression(0); this.state = 1290; this.match(SqlBaseParser.T__3); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function OverContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_over; this._expression = null; // ExpressionContext this.partition = []; // of ExpressionContexts // return this; } OverContext.prototype = Object.create(ParserRuleContext.prototype); OverContext.prototype.constructor = OverContext; OverContext.prototype.OVER = function() { return this.getToken(SqlBaseParser.OVER, 0); }; OverContext.prototype.PARTITION = function() { return this.getToken(SqlBaseParser.PARTITION, 0); }; OverContext.prototype.BY = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(SqlBaseParser.BY); } else { return this.getToken(SqlBaseParser.BY, i); } }; OverContext.prototype.ORDER = function() { return this.getToken(SqlBaseParser.ORDER, 0); }; OverContext.prototype.sortItem = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SortItemContext); } else { return this.getTypedRuleContext(SortItemContext,i); } }; OverContext.prototype.windowFrame = function() { return this.getTypedRuleContext(WindowFrameContext,0); }; OverContext.prototype.expression = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ExpressionContext); } else { return this.getTypedRuleContext(ExpressionContext,i); } }; OverContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterOver(this); } }; OverContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitOver(this); } }; OverContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitOver(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.OverContext = OverContext; SqlBaseParser.prototype.over = function() { var localctx = new OverContext(this, this._ctx, this.state); this.enterRule(localctx, 96, SqlBaseParser.RULE_over); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1292; this.match(SqlBaseParser.OVER); this.state = 1293; this.match(SqlBaseParser.T__1); this.state = 1304; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.PARTITION) { this.state = 1294; this.match(SqlBaseParser.PARTITION); this.state = 1295; this.match(SqlBaseParser.BY); this.state = 1296; localctx._expression = this.expression(); localctx.partition.push(localctx._expression); this.state = 1301; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1297; this.match(SqlBaseParser.T__2); this.state = 1298; localctx._expression = this.expression(); localctx.partition.push(localctx._expression); this.state = 1303; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 1316; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.ORDER) { this.state = 1306; this.match(SqlBaseParser.ORDER); this.state = 1307; this.match(SqlBaseParser.BY); this.state = 1308; this.sortItem(); this.state = 1313; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===SqlBaseParser.T__2) { this.state = 1309; this.match(SqlBaseParser.T__2); this.state = 1310; this.sortItem(); this.state = 1315; this._errHandler.sync(this); _la = this._input.LA(1); } } this.state = 1319; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===SqlBaseParser.RANGE || _la===SqlBaseParser.ROWS) { this.state = 1318; this.windowFrame(); } this.state = 1321; this.match(SqlBaseParser.T__3); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function WindowFrameContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_windowFrame; this.frameType = null; // Token this.start = null; // FrameBoundContext this.end = null; // FrameBoundContext // return this; } WindowFrameContext.prototype = Object.create(ParserRuleContext.prototype); WindowFrameContext.prototype.constructor = WindowFrameContext; WindowFrameContext.prototype.RANGE = function() { return this.getToken(SqlBaseParser.RANGE, 0); }; WindowFrameContext.prototype.frameBound = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(FrameBoundContext); } else { return this.getTypedRuleContext(FrameBoundContext,i); } }; WindowFrameContext.prototype.ROWS = function() { return this.getToken(SqlBaseParser.ROWS, 0); }; WindowFrameContext.prototype.BETWEEN = function() { return this.getToken(SqlBaseParser.BETWEEN, 0); }; WindowFrameContext.prototype.AND = function() { return this.getToken(SqlBaseParser.AND, 0); }; WindowFrameContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterWindowFrame(this); } }; WindowFrameContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitWindowFrame(this); } }; WindowFrameContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitWindowFrame(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.WindowFrameContext = WindowFrameContext; SqlBaseParser.prototype.windowFrame = function() { var localctx = new WindowFrameContext(this, this._ctx, this.state); this.enterRule(localctx, 98, SqlBaseParser.RULE_windowFrame); try { this.state = 1339; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,162,this._ctx); switch(la_) { case 1: this.enterOuterAlt(localctx, 1); this.state = 1323; localctx.frameType = this.match(SqlBaseParser.RANGE); this.state = 1324; localctx.start = this.frameBound(); break; case 2: this.enterOuterAlt(localctx, 2); this.state = 1325; localctx.frameType = this.match(SqlBaseParser.ROWS); this.state = 1326; localctx.start = this.frameBound(); break; case 3: this.enterOuterAlt(localctx, 3); this.state = 1327; localctx.frameType = this.match(SqlBaseParser.RANGE); this.state = 1328; this.match(SqlBaseParser.BETWEEN); this.state = 1329; localctx.start = this.frameBound(); this.state = 1330; this.match(SqlBaseParser.AND); this.state = 1331; localctx.end = this.frameBound(); break; case 4: this.enterOuterAlt(localctx, 4); this.state = 1333; localctx.frameType = this.match(SqlBaseParser.ROWS); this.state = 1334; this.match(SqlBaseParser.BETWEEN); this.state = 1335; localctx.start = this.frameBound(); this.state = 1336; this.match(SqlBaseParser.AND); this.state = 1337; localctx.end = this.frameBound(); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function FrameBoundContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_frameBound; // return this; } FrameBoundContext.prototype = Object.create(ParserRuleContext.prototype); FrameBoundContext.prototype.constructor = FrameBoundContext; FrameBoundContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function BoundedFrameContext(parser, ctx) { FrameBoundContext.call(this, parser); this.boundType = null; // Token; FrameBoundContext.prototype.copyFrom.call(this, ctx); // return this; } BoundedFrameContext.prototype = Object.create(FrameBoundContext.prototype); BoundedFrameContext.prototype.constructor = BoundedFrameContext; SqlBaseParser.BoundedFrameContext = BoundedFrameContext; BoundedFrameContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; BoundedFrameContext.prototype.PRECEDING = function() { return this.getToken(SqlBaseParser.PRECEDING, 0); }; BoundedFrameContext.prototype.FOLLOWING = function() { return this.getToken(SqlBaseParser.FOLLOWING, 0); }; BoundedFrameContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBoundedFrame(this); } }; BoundedFrameContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBoundedFrame(this); } }; BoundedFrameContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBoundedFrame(this); } else { return (visitor as any).visitChildren(this); } }; function UnboundedFrameContext(parser, ctx) { FrameBoundContext.call(this, parser); this.boundType = null; // Token; FrameBoundContext.prototype.copyFrom.call(this, ctx); // return this; } UnboundedFrameContext.prototype = Object.create(FrameBoundContext.prototype); UnboundedFrameContext.prototype.constructor = UnboundedFrameContext; SqlBaseParser.UnboundedFrameContext = UnboundedFrameContext; UnboundedFrameContext.prototype.UNBOUNDED = function() { return this.getToken(SqlBaseParser.UNBOUNDED, 0); }; UnboundedFrameContext.prototype.PRECEDING = function() { return this.getToken(SqlBaseParser.PRECEDING, 0); }; UnboundedFrameContext.prototype.FOLLOWING = function() { return this.getToken(SqlBaseParser.FOLLOWING, 0); }; UnboundedFrameContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterUnboundedFrame(this); } }; UnboundedFrameContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitUnboundedFrame(this); } }; UnboundedFrameContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitUnboundedFrame(this); } else { return (visitor as any).visitChildren(this); } }; function CurrentRowBoundContext(parser, ctx) { FrameBoundContext.call(this, parser); FrameBoundContext.prototype.copyFrom.call(this, ctx); // return this; } CurrentRowBoundContext.prototype = Object.create(FrameBoundContext.prototype); CurrentRowBoundContext.prototype.constructor = CurrentRowBoundContext; SqlBaseParser.CurrentRowBoundContext = CurrentRowBoundContext; CurrentRowBoundContext.prototype.CURRENT = function() { return this.getToken(SqlBaseParser.CURRENT, 0); }; CurrentRowBoundContext.prototype.ROW = function() { return this.getToken(SqlBaseParser.ROW, 0); }; CurrentRowBoundContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterCurrentRowBound(this); } }; CurrentRowBoundContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitCurrentRowBound(this); } }; CurrentRowBoundContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitCurrentRowBound(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.FrameBoundContext = FrameBoundContext; SqlBaseParser.prototype.frameBound = function() { var localctx = new FrameBoundContext(this, this._ctx, this.state); this.enterRule(localctx, 100, SqlBaseParser.RULE_frameBound); var _la = 0; // Token type try { this.state = 1350; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,163,this._ctx); switch(la_) { case 1: localctx = new UnboundedFrameContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1341; this.match(SqlBaseParser.UNBOUNDED); this.state = 1342; localctx.boundType = this.match(SqlBaseParser.PRECEDING); break; case 2: localctx = new UnboundedFrameContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1343; this.match(SqlBaseParser.UNBOUNDED); this.state = 1344; localctx.boundType = this.match(SqlBaseParser.FOLLOWING); break; case 3: localctx = new CurrentRowBoundContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 1345; this.match(SqlBaseParser.CURRENT); this.state = 1346; this.match(SqlBaseParser.ROW); break; case 4: localctx = new BoundedFrameContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 1347; this.expression(); this.state = 1348; localctx.boundType = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.PRECEDING || _la===SqlBaseParser.FOLLOWING)) { localctx.boundType = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ExplainOptionContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_explainOption; // return this; } ExplainOptionContext.prototype = Object.create(ParserRuleContext.prototype); ExplainOptionContext.prototype.constructor = ExplainOptionContext; ExplainOptionContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function ExplainFormatContext(parser, ctx) { ExplainOptionContext.call(this, parser); this.value = null; // Token; ExplainOptionContext.prototype.copyFrom.call(this, ctx); // return this; } ExplainFormatContext.prototype = Object.create(ExplainOptionContext.prototype); ExplainFormatContext.prototype.constructor = ExplainFormatContext; SqlBaseParser.ExplainFormatContext = ExplainFormatContext; ExplainFormatContext.prototype.FORMAT = function() { return this.getToken(SqlBaseParser.FORMAT, 0); }; ExplainFormatContext.prototype.TEXT = function() { return this.getToken(SqlBaseParser.TEXT, 0); }; ExplainFormatContext.prototype.GRAPHVIZ = function() { return this.getToken(SqlBaseParser.GRAPHVIZ, 0); }; ExplainFormatContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExplainFormat(this); } }; ExplainFormatContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExplainFormat(this); } }; ExplainFormatContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExplainFormat(this); } else { return (visitor as any).visitChildren(this); } }; function ExplainTypeContext(parser, ctx) { ExplainOptionContext.call(this, parser); this.value = null; // Token; ExplainOptionContext.prototype.copyFrom.call(this, ctx); // return this; } ExplainTypeContext.prototype = Object.create(ExplainOptionContext.prototype); ExplainTypeContext.prototype.constructor = ExplainTypeContext; SqlBaseParser.ExplainTypeContext = ExplainTypeContext; ExplainTypeContext.prototype.TYPE = function() { return this.getToken(SqlBaseParser.TYPE, 0); }; ExplainTypeContext.prototype.LOGICAL = function() { return this.getToken(SqlBaseParser.LOGICAL, 0); }; ExplainTypeContext.prototype.DISTRIBUTED = function() { return this.getToken(SqlBaseParser.DISTRIBUTED, 0); }; ExplainTypeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterExplainType(this); } }; ExplainTypeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitExplainType(this); } }; ExplainTypeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitExplainType(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.ExplainOptionContext = ExplainOptionContext; SqlBaseParser.prototype.explainOption = function() { var localctx = new ExplainOptionContext(this, this._ctx, this.state); this.enterRule(localctx, 102, SqlBaseParser.RULE_explainOption); var _la = 0; // Token type try { this.state = 1356; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.FORMAT: localctx = new ExplainFormatContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1352; this.match(SqlBaseParser.FORMAT); this.state = 1353; localctx.value = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.TEXT || _la===SqlBaseParser.GRAPHVIZ)) { localctx.value = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } break; case SqlBaseParser.TYPE: localctx = new ExplainTypeContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1354; this.match(SqlBaseParser.TYPE); this.state = 1355; localctx.value = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.LOGICAL || _la===SqlBaseParser.DISTRIBUTED)) { localctx.value = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TransactionModeContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_transactionMode; // return this; } TransactionModeContext.prototype = Object.create(ParserRuleContext.prototype); TransactionModeContext.prototype.constructor = TransactionModeContext; TransactionModeContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function TransactionAccessModeContext(parser, ctx) { TransactionModeContext.call(this, parser); this.accessMode = null; // Token; TransactionModeContext.prototype.copyFrom.call(this, ctx); // return this; } TransactionAccessModeContext.prototype = Object.create(TransactionModeContext.prototype); TransactionAccessModeContext.prototype.constructor = TransactionAccessModeContext; SqlBaseParser.TransactionAccessModeContext = TransactionAccessModeContext; TransactionAccessModeContext.prototype.READ = function() { return this.getToken(SqlBaseParser.READ, 0); }; TransactionAccessModeContext.prototype.ONLY = function() { return this.getToken(SqlBaseParser.ONLY, 0); }; TransactionAccessModeContext.prototype.WRITE = function() { return this.getToken(SqlBaseParser.WRITE, 0); }; TransactionAccessModeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterTransactionAccessMode(this); } }; TransactionAccessModeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitTransactionAccessMode(this); } }; TransactionAccessModeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitTransactionAccessMode(this); } else { return (visitor as any).visitChildren(this); } }; function IsolationLevelContext(parser, ctx) { TransactionModeContext.call(this, parser); TransactionModeContext.prototype.copyFrom.call(this, ctx); // return this; } IsolationLevelContext.prototype = Object.create(TransactionModeContext.prototype); IsolationLevelContext.prototype.constructor = IsolationLevelContext; SqlBaseParser.IsolationLevelContext = IsolationLevelContext; IsolationLevelContext.prototype.ISOLATION = function() { return this.getToken(SqlBaseParser.ISOLATION, 0); }; IsolationLevelContext.prototype.LEVEL = function() { return this.getToken(SqlBaseParser.LEVEL, 0); }; IsolationLevelContext.prototype.levelOfIsolation = function() { return this.getTypedRuleContext(LevelOfIsolationContext,0); }; IsolationLevelContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterIsolationLevel(this); } }; IsolationLevelContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitIsolationLevel(this); } }; IsolationLevelContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitIsolationLevel(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.TransactionModeContext = TransactionModeContext; SqlBaseParser.prototype.transactionMode = function() { var localctx = new TransactionModeContext(this, this._ctx, this.state); this.enterRule(localctx, 104, SqlBaseParser.RULE_transactionMode); var _la = 0; // Token type try { this.state = 1363; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.ISOLATION: localctx = new IsolationLevelContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1358; this.match(SqlBaseParser.ISOLATION); this.state = 1359; this.match(SqlBaseParser.LEVEL); this.state = 1360; this.levelOfIsolation(); break; case SqlBaseParser.READ: localctx = new TransactionAccessModeContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1361; this.match(SqlBaseParser.READ); this.state = 1362; localctx.accessMode = this._input.LT(1); _la = this._input.LA(1); if(!(_la===SqlBaseParser.WRITE || _la===SqlBaseParser.ONLY)) { localctx.accessMode = this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function LevelOfIsolationContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_levelOfIsolation; // return this; } LevelOfIsolationContext.prototype = Object.create(ParserRuleContext.prototype); LevelOfIsolationContext.prototype.constructor = LevelOfIsolationContext; LevelOfIsolationContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function ReadUncommittedContext(parser, ctx) { LevelOfIsolationContext.call(this, parser); LevelOfIsolationContext.prototype.copyFrom.call(this, ctx); // return this; } ReadUncommittedContext.prototype = Object.create(LevelOfIsolationContext.prototype); ReadUncommittedContext.prototype.constructor = ReadUncommittedContext; SqlBaseParser.ReadUncommittedContext = ReadUncommittedContext; ReadUncommittedContext.prototype.READ = function() { return this.getToken(SqlBaseParser.READ, 0); }; ReadUncommittedContext.prototype.UNCOMMITTED = function() { return this.getToken(SqlBaseParser.UNCOMMITTED, 0); }; ReadUncommittedContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterReadUncommitted(this); } }; ReadUncommittedContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitReadUncommitted(this); } }; ReadUncommittedContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitReadUncommitted(this); } else { return (visitor as any).visitChildren(this); } }; function SerializableContext(parser, ctx) { LevelOfIsolationContext.call(this, parser); LevelOfIsolationContext.prototype.copyFrom.call(this, ctx); // return this; } SerializableContext.prototype = Object.create(LevelOfIsolationContext.prototype); SerializableContext.prototype.constructor = SerializableContext; SqlBaseParser.SerializableContext = SerializableContext; SerializableContext.prototype.SERIALIZABLE = function() { return this.getToken(SqlBaseParser.SERIALIZABLE, 0); }; SerializableContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterSerializable(this); } }; SerializableContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitSerializable(this); } }; SerializableContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitSerializable(this); } else { return (visitor as any).visitChildren(this); } }; function ReadCommittedContext(parser, ctx) { LevelOfIsolationContext.call(this, parser); LevelOfIsolationContext.prototype.copyFrom.call(this, ctx); // return this; } ReadCommittedContext.prototype = Object.create(LevelOfIsolationContext.prototype); ReadCommittedContext.prototype.constructor = ReadCommittedContext; SqlBaseParser.ReadCommittedContext = ReadCommittedContext; ReadCommittedContext.prototype.READ = function() { return this.getToken(SqlBaseParser.READ, 0); }; ReadCommittedContext.prototype.COMMITTED = function() { return this.getToken(SqlBaseParser.COMMITTED, 0); }; ReadCommittedContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterReadCommitted(this); } }; ReadCommittedContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitReadCommitted(this); } }; ReadCommittedContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitReadCommitted(this); } else { return (visitor as any).visitChildren(this); } }; function RepeatableReadContext(parser, ctx) { LevelOfIsolationContext.call(this, parser); LevelOfIsolationContext.prototype.copyFrom.call(this, ctx); // return this; } RepeatableReadContext.prototype = Object.create(LevelOfIsolationContext.prototype); RepeatableReadContext.prototype.constructor = RepeatableReadContext; SqlBaseParser.RepeatableReadContext = RepeatableReadContext; RepeatableReadContext.prototype.REPEATABLE = function() { return this.getToken(SqlBaseParser.REPEATABLE, 0); }; RepeatableReadContext.prototype.READ = function() { return this.getToken(SqlBaseParser.READ, 0); }; RepeatableReadContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterRepeatableRead(this); } }; RepeatableReadContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitRepeatableRead(this); } }; RepeatableReadContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitRepeatableRead(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.LevelOfIsolationContext = LevelOfIsolationContext; SqlBaseParser.prototype.levelOfIsolation = function() { var localctx = new LevelOfIsolationContext(this, this._ctx, this.state); this.enterRule(localctx, 106, SqlBaseParser.RULE_levelOfIsolation); try { this.state = 1372; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,166,this._ctx); switch(la_) { case 1: localctx = new ReadUncommittedContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1365; this.match(SqlBaseParser.READ); this.state = 1366; this.match(SqlBaseParser.UNCOMMITTED); break; case 2: localctx = new ReadCommittedContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1367; this.match(SqlBaseParser.READ); this.state = 1368; this.match(SqlBaseParser.COMMITTED); break; case 3: localctx = new RepeatableReadContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 1369; this.match(SqlBaseParser.REPEATABLE); this.state = 1370; this.match(SqlBaseParser.READ); break; case 4: localctx = new SerializableContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 1371; this.match(SqlBaseParser.SERIALIZABLE); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function CallArgumentContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_callArgument; // return this; } CallArgumentContext.prototype = Object.create(ParserRuleContext.prototype); CallArgumentContext.prototype.constructor = CallArgumentContext; CallArgumentContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function PositionalArgumentContext(parser, ctx) { CallArgumentContext.call(this, parser); CallArgumentContext.prototype.copyFrom.call(this, ctx); // return this; } PositionalArgumentContext.prototype = Object.create(CallArgumentContext.prototype); PositionalArgumentContext.prototype.constructor = PositionalArgumentContext; SqlBaseParser.PositionalArgumentContext = PositionalArgumentContext; PositionalArgumentContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; PositionalArgumentContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterPositionalArgument(this); } }; PositionalArgumentContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitPositionalArgument(this); } }; PositionalArgumentContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitPositionalArgument(this); } else { return (visitor as any).visitChildren(this); } }; function NamedArgumentContext(parser, ctx) { CallArgumentContext.call(this, parser); CallArgumentContext.prototype.copyFrom.call(this, ctx); // return this; } NamedArgumentContext.prototype = Object.create(CallArgumentContext.prototype); NamedArgumentContext.prototype.constructor = NamedArgumentContext; SqlBaseParser.NamedArgumentContext = NamedArgumentContext; NamedArgumentContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; NamedArgumentContext.prototype.expression = function() { return this.getTypedRuleContext(ExpressionContext,0); }; NamedArgumentContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNamedArgument(this); } }; NamedArgumentContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNamedArgument(this); } }; NamedArgumentContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNamedArgument(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.CallArgumentContext = CallArgumentContext; SqlBaseParser.prototype.callArgument = function() { var localctx = new CallArgumentContext(this, this._ctx, this.state); this.enterRule(localctx, 108, SqlBaseParser.RULE_callArgument); try { this.state = 1379; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,167,this._ctx); switch(la_) { case 1: localctx = new PositionalArgumentContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1374; this.expression(); break; case 2: localctx = new NamedArgumentContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1375; this.identifier(); this.state = 1376; this.match(SqlBaseParser.T__8); this.state = 1377; this.expression(); break; } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function PrivilegeContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_privilege; // return this; } PrivilegeContext.prototype = Object.create(ParserRuleContext.prototype); PrivilegeContext.prototype.constructor = PrivilegeContext; PrivilegeContext.prototype.SELECT = function() { return this.getToken(SqlBaseParser.SELECT, 0); }; PrivilegeContext.prototype.DELETE = function() { return this.getToken(SqlBaseParser.DELETE, 0); }; PrivilegeContext.prototype.INSERT = function() { return this.getToken(SqlBaseParser.INSERT, 0); }; PrivilegeContext.prototype.identifier = function() { return this.getTypedRuleContext(IdentifierContext,0); }; PrivilegeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterPrivilege(this); } }; PrivilegeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitPrivilege(this); } }; PrivilegeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitPrivilege(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.PrivilegeContext = PrivilegeContext; SqlBaseParser.prototype.privilege = function() { var localctx = new PrivilegeContext(this, this._ctx, this.state); this.enterRule(localctx, 110, SqlBaseParser.RULE_privilege); try { this.state = 1385; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.SELECT: this.enterOuterAlt(localctx, 1); this.state = 1381; this.match(SqlBaseParser.SELECT); break; case SqlBaseParser.DELETE: this.enterOuterAlt(localctx, 2); this.state = 1382; this.match(SqlBaseParser.DELETE); break; case SqlBaseParser.INSERT: this.enterOuterAlt(localctx, 3); this.state = 1383; this.match(SqlBaseParser.INSERT); break; case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: case SqlBaseParser.IDENTIFIER: case SqlBaseParser.DIGIT_IDENTIFIER: case SqlBaseParser.QUOTED_IDENTIFIER: case SqlBaseParser.BACKQUOTED_IDENTIFIER: this.enterOuterAlt(localctx, 4); this.state = 1384; this.identifier(); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function QualifiedNameContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_qualifiedName; // return this; } QualifiedNameContext.prototype = Object.create(ParserRuleContext.prototype); QualifiedNameContext.prototype.constructor = QualifiedNameContext; QualifiedNameContext.prototype.identifier = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(IdentifierContext); } else { return this.getTypedRuleContext(IdentifierContext,i); } }; QualifiedNameContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQualifiedName(this); } }; QualifiedNameContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQualifiedName(this); } }; QualifiedNameContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQualifiedName(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.QualifiedNameContext = QualifiedNameContext; SqlBaseParser.prototype.qualifiedName = function() { var localctx = new QualifiedNameContext(this, this._ctx, this.state); this.enterRule(localctx, 112, SqlBaseParser.RULE_qualifiedName); try { this.enterOuterAlt(localctx, 1); this.state = 1387; this.identifier(); this.state = 1392; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,169,this._ctx) while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 1388; this.match(SqlBaseParser.T__0); this.state = 1389; this.identifier(); } this.state = 1394; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,169,this._ctx); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function IdentifierContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_identifier; // return this; } IdentifierContext.prototype = Object.create(ParserRuleContext.prototype); IdentifierContext.prototype.constructor = IdentifierContext; IdentifierContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function BackQuotedIdentifierContext(parser, ctx) { IdentifierContext.call(this, parser); IdentifierContext.prototype.copyFrom.call(this, ctx); // return this; } BackQuotedIdentifierContext.prototype = Object.create(IdentifierContext.prototype); BackQuotedIdentifierContext.prototype.constructor = BackQuotedIdentifierContext; SqlBaseParser.BackQuotedIdentifierContext = BackQuotedIdentifierContext; BackQuotedIdentifierContext.prototype.BACKQUOTED_IDENTIFIER = function() { return this.getToken(SqlBaseParser.BACKQUOTED_IDENTIFIER, 0); }; BackQuotedIdentifierContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterBackQuotedIdentifier(this); } }; BackQuotedIdentifierContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitBackQuotedIdentifier(this); } }; BackQuotedIdentifierContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitBackQuotedIdentifier(this); } else { return (visitor as any).visitChildren(this); } }; function QuotedIdentifierAlternativeContext(parser, ctx) { IdentifierContext.call(this, parser); IdentifierContext.prototype.copyFrom.call(this, ctx); // return this; } QuotedIdentifierAlternativeContext.prototype = Object.create(IdentifierContext.prototype); QuotedIdentifierAlternativeContext.prototype.constructor = QuotedIdentifierAlternativeContext; SqlBaseParser.QuotedIdentifierAlternativeContext = QuotedIdentifierAlternativeContext; QuotedIdentifierAlternativeContext.prototype.quotedIdentifier = function() { return this.getTypedRuleContext(QuotedIdentifierContext,0); }; QuotedIdentifierAlternativeContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQuotedIdentifierAlternative(this); } }; QuotedIdentifierAlternativeContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQuotedIdentifierAlternative(this); } }; QuotedIdentifierAlternativeContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQuotedIdentifierAlternative(this); } else { return (visitor as any).visitChildren(this); } }; function DigitIdentifierContext(parser, ctx) { IdentifierContext.call(this, parser); IdentifierContext.prototype.copyFrom.call(this, ctx); // return this; } DigitIdentifierContext.prototype = Object.create(IdentifierContext.prototype); DigitIdentifierContext.prototype.constructor = DigitIdentifierContext; SqlBaseParser.DigitIdentifierContext = DigitIdentifierContext; DigitIdentifierContext.prototype.DIGIT_IDENTIFIER = function() { return this.getToken(SqlBaseParser.DIGIT_IDENTIFIER, 0); }; DigitIdentifierContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDigitIdentifier(this); } }; DigitIdentifierContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDigitIdentifier(this); } }; DigitIdentifierContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDigitIdentifier(this); } else { return (visitor as any).visitChildren(this); } }; function UnquotedIdentifierContext(parser, ctx) { IdentifierContext.call(this, parser); IdentifierContext.prototype.copyFrom.call(this, ctx); // return this; } UnquotedIdentifierContext.prototype = Object.create(IdentifierContext.prototype); UnquotedIdentifierContext.prototype.constructor = UnquotedIdentifierContext; SqlBaseParser.UnquotedIdentifierContext = UnquotedIdentifierContext; UnquotedIdentifierContext.prototype.IDENTIFIER = function() { return this.getToken(SqlBaseParser.IDENTIFIER, 0); }; UnquotedIdentifierContext.prototype.nonReserved = function() { return this.getTypedRuleContext(NonReservedContext,0); }; UnquotedIdentifierContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterUnquotedIdentifier(this); } }; UnquotedIdentifierContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitUnquotedIdentifier(this); } }; UnquotedIdentifierContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitUnquotedIdentifier(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.IdentifierContext = IdentifierContext; SqlBaseParser.prototype.identifier = function() { var localctx = new IdentifierContext(this, this._ctx, this.state); this.enterRule(localctx, 114, SqlBaseParser.RULE_identifier); try { this.state = 1400; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.IDENTIFIER: localctx = new UnquotedIdentifierContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1395; this.match(SqlBaseParser.IDENTIFIER); break; case SqlBaseParser.QUOTED_IDENTIFIER: localctx = new QuotedIdentifierAlternativeContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1396; this.quotedIdentifier(); break; case SqlBaseParser.ADD: case SqlBaseParser.NO: case SqlBaseParser.SUBSTRING: case SqlBaseParser.POSITION: case SqlBaseParser.TINYINT: case SqlBaseParser.SMALLINT: case SqlBaseParser.INTEGER: case SqlBaseParser.DATE: case SqlBaseParser.TIME: case SqlBaseParser.TIMESTAMP: case SqlBaseParser.INTERVAL: case SqlBaseParser.YEAR: case SqlBaseParser.MONTH: case SqlBaseParser.DAY: case SqlBaseParser.HOUR: case SqlBaseParser.MINUTE: case SqlBaseParser.SECOND: case SqlBaseParser.ZONE: case SqlBaseParser.FILTER: case SqlBaseParser.OVER: case SqlBaseParser.PARTITION: case SqlBaseParser.RANGE: case SqlBaseParser.ROWS: case SqlBaseParser.PRECEDING: case SqlBaseParser.FOLLOWING: case SqlBaseParser.CURRENT: case SqlBaseParser.ROW: case SqlBaseParser.SCHEMA: case SqlBaseParser.VIEW: case SqlBaseParser.REPLACE: case SqlBaseParser.GRANT: case SqlBaseParser.REVOKE: case SqlBaseParser.PRIVILEGES: case SqlBaseParser.PUBLIC: case SqlBaseParser.OPTION: case SqlBaseParser.EXPLAIN: case SqlBaseParser.ANALYZE: case SqlBaseParser.FORMAT: case SqlBaseParser.TYPE: case SqlBaseParser.TEXT: case SqlBaseParser.GRAPHVIZ: case SqlBaseParser.LOGICAL: case SqlBaseParser.DISTRIBUTED: case SqlBaseParser.SHOW: case SqlBaseParser.TABLES: case SqlBaseParser.SCHEMAS: case SqlBaseParser.CATALOGS: case SqlBaseParser.COLUMNS: case SqlBaseParser.COLUMN: case SqlBaseParser.USE: case SqlBaseParser.PARTITIONS: case SqlBaseParser.FUNCTIONS: case SqlBaseParser.TO: case SqlBaseParser.SYSTEM: case SqlBaseParser.BERNOULLI: case SqlBaseParser.POISSONIZED: case SqlBaseParser.TABLESAMPLE: case SqlBaseParser.ARRAY: case SqlBaseParser.MAP: case SqlBaseParser.SET: case SqlBaseParser.RESET: case SqlBaseParser.SESSION: case SqlBaseParser.DATA: case SqlBaseParser.START: case SqlBaseParser.TRANSACTION: case SqlBaseParser.COMMIT: case SqlBaseParser.ROLLBACK: case SqlBaseParser.WORK: case SqlBaseParser.ISOLATION: case SqlBaseParser.LEVEL: case SqlBaseParser.SERIALIZABLE: case SqlBaseParser.REPEATABLE: case SqlBaseParser.COMMITTED: case SqlBaseParser.UNCOMMITTED: case SqlBaseParser.READ: case SqlBaseParser.WRITE: case SqlBaseParser.ONLY: case SqlBaseParser.CALL: case SqlBaseParser.INPUT: case SqlBaseParser.OUTPUT: case SqlBaseParser.CASCADE: case SqlBaseParser.RESTRICT: case SqlBaseParser.INCLUDING: case SqlBaseParser.EXCLUDING: case SqlBaseParser.PROPERTIES: case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: case SqlBaseParser.IF: case SqlBaseParser.NULLIF: case SqlBaseParser.COALESCE: localctx = new UnquotedIdentifierContext(this, localctx); this.enterOuterAlt(localctx, 3); this.state = 1397; this.nonReserved(); break; case SqlBaseParser.BACKQUOTED_IDENTIFIER: localctx = new BackQuotedIdentifierContext(this, localctx); this.enterOuterAlt(localctx, 4); this.state = 1398; this.match(SqlBaseParser.BACKQUOTED_IDENTIFIER); break; case SqlBaseParser.DIGIT_IDENTIFIER: localctx = new DigitIdentifierContext(this, localctx); this.enterOuterAlt(localctx, 5); this.state = 1399; this.match(SqlBaseParser.DIGIT_IDENTIFIER); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function QuotedIdentifierContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_quotedIdentifier; // return this; } QuotedIdentifierContext.prototype = Object.create(ParserRuleContext.prototype); QuotedIdentifierContext.prototype.constructor = QuotedIdentifierContext; QuotedIdentifierContext.prototype.QUOTED_IDENTIFIER = function() { return this.getToken(SqlBaseParser.QUOTED_IDENTIFIER, 0); }; QuotedIdentifierContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterQuotedIdentifier(this); } }; QuotedIdentifierContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitQuotedIdentifier(this); } }; QuotedIdentifierContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitQuotedIdentifier(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.QuotedIdentifierContext = QuotedIdentifierContext; SqlBaseParser.prototype.quotedIdentifier = function() { var localctx = new QuotedIdentifierContext(this, this._ctx, this.state); this.enterRule(localctx, 116, SqlBaseParser.RULE_quotedIdentifier); try { this.enterOuterAlt(localctx, 1); this.state = 1402; this.match(SqlBaseParser.QUOTED_IDENTIFIER); } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function NumberContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_number; // return this; } NumberContext.prototype = Object.create(ParserRuleContext.prototype); NumberContext.prototype.constructor = NumberContext; NumberContext.prototype.copyFrom = function(ctx) { ParserRuleContext.prototype.copyFrom.call(this, ctx); }; function DecimalLiteralContext(parser, ctx) { NumberContext.call(this, parser); NumberContext.prototype.copyFrom.call(this, ctx); // return this; } DecimalLiteralContext.prototype = Object.create(NumberContext.prototype); DecimalLiteralContext.prototype.constructor = DecimalLiteralContext; SqlBaseParser.DecimalLiteralContext = DecimalLiteralContext; DecimalLiteralContext.prototype.DECIMAL_VALUE = function() { return this.getToken(SqlBaseParser.DECIMAL_VALUE, 0); }; DecimalLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterDecimalLiteral(this); } }; DecimalLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitDecimalLiteral(this); } }; DecimalLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitDecimalLiteral(this); } else { return (visitor as any).visitChildren(this); } }; function IntegerLiteralContext(parser, ctx) { NumberContext.call(this, parser); NumberContext.prototype.copyFrom.call(this, ctx); // return this; } IntegerLiteralContext.prototype = Object.create(NumberContext.prototype); IntegerLiteralContext.prototype.constructor = IntegerLiteralContext; SqlBaseParser.IntegerLiteralContext = IntegerLiteralContext; IntegerLiteralContext.prototype.INTEGER_VALUE = function() { return this.getToken(SqlBaseParser.INTEGER_VALUE, 0); }; IntegerLiteralContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterIntegerLiteral(this); } }; IntegerLiteralContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitIntegerLiteral(this); } }; IntegerLiteralContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitIntegerLiteral(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.NumberContext = NumberContext; SqlBaseParser.prototype.number = function() { var localctx = new NumberContext(this, this._ctx, this.state); this.enterRule(localctx, 118, SqlBaseParser.RULE_number); try { this.state = 1406; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.DECIMAL_VALUE: localctx = new DecimalLiteralContext(this, localctx); this.enterOuterAlt(localctx, 1); this.state = 1404; this.match(SqlBaseParser.DECIMAL_VALUE); break; case SqlBaseParser.INTEGER_VALUE: localctx = new IntegerLiteralContext(this, localctx); this.enterOuterAlt(localctx, 2); this.state = 1405; this.match(SqlBaseParser.INTEGER_VALUE); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function NonReservedContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_nonReserved; // return this; } NonReservedContext.prototype = Object.create(ParserRuleContext.prototype); NonReservedContext.prototype.constructor = NonReservedContext; NonReservedContext.prototype.SHOW = function() { return this.getToken(SqlBaseParser.SHOW, 0); }; NonReservedContext.prototype.TABLES = function() { return this.getToken(SqlBaseParser.TABLES, 0); }; NonReservedContext.prototype.COLUMNS = function() { return this.getToken(SqlBaseParser.COLUMNS, 0); }; NonReservedContext.prototype.COLUMN = function() { return this.getToken(SqlBaseParser.COLUMN, 0); }; NonReservedContext.prototype.PARTITIONS = function() { return this.getToken(SqlBaseParser.PARTITIONS, 0); }; NonReservedContext.prototype.FUNCTIONS = function() { return this.getToken(SqlBaseParser.FUNCTIONS, 0); }; NonReservedContext.prototype.SCHEMAS = function() { return this.getToken(SqlBaseParser.SCHEMAS, 0); }; NonReservedContext.prototype.CATALOGS = function() { return this.getToken(SqlBaseParser.CATALOGS, 0); }; NonReservedContext.prototype.SESSION = function() { return this.getToken(SqlBaseParser.SESSION, 0); }; NonReservedContext.prototype.ADD = function() { return this.getToken(SqlBaseParser.ADD, 0); }; NonReservedContext.prototype.FILTER = function() { return this.getToken(SqlBaseParser.FILTER, 0); }; NonReservedContext.prototype.OVER = function() { return this.getToken(SqlBaseParser.OVER, 0); }; NonReservedContext.prototype.PARTITION = function() { return this.getToken(SqlBaseParser.PARTITION, 0); }; NonReservedContext.prototype.RANGE = function() { return this.getToken(SqlBaseParser.RANGE, 0); }; NonReservedContext.prototype.ROWS = function() { return this.getToken(SqlBaseParser.ROWS, 0); }; NonReservedContext.prototype.PRECEDING = function() { return this.getToken(SqlBaseParser.PRECEDING, 0); }; NonReservedContext.prototype.FOLLOWING = function() { return this.getToken(SqlBaseParser.FOLLOWING, 0); }; NonReservedContext.prototype.CURRENT = function() { return this.getToken(SqlBaseParser.CURRENT, 0); }; NonReservedContext.prototype.ROW = function() { return this.getToken(SqlBaseParser.ROW, 0); }; NonReservedContext.prototype.MAP = function() { return this.getToken(SqlBaseParser.MAP, 0); }; NonReservedContext.prototype.ARRAY = function() { return this.getToken(SqlBaseParser.ARRAY, 0); }; NonReservedContext.prototype.TINYINT = function() { return this.getToken(SqlBaseParser.TINYINT, 0); }; NonReservedContext.prototype.SMALLINT = function() { return this.getToken(SqlBaseParser.SMALLINT, 0); }; NonReservedContext.prototype.INTEGER = function() { return this.getToken(SqlBaseParser.INTEGER, 0); }; NonReservedContext.prototype.DATE = function() { return this.getToken(SqlBaseParser.DATE, 0); }; NonReservedContext.prototype.TIME = function() { return this.getToken(SqlBaseParser.TIME, 0); }; NonReservedContext.prototype.TIMESTAMP = function() { return this.getToken(SqlBaseParser.TIMESTAMP, 0); }; NonReservedContext.prototype.INTERVAL = function() { return this.getToken(SqlBaseParser.INTERVAL, 0); }; NonReservedContext.prototype.ZONE = function() { return this.getToken(SqlBaseParser.ZONE, 0); }; NonReservedContext.prototype.YEAR = function() { return this.getToken(SqlBaseParser.YEAR, 0); }; NonReservedContext.prototype.MONTH = function() { return this.getToken(SqlBaseParser.MONTH, 0); }; NonReservedContext.prototype.DAY = function() { return this.getToken(SqlBaseParser.DAY, 0); }; NonReservedContext.prototype.HOUR = function() { return this.getToken(SqlBaseParser.HOUR, 0); }; NonReservedContext.prototype.MINUTE = function() { return this.getToken(SqlBaseParser.MINUTE, 0); }; NonReservedContext.prototype.SECOND = function() { return this.getToken(SqlBaseParser.SECOND, 0); }; NonReservedContext.prototype.EXPLAIN = function() { return this.getToken(SqlBaseParser.EXPLAIN, 0); }; NonReservedContext.prototype.ANALYZE = function() { return this.getToken(SqlBaseParser.ANALYZE, 0); }; NonReservedContext.prototype.FORMAT = function() { return this.getToken(SqlBaseParser.FORMAT, 0); }; NonReservedContext.prototype.TYPE = function() { return this.getToken(SqlBaseParser.TYPE, 0); }; NonReservedContext.prototype.TEXT = function() { return this.getToken(SqlBaseParser.TEXT, 0); }; NonReservedContext.prototype.GRAPHVIZ = function() { return this.getToken(SqlBaseParser.GRAPHVIZ, 0); }; NonReservedContext.prototype.LOGICAL = function() { return this.getToken(SqlBaseParser.LOGICAL, 0); }; NonReservedContext.prototype.DISTRIBUTED = function() { return this.getToken(SqlBaseParser.DISTRIBUTED, 0); }; NonReservedContext.prototype.TABLESAMPLE = function() { return this.getToken(SqlBaseParser.TABLESAMPLE, 0); }; NonReservedContext.prototype.SYSTEM = function() { return this.getToken(SqlBaseParser.SYSTEM, 0); }; NonReservedContext.prototype.BERNOULLI = function() { return this.getToken(SqlBaseParser.BERNOULLI, 0); }; NonReservedContext.prototype.POISSONIZED = function() { return this.getToken(SqlBaseParser.POISSONIZED, 0); }; NonReservedContext.prototype.USE = function() { return this.getToken(SqlBaseParser.USE, 0); }; NonReservedContext.prototype.TO = function() { return this.getToken(SqlBaseParser.TO, 0); }; NonReservedContext.prototype.SET = function() { return this.getToken(SqlBaseParser.SET, 0); }; NonReservedContext.prototype.RESET = function() { return this.getToken(SqlBaseParser.RESET, 0); }; NonReservedContext.prototype.VIEW = function() { return this.getToken(SqlBaseParser.VIEW, 0); }; NonReservedContext.prototype.REPLACE = function() { return this.getToken(SqlBaseParser.REPLACE, 0); }; NonReservedContext.prototype.IF = function() { return this.getToken(SqlBaseParser.IF, 0); }; NonReservedContext.prototype.NULLIF = function() { return this.getToken(SqlBaseParser.NULLIF, 0); }; NonReservedContext.prototype.COALESCE = function() { return this.getToken(SqlBaseParser.COALESCE, 0); }; NonReservedContext.prototype.normalForm = function() { return this.getTypedRuleContext(NormalFormContext,0); }; NonReservedContext.prototype.POSITION = function() { return this.getToken(SqlBaseParser.POSITION, 0); }; NonReservedContext.prototype.NO = function() { return this.getToken(SqlBaseParser.NO, 0); }; NonReservedContext.prototype.DATA = function() { return this.getToken(SqlBaseParser.DATA, 0); }; NonReservedContext.prototype.START = function() { return this.getToken(SqlBaseParser.START, 0); }; NonReservedContext.prototype.TRANSACTION = function() { return this.getToken(SqlBaseParser.TRANSACTION, 0); }; NonReservedContext.prototype.COMMIT = function() { return this.getToken(SqlBaseParser.COMMIT, 0); }; NonReservedContext.prototype.ROLLBACK = function() { return this.getToken(SqlBaseParser.ROLLBACK, 0); }; NonReservedContext.prototype.WORK = function() { return this.getToken(SqlBaseParser.WORK, 0); }; NonReservedContext.prototype.ISOLATION = function() { return this.getToken(SqlBaseParser.ISOLATION, 0); }; NonReservedContext.prototype.LEVEL = function() { return this.getToken(SqlBaseParser.LEVEL, 0); }; NonReservedContext.prototype.SERIALIZABLE = function() { return this.getToken(SqlBaseParser.SERIALIZABLE, 0); }; NonReservedContext.prototype.REPEATABLE = function() { return this.getToken(SqlBaseParser.REPEATABLE, 0); }; NonReservedContext.prototype.COMMITTED = function() { return this.getToken(SqlBaseParser.COMMITTED, 0); }; NonReservedContext.prototype.UNCOMMITTED = function() { return this.getToken(SqlBaseParser.UNCOMMITTED, 0); }; NonReservedContext.prototype.READ = function() { return this.getToken(SqlBaseParser.READ, 0); }; NonReservedContext.prototype.WRITE = function() { return this.getToken(SqlBaseParser.WRITE, 0); }; NonReservedContext.prototype.ONLY = function() { return this.getToken(SqlBaseParser.ONLY, 0); }; NonReservedContext.prototype.CALL = function() { return this.getToken(SqlBaseParser.CALL, 0); }; NonReservedContext.prototype.GRANT = function() { return this.getToken(SqlBaseParser.GRANT, 0); }; NonReservedContext.prototype.REVOKE = function() { return this.getToken(SqlBaseParser.REVOKE, 0); }; NonReservedContext.prototype.PRIVILEGES = function() { return this.getToken(SqlBaseParser.PRIVILEGES, 0); }; NonReservedContext.prototype.PUBLIC = function() { return this.getToken(SqlBaseParser.PUBLIC, 0); }; NonReservedContext.prototype.OPTION = function() { return this.getToken(SqlBaseParser.OPTION, 0); }; NonReservedContext.prototype.SUBSTRING = function() { return this.getToken(SqlBaseParser.SUBSTRING, 0); }; NonReservedContext.prototype.SCHEMA = function() { return this.getToken(SqlBaseParser.SCHEMA, 0); }; NonReservedContext.prototype.CASCADE = function() { return this.getToken(SqlBaseParser.CASCADE, 0); }; NonReservedContext.prototype.RESTRICT = function() { return this.getToken(SqlBaseParser.RESTRICT, 0); }; NonReservedContext.prototype.INPUT = function() { return this.getToken(SqlBaseParser.INPUT, 0); }; NonReservedContext.prototype.OUTPUT = function() { return this.getToken(SqlBaseParser.OUTPUT, 0); }; NonReservedContext.prototype.INCLUDING = function() { return this.getToken(SqlBaseParser.INCLUDING, 0); }; NonReservedContext.prototype.EXCLUDING = function() { return this.getToken(SqlBaseParser.EXCLUDING, 0); }; NonReservedContext.prototype.PROPERTIES = function() { return this.getToken(SqlBaseParser.PROPERTIES, 0); }; NonReservedContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNonReserved(this); } }; NonReservedContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNonReserved(this); } }; NonReservedContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNonReserved(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.NonReservedContext = NonReservedContext; SqlBaseParser.prototype.nonReserved = function() { var localctx = new NonReservedContext(this, this._ctx, this.state); this.enterRule(localctx, 120, SqlBaseParser.RULE_nonReserved); try { this.state = 1497; this._errHandler.sync(this); switch(this._input.LA(1)) { case SqlBaseParser.SHOW: this.enterOuterAlt(localctx, 1); this.state = 1408; this.match(SqlBaseParser.SHOW); break; case SqlBaseParser.TABLES: this.enterOuterAlt(localctx, 2); this.state = 1409; this.match(SqlBaseParser.TABLES); break; case SqlBaseParser.COLUMNS: this.enterOuterAlt(localctx, 3); this.state = 1410; this.match(SqlBaseParser.COLUMNS); break; case SqlBaseParser.COLUMN: this.enterOuterAlt(localctx, 4); this.state = 1411; this.match(SqlBaseParser.COLUMN); break; case SqlBaseParser.PARTITIONS: this.enterOuterAlt(localctx, 5); this.state = 1412; this.match(SqlBaseParser.PARTITIONS); break; case SqlBaseParser.FUNCTIONS: this.enterOuterAlt(localctx, 6); this.state = 1413; this.match(SqlBaseParser.FUNCTIONS); break; case SqlBaseParser.SCHEMAS: this.enterOuterAlt(localctx, 7); this.state = 1414; this.match(SqlBaseParser.SCHEMAS); break; case SqlBaseParser.CATALOGS: this.enterOuterAlt(localctx, 8); this.state = 1415; this.match(SqlBaseParser.CATALOGS); break; case SqlBaseParser.SESSION: this.enterOuterAlt(localctx, 9); this.state = 1416; this.match(SqlBaseParser.SESSION); break; case SqlBaseParser.ADD: this.enterOuterAlt(localctx, 10); this.state = 1417; this.match(SqlBaseParser.ADD); break; case SqlBaseParser.FILTER: this.enterOuterAlt(localctx, 11); this.state = 1418; this.match(SqlBaseParser.FILTER); break; case SqlBaseParser.OVER: this.enterOuterAlt(localctx, 12); this.state = 1419; this.match(SqlBaseParser.OVER); break; case SqlBaseParser.PARTITION: this.enterOuterAlt(localctx, 13); this.state = 1420; this.match(SqlBaseParser.PARTITION); break; case SqlBaseParser.RANGE: this.enterOuterAlt(localctx, 14); this.state = 1421; this.match(SqlBaseParser.RANGE); break; case SqlBaseParser.ROWS: this.enterOuterAlt(localctx, 15); this.state = 1422; this.match(SqlBaseParser.ROWS); break; case SqlBaseParser.PRECEDING: this.enterOuterAlt(localctx, 16); this.state = 1423; this.match(SqlBaseParser.PRECEDING); break; case SqlBaseParser.FOLLOWING: this.enterOuterAlt(localctx, 17); this.state = 1424; this.match(SqlBaseParser.FOLLOWING); break; case SqlBaseParser.CURRENT: this.enterOuterAlt(localctx, 18); this.state = 1425; this.match(SqlBaseParser.CURRENT); break; case SqlBaseParser.ROW: this.enterOuterAlt(localctx, 19); this.state = 1426; this.match(SqlBaseParser.ROW); break; case SqlBaseParser.MAP: this.enterOuterAlt(localctx, 20); this.state = 1427; this.match(SqlBaseParser.MAP); break; case SqlBaseParser.ARRAY: this.enterOuterAlt(localctx, 21); this.state = 1428; this.match(SqlBaseParser.ARRAY); break; case SqlBaseParser.TINYINT: this.enterOuterAlt(localctx, 22); this.state = 1429; this.match(SqlBaseParser.TINYINT); break; case SqlBaseParser.SMALLINT: this.enterOuterAlt(localctx, 23); this.state = 1430; this.match(SqlBaseParser.SMALLINT); break; case SqlBaseParser.INTEGER: this.enterOuterAlt(localctx, 24); this.state = 1431; this.match(SqlBaseParser.INTEGER); break; case SqlBaseParser.DATE: this.enterOuterAlt(localctx, 25); this.state = 1432; this.match(SqlBaseParser.DATE); break; case SqlBaseParser.TIME: this.enterOuterAlt(localctx, 26); this.state = 1433; this.match(SqlBaseParser.TIME); break; case SqlBaseParser.TIMESTAMP: this.enterOuterAlt(localctx, 27); this.state = 1434; this.match(SqlBaseParser.TIMESTAMP); break; case SqlBaseParser.INTERVAL: this.enterOuterAlt(localctx, 28); this.state = 1435; this.match(SqlBaseParser.INTERVAL); break; case SqlBaseParser.ZONE: this.enterOuterAlt(localctx, 29); this.state = 1436; this.match(SqlBaseParser.ZONE); break; case SqlBaseParser.YEAR: this.enterOuterAlt(localctx, 30); this.state = 1437; this.match(SqlBaseParser.YEAR); break; case SqlBaseParser.MONTH: this.enterOuterAlt(localctx, 31); this.state = 1438; this.match(SqlBaseParser.MONTH); break; case SqlBaseParser.DAY: this.enterOuterAlt(localctx, 32); this.state = 1439; this.match(SqlBaseParser.DAY); break; case SqlBaseParser.HOUR: this.enterOuterAlt(localctx, 33); this.state = 1440; this.match(SqlBaseParser.HOUR); break; case SqlBaseParser.MINUTE: this.enterOuterAlt(localctx, 34); this.state = 1441; this.match(SqlBaseParser.MINUTE); break; case SqlBaseParser.SECOND: this.enterOuterAlt(localctx, 35); this.state = 1442; this.match(SqlBaseParser.SECOND); break; case SqlBaseParser.EXPLAIN: this.enterOuterAlt(localctx, 36); this.state = 1443; this.match(SqlBaseParser.EXPLAIN); break; case SqlBaseParser.ANALYZE: this.enterOuterAlt(localctx, 37); this.state = 1444; this.match(SqlBaseParser.ANALYZE); break; case SqlBaseParser.FORMAT: this.enterOuterAlt(localctx, 38); this.state = 1445; this.match(SqlBaseParser.FORMAT); break; case SqlBaseParser.TYPE: this.enterOuterAlt(localctx, 39); this.state = 1446; this.match(SqlBaseParser.TYPE); break; case SqlBaseParser.TEXT: this.enterOuterAlt(localctx, 40); this.state = 1447; this.match(SqlBaseParser.TEXT); break; case SqlBaseParser.GRAPHVIZ: this.enterOuterAlt(localctx, 41); this.state = 1448; this.match(SqlBaseParser.GRAPHVIZ); break; case SqlBaseParser.LOGICAL: this.enterOuterAlt(localctx, 42); this.state = 1449; this.match(SqlBaseParser.LOGICAL); break; case SqlBaseParser.DISTRIBUTED: this.enterOuterAlt(localctx, 43); this.state = 1450; this.match(SqlBaseParser.DISTRIBUTED); break; case SqlBaseParser.TABLESAMPLE: this.enterOuterAlt(localctx, 44); this.state = 1451; this.match(SqlBaseParser.TABLESAMPLE); break; case SqlBaseParser.SYSTEM: this.enterOuterAlt(localctx, 45); this.state = 1452; this.match(SqlBaseParser.SYSTEM); break; case SqlBaseParser.BERNOULLI: this.enterOuterAlt(localctx, 46); this.state = 1453; this.match(SqlBaseParser.BERNOULLI); break; case SqlBaseParser.POISSONIZED: this.enterOuterAlt(localctx, 47); this.state = 1454; this.match(SqlBaseParser.POISSONIZED); break; case SqlBaseParser.USE: this.enterOuterAlt(localctx, 48); this.state = 1455; this.match(SqlBaseParser.USE); break; case SqlBaseParser.TO: this.enterOuterAlt(localctx, 49); this.state = 1456; this.match(SqlBaseParser.TO); break; case SqlBaseParser.SET: this.enterOuterAlt(localctx, 50); this.state = 1457; this.match(SqlBaseParser.SET); break; case SqlBaseParser.RESET: this.enterOuterAlt(localctx, 51); this.state = 1458; this.match(SqlBaseParser.RESET); break; case SqlBaseParser.VIEW: this.enterOuterAlt(localctx, 52); this.state = 1459; this.match(SqlBaseParser.VIEW); break; case SqlBaseParser.REPLACE: this.enterOuterAlt(localctx, 53); this.state = 1460; this.match(SqlBaseParser.REPLACE); break; case SqlBaseParser.IF: this.enterOuterAlt(localctx, 54); this.state = 1461; this.match(SqlBaseParser.IF); break; case SqlBaseParser.NULLIF: this.enterOuterAlt(localctx, 55); this.state = 1462; this.match(SqlBaseParser.NULLIF); break; case SqlBaseParser.COALESCE: this.enterOuterAlt(localctx, 56); this.state = 1463; this.match(SqlBaseParser.COALESCE); break; case SqlBaseParser.NFD: case SqlBaseParser.NFC: case SqlBaseParser.NFKD: case SqlBaseParser.NFKC: this.enterOuterAlt(localctx, 57); this.state = 1464; this.normalForm(); break; case SqlBaseParser.POSITION: this.enterOuterAlt(localctx, 58); this.state = 1465; this.match(SqlBaseParser.POSITION); break; case SqlBaseParser.NO: this.enterOuterAlt(localctx, 59); this.state = 1466; this.match(SqlBaseParser.NO); break; case SqlBaseParser.DATA: this.enterOuterAlt(localctx, 60); this.state = 1467; this.match(SqlBaseParser.DATA); break; case SqlBaseParser.START: this.enterOuterAlt(localctx, 61); this.state = 1468; this.match(SqlBaseParser.START); break; case SqlBaseParser.TRANSACTION: this.enterOuterAlt(localctx, 62); this.state = 1469; this.match(SqlBaseParser.TRANSACTION); break; case SqlBaseParser.COMMIT: this.enterOuterAlt(localctx, 63); this.state = 1470; this.match(SqlBaseParser.COMMIT); break; case SqlBaseParser.ROLLBACK: this.enterOuterAlt(localctx, 64); this.state = 1471; this.match(SqlBaseParser.ROLLBACK); break; case SqlBaseParser.WORK: this.enterOuterAlt(localctx, 65); this.state = 1472; this.match(SqlBaseParser.WORK); break; case SqlBaseParser.ISOLATION: this.enterOuterAlt(localctx, 66); this.state = 1473; this.match(SqlBaseParser.ISOLATION); break; case SqlBaseParser.LEVEL: this.enterOuterAlt(localctx, 67); this.state = 1474; this.match(SqlBaseParser.LEVEL); break; case SqlBaseParser.SERIALIZABLE: this.enterOuterAlt(localctx, 68); this.state = 1475; this.match(SqlBaseParser.SERIALIZABLE); break; case SqlBaseParser.REPEATABLE: this.enterOuterAlt(localctx, 69); this.state = 1476; this.match(SqlBaseParser.REPEATABLE); break; case SqlBaseParser.COMMITTED: this.enterOuterAlt(localctx, 70); this.state = 1477; this.match(SqlBaseParser.COMMITTED); break; case SqlBaseParser.UNCOMMITTED: this.enterOuterAlt(localctx, 71); this.state = 1478; this.match(SqlBaseParser.UNCOMMITTED); break; case SqlBaseParser.READ: this.enterOuterAlt(localctx, 72); this.state = 1479; this.match(SqlBaseParser.READ); break; case SqlBaseParser.WRITE: this.enterOuterAlt(localctx, 73); this.state = 1480; this.match(SqlBaseParser.WRITE); break; case SqlBaseParser.ONLY: this.enterOuterAlt(localctx, 74); this.state = 1481; this.match(SqlBaseParser.ONLY); break; case SqlBaseParser.CALL: this.enterOuterAlt(localctx, 75); this.state = 1482; this.match(SqlBaseParser.CALL); break; case SqlBaseParser.GRANT: this.enterOuterAlt(localctx, 76); this.state = 1483; this.match(SqlBaseParser.GRANT); break; case SqlBaseParser.REVOKE: this.enterOuterAlt(localctx, 77); this.state = 1484; this.match(SqlBaseParser.REVOKE); break; case SqlBaseParser.PRIVILEGES: this.enterOuterAlt(localctx, 78); this.state = 1485; this.match(SqlBaseParser.PRIVILEGES); break; case SqlBaseParser.PUBLIC: this.enterOuterAlt(localctx, 79); this.state = 1486; this.match(SqlBaseParser.PUBLIC); break; case SqlBaseParser.OPTION: this.enterOuterAlt(localctx, 80); this.state = 1487; this.match(SqlBaseParser.OPTION); break; case SqlBaseParser.SUBSTRING: this.enterOuterAlt(localctx, 81); this.state = 1488; this.match(SqlBaseParser.SUBSTRING); break; case SqlBaseParser.SCHEMA: this.enterOuterAlt(localctx, 82); this.state = 1489; this.match(SqlBaseParser.SCHEMA); break; case SqlBaseParser.CASCADE: this.enterOuterAlt(localctx, 83); this.state = 1490; this.match(SqlBaseParser.CASCADE); break; case SqlBaseParser.RESTRICT: this.enterOuterAlt(localctx, 84); this.state = 1491; this.match(SqlBaseParser.RESTRICT); break; case SqlBaseParser.INPUT: this.enterOuterAlt(localctx, 85); this.state = 1492; this.match(SqlBaseParser.INPUT); break; case SqlBaseParser.OUTPUT: this.enterOuterAlt(localctx, 86); this.state = 1493; this.match(SqlBaseParser.OUTPUT); break; case SqlBaseParser.INCLUDING: this.enterOuterAlt(localctx, 87); this.state = 1494; this.match(SqlBaseParser.INCLUDING); break; case SqlBaseParser.EXCLUDING: this.enterOuterAlt(localctx, 88); this.state = 1495; this.match(SqlBaseParser.EXCLUDING); break; case SqlBaseParser.PROPERTIES: this.enterOuterAlt(localctx, 89); this.state = 1496; this.match(SqlBaseParser.PROPERTIES); break; default: throw new _error.NoViableAltException(this); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function NormalFormContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = SqlBaseParser.RULE_normalForm; // return this; } NormalFormContext.prototype = Object.create(ParserRuleContext.prototype); NormalFormContext.prototype.constructor = NormalFormContext; NormalFormContext.prototype.NFD = function() { return this.getToken(SqlBaseParser.NFD, 0); }; NormalFormContext.prototype.NFC = function() { return this.getToken(SqlBaseParser.NFC, 0); }; NormalFormContext.prototype.NFKD = function() { return this.getToken(SqlBaseParser.NFKD, 0); }; NormalFormContext.prototype.NFKC = function() { return this.getToken(SqlBaseParser.NFKC, 0); }; NormalFormContext.prototype.enterRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).enterNormalForm(this); } }; NormalFormContext.prototype.exitRule = function(listener) { if(listener instanceof SqlBaseListener ) { (listener as any).exitNormalForm(this); } }; NormalFormContext.prototype.accept = function(visitor) { if ( visitor instanceof SqlBaseVisitor ) { return (visitor as any).visitNormalForm(this); } else { return (visitor as any).visitChildren(this); } }; SqlBaseParser.NormalFormContext = NormalFormContext; SqlBaseParser.prototype.normalForm = function() { var localctx = new NormalFormContext(this, this._ctx, this.state); this.enterRule(localctx, 122, SqlBaseParser.RULE_normalForm); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1499; _la = this._input.LA(1); if(!(((((_la - 177)) & ~0x1f) == 0 && ((1 << (_la - 177)) & ((1 << (SqlBaseParser.NFD - 177)) | (1 << (SqlBaseParser.NFC - 177)) | (1 << (SqlBaseParser.NFKD - 177)) | (1 << (SqlBaseParser.NFKC - 177)))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof _error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; SqlBaseParser.prototype.sempred = function(localctx, ruleIndex, predIndex) { switch(ruleIndex) { case 12: return this.queryTerm_sempred(localctx, predIndex); case 23: return this.relation_sempred(localctx, predIndex); case 32: return this.booleanExpression_sempred(localctx, predIndex); case 35: return this.valueExpression_sempred(localctx, predIndex); case 36: return this.primaryExpression_sempred(localctx, predIndex); case 43: return this.type_sempred(localctx, predIndex); default: throw "No predicate with index:" + ruleIndex; } }; SqlBaseParser.prototype.queryTerm_sempred = function(localctx, predIndex) { switch(predIndex) { case 0: return this.precpred(this._ctx, 2); case 1: return this.precpred(this._ctx, 1); default: throw "No predicate with index:" + predIndex; } }; SqlBaseParser.prototype.relation_sempred = function(localctx, predIndex) { switch(predIndex) { case 2: return this.precpred(this._ctx, 2); default: throw "No predicate with index:" + predIndex; } }; SqlBaseParser.prototype.booleanExpression_sempred = function(localctx, predIndex) { switch(predIndex) { case 3: return this.precpred(this._ctx, 2); case 4: return this.precpred(this._ctx, 1); default: throw "No predicate with index:" + predIndex; } }; SqlBaseParser.prototype.valueExpression_sempred = function(localctx, predIndex) { switch(predIndex) { case 5: return this.precpred(this._ctx, 3); case 6: return this.precpred(this._ctx, 2); case 7: return this.precpred(this._ctx, 1); case 8: return this.precpred(this._ctx, 5); default: throw "No predicate with index:" + predIndex; } }; SqlBaseParser.prototype.primaryExpression_sempred = function(localctx, predIndex) { switch(predIndex) { case 9: return this.precpred(this._ctx, 11); case 10: return this.precpred(this._ctx, 9); default: throw "No predicate with index:" + predIndex; } }; SqlBaseParser.prototype.type_sempred = function(localctx, predIndex) { switch(predIndex) { case 11: return this.precpred(this._ctx, 5); default: throw "No predicate with index:" + predIndex; } }; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseVisitor.ts ================================================ // Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7 // jshint ignore: start import { tree } from 'antlr4'; // This class defines a complete generic visitor for a parse tree produced by SqlBaseParser. export const SqlBaseVisitor = function() { tree.ParseTreeVisitor.call(this); return this; } as any; SqlBaseVisitor.prototype = Object.create(tree.ParseTreeVisitor.prototype); SqlBaseVisitor.prototype.constructor = SqlBaseVisitor; // Visit a parse tree produced by SqlBaseParser#multiStatement. SqlBaseVisitor.prototype.visitMultiStatement = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#singleStatement. SqlBaseVisitor.prototype.visitSingleStatement = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#singleExpression. SqlBaseVisitor.prototype.visitSingleExpression = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#statementDefault. SqlBaseVisitor.prototype.visitStatementDefault = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#use. SqlBaseVisitor.prototype.visitUse = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#createSchema. SqlBaseVisitor.prototype.visitCreateSchema = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#dropSchema. SqlBaseVisitor.prototype.visitDropSchema = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#renameSchema. SqlBaseVisitor.prototype.visitRenameSchema = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#createTableAsSelect. SqlBaseVisitor.prototype.visitCreateTableAsSelect = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#createTable. SqlBaseVisitor.prototype.visitCreateTable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#dropTable. SqlBaseVisitor.prototype.visitDropTable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#insertInto. SqlBaseVisitor.prototype.visitInsertInto = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#delete. SqlBaseVisitor.prototype.visitDelete = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#renameTable. SqlBaseVisitor.prototype.visitRenameTable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#renameColumn. SqlBaseVisitor.prototype.visitRenameColumn = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#addColumn. SqlBaseVisitor.prototype.visitAddColumn = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#createView. SqlBaseVisitor.prototype.visitCreateView = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#dropView. SqlBaseVisitor.prototype.visitDropView = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#call. SqlBaseVisitor.prototype.visitCall = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#grant. SqlBaseVisitor.prototype.visitGrant = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#revoke. SqlBaseVisitor.prototype.visitRevoke = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#explain. SqlBaseVisitor.prototype.visitExplain = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showCreateTable. SqlBaseVisitor.prototype.visitShowCreateTable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showCreateView. SqlBaseVisitor.prototype.visitShowCreateView = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showTables. SqlBaseVisitor.prototype.visitShowTables = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showSchemas. SqlBaseVisitor.prototype.visitShowSchemas = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showCatalogs. SqlBaseVisitor.prototype.visitShowCatalogs = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showColumns. SqlBaseVisitor.prototype.visitShowColumns = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showFunctions. SqlBaseVisitor.prototype.visitShowFunctions = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showSession. SqlBaseVisitor.prototype.visitShowSession = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#setSession. SqlBaseVisitor.prototype.visitSetSession = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#resetSession. SqlBaseVisitor.prototype.visitResetSession = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#startTransaction. SqlBaseVisitor.prototype.visitStartTransaction = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#commit. SqlBaseVisitor.prototype.visitCommit = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#rollback. SqlBaseVisitor.prototype.visitRollback = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#showPartitions. SqlBaseVisitor.prototype.visitShowPartitions = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#prepare. SqlBaseVisitor.prototype.visitPrepare = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#deallocate. SqlBaseVisitor.prototype.visitDeallocate = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#execute. SqlBaseVisitor.prototype.visitExecute = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#describeInput. SqlBaseVisitor.prototype.visitDescribeInput = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#describeOutput. SqlBaseVisitor.prototype.visitDescribeOutput = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#query. SqlBaseVisitor.prototype.visitQuery = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#presto_with. SqlBaseVisitor.prototype.visitPresto_with = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#tableElement. SqlBaseVisitor.prototype.visitTableElement = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#columnDefinition. SqlBaseVisitor.prototype.visitColumnDefinition = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#likeClause. SqlBaseVisitor.prototype.visitLikeClause = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#tableProperties. SqlBaseVisitor.prototype.visitTableProperties = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#tableProperty. SqlBaseVisitor.prototype.visitTableProperty = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#queryNoWith. SqlBaseVisitor.prototype.visitQueryNoWith = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#queryTermDefault. SqlBaseVisitor.prototype.visitQueryTermDefault = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#setOperation. SqlBaseVisitor.prototype.visitSetOperation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#queryPrimaryDefault. SqlBaseVisitor.prototype.visitQueryPrimaryDefault = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#table. SqlBaseVisitor.prototype.visitTable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#inlineTable. SqlBaseVisitor.prototype.visitInlineTable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#subquery. SqlBaseVisitor.prototype.visitSubquery = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#sortItem. SqlBaseVisitor.prototype.visitSortItem = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#querySpecification. SqlBaseVisitor.prototype.visitQuerySpecification = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#groupBy. SqlBaseVisitor.prototype.visitGroupBy = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#singleGroupingSet. SqlBaseVisitor.prototype.visitSingleGroupingSet = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#rollup. SqlBaseVisitor.prototype.visitRollup = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#cube. SqlBaseVisitor.prototype.visitCube = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#multipleGroupingSets. SqlBaseVisitor.prototype.visitMultipleGroupingSets = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#groupingExpressions. SqlBaseVisitor.prototype.visitGroupingExpressions = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#groupingSet. SqlBaseVisitor.prototype.visitGroupingSet = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#namedQuery. SqlBaseVisitor.prototype.visitNamedQuery = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#setQuantifier. SqlBaseVisitor.prototype.visitSetQuantifier = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#selectSingle. SqlBaseVisitor.prototype.visitSelectSingle = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#selectAll. SqlBaseVisitor.prototype.visitSelectAll = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#relationDefault. SqlBaseVisitor.prototype.visitRelationDefault = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#joinRelation. SqlBaseVisitor.prototype.visitJoinRelation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#joinType. SqlBaseVisitor.prototype.visitJoinType = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#joinCriteria. SqlBaseVisitor.prototype.visitJoinCriteria = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#sampledRelation. SqlBaseVisitor.prototype.visitSampledRelation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#sampleType. SqlBaseVisitor.prototype.visitSampleType = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#aliasedRelation. SqlBaseVisitor.prototype.visitAliasedRelation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#columnAliases. SqlBaseVisitor.prototype.visitColumnAliases = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#tableName. SqlBaseVisitor.prototype.visitTableName = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#subqueryRelation. SqlBaseVisitor.prototype.visitSubqueryRelation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#unnest. SqlBaseVisitor.prototype.visitUnnest = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#parenthesizedRelation. SqlBaseVisitor.prototype.visitParenthesizedRelation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#expression. SqlBaseVisitor.prototype.visitExpression = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#logicalNot. SqlBaseVisitor.prototype.visitLogicalNot = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#booleanDefault. SqlBaseVisitor.prototype.visitBooleanDefault = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#logicalBinary. SqlBaseVisitor.prototype.visitLogicalBinary = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#predicated. SqlBaseVisitor.prototype.visitPredicated = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#comparison. SqlBaseVisitor.prototype.visitComparison = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#quantifiedComparison. SqlBaseVisitor.prototype.visitQuantifiedComparison = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#between. SqlBaseVisitor.prototype.visitBetween = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#inList. SqlBaseVisitor.prototype.visitInList = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#inSubquery. SqlBaseVisitor.prototype.visitInSubquery = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#like. SqlBaseVisitor.prototype.visitLike = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#nullPredicate. SqlBaseVisitor.prototype.visitNullPredicate = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#distinctFrom. SqlBaseVisitor.prototype.visitDistinctFrom = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#valueExpressionDefault. SqlBaseVisitor.prototype.visitValueExpressionDefault = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#concatenation. SqlBaseVisitor.prototype.visitConcatenation = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#arithmeticBinary. SqlBaseVisitor.prototype.visitArithmeticBinary = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#arithmeticUnary. SqlBaseVisitor.prototype.visitArithmeticUnary = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#atTimeZone. SqlBaseVisitor.prototype.visitAtTimeZone = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#dereference. SqlBaseVisitor.prototype.visitDereference = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#typeConstructor. SqlBaseVisitor.prototype.visitTypeConstructor = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#specialDateTimeFunction. SqlBaseVisitor.prototype.visitSpecialDateTimeFunction = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#substring. SqlBaseVisitor.prototype.visitSubstring = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#cast. SqlBaseVisitor.prototype.visitCast = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#lambda. SqlBaseVisitor.prototype.visitLambda = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#parameter. SqlBaseVisitor.prototype.visitParameter = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#normalize. SqlBaseVisitor.prototype.visitNormalize = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#intervalLiteral. SqlBaseVisitor.prototype.visitIntervalLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#numericLiteral. SqlBaseVisitor.prototype.visitNumericLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#booleanLiteral. SqlBaseVisitor.prototype.visitBooleanLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#implicitRowConstructor. SqlBaseVisitor.prototype.visitImplicitRowConstructor = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#simpleCase. SqlBaseVisitor.prototype.visitSimpleCase = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#columnReference. SqlBaseVisitor.prototype.visitColumnReference = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#nullLiteral. SqlBaseVisitor.prototype.visitNullLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#rowConstructor. SqlBaseVisitor.prototype.visitRowConstructor = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#subscript. SqlBaseVisitor.prototype.visitSubscript = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#subqueryExpression. SqlBaseVisitor.prototype.visitSubqueryExpression = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#binaryLiteral. SqlBaseVisitor.prototype.visitBinaryLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#extract. SqlBaseVisitor.prototype.visitExtract = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#stringLiteral. SqlBaseVisitor.prototype.visitStringLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#arrayConstructor. SqlBaseVisitor.prototype.visitArrayConstructor = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#functionCall. SqlBaseVisitor.prototype.visitFunctionCall = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#exists. SqlBaseVisitor.prototype.visitExists = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#position. SqlBaseVisitor.prototype.visitPosition = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#searchedCase. SqlBaseVisitor.prototype.visitSearchedCase = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#timeZoneInterval. SqlBaseVisitor.prototype.visitTimeZoneInterval = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#timeZoneString. SqlBaseVisitor.prototype.visitTimeZoneString = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#comparisonOperator. SqlBaseVisitor.prototype.visitComparisonOperator = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#comparisonQuantifier. SqlBaseVisitor.prototype.visitComparisonQuantifier = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#booleanValue. SqlBaseVisitor.prototype.visitBooleanValue = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#interval. SqlBaseVisitor.prototype.visitInterval = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#intervalField. SqlBaseVisitor.prototype.visitIntervalField = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#type. SqlBaseVisitor.prototype.visitType = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#typeParameter. SqlBaseVisitor.prototype.visitTypeParameter = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#baseType. SqlBaseVisitor.prototype.visitBaseType = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#whenClause. SqlBaseVisitor.prototype.visitWhenClause = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#filter. SqlBaseVisitor.prototype.visitFilter = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#over. SqlBaseVisitor.prototype.visitOver = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#windowFrame. SqlBaseVisitor.prototype.visitWindowFrame = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#unboundedFrame. SqlBaseVisitor.prototype.visitUnboundedFrame = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#currentRowBound. SqlBaseVisitor.prototype.visitCurrentRowBound = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#boundedFrame. SqlBaseVisitor.prototype.visitBoundedFrame = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#explainFormat. SqlBaseVisitor.prototype.visitExplainFormat = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#explainType. SqlBaseVisitor.prototype.visitExplainType = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#isolationLevel. SqlBaseVisitor.prototype.visitIsolationLevel = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#transactionAccessMode. SqlBaseVisitor.prototype.visitTransactionAccessMode = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#readUncommitted. SqlBaseVisitor.prototype.visitReadUncommitted = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#readCommitted. SqlBaseVisitor.prototype.visitReadCommitted = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#repeatableRead. SqlBaseVisitor.prototype.visitRepeatableRead = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#serializable. SqlBaseVisitor.prototype.visitSerializable = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#positionalArgument. SqlBaseVisitor.prototype.visitPositionalArgument = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#namedArgument. SqlBaseVisitor.prototype.visitNamedArgument = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#privilege. SqlBaseVisitor.prototype.visitPrivilege = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#qualifiedName. SqlBaseVisitor.prototype.visitQualifiedName = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#unquotedIdentifier. SqlBaseVisitor.prototype.visitUnquotedIdentifier = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#quotedIdentifierAlternative. SqlBaseVisitor.prototype.visitQuotedIdentifierAlternative = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#backQuotedIdentifier. SqlBaseVisitor.prototype.visitBackQuotedIdentifier = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#digitIdentifier. SqlBaseVisitor.prototype.visitDigitIdentifier = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#quotedIdentifier. SqlBaseVisitor.prototype.visitQuotedIdentifier = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#decimalLiteral. SqlBaseVisitor.prototype.visitDecimalLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#integerLiteral. SqlBaseVisitor.prototype.visitIntegerLiteral = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#nonReserved. SqlBaseVisitor.prototype.visitNonReserved = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by SqlBaseParser#normalForm. SqlBaseVisitor.prototype.visitNormalForm = function(ctx) { return this.visitChildren(ctx); }; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Lexer.js ================================================ // Generated from ./lang/python/Python3.g4 by ANTLR 4.7 // jshint ignore: start var antlr4 = require('antlr4/index'); var serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964", "\u0002^\u0347\b\u0001\u0004\u0002\t\u0002\u0004\u0003\t\u0003\u0004", "\u0004\t\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007\t", "\u0007\u0004\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004", "\f\t\f\u0004\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010", "\t\u0010\u0004\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013", "\u0004\u0014\t\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017", "\t\u0017\u0004\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a", "\u0004\u001b\t\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e", "\t\u001e\u0004\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#", "\t#\u0004$\t$\u0004%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004", "*\t*\u0004+\t+\u0004,\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u0004", "1\t1\u00042\t2\u00043\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u0004", "8\t8\u00049\t9\u0004:\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004", "?\t?\u0004@\t@\u0004A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004", "F\tF\u0004G\tG\u0004H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004", "M\tM\u0004N\tN\u0004O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004", "T\tT\u0004U\tU\u0004V\tV\u0004W\tW\u0004X\tX\u0004Y\tY\u0004Z\tZ\u0004", "[\t[\u0004\\\t\\\u0004]\t]\u0004^\t^\u0004_\t_\u0004`\t`\u0004a\ta\u0004", "b\tb\u0004c\tc\u0004d\td\u0004e\te\u0004f\tf\u0004g\tg\u0004h\th\u0004", "i\ti\u0004j\tj\u0004k\tk\u0004l\tl\u0004m\tm\u0004n\tn\u0004o\to\u0004", "p\tp\u0004q\tq\u0004r\tr\u0004s\ts\u0004t\tt\u0004u\tu\u0004v\tv\u0004", "w\tw\u0004x\tx\u0003\u0002\u0003\u0002\u0003\u0002\u0003\u0002\u0003", "\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003", "\u0003\u0003\u0004\u0003\u0004\u0003\u0004\u0003\u0004\u0003\u0004\u0003", "\u0004\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0003", "\u0006\u0003\u0006\u0003\u0006\u0003\u0006\u0003\u0006\u0003\u0006\u0003", "\u0006\u0003\u0007\u0003\u0007\u0003\u0007\u0003\b\u0003\b\u0003\b\u0003", "\b\u0003\b\u0003\b\u0003\b\u0003\t\u0003\t\u0003\t\u0003\t\u0003\t\u0003", "\t\u0003\t\u0003\t\u0003\t\u0003\n\u0003\n\u0003\n\u0003\n\u0003\n\u0003", "\n\u0003\n\u0003\u000b\u0003\u000b\u0003\u000b\u0003\f\u0003\f\u0003", "\f\u0003\f\u0003\f\u0003\r\u0003\r\u0003\r\u0003\r\u0003\r\u0003\u000e", "\u0003\u000e\u0003\u000e\u0003\u000e\u0003\u000e\u0003\u000e\u0003\u000f", "\u0003\u000f\u0003\u000f\u0003\u000f\u0003\u0010\u0003\u0010\u0003\u0010", "\u0003\u0011\u0003\u0011\u0003\u0011\u0003\u0011\u0003\u0012\u0003\u0012", "\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0003\u0012", "\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0013\u0003\u0014", "\u0003\u0014\u0003\u0014\u0003\u0014\u0003\u0014\u0003\u0014\u0003\u0014", "\u0003\u0015\u0003\u0015\u0003\u0015\u0003\u0015\u0003\u0015\u0003\u0015", "\u0003\u0015\u0003\u0016\u0003\u0016\u0003\u0016\u0003\u0017\u0003\u0017", "\u0003\u0017\u0003\u0017\u0003\u0018\u0003\u0018\u0003\u0018\u0003\u0018", "\u0003\u0019\u0003\u0019\u0003\u0019\u0003\u001a\u0003\u001a\u0003\u001a", "\u0003\u001a\u0003\u001a\u0003\u001b\u0003\u001b\u0003\u001b\u0003\u001b", "\u0003\u001b\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c\u0003\u001c", "\u0003\u001c\u0003\u001d\u0003\u001d\u0003\u001d\u0003\u001d\u0003\u001d", "\u0003\u001d\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e", "\u0003\u001e\u0003\u001f\u0003\u001f\u0003\u001f\u0003\u001f\u0003 ", "\u0003 \u0003 \u0003 \u0003 \u0003!\u0003!\u0003!\u0003!\u0003!\u0003", "!\u0003!\u0003!\u0003!\u0003\"\u0003\"\u0003\"\u0003\"\u0003\"\u0003", "\"\u0003#\u0003#\u0003#\u0005#\u01a7\n#\u0003#\u0003#\u0005#\u01ab\n", "#\u0003#\u0005#\u01ae\n#\u0005#\u01b0\n#\u0003#\u0003#\u0003$\u0003", "$\u0007$\u01b6\n$\f$\u000e$\u01b9\u000b$\u0003%\u0005%\u01bc\n%\u0003", "%\u0005%\u01bf\n%\u0003%\u0003%\u0005%\u01c3\n%\u0003&\u0003&\u0005", "&\u01c7\n&\u0003&\u0003&\u0005&\u01cb\n&\u0003\'\u0003\'\u0007\'\u01cf", "\n\'\f\'\u000e\'\u01d2\u000b\'\u0003\'\u0006\'\u01d5\n\'\r\'\u000e\'", "\u01d6\u0005\'\u01d9\n\'\u0003(\u0003(\u0003(\u0006(\u01de\n(\r(\u000e", "(\u01df\u0003)\u0003)\u0003)\u0006)\u01e5\n)\r)\u000e)\u01e6\u0003*", "\u0003*\u0003*\u0006*\u01ec\n*\r*\u000e*\u01ed\u0003+\u0003+\u0005+", "\u01f2\n+\u0003,\u0003,\u0005,\u01f6\n,\u0003,\u0003,\u0003-\u0003-", "\u0003.\u0003.\u0003.\u0003.\u0003/\u0003/\u00030\u00030\u00030\u0003", "1\u00031\u00031\u00032\u00032\u00033\u00033\u00034\u00034\u00035\u0003", "5\u00035\u00036\u00036\u00037\u00037\u00037\u00038\u00038\u00038\u0003", "9\u00039\u0003:\u0003:\u0003;\u0003;\u0003<\u0003<\u0003<\u0003=\u0003", "=\u0003=\u0003>\u0003>\u0003?\u0003?\u0003@\u0003@\u0003A\u0003A\u0003", "B\u0003B\u0003B\u0003C\u0003C\u0003D\u0003D\u0003D\u0003E\u0003E\u0003", "E\u0003F\u0003F\u0003G\u0003G\u0003H\u0003H\u0003H\u0003I\u0003I\u0003", "I\u0003J\u0003J\u0003J\u0003K\u0003K\u0003K\u0003L\u0003L\u0003L\u0003", "M\u0003M\u0003N\u0003N\u0003N\u0003O\u0003O\u0003O\u0003P\u0003P\u0003", "P\u0003Q\u0003Q\u0003Q\u0003R\u0003R\u0003R\u0003S\u0003S\u0003S\u0003", "T\u0003T\u0003T\u0003U\u0003U\u0003U\u0003V\u0003V\u0003V\u0003W\u0003", "W\u0003W\u0003X\u0003X\u0003X\u0003X\u0003Y\u0003Y\u0003Y\u0003Y\u0003", "Z\u0003Z\u0003Z\u0003Z\u0003[\u0003[\u0003[\u0003[\u0003\\\u0003\\\u0003", "\\\u0005\\\u027e\n\\\u0003\\\u0003\\\u0003]\u0003]\u0003^\u0003^\u0003", "^\u0007^\u0287\n^\f^\u000e^\u028a\u000b^\u0003^\u0003^\u0003^\u0003", "^\u0007^\u0290\n^\f^\u000e^\u0293\u000b^\u0003^\u0005^\u0296\n^\u0003", "_\u0003_\u0003_\u0003_\u0003_\u0007_\u029d\n_\f_\u000e_\u02a0\u000b", "_\u0003_\u0003_\u0003_\u0003_\u0003_\u0003_\u0003_\u0003_\u0007_\u02aa", "\n_\f_\u000e_\u02ad\u000b_\u0003_\u0003_\u0003_\u0005_\u02b2\n_\u0003", "`\u0003`\u0005`\u02b6\n`\u0003a\u0003a\u0003b\u0003b\u0003b\u0003c\u0003", "c\u0003d\u0003d\u0003e\u0003e\u0003f\u0003f\u0003g\u0003g\u0003h\u0005", "h\u02c8\nh\u0003h\u0003h\u0003h\u0003h\u0005h\u02ce\nh\u0003i\u0003", "i\u0005i\u02d2\ni\u0003i\u0003i\u0003j\u0006j\u02d7\nj\rj\u000ej\u02d8", "\u0003k\u0003k\u0006k\u02dd\nk\rk\u000ek\u02de\u0003l\u0003l\u0005l", "\u02e3\nl\u0003l\u0006l\u02e6\nl\rl\u000el\u02e7\u0003m\u0003m\u0003", "m\u0007m\u02ed\nm\fm\u000em\u02f0\u000bm\u0003m\u0003m\u0003m\u0003", "m\u0007m\u02f6\nm\fm\u000em\u02f9\u000bm\u0003m\u0005m\u02fc\nm\u0003", "n\u0003n\u0003n\u0003n\u0003n\u0007n\u0303\nn\fn\u000en\u0306\u000b", "n\u0003n\u0003n\u0003n\u0003n\u0003n\u0003n\u0003n\u0003n\u0007n\u0310", "\nn\fn\u000en\u0313\u000bn\u0003n\u0003n\u0003n\u0005n\u0318\nn\u0003", "o\u0003o\u0005o\u031c\no\u0003p\u0005p\u031f\np\u0003q\u0005q\u0322", "\nq\u0003r\u0005r\u0325\nr\u0003s\u0003s\u0003s\u0003t\u0006t\u032b", "\nt\rt\u000et\u032c\u0003u\u0003u\u0007u\u0331\nu\fu\u000eu\u0334\u000b", "u\u0003v\u0003v\u0005v\u0338\nv\u0003v\u0005v\u033b\nv\u0003v\u0003", "v\u0005v\u033f\nv\u0003w\u0005w\u0342\nw\u0003x\u0003x\u0005x\u0346", "\nx\u0006\u029e\u02ab\u0304\u0311\u0002y\u0003\u0003\u0005\u0004\u0007", "\u0005\t\u0006\u000b\u0007\r\b\u000f\t\u0011\n\u0013\u000b\u0015\f\u0017", "\r\u0019\u000e\u001b\u000f\u001d\u0010\u001f\u0011!\u0012#\u0013%\u0014", "\'\u0015)\u0016+\u0017-\u0018/\u00191\u001a3\u001b5\u001c7\u001d9\u001e", ";\u001f= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o9q:s;u<", "w=y>{?}@\u007fA\u0081B\u0083C\u0085D\u0087E\u0089F\u008bG\u008dH\u008f", "I\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3", "S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00afY\u00b1Z\u00b3[\u00b5\\\u00b7", "]\u00b9^\u00bb\u0002\u00bd\u0002\u00bf\u0002\u00c1\u0002\u00c3\u0002", "\u00c5\u0002\u00c7\u0002\u00c9\u0002\u00cb\u0002\u00cd\u0002\u00cf\u0002", "\u00d1\u0002\u00d3\u0002\u00d5\u0002\u00d7\u0002\u00d9\u0002\u00db\u0002", "\u00dd\u0002\u00df\u0002\u00e1\u0002\u00e3\u0002\u00e5\u0002\u00e7\u0002", "\u00e9\u0002\u00eb\u0002\u00ed\u0002\u00ef\u0002\u0003\u0002\u001a\u0004", "\u0002WWww\u0004\u0002TTtt\u0004\u0002DDdd\u0004\u0002QQqq\u0004\u0002", "ZZzz\u0004\u0002LLll\u0006\u0002\f\f\u000f\u000f))^^\u0006\u0002\f\f", "\u000f\u000f$$^^\u0003\u0002^^\u0003\u00023;\u0003\u00022;\u0003\u0002", "29\u0005\u00022;CHch\u0003\u000223\u0004\u0002GGgg\u0004\u0002--//\u0007", "\u0002\u0002\u000b\r\u000e\u0010(*]_\u0081\u0007\u0002\u0002\u000b\r", "\u000e\u0010#%]_\u0081\u0004\u0002\u0002]_\u0081\u0003\u0002\u0002\u0081", "\u0004\u0002\u000b\u000b\"\"\u0004\u0002\f\f\u000f\u000f\u0129\u0002", "C\\aac|\u00ac\u00ac\u00b7\u00b7\u00bc\u00bc\u00c2\u00d8\u00da\u00f8", "\u00fa\u0243\u0252\u02c3\u02c8\u02d3\u02e2\u02e6\u02f0\u02f0\u037c\u037c", "\u0388\u0388\u038a\u038c\u038e\u038e\u0390\u03a3\u03a5\u03d0\u03d2\u03f7", "\u03f9\u0483\u048c\u04d0\u04d2\u04fb\u0502\u0511\u0533\u0558\u055b\u055b", "\u0563\u0589\u05d2\u05ec\u05f2\u05f4\u0623\u063c\u0642\u064c\u0670\u0671", "\u0673\u06d5\u06d7\u06d7\u06e7\u06e8\u06f0\u06f1\u06fc\u06fe\u0701\u0701", "\u0712\u0712\u0714\u0731\u074f\u076f\u0782\u07a7\u07b3\u07b3\u0906\u093b", "\u093f\u093f\u0952\u0952\u095a\u0963\u097f\u097f\u0987\u098e\u0991\u0992", "\u0995\u09aa\u09ac\u09b2\u09b4\u09b4\u09b8\u09bb\u09bf\u09bf\u09d0\u09d0", "\u09de\u09df\u09e1\u09e3\u09f2\u09f3\u0a07\u0a0c\u0a11\u0a12\u0a15\u0a2a", "\u0a2c\u0a32\u0a34\u0a35\u0a37\u0a38\u0a3a\u0a3b\u0a5b\u0a5e\u0a60\u0a60", "\u0a74\u0a76\u0a87\u0a8f\u0a91\u0a93\u0a95\u0aaa\u0aac\u0ab2\u0ab4\u0ab5", "\u0ab7\u0abb\u0abf\u0abf\u0ad2\u0ad2\u0ae2\u0ae3\u0b07\u0b0e\u0b11\u0b12", "\u0b15\u0b2a\u0b2c\u0b32\u0b34\u0b35\u0b37\u0b3b\u0b3f\u0b3f\u0b5e\u0b5f", "\u0b61\u0b63\u0b73\u0b73\u0b85\u0b85\u0b87\u0b8c\u0b90\u0b92\u0b94\u0b97", "\u0b9b\u0b9c\u0b9e\u0b9e\u0ba0\u0ba1\u0ba5\u0ba6\u0baa\u0bac\u0bb0\u0bbb", "\u0c07\u0c0e\u0c10\u0c12\u0c14\u0c2a\u0c2c\u0c35\u0c37\u0c3b\u0c62\u0c63", "\u0c87\u0c8e\u0c90\u0c92\u0c94\u0caa\u0cac\u0cb5\u0cb7\u0cbb\u0cbf\u0cbf", "\u0ce0\u0ce0\u0ce2\u0ce3\u0d07\u0d0e\u0d10\u0d12\u0d14\u0d2a\u0d2c\u0d3b", "\u0d62\u0d63\u0d87\u0d98\u0d9c\u0db3\u0db5\u0dbd\u0dbf\u0dbf\u0dc2\u0dc8", "\u0e03\u0e32\u0e34\u0e35\u0e42\u0e48\u0e83\u0e84\u0e86\u0e86\u0e89\u0e8a", "\u0e8c\u0e8c\u0e8f\u0e8f\u0e96\u0e99\u0e9b\u0ea1\u0ea3\u0ea5\u0ea7\u0ea7", "\u0ea9\u0ea9\u0eac\u0ead\u0eaf\u0eb2\u0eb4\u0eb5\u0ebf\u0ebf\u0ec2\u0ec6", "\u0ec8\u0ec8\u0ede\u0edf\u0f02\u0f02\u0f42\u0f49\u0f4b\u0f6c\u0f8a\u0f8d", "\u1002\u1023\u1025\u1029\u102b\u102c\u1052\u1057\u10a2\u10c7\u10d2\u10fc", "\u10fe\u10fe\u1102\u115b\u1161\u11a4\u11aa\u11fb\u1202\u124a\u124c\u124f", "\u1252\u1258\u125a\u125a\u125c\u125f\u1262\u128a\u128c\u128f\u1292\u12b2", "\u12b4\u12b7\u12ba\u12c0\u12c2\u12c2\u12c4\u12c7\u12ca\u12d8\u12da\u1312", "\u1314\u1317\u131a\u135c\u1382\u1391\u13a2\u13f6\u1403\u166e\u1671\u1678", "\u1683\u169c\u16a2\u16ec\u16f0\u16f2\u1702\u170e\u1710\u1713\u1722\u1733", "\u1742\u1753\u1762\u176e\u1770\u1772\u1782\u17b5\u17d9\u17d9\u17de\u17de", "\u1822\u1879\u1882\u18aa\u1902\u191e\u1952\u196f\u1972\u1976\u1982\u19ab", "\u19c3\u19c9\u1a02\u1a18\u1d02\u1dc1\u1e02\u1e9d\u1ea2\u1efb\u1f02\u1f17", "\u1f1a\u1f1f\u1f22\u1f47\u1f4a\u1f4f\u1f52\u1f59\u1f5b\u1f5b\u1f5d\u1f5d", "\u1f5f\u1f5f\u1f61\u1f7f\u1f82\u1fb6\u1fb8\u1fbe\u1fc0\u1fc0\u1fc4\u1fc6", "\u1fc8\u1fce\u1fd2\u1fd5\u1fd8\u1fdd\u1fe2\u1fee\u1ff4\u1ff6\u1ff8\u1ffe", "\u2073\u2073\u2081\u2081\u2092\u2096\u2104\u2104\u2109\u2109\u210c\u2115", "\u2117\u2117\u211a\u211f\u2126\u2126\u2128\u2128\u212a\u212a\u212c\u2133", "\u2135\u213b\u213e\u2141\u2147\u214b\u2162\u2185\u2c02\u2c30\u2c32\u2c60", "\u2c82\u2ce6\u2d02\u2d27\u2d32\u2d67\u2d71\u2d71\u2d82\u2d98\u2da2\u2da8", "\u2daa\u2db0\u2db2\u2db8\u2dba\u2dc0\u2dc2\u2dc8\u2dca\u2dd0\u2dd2\u2dd8", "\u2dda\u2de0\u3007\u3009\u3023\u302b\u3033\u3037\u303a\u303e\u3043\u3098", "\u309d\u30a1\u30a3\u30fc\u30fe\u3101\u3107\u312e\u3133\u3190\u31a2\u31b9", "\u31f2\u3201\u3402\u4db7\u4e02\u9fbd\ua002\ua48e\ua802\ua803\ua805\ua807", "\ua809\ua80c\ua80e\ua824\uac02\ud7a5\uf902\ufa2f\ufa32\ufa6c\ufa72\ufadb", "\ufb02\ufb08\ufb15\ufb19\ufb1f\ufb1f\ufb21\ufb2a\ufb2c\ufb38\ufb3a\ufb3e", "\ufb40\ufb40\ufb42\ufb43\ufb45\ufb46\ufb48\ufbb3\ufbd5\ufd3f\ufd52\ufd91", "\ufd94\ufdc9\ufdf2\ufdfd\ufe72\ufe76\ufe78\ufefe\uff23\uff3c\uff43\uff5c", "\uff68\uffc0\uffc4\uffc9\uffcc\uffd1\uffd4\uffd9\uffdc\uffde\u0096\u0002", "2;\u0302\u0371\u0485\u0488\u0593\u05bb\u05bd\u05bf\u05c1\u05c1\u05c3", "\u05c4\u05c6\u05c7\u05c9\u05c9\u0612\u0617\u064d\u0660\u0662\u066b\u0672", "\u0672\u06d8\u06de\u06e1\u06e6\u06e9\u06ea\u06ec\u06ef\u06f2\u06fb\u0713", "\u0713\u0732\u074c\u07a8\u07b2\u0903\u0905\u093e\u093e\u0940\u094f\u0953", "\u0956\u0964\u0965\u0968\u0971\u0983\u0985\u09be\u09be\u09c0\u09c6\u09c9", "\u09ca\u09cd\u09cf\u09d9\u09d9\u09e4\u09e5\u09e8\u09f1\u0a03\u0a05\u0a3e", "\u0a3e\u0a40\u0a44\u0a49\u0a4a\u0a4d\u0a4f\u0a68\u0a73\u0a83\u0a85\u0abe", "\u0abe\u0ac0\u0ac7\u0ac9\u0acb\u0acd\u0acf\u0ae4\u0ae5\u0ae8\u0af1\u0b03", "\u0b05\u0b3e\u0b3e\u0b40\u0b45\u0b49\u0b4a\u0b4d\u0b4f\u0b58\u0b59\u0b68", "\u0b71\u0b84\u0b84\u0bc0\u0bc4\u0bc8\u0bca\u0bcc\u0bcf\u0bd9\u0bd9\u0be8", "\u0bf1\u0c03\u0c05\u0c40\u0c46\u0c48\u0c4a\u0c4c\u0c4f\u0c57\u0c58\u0c68", "\u0c71\u0c84\u0c85\u0cbe\u0cbe\u0cc0\u0cc6\u0cc8\u0cca\u0ccc\u0ccf\u0cd7", "\u0cd8\u0ce8\u0cf1\u0d04\u0d05\u0d40\u0d45\u0d48\u0d4a\u0d4c\u0d4f\u0d59", "\u0d59\u0d68\u0d71\u0d84\u0d85\u0dcc\u0dcc\u0dd1\u0dd6\u0dd8\u0dd8\u0dda", "\u0de1\u0df4\u0df5\u0e33\u0e33\u0e36\u0e3c\u0e49\u0e50\u0e52\u0e5b\u0eb3", "\u0eb3\u0eb6\u0ebb\u0ebd\u0ebe\u0eca\u0ecf\u0ed2\u0edb\u0f1a\u0f1b\u0f22", "\u0f2b\u0f37\u0f37\u0f39\u0f39\u0f3b\u0f3b\u0f40\u0f41\u0f73\u0f86\u0f88", "\u0f89\u0f92\u0f99\u0f9b\u0fbe\u0fc8\u0fc8\u102e\u1034\u1038\u103b\u1042", "\u104b\u1058\u105b\u1361\u1361\u136b\u1373\u1714\u1716\u1734\u1736\u1754", "\u1755\u1774\u1775\u17b8\u17d5\u17df\u17df\u17e2\u17eb\u180d\u180f\u1812", "\u181b\u18ab\u18ab\u1922\u192d\u1932\u193d\u1948\u1951\u19b2\u19c2\u19ca", "\u19cb\u19d2\u19db\u1a19\u1a1d\u1dc2\u1dc5\u2041\u2042\u2056\u2056\u20d2", "\u20de\u20e3\u20e3\u20e7\u20ed\u302c\u3031\u309b\u309c\ua804\ua804\ua808", "\ua808\ua80d\ua80d\ua825\ua829\ufb20\ufb20\ufe02\ufe11\ufe22\ufe25\ufe35", "\ufe36\ufe4f\ufe51\uff12\uff1b\uff41\uff41\u0002\u035e\u0002\u0003\u0003", "\u0002\u0002\u0002\u0002\u0005\u0003\u0002\u0002\u0002\u0002\u0007\u0003", "\u0002\u0002\u0002\u0002\t\u0003\u0002\u0002\u0002\u0002\u000b\u0003", "\u0002\u0002\u0002\u0002\r\u0003\u0002\u0002\u0002\u0002\u000f\u0003", "\u0002\u0002\u0002\u0002\u0011\u0003\u0002\u0002\u0002\u0002\u0013\u0003", "\u0002\u0002\u0002\u0002\u0015\u0003\u0002\u0002\u0002\u0002\u0017\u0003", "\u0002\u0002\u0002\u0002\u0019\u0003\u0002\u0002\u0002\u0002\u001b\u0003", "\u0002\u0002\u0002\u0002\u001d\u0003\u0002\u0002\u0002\u0002\u001f\u0003", "\u0002\u0002\u0002\u0002!\u0003\u0002\u0002\u0002\u0002#\u0003\u0002", "\u0002\u0002\u0002%\u0003\u0002\u0002\u0002\u0002\'\u0003\u0002\u0002", "\u0002\u0002)\u0003\u0002\u0002\u0002\u0002+\u0003\u0002\u0002\u0002", "\u0002-\u0003\u0002\u0002\u0002\u0002/\u0003\u0002\u0002\u0002\u0002", "1\u0003\u0002\u0002\u0002\u00023\u0003\u0002\u0002\u0002\u00025\u0003", "\u0002\u0002\u0002\u00027\u0003\u0002\u0002\u0002\u00029\u0003\u0002", "\u0002\u0002\u0002;\u0003\u0002\u0002\u0002\u0002=\u0003\u0002\u0002", "\u0002\u0002?\u0003\u0002\u0002\u0002\u0002A\u0003\u0002\u0002\u0002", "\u0002C\u0003\u0002\u0002\u0002\u0002E\u0003\u0002\u0002\u0002\u0002", "G\u0003\u0002\u0002\u0002\u0002I\u0003\u0002\u0002\u0002\u0002K\u0003", "\u0002\u0002\u0002\u0002M\u0003\u0002\u0002\u0002\u0002O\u0003\u0002", "\u0002\u0002\u0002Q\u0003\u0002\u0002\u0002\u0002S\u0003\u0002\u0002", "\u0002\u0002U\u0003\u0002\u0002\u0002\u0002W\u0003\u0002\u0002\u0002", "\u0002Y\u0003\u0002\u0002\u0002\u0002[\u0003\u0002\u0002\u0002\u0002", "]\u0003\u0002\u0002\u0002\u0002_\u0003\u0002\u0002\u0002\u0002a\u0003", "\u0002\u0002\u0002\u0002c\u0003\u0002\u0002\u0002\u0002e\u0003\u0002", "\u0002\u0002\u0002g\u0003\u0002\u0002\u0002\u0002i\u0003\u0002\u0002", "\u0002\u0002k\u0003\u0002\u0002\u0002\u0002m\u0003\u0002\u0002\u0002", "\u0002o\u0003\u0002\u0002\u0002\u0002q\u0003\u0002\u0002\u0002\u0002", "s\u0003\u0002\u0002\u0002\u0002u\u0003\u0002\u0002\u0002\u0002w\u0003", "\u0002\u0002\u0002\u0002y\u0003\u0002\u0002\u0002\u0002{\u0003\u0002", "\u0002\u0002\u0002}\u0003\u0002\u0002\u0002\u0002\u007f\u0003\u0002", "\u0002\u0002\u0002\u0081\u0003\u0002\u0002\u0002\u0002\u0083\u0003\u0002", "\u0002\u0002\u0002\u0085\u0003\u0002\u0002\u0002\u0002\u0087\u0003\u0002", "\u0002\u0002\u0002\u0089\u0003\u0002\u0002\u0002\u0002\u008b\u0003\u0002", "\u0002\u0002\u0002\u008d\u0003\u0002\u0002\u0002\u0002\u008f\u0003\u0002", "\u0002\u0002\u0002\u0091\u0003\u0002\u0002\u0002\u0002\u0093\u0003\u0002", "\u0002\u0002\u0002\u0095\u0003\u0002\u0002\u0002\u0002\u0097\u0003\u0002", "\u0002\u0002\u0002\u0099\u0003\u0002\u0002\u0002\u0002\u009b\u0003\u0002", "\u0002\u0002\u0002\u009d\u0003\u0002\u0002\u0002\u0002\u009f\u0003\u0002", "\u0002\u0002\u0002\u00a1\u0003\u0002\u0002\u0002\u0002\u00a3\u0003\u0002", "\u0002\u0002\u0002\u00a5\u0003\u0002\u0002\u0002\u0002\u00a7\u0003\u0002", "\u0002\u0002\u0002\u00a9\u0003\u0002\u0002\u0002\u0002\u00ab\u0003\u0002", "\u0002\u0002\u0002\u00ad\u0003\u0002\u0002\u0002\u0002\u00af\u0003\u0002", "\u0002\u0002\u0002\u00b1\u0003\u0002\u0002\u0002\u0002\u00b3\u0003\u0002", "\u0002\u0002\u0002\u00b5\u0003\u0002\u0002\u0002\u0002\u00b7\u0003\u0002", "\u0002\u0002\u0002\u00b9\u0003\u0002\u0002\u0002\u0003\u00f1\u0003\u0002", "\u0002\u0002\u0005\u00f5\u0003\u0002\u0002\u0002\u0007\u00fc\u0003\u0002", "\u0002\u0002\t\u0102\u0003\u0002\u0002\u0002\u000b\u0107\u0003\u0002", "\u0002\u0002\r\u010e\u0003\u0002\u0002\u0002\u000f\u0111\u0003\u0002", "\u0002\u0002\u0011\u0118\u0003\u0002\u0002\u0002\u0013\u0121\u0003\u0002", "\u0002\u0002\u0015\u0128\u0003\u0002\u0002\u0002\u0017\u012b\u0003\u0002", "\u0002\u0002\u0019\u0130\u0003\u0002\u0002\u0002\u001b\u0135\u0003\u0002", "\u0002\u0002\u001d\u013b\u0003\u0002\u0002\u0002\u001f\u013f\u0003\u0002", "\u0002\u0002!\u0142\u0003\u0002\u0002\u0002#\u0146\u0003\u0002\u0002", "\u0002%\u014e\u0003\u0002\u0002\u0002\'\u0153\u0003\u0002\u0002\u0002", ")\u015a\u0003\u0002\u0002\u0002+\u0161\u0003\u0002\u0002\u0002-\u0164", "\u0003\u0002\u0002\u0002/\u0168\u0003\u0002\u0002\u00021\u016c\u0003", "\u0002\u0002\u00023\u016f\u0003\u0002\u0002\u00025\u0174\u0003\u0002", "\u0002\u00027\u0179\u0003\u0002\u0002\u00029\u017f\u0003\u0002\u0002", "\u0002;\u0185\u0003\u0002\u0002\u0002=\u018b\u0003\u0002\u0002\u0002", "?\u018f\u0003\u0002\u0002\u0002A\u0194\u0003\u0002\u0002\u0002C\u019d", "\u0003\u0002\u0002\u0002E\u01af\u0003\u0002\u0002\u0002G\u01b3\u0003", "\u0002\u0002\u0002I\u01bb\u0003\u0002\u0002\u0002K\u01c4\u0003\u0002", "\u0002\u0002M\u01d8\u0003\u0002\u0002\u0002O\u01da\u0003\u0002\u0002", "\u0002Q\u01e1\u0003\u0002\u0002\u0002S\u01e8\u0003\u0002\u0002\u0002", "U\u01f1\u0003\u0002\u0002\u0002W\u01f5\u0003\u0002\u0002\u0002Y\u01f9", "\u0003\u0002\u0002\u0002[\u01fb\u0003\u0002\u0002\u0002]\u01ff\u0003", "\u0002\u0002\u0002_\u0201\u0003\u0002\u0002\u0002a\u0204\u0003\u0002", "\u0002\u0002c\u0207\u0003\u0002\u0002\u0002e\u0209\u0003\u0002\u0002", "\u0002g\u020b\u0003\u0002\u0002\u0002i\u020d\u0003\u0002\u0002\u0002", "k\u0210\u0003\u0002\u0002\u0002m\u0212\u0003\u0002\u0002\u0002o\u0215", "\u0003\u0002\u0002\u0002q\u0218\u0003\u0002\u0002\u0002s\u021a\u0003", "\u0002\u0002\u0002u\u021c\u0003\u0002\u0002\u0002w\u021e\u0003\u0002", "\u0002\u0002y\u0221\u0003\u0002\u0002\u0002{\u0224\u0003\u0002\u0002", "\u0002}\u0226\u0003\u0002\u0002\u0002\u007f\u0228\u0003\u0002\u0002", "\u0002\u0081\u022a\u0003\u0002\u0002\u0002\u0083\u022c\u0003\u0002\u0002", "\u0002\u0085\u022f\u0003\u0002\u0002\u0002\u0087\u0231\u0003\u0002\u0002", "\u0002\u0089\u0234\u0003\u0002\u0002\u0002\u008b\u0237\u0003\u0002\u0002", "\u0002\u008d\u0239\u0003\u0002\u0002\u0002\u008f\u023b\u0003\u0002\u0002", "\u0002\u0091\u023e\u0003\u0002\u0002\u0002\u0093\u0241\u0003\u0002\u0002", "\u0002\u0095\u0244\u0003\u0002\u0002\u0002\u0097\u0247\u0003\u0002\u0002", "\u0002\u0099\u024a\u0003\u0002\u0002\u0002\u009b\u024c\u0003\u0002\u0002", "\u0002\u009d\u024f\u0003\u0002\u0002\u0002\u009f\u0252\u0003\u0002\u0002", "\u0002\u00a1\u0255\u0003\u0002\u0002\u0002\u00a3\u0258\u0003\u0002\u0002", "\u0002\u00a5\u025b\u0003\u0002\u0002\u0002\u00a7\u025e\u0003\u0002\u0002", "\u0002\u00a9\u0261\u0003\u0002\u0002\u0002\u00ab\u0264\u0003\u0002\u0002", "\u0002\u00ad\u0267\u0003\u0002\u0002\u0002\u00af\u026a\u0003\u0002\u0002", "\u0002\u00b1\u026e\u0003\u0002\u0002\u0002\u00b3\u0272\u0003\u0002\u0002", "\u0002\u00b5\u0276\u0003\u0002\u0002\u0002\u00b7\u027d\u0003\u0002\u0002", "\u0002\u00b9\u0281\u0003\u0002\u0002\u0002\u00bb\u0295\u0003\u0002\u0002", "\u0002\u00bd\u02b1\u0003\u0002\u0002\u0002\u00bf\u02b5\u0003\u0002\u0002", "\u0002\u00c1\u02b7\u0003\u0002\u0002\u0002\u00c3\u02b9\u0003\u0002\u0002", "\u0002\u00c5\u02bc\u0003\u0002\u0002\u0002\u00c7\u02be\u0003\u0002\u0002", "\u0002\u00c9\u02c0\u0003\u0002\u0002\u0002\u00cb\u02c2\u0003\u0002\u0002", "\u0002\u00cd\u02c4\u0003\u0002\u0002\u0002\u00cf\u02cd\u0003\u0002\u0002", "\u0002\u00d1\u02d1\u0003\u0002\u0002\u0002\u00d3\u02d6\u0003\u0002\u0002", "\u0002\u00d5\u02da\u0003\u0002\u0002\u0002\u00d7\u02e0\u0003\u0002\u0002", "\u0002\u00d9\u02fb\u0003\u0002\u0002\u0002\u00db\u0317\u0003\u0002\u0002", "\u0002\u00dd\u031b\u0003\u0002\u0002\u0002\u00df\u031e\u0003\u0002\u0002", "\u0002\u00e1\u0321\u0003\u0002\u0002\u0002\u00e3\u0324\u0003\u0002\u0002", "\u0002\u00e5\u0326\u0003\u0002\u0002\u0002\u00e7\u032a\u0003\u0002\u0002", "\u0002\u00e9\u032e\u0003\u0002\u0002\u0002\u00eb\u0335\u0003\u0002\u0002", "\u0002\u00ed\u0341\u0003\u0002\u0002\u0002\u00ef\u0345\u0003\u0002\u0002", "\u0002\u00f1\u00f2\u0007f\u0002\u0002\u00f2\u00f3\u0007g\u0002\u0002", "\u00f3\u00f4\u0007h\u0002\u0002\u00f4\u0004\u0003\u0002\u0002\u0002", "\u00f5\u00f6\u0007t\u0002\u0002\u00f6\u00f7\u0007g\u0002\u0002\u00f7", "\u00f8\u0007v\u0002\u0002\u00f8\u00f9\u0007w\u0002\u0002\u00f9\u00fa", "\u0007t\u0002\u0002\u00fa\u00fb\u0007p\u0002\u0002\u00fb\u0006\u0003", "\u0002\u0002\u0002\u00fc\u00fd\u0007t\u0002\u0002\u00fd\u00fe\u0007", "c\u0002\u0002\u00fe\u00ff\u0007k\u0002\u0002\u00ff\u0100\u0007u\u0002", "\u0002\u0100\u0101\u0007g\u0002\u0002\u0101\b\u0003\u0002\u0002\u0002", "\u0102\u0103\u0007h\u0002\u0002\u0103\u0104\u0007t\u0002\u0002\u0104", "\u0105\u0007q\u0002\u0002\u0105\u0106\u0007o\u0002\u0002\u0106\n\u0003", "\u0002\u0002\u0002\u0107\u0108\u0007k\u0002\u0002\u0108\u0109\u0007", "o\u0002\u0002\u0109\u010a\u0007r\u0002\u0002\u010a\u010b\u0007q\u0002", "\u0002\u010b\u010c\u0007t\u0002\u0002\u010c\u010d\u0007v\u0002\u0002", "\u010d\f\u0003\u0002\u0002\u0002\u010e\u010f\u0007c\u0002\u0002\u010f", "\u0110\u0007u\u0002\u0002\u0110\u000e\u0003\u0002\u0002\u0002\u0111", "\u0112\u0007i\u0002\u0002\u0112\u0113\u0007n\u0002\u0002\u0113\u0114", "\u0007q\u0002\u0002\u0114\u0115\u0007d\u0002\u0002\u0115\u0116\u0007", "c\u0002\u0002\u0116\u0117\u0007n\u0002\u0002\u0117\u0010\u0003\u0002", "\u0002\u0002\u0118\u0119\u0007p\u0002\u0002\u0119\u011a\u0007q\u0002", "\u0002\u011a\u011b\u0007p\u0002\u0002\u011b\u011c\u0007n\u0002\u0002", "\u011c\u011d\u0007q\u0002\u0002\u011d\u011e\u0007e\u0002\u0002\u011e", "\u011f\u0007c\u0002\u0002\u011f\u0120\u0007n\u0002\u0002\u0120\u0012", "\u0003\u0002\u0002\u0002\u0121\u0122\u0007c\u0002\u0002\u0122\u0123", "\u0007u\u0002\u0002\u0123\u0124\u0007u\u0002\u0002\u0124\u0125\u0007", "g\u0002\u0002\u0125\u0126\u0007t\u0002\u0002\u0126\u0127\u0007v\u0002", "\u0002\u0127\u0014\u0003\u0002\u0002\u0002\u0128\u0129\u0007k\u0002", "\u0002\u0129\u012a\u0007h\u0002\u0002\u012a\u0016\u0003\u0002\u0002", "\u0002\u012b\u012c\u0007g\u0002\u0002\u012c\u012d\u0007n\u0002\u0002", "\u012d\u012e\u0007k\u0002\u0002\u012e\u012f\u0007h\u0002\u0002\u012f", "\u0018\u0003\u0002\u0002\u0002\u0130\u0131\u0007g\u0002\u0002\u0131", "\u0132\u0007n\u0002\u0002\u0132\u0133\u0007u\u0002\u0002\u0133\u0134", "\u0007g\u0002\u0002\u0134\u001a\u0003\u0002\u0002\u0002\u0135\u0136", "\u0007y\u0002\u0002\u0136\u0137\u0007j\u0002\u0002\u0137\u0138\u0007", "k\u0002\u0002\u0138\u0139\u0007n\u0002\u0002\u0139\u013a\u0007g\u0002", "\u0002\u013a\u001c\u0003\u0002\u0002\u0002\u013b\u013c\u0007h\u0002", "\u0002\u013c\u013d\u0007q\u0002\u0002\u013d\u013e\u0007t\u0002\u0002", "\u013e\u001e\u0003\u0002\u0002\u0002\u013f\u0140\u0007k\u0002\u0002", "\u0140\u0141\u0007p\u0002\u0002\u0141 \u0003\u0002\u0002\u0002\u0142", "\u0143\u0007v\u0002\u0002\u0143\u0144\u0007t\u0002\u0002\u0144\u0145", "\u0007{\u0002\u0002\u0145\"\u0003\u0002\u0002\u0002\u0146\u0147\u0007", "h\u0002\u0002\u0147\u0148\u0007k\u0002\u0002\u0148\u0149\u0007p\u0002", "\u0002\u0149\u014a\u0007c\u0002\u0002\u014a\u014b\u0007n\u0002\u0002", "\u014b\u014c\u0007n\u0002\u0002\u014c\u014d\u0007{\u0002\u0002\u014d", "$\u0003\u0002\u0002\u0002\u014e\u014f\u0007y\u0002\u0002\u014f\u0150", "\u0007k\u0002\u0002\u0150\u0151\u0007v\u0002\u0002\u0151\u0152\u0007", "j\u0002\u0002\u0152&\u0003\u0002\u0002\u0002\u0153\u0154\u0007g\u0002", "\u0002\u0154\u0155\u0007z\u0002\u0002\u0155\u0156\u0007e\u0002\u0002", "\u0156\u0157\u0007g\u0002\u0002\u0157\u0158\u0007r\u0002\u0002\u0158", "\u0159\u0007v\u0002\u0002\u0159(\u0003\u0002\u0002\u0002\u015a\u015b", "\u0007n\u0002\u0002\u015b\u015c\u0007c\u0002\u0002\u015c\u015d\u0007", "o\u0002\u0002\u015d\u015e\u0007d\u0002\u0002\u015e\u015f\u0007f\u0002", "\u0002\u015f\u0160\u0007c\u0002\u0002\u0160*\u0003\u0002\u0002\u0002", "\u0161\u0162\u0007q\u0002\u0002\u0162\u0163\u0007t\u0002\u0002\u0163", ",\u0003\u0002\u0002\u0002\u0164\u0165\u0007c\u0002\u0002\u0165\u0166", "\u0007p\u0002\u0002\u0166\u0167\u0007f\u0002\u0002\u0167.\u0003\u0002", "\u0002\u0002\u0168\u0169\u0007p\u0002\u0002\u0169\u016a\u0007q\u0002", "\u0002\u016a\u016b\u0007v\u0002\u0002\u016b0\u0003\u0002\u0002\u0002", "\u016c\u016d\u0007k\u0002\u0002\u016d\u016e\u0007u\u0002\u0002\u016e", "2\u0003\u0002\u0002\u0002\u016f\u0170\u0007P\u0002\u0002\u0170\u0171", "\u0007q\u0002\u0002\u0171\u0172\u0007p\u0002\u0002\u0172\u0173\u0007", "g\u0002\u0002\u01734\u0003\u0002\u0002\u0002\u0174\u0175\u0007V\u0002", "\u0002\u0175\u0176\u0007t\u0002\u0002\u0176\u0177\u0007w\u0002\u0002", "\u0177\u0178\u0007g\u0002\u0002\u01786\u0003\u0002\u0002\u0002\u0179", "\u017a\u0007H\u0002\u0002\u017a\u017b\u0007c\u0002\u0002\u017b\u017c", "\u0007n\u0002\u0002\u017c\u017d\u0007u\u0002\u0002\u017d\u017e\u0007", "g\u0002\u0002\u017e8\u0003\u0002\u0002\u0002\u017f\u0180\u0007e\u0002", "\u0002\u0180\u0181\u0007n\u0002\u0002\u0181\u0182\u0007c\u0002\u0002", "\u0182\u0183\u0007u\u0002\u0002\u0183\u0184\u0007u\u0002\u0002\u0184", ":\u0003\u0002\u0002\u0002\u0185\u0186\u0007{\u0002\u0002\u0186\u0187", "\u0007k\u0002\u0002\u0187\u0188\u0007g\u0002\u0002\u0188\u0189\u0007", "n\u0002\u0002\u0189\u018a\u0007f\u0002\u0002\u018a<\u0003\u0002\u0002", "\u0002\u018b\u018c\u0007f\u0002\u0002\u018c\u018d\u0007g\u0002\u0002", "\u018d\u018e\u0007n\u0002\u0002\u018e>\u0003\u0002\u0002\u0002\u018f", "\u0190\u0007r\u0002\u0002\u0190\u0191\u0007c\u0002\u0002\u0191\u0192", "\u0007u\u0002\u0002\u0192\u0193\u0007u\u0002\u0002\u0193@\u0003\u0002", "\u0002\u0002\u0194\u0195\u0007e\u0002\u0002\u0195\u0196\u0007q\u0002", "\u0002\u0196\u0197\u0007p\u0002\u0002\u0197\u0198\u0007v\u0002\u0002", "\u0198\u0199\u0007k\u0002\u0002\u0199\u019a\u0007p\u0002\u0002\u019a", "\u019b\u0007w\u0002\u0002\u019b\u019c\u0007g\u0002\u0002\u019cB\u0003", "\u0002\u0002\u0002\u019d\u019e\u0007d\u0002\u0002\u019e\u019f\u0007", "t\u0002\u0002\u019f\u01a0\u0007g\u0002\u0002\u01a0\u01a1\u0007c\u0002", "\u0002\u01a1\u01a2\u0007m\u0002\u0002\u01a2D\u0003\u0002\u0002\u0002", "\u01a3\u01a4\u0006#\u0002\u0002\u01a4\u01b0\u0005\u00e7t\u0002\u01a5", "\u01a7\u0007\u000f\u0002\u0002\u01a6\u01a5\u0003\u0002\u0002\u0002\u01a6", "\u01a7\u0003\u0002\u0002\u0002\u01a7\u01a8\u0003\u0002\u0002\u0002\u01a8", "\u01ab\u0007\f\u0002\u0002\u01a9\u01ab\u0007\u000f\u0002\u0002\u01aa", "\u01a6\u0003\u0002\u0002\u0002\u01aa\u01a9\u0003\u0002\u0002\u0002\u01ab", "\u01ad\u0003\u0002\u0002\u0002\u01ac\u01ae\u0005\u00e7t\u0002\u01ad", "\u01ac\u0003\u0002\u0002\u0002\u01ad\u01ae\u0003\u0002\u0002\u0002\u01ae", "\u01b0\u0003\u0002\u0002\u0002\u01af\u01a3\u0003\u0002\u0002\u0002\u01af", "\u01aa\u0003\u0002\u0002\u0002\u01b0\u01b1\u0003\u0002\u0002\u0002\u01b1", "\u01b2\b#\u0002\u0002\u01b2F\u0003\u0002\u0002\u0002\u01b3\u01b7\u0005", "\u00edw\u0002\u01b4\u01b6\u0005\u00efx\u0002\u01b5\u01b4\u0003\u0002", "\u0002\u0002\u01b6\u01b9\u0003\u0002\u0002\u0002\u01b7\u01b5\u0003\u0002", "\u0002\u0002\u01b7\u01b8\u0003\u0002\u0002\u0002\u01b8H\u0003\u0002", "\u0002\u0002\u01b9\u01b7\u0003\u0002\u0002\u0002\u01ba\u01bc\t\u0002", "\u0002\u0002\u01bb\u01ba\u0003\u0002\u0002\u0002\u01bb\u01bc\u0003\u0002", "\u0002\u0002\u01bc\u01be\u0003\u0002\u0002\u0002\u01bd\u01bf\t\u0003", "\u0002\u0002\u01be\u01bd\u0003\u0002\u0002\u0002\u01be\u01bf\u0003\u0002", "\u0002\u0002\u01bf\u01c2\u0003\u0002\u0002\u0002\u01c0\u01c3\u0005\u00bb", "^\u0002\u01c1\u01c3\u0005\u00bd_\u0002\u01c2\u01c0\u0003\u0002\u0002", "\u0002\u01c2\u01c1\u0003\u0002\u0002\u0002\u01c3J\u0003\u0002\u0002", "\u0002\u01c4\u01c6\t\u0004\u0002\u0002\u01c5\u01c7\t\u0003\u0002\u0002", "\u01c6\u01c5\u0003\u0002\u0002\u0002\u01c6\u01c7\u0003\u0002\u0002\u0002", "\u01c7\u01ca\u0003\u0002\u0002\u0002\u01c8\u01cb\u0005\u00d9m\u0002", "\u01c9\u01cb\u0005\u00dbn\u0002\u01ca\u01c8\u0003\u0002\u0002\u0002", "\u01ca\u01c9\u0003\u0002\u0002\u0002\u01cbL\u0003\u0002\u0002\u0002", "\u01cc\u01d0\u0005\u00c5c\u0002\u01cd\u01cf\u0005\u00c7d\u0002\u01ce", "\u01cd\u0003\u0002\u0002\u0002\u01cf\u01d2\u0003\u0002\u0002\u0002\u01d0", "\u01ce\u0003\u0002\u0002\u0002\u01d0\u01d1\u0003\u0002\u0002\u0002\u01d1", "\u01d9\u0003\u0002\u0002\u0002\u01d2\u01d0\u0003\u0002\u0002\u0002\u01d3", "\u01d5\u00072\u0002\u0002\u01d4\u01d3\u0003\u0002\u0002\u0002\u01d5", "\u01d6\u0003\u0002\u0002\u0002\u01d6\u01d4\u0003\u0002\u0002\u0002\u01d6", "\u01d7\u0003\u0002\u0002\u0002\u01d7\u01d9\u0003\u0002\u0002\u0002\u01d8", "\u01cc\u0003\u0002\u0002\u0002\u01d8\u01d4\u0003\u0002\u0002\u0002\u01d9", "N\u0003\u0002\u0002\u0002\u01da\u01db\u00072\u0002\u0002\u01db\u01dd", "\t\u0005\u0002\u0002\u01dc\u01de\u0005\u00c9e\u0002\u01dd\u01dc\u0003", "\u0002\u0002\u0002\u01de\u01df\u0003\u0002\u0002\u0002\u01df\u01dd\u0003", "\u0002\u0002\u0002\u01df\u01e0\u0003\u0002\u0002\u0002\u01e0P\u0003", "\u0002\u0002\u0002\u01e1\u01e2\u00072\u0002\u0002\u01e2\u01e4\t\u0006", "\u0002\u0002\u01e3\u01e5\u0005\u00cbf\u0002\u01e4\u01e3\u0003\u0002", "\u0002\u0002\u01e5\u01e6\u0003\u0002\u0002\u0002\u01e6\u01e4\u0003\u0002", "\u0002\u0002\u01e6\u01e7\u0003\u0002\u0002\u0002\u01e7R\u0003\u0002", "\u0002\u0002\u01e8\u01e9\u00072\u0002\u0002\u01e9\u01eb\t\u0004\u0002", "\u0002\u01ea\u01ec\u0005\u00cdg\u0002\u01eb\u01ea\u0003\u0002\u0002", "\u0002\u01ec\u01ed\u0003\u0002\u0002\u0002\u01ed\u01eb\u0003\u0002\u0002", "\u0002\u01ed\u01ee\u0003\u0002\u0002\u0002\u01eeT\u0003\u0002\u0002", "\u0002\u01ef\u01f2\u0005\u00cfh\u0002\u01f0\u01f2\u0005\u00d1i\u0002", "\u01f1\u01ef\u0003\u0002\u0002\u0002\u01f1\u01f0\u0003\u0002\u0002\u0002", "\u01f2V\u0003\u0002\u0002\u0002\u01f3\u01f6\u0005U+\u0002\u01f4\u01f6", "\u0005\u00d3j\u0002\u01f5\u01f3\u0003\u0002\u0002\u0002\u01f5\u01f4", "\u0003\u0002\u0002\u0002\u01f6\u01f7\u0003\u0002\u0002\u0002\u01f7\u01f8", "\t\u0007\u0002\u0002\u01f8X\u0003\u0002\u0002\u0002\u01f9\u01fa\u0007", "0\u0002\u0002\u01faZ\u0003\u0002\u0002\u0002\u01fb\u01fc\u00070\u0002", "\u0002\u01fc\u01fd\u00070\u0002\u0002\u01fd\u01fe\u00070\u0002\u0002", "\u01fe\\\u0003\u0002\u0002\u0002\u01ff\u0200\u0007,\u0002\u0002\u0200", "^\u0003\u0002\u0002\u0002\u0201\u0202\u0007*\u0002\u0002\u0202\u0203", "\b0\u0003\u0002\u0203`\u0003\u0002\u0002\u0002\u0204\u0205\u0007+\u0002", "\u0002\u0205\u0206\b1\u0004\u0002\u0206b\u0003\u0002\u0002\u0002\u0207", "\u0208\u0007.\u0002\u0002\u0208d\u0003\u0002\u0002\u0002\u0209\u020a", "\u0007<\u0002\u0002\u020af\u0003\u0002\u0002\u0002\u020b\u020c\u0007", "=\u0002\u0002\u020ch\u0003\u0002\u0002\u0002\u020d\u020e\u0007,\u0002", "\u0002\u020e\u020f\u0007,\u0002\u0002\u020fj\u0003\u0002\u0002\u0002", "\u0210\u0211\u0007?\u0002\u0002\u0211l\u0003\u0002\u0002\u0002\u0212", "\u0213\u0007]\u0002\u0002\u0213\u0214\b7\u0005\u0002\u0214n\u0003\u0002", "\u0002\u0002\u0215\u0216\u0007_\u0002\u0002\u0216\u0217\b8\u0006\u0002", "\u0217p\u0003\u0002\u0002\u0002\u0218\u0219\u0007~\u0002\u0002\u0219", "r\u0003\u0002\u0002\u0002\u021a\u021b\u0007`\u0002\u0002\u021bt\u0003", "\u0002\u0002\u0002\u021c\u021d\u0007(\u0002\u0002\u021dv\u0003\u0002", "\u0002\u0002\u021e\u021f\u0007>\u0002\u0002\u021f\u0220\u0007>\u0002", "\u0002\u0220x\u0003\u0002\u0002\u0002\u0221\u0222\u0007@\u0002\u0002", "\u0222\u0223\u0007@\u0002\u0002\u0223z\u0003\u0002\u0002\u0002\u0224", "\u0225\u0007-\u0002\u0002\u0225|\u0003\u0002\u0002\u0002\u0226\u0227", "\u0007/\u0002\u0002\u0227~\u0003\u0002\u0002\u0002\u0228\u0229\u0007", "1\u0002\u0002\u0229\u0080\u0003\u0002\u0002\u0002\u022a\u022b\u0007", "\'\u0002\u0002\u022b\u0082\u0003\u0002\u0002\u0002\u022c\u022d\u0007", "1\u0002\u0002\u022d\u022e\u00071\u0002\u0002\u022e\u0084\u0003\u0002", "\u0002\u0002\u022f\u0230\u0007\u0080\u0002\u0002\u0230\u0086\u0003\u0002", "\u0002\u0002\u0231\u0232\u0007}\u0002\u0002\u0232\u0233\bD\u0007\u0002", "\u0233\u0088\u0003\u0002\u0002\u0002\u0234\u0235\u0007\u007f\u0002\u0002", "\u0235\u0236\bE\b\u0002\u0236\u008a\u0003\u0002\u0002\u0002\u0237\u0238", "\u0007>\u0002\u0002\u0238\u008c\u0003\u0002\u0002\u0002\u0239\u023a", "\u0007@\u0002\u0002\u023a\u008e\u0003\u0002\u0002\u0002\u023b\u023c", "\u0007?\u0002\u0002\u023c\u023d\u0007?\u0002\u0002\u023d\u0090\u0003", "\u0002\u0002\u0002\u023e\u023f\u0007@\u0002\u0002\u023f\u0240\u0007", "?\u0002\u0002\u0240\u0092\u0003\u0002\u0002\u0002\u0241\u0242\u0007", ">\u0002\u0002\u0242\u0243\u0007?\u0002\u0002\u0243\u0094\u0003\u0002", "\u0002\u0002\u0244\u0245\u0007>\u0002\u0002\u0245\u0246\u0007@\u0002", "\u0002\u0246\u0096\u0003\u0002\u0002\u0002\u0247\u0248\u0007#\u0002", "\u0002\u0248\u0249\u0007?\u0002\u0002\u0249\u0098\u0003\u0002\u0002", "\u0002\u024a\u024b\u0007B\u0002\u0002\u024b\u009a\u0003\u0002\u0002", "\u0002\u024c\u024d\u0007/\u0002\u0002\u024d\u024e\u0007@\u0002\u0002", "\u024e\u009c\u0003\u0002\u0002\u0002\u024f\u0250\u0007-\u0002\u0002", "\u0250\u0251\u0007?\u0002\u0002\u0251\u009e\u0003\u0002\u0002\u0002", "\u0252\u0253\u0007/\u0002\u0002\u0253\u0254\u0007?\u0002\u0002\u0254", "\u00a0\u0003\u0002\u0002\u0002\u0255\u0256\u0007,\u0002\u0002\u0256", "\u0257\u0007?\u0002\u0002\u0257\u00a2\u0003\u0002\u0002\u0002\u0258", "\u0259\u0007B\u0002\u0002\u0259\u025a\u0007?\u0002\u0002\u025a\u00a4", "\u0003\u0002\u0002\u0002\u025b\u025c\u00071\u0002\u0002\u025c\u025d", "\u0007?\u0002\u0002\u025d\u00a6\u0003\u0002\u0002\u0002\u025e\u025f", "\u0007\'\u0002\u0002\u025f\u0260\u0007?\u0002\u0002\u0260\u00a8\u0003", "\u0002\u0002\u0002\u0261\u0262\u0007(\u0002\u0002\u0262\u0263\u0007", "?\u0002\u0002\u0263\u00aa\u0003\u0002\u0002\u0002\u0264\u0265\u0007", "~\u0002\u0002\u0265\u0266\u0007?\u0002\u0002\u0266\u00ac\u0003\u0002", "\u0002\u0002\u0267\u0268\u0007`\u0002\u0002\u0268\u0269\u0007?\u0002", "\u0002\u0269\u00ae\u0003\u0002\u0002\u0002\u026a\u026b\u0007>\u0002", "\u0002\u026b\u026c\u0007>\u0002\u0002\u026c\u026d\u0007?\u0002\u0002", "\u026d\u00b0\u0003\u0002\u0002\u0002\u026e\u026f\u0007@\u0002\u0002", "\u026f\u0270\u0007@\u0002\u0002\u0270\u0271\u0007?\u0002\u0002\u0271", "\u00b2\u0003\u0002\u0002\u0002\u0272\u0273\u0007,\u0002\u0002\u0273", "\u0274\u0007,\u0002\u0002\u0274\u0275\u0007?\u0002\u0002\u0275\u00b4", "\u0003\u0002\u0002\u0002\u0276\u0277\u00071\u0002\u0002\u0277\u0278", "\u00071\u0002\u0002\u0278\u0279\u0007?\u0002\u0002\u0279\u00b6\u0003", "\u0002\u0002\u0002\u027a\u027e\u0005\u00e7t\u0002\u027b\u027e\u0005", "\u00e9u\u0002\u027c\u027e\u0005\u00ebv\u0002\u027d\u027a\u0003\u0002", "\u0002\u0002\u027d\u027b\u0003\u0002\u0002\u0002\u027d\u027c\u0003\u0002", "\u0002\u0002\u027e\u027f\u0003\u0002\u0002\u0002\u027f\u0280\b\\\t\u0002", "\u0280\u00b8\u0003\u0002\u0002\u0002\u0281\u0282\u000b\u0002\u0002\u0002", "\u0282\u00ba\u0003\u0002\u0002\u0002\u0283\u0288\u0007)\u0002\u0002", "\u0284\u0287\u0005\u00c3b\u0002\u0285\u0287\n\b\u0002\u0002\u0286\u0284", "\u0003\u0002\u0002\u0002\u0286\u0285\u0003\u0002\u0002\u0002\u0287\u028a", "\u0003\u0002\u0002\u0002\u0288\u0286\u0003\u0002\u0002\u0002\u0288\u0289", "\u0003\u0002\u0002\u0002\u0289\u028b\u0003\u0002\u0002\u0002\u028a\u0288", "\u0003\u0002\u0002\u0002\u028b\u0296\u0007)\u0002\u0002\u028c\u0291", "\u0007$\u0002\u0002\u028d\u0290\u0005\u00c3b\u0002\u028e\u0290\n\t\u0002", "\u0002\u028f\u028d\u0003\u0002\u0002\u0002\u028f\u028e\u0003\u0002\u0002", "\u0002\u0290\u0293\u0003\u0002\u0002\u0002\u0291\u028f\u0003\u0002\u0002", "\u0002\u0291\u0292\u0003\u0002\u0002\u0002\u0292\u0294\u0003\u0002\u0002", "\u0002\u0293\u0291\u0003\u0002\u0002\u0002\u0294\u0296\u0007$\u0002", "\u0002\u0295\u0283\u0003\u0002\u0002\u0002\u0295\u028c\u0003\u0002\u0002", "\u0002\u0296\u00bc\u0003\u0002\u0002\u0002\u0297\u0298\u0007)\u0002", "\u0002\u0298\u0299\u0007)\u0002\u0002\u0299\u029a\u0007)\u0002\u0002", "\u029a\u029e\u0003\u0002\u0002\u0002\u029b\u029d\u0005\u00bf`\u0002", "\u029c\u029b\u0003\u0002\u0002\u0002\u029d\u02a0\u0003\u0002\u0002\u0002", "\u029e\u029f\u0003\u0002\u0002\u0002\u029e\u029c\u0003\u0002\u0002\u0002", "\u029f\u02a1\u0003\u0002\u0002\u0002\u02a0\u029e\u0003\u0002\u0002\u0002", "\u02a1\u02a2\u0007)\u0002\u0002\u02a2\u02a3\u0007)\u0002\u0002\u02a3", "\u02b2\u0007)\u0002\u0002\u02a4\u02a5\u0007$\u0002\u0002\u02a5\u02a6", "\u0007$\u0002\u0002\u02a6\u02a7\u0007$\u0002\u0002\u02a7\u02ab\u0003", "\u0002\u0002\u0002\u02a8\u02aa\u0005\u00bf`\u0002\u02a9\u02a8\u0003", "\u0002\u0002\u0002\u02aa\u02ad\u0003\u0002\u0002\u0002\u02ab\u02ac\u0003", "\u0002\u0002\u0002\u02ab\u02a9\u0003\u0002\u0002\u0002\u02ac\u02ae\u0003", "\u0002\u0002\u0002\u02ad\u02ab\u0003\u0002\u0002\u0002\u02ae\u02af\u0007", "$\u0002\u0002\u02af\u02b0\u0007$\u0002\u0002\u02b0\u02b2\u0007$\u0002", "\u0002\u02b1\u0297\u0003\u0002\u0002\u0002\u02b1\u02a4\u0003\u0002\u0002", "\u0002\u02b2\u00be\u0003\u0002\u0002\u0002\u02b3\u02b6\u0005\u00c1a", "\u0002\u02b4\u02b6\u0005\u00c3b\u0002\u02b5\u02b3\u0003\u0002\u0002", "\u0002\u02b5\u02b4\u0003\u0002\u0002\u0002\u02b6\u00c0\u0003\u0002\u0002", "\u0002\u02b7\u02b8\n\n\u0002\u0002\u02b8\u00c2\u0003\u0002\u0002\u0002", "\u02b9\u02ba\u0007^\u0002\u0002\u02ba\u02bb\u000b\u0002\u0002\u0002", "\u02bb\u00c4\u0003\u0002\u0002\u0002\u02bc\u02bd\t\u000b\u0002\u0002", "\u02bd\u00c6\u0003\u0002\u0002\u0002\u02be\u02bf\t\f\u0002\u0002\u02bf", "\u00c8\u0003\u0002\u0002\u0002\u02c0\u02c1\t\r\u0002\u0002\u02c1\u00ca", "\u0003\u0002\u0002\u0002\u02c2\u02c3\t\u000e\u0002\u0002\u02c3\u00cc", "\u0003\u0002\u0002\u0002\u02c4\u02c5\t\u000f\u0002\u0002\u02c5\u00ce", "\u0003\u0002\u0002\u0002\u02c6\u02c8\u0005\u00d3j\u0002\u02c7\u02c6", "\u0003\u0002\u0002\u0002\u02c7\u02c8\u0003\u0002\u0002\u0002\u02c8\u02c9", "\u0003\u0002\u0002\u0002\u02c9\u02ce\u0005\u00d5k\u0002\u02ca\u02cb", "\u0005\u00d3j\u0002\u02cb\u02cc\u00070\u0002\u0002\u02cc\u02ce\u0003", "\u0002\u0002\u0002\u02cd\u02c7\u0003\u0002\u0002\u0002\u02cd\u02ca\u0003", "\u0002\u0002\u0002\u02ce\u00d0\u0003\u0002\u0002\u0002\u02cf\u02d2\u0005", "\u00d3j\u0002\u02d0\u02d2\u0005\u00cfh\u0002\u02d1\u02cf\u0003\u0002", "\u0002\u0002\u02d1\u02d0\u0003\u0002\u0002\u0002\u02d2\u02d3\u0003\u0002", "\u0002\u0002\u02d3\u02d4\u0005\u00d7l\u0002\u02d4\u00d2\u0003\u0002", "\u0002\u0002\u02d5\u02d7\u0005\u00c7d\u0002\u02d6\u02d5\u0003\u0002", "\u0002\u0002\u02d7\u02d8\u0003\u0002\u0002\u0002\u02d8\u02d6\u0003\u0002", "\u0002\u0002\u02d8\u02d9\u0003\u0002\u0002\u0002\u02d9\u00d4\u0003\u0002", "\u0002\u0002\u02da\u02dc\u00070\u0002\u0002\u02db\u02dd\u0005\u00c7", "d\u0002\u02dc\u02db\u0003\u0002\u0002\u0002\u02dd\u02de\u0003\u0002", "\u0002\u0002\u02de\u02dc\u0003\u0002\u0002\u0002\u02de\u02df\u0003\u0002", "\u0002\u0002\u02df\u00d6\u0003\u0002\u0002\u0002\u02e0\u02e2\t\u0010", "\u0002\u0002\u02e1\u02e3\t\u0011\u0002\u0002\u02e2\u02e1\u0003\u0002", "\u0002\u0002\u02e2\u02e3\u0003\u0002\u0002\u0002\u02e3\u02e5\u0003\u0002", "\u0002\u0002\u02e4\u02e6\u0005\u00c7d\u0002\u02e5\u02e4\u0003\u0002", "\u0002\u0002\u02e6\u02e7\u0003\u0002\u0002\u0002\u02e7\u02e5\u0003\u0002", "\u0002\u0002\u02e7\u02e8\u0003\u0002\u0002\u0002\u02e8\u00d8\u0003\u0002", "\u0002\u0002\u02e9\u02ee\u0007)\u0002\u0002\u02ea\u02ed\u0005\u00df", "p\u0002\u02eb\u02ed\u0005\u00e5s\u0002\u02ec\u02ea\u0003\u0002\u0002", "\u0002\u02ec\u02eb\u0003\u0002\u0002\u0002\u02ed\u02f0\u0003\u0002\u0002", "\u0002\u02ee\u02ec\u0003\u0002\u0002\u0002\u02ee\u02ef\u0003\u0002\u0002", "\u0002\u02ef\u02f1\u0003\u0002\u0002\u0002\u02f0\u02ee\u0003\u0002\u0002", "\u0002\u02f1\u02fc\u0007)\u0002\u0002\u02f2\u02f7\u0007$\u0002\u0002", "\u02f3\u02f6\u0005\u00e1q\u0002\u02f4\u02f6\u0005\u00e5s\u0002\u02f5", "\u02f3\u0003\u0002\u0002\u0002\u02f5\u02f4\u0003\u0002\u0002\u0002\u02f6", "\u02f9\u0003\u0002\u0002\u0002\u02f7\u02f5\u0003\u0002\u0002\u0002\u02f7", "\u02f8\u0003\u0002\u0002\u0002\u02f8\u02fa\u0003\u0002\u0002\u0002\u02f9", "\u02f7\u0003\u0002\u0002\u0002\u02fa\u02fc\u0007$\u0002\u0002\u02fb", "\u02e9\u0003\u0002\u0002\u0002\u02fb\u02f2\u0003\u0002\u0002\u0002\u02fc", "\u00da\u0003\u0002\u0002\u0002\u02fd\u02fe\u0007)\u0002\u0002\u02fe", "\u02ff\u0007)\u0002\u0002\u02ff\u0300\u0007)\u0002\u0002\u0300\u0304", "\u0003\u0002\u0002\u0002\u0301\u0303\u0005\u00ddo\u0002\u0302\u0301", "\u0003\u0002\u0002\u0002\u0303\u0306\u0003\u0002\u0002\u0002\u0304\u0305", "\u0003\u0002\u0002\u0002\u0304\u0302\u0003\u0002\u0002\u0002\u0305\u0307", "\u0003\u0002\u0002\u0002\u0306\u0304\u0003\u0002\u0002\u0002\u0307\u0308", "\u0007)\u0002\u0002\u0308\u0309\u0007)\u0002\u0002\u0309\u0318\u0007", ")\u0002\u0002\u030a\u030b\u0007$\u0002\u0002\u030b\u030c\u0007$\u0002", "\u0002\u030c\u030d\u0007$\u0002\u0002\u030d\u0311\u0003\u0002\u0002", "\u0002\u030e\u0310\u0005\u00ddo\u0002\u030f\u030e\u0003\u0002\u0002", "\u0002\u0310\u0313\u0003\u0002\u0002\u0002\u0311\u0312\u0003\u0002\u0002", "\u0002\u0311\u030f\u0003\u0002\u0002\u0002\u0312\u0314\u0003\u0002\u0002", "\u0002\u0313\u0311\u0003\u0002\u0002\u0002\u0314\u0315\u0007$\u0002", "\u0002\u0315\u0316\u0007$\u0002\u0002\u0316\u0318\u0007$\u0002\u0002", "\u0317\u02fd\u0003\u0002\u0002\u0002\u0317\u030a\u0003\u0002\u0002\u0002", "\u0318\u00dc\u0003\u0002\u0002\u0002\u0319\u031c\u0005\u00e3r\u0002", "\u031a\u031c\u0005\u00e5s\u0002\u031b\u0319\u0003\u0002\u0002\u0002", "\u031b\u031a\u0003\u0002\u0002\u0002\u031c\u00de\u0003\u0002\u0002\u0002", "\u031d\u031f\t\u0012\u0002\u0002\u031e\u031d\u0003\u0002\u0002\u0002", "\u031f\u00e0\u0003\u0002\u0002\u0002\u0320\u0322\t\u0013\u0002\u0002", "\u0321\u0320\u0003\u0002\u0002\u0002\u0322\u00e2\u0003\u0002\u0002\u0002", "\u0323\u0325\t\u0014\u0002\u0002\u0324\u0323\u0003\u0002\u0002\u0002", "\u0325\u00e4\u0003\u0002\u0002\u0002\u0326\u0327\u0007^\u0002\u0002", "\u0327\u0328\t\u0015\u0002\u0002\u0328\u00e6\u0003\u0002\u0002\u0002", "\u0329\u032b\t\u0016\u0002\u0002\u032a\u0329\u0003\u0002\u0002\u0002", "\u032b\u032c\u0003\u0002\u0002\u0002\u032c\u032a\u0003\u0002\u0002\u0002", "\u032c\u032d\u0003\u0002\u0002\u0002\u032d\u00e8\u0003\u0002\u0002\u0002", "\u032e\u0332\u0007%\u0002\u0002\u032f\u0331\n\u0017\u0002\u0002\u0330", "\u032f\u0003\u0002\u0002\u0002\u0331\u0334\u0003\u0002\u0002\u0002\u0332", "\u0330\u0003\u0002\u0002\u0002\u0332\u0333\u0003\u0002\u0002\u0002\u0333", "\u00ea\u0003\u0002\u0002\u0002\u0334\u0332\u0003\u0002\u0002\u0002\u0335", "\u0337\u0007^\u0002\u0002\u0336\u0338\u0005\u00e7t\u0002\u0337\u0336", "\u0003\u0002\u0002\u0002\u0337\u0338\u0003\u0002\u0002\u0002\u0338\u033e", "\u0003\u0002\u0002\u0002\u0339\u033b\u0007\u000f\u0002\u0002\u033a\u0339", "\u0003\u0002\u0002\u0002\u033a\u033b\u0003\u0002\u0002\u0002\u033b\u033c", "\u0003\u0002\u0002\u0002\u033c\u033f\u0007\f\u0002\u0002\u033d\u033f", "\u0007\u000f\u0002\u0002\u033e\u033a\u0003\u0002\u0002\u0002\u033e\u033d", "\u0003\u0002\u0002\u0002\u033f\u00ec\u0003\u0002\u0002\u0002\u0340\u0342", "\t\u0018\u0002\u0002\u0341\u0340\u0003\u0002\u0002\u0002\u0342\u00ee", "\u0003\u0002\u0002\u0002\u0343\u0346\u0005\u00edw\u0002\u0344\u0346", "\t\u0019\u0002\u0002\u0345\u0343\u0003\u0002\u0002\u0002\u0345\u0344", "\u0003\u0002\u0002\u0002\u0346\u00f0\u0003\u0002\u0002\u00029\u0002", "\u01a6\u01aa\u01ad\u01af\u01b7\u01bb\u01be\u01c2\u01c6\u01ca\u01d0\u01d6", "\u01d8\u01df\u01e6\u01ed\u01f1\u01f5\u027d\u0286\u0288\u028f\u0291\u0295", "\u029e\u02ab\u02b1\u02b5\u02c7\u02cd\u02d1\u02d8\u02de\u02e2\u02e7\u02ec", "\u02ee\u02f5\u02f7\u02fb\u0304\u0311\u0317\u031b\u031e\u0321\u0324\u032c", "\u0332\u0337\u033a\u033e\u0341\u0345\n\u0003#\u0002\u00030\u0003\u0003", "1\u0004\u00037\u0005\u00038\u0006\u0003D\u0007\u0003E\b\b\u0002\u0002"].join(""); var atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); }); function Python3Lexer(input) { antlr4.Lexer.call(this, input); this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache()); return this; } Python3Lexer.prototype = Object.create(antlr4.Lexer.prototype); Python3Lexer.prototype.constructor = Python3Lexer; Python3Lexer.EOF = antlr4.Token.EOF; Python3Lexer.DEF = 1; Python3Lexer.RETURN = 2; Python3Lexer.RAISE = 3; Python3Lexer.FROM = 4; Python3Lexer.IMPORT = 5; Python3Lexer.AS = 6; Python3Lexer.GLOBAL = 7; Python3Lexer.NONLOCAL = 8; Python3Lexer.ASSERT = 9; Python3Lexer.IF = 10; Python3Lexer.ELIF = 11; Python3Lexer.ELSE = 12; Python3Lexer.WHILE = 13; Python3Lexer.FOR = 14; Python3Lexer.IN = 15; Python3Lexer.TRY = 16; Python3Lexer.FINALLY = 17; Python3Lexer.WITH = 18; Python3Lexer.EXCEPT = 19; Python3Lexer.LAMBDA = 20; Python3Lexer.OR = 21; Python3Lexer.AND = 22; Python3Lexer.NOT = 23; Python3Lexer.IS = 24; Python3Lexer.NONE = 25; Python3Lexer.TRUE = 26; Python3Lexer.FALSE = 27; Python3Lexer.CLASS = 28; Python3Lexer.YIELD = 29; Python3Lexer.DEL = 30; Python3Lexer.PASS = 31; Python3Lexer.CONTINUE = 32; Python3Lexer.BREAK = 33; Python3Lexer.NEWLINE = 34; Python3Lexer.NAME = 35; Python3Lexer.STRING_LITERAL = 36; Python3Lexer.BYTES_LITERAL = 37; Python3Lexer.DECIMAL_INTEGER = 38; Python3Lexer.OCT_INTEGER = 39; Python3Lexer.HEX_INTEGER = 40; Python3Lexer.BIN_INTEGER = 41; Python3Lexer.FLOAT_NUMBER = 42; Python3Lexer.IMAG_NUMBER = 43; Python3Lexer.DOT = 44; Python3Lexer.ELLIPSIS = 45; Python3Lexer.STAR = 46; Python3Lexer.OPEN_PAREN = 47; Python3Lexer.CLOSE_PAREN = 48; Python3Lexer.COMMA = 49; Python3Lexer.COLON = 50; Python3Lexer.SEMI_COLON = 51; Python3Lexer.POWER = 52; Python3Lexer.ASSIGN = 53; Python3Lexer.OPEN_BRACK = 54; Python3Lexer.CLOSE_BRACK = 55; Python3Lexer.OR_OP = 56; Python3Lexer.XOR = 57; Python3Lexer.AND_OP = 58; Python3Lexer.LEFT_SHIFT = 59; Python3Lexer.RIGHT_SHIFT = 60; Python3Lexer.ADD = 61; Python3Lexer.MINUS = 62; Python3Lexer.DIV = 63; Python3Lexer.MOD = 64; Python3Lexer.IDIV = 65; Python3Lexer.NOT_OP = 66; Python3Lexer.OPEN_BRACE = 67; Python3Lexer.CLOSE_BRACE = 68; Python3Lexer.LESS_THAN = 69; Python3Lexer.GREATER_THAN = 70; Python3Lexer.EQUALS = 71; Python3Lexer.GT_EQ = 72; Python3Lexer.LT_EQ = 73; Python3Lexer.NOT_EQ_1 = 74; Python3Lexer.NOT_EQ_2 = 75; Python3Lexer.AT = 76; Python3Lexer.ARROW = 77; Python3Lexer.ADD_ASSIGN = 78; Python3Lexer.SUB_ASSIGN = 79; Python3Lexer.MULT_ASSIGN = 80; Python3Lexer.AT_ASSIGN = 81; Python3Lexer.DIV_ASSIGN = 82; Python3Lexer.MOD_ASSIGN = 83; Python3Lexer.AND_ASSIGN = 84; Python3Lexer.OR_ASSIGN = 85; Python3Lexer.XOR_ASSIGN = 86; Python3Lexer.LEFT_SHIFT_ASSIGN = 87; Python3Lexer.RIGHT_SHIFT_ASSIGN = 88; Python3Lexer.POWER_ASSIGN = 89; Python3Lexer.IDIV_ASSIGN = 90; Python3Lexer.SKIP_ = 91; Python3Lexer.UNKNOWN_CHAR = 92; Python3Lexer.prototype.channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN" ]; Python3Lexer.prototype.modeNames = [ "DEFAULT_MODE" ]; Python3Lexer.prototype.literalNames = [ null, "'def'", "'return'", "'raise'", "'from'", "'import'", "'as'", "'global'", "'nonlocal'", "'assert'", "'if'", "'elif'", "'else'", "'while'", "'for'", "'in'", "'try'", "'finally'", "'with'", "'except'", "'lambda'", "'or'", "'and'", "'not'", "'is'", "'None'", "'True'", "'False'", "'class'", "'yield'", "'del'", "'pass'", "'continue'", "'break'", null, null, null, null, null, null, null, null, null, null, "'.'", "'...'", "'*'", "'('", "')'", "','", "':'", "';'", "'**'", "'='", "'['", "']'", "'|'", "'^'", "'&'", "'<<'", "'>>'", "'+'", "'-'", "'/'", "'%'", "'//'", "'~'", "'{'", "'}'", "'<'", "'>'", "'=='", "'>='", "'<='", "'<>'", "'!='", "'@'", "'->'", "'+='", "'-='", "'*='", "'@='", "'/='", "'%='", "'&='", "'|='", "'^='", "'<<='", "'>>='", "'**='", "'//='" ]; Python3Lexer.prototype.symbolicNames = [ null, "DEF", "RETURN", "RAISE", "FROM", "IMPORT", "AS", "GLOBAL", "NONLOCAL", "ASSERT", "IF", "ELIF", "ELSE", "WHILE", "FOR", "IN", "TRY", "FINALLY", "WITH", "EXCEPT", "LAMBDA", "OR", "AND", "NOT", "IS", "NONE", "TRUE", "FALSE", "CLASS", "YIELD", "DEL", "PASS", "CONTINUE", "BREAK", "NEWLINE", "NAME", "STRING_LITERAL", "BYTES_LITERAL", "DECIMAL_INTEGER", "OCT_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER", "IMAG_NUMBER", "DOT", "ELLIPSIS", "STAR", "OPEN_PAREN", "CLOSE_PAREN", "COMMA", "COLON", "SEMI_COLON", "POWER", "ASSIGN", "OPEN_BRACK", "CLOSE_BRACK", "OR_OP", "XOR", "AND_OP", "LEFT_SHIFT", "RIGHT_SHIFT", "ADD", "MINUS", "DIV", "MOD", "IDIV", "NOT_OP", "OPEN_BRACE", "CLOSE_BRACE", "LESS_THAN", "GREATER_THAN", "EQUALS", "GT_EQ", "LT_EQ", "NOT_EQ_1", "NOT_EQ_2", "AT", "ARROW", "ADD_ASSIGN", "SUB_ASSIGN", "MULT_ASSIGN", "AT_ASSIGN", "DIV_ASSIGN", "MOD_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", "XOR_ASSIGN", "LEFT_SHIFT_ASSIGN", "RIGHT_SHIFT_ASSIGN", "POWER_ASSIGN", "IDIV_ASSIGN", "SKIP_", "UNKNOWN_CHAR" ]; Python3Lexer.prototype.ruleNames = [ "DEF", "RETURN", "RAISE", "FROM", "IMPORT", "AS", "GLOBAL", "NONLOCAL", "ASSERT", "IF", "ELIF", "ELSE", "WHILE", "FOR", "IN", "TRY", "FINALLY", "WITH", "EXCEPT", "LAMBDA", "OR", "AND", "NOT", "IS", "NONE", "TRUE", "FALSE", "CLASS", "YIELD", "DEL", "PASS", "CONTINUE", "BREAK", "NEWLINE", "NAME", "STRING_LITERAL", "BYTES_LITERAL", "DECIMAL_INTEGER", "OCT_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER", "IMAG_NUMBER", "DOT", "ELLIPSIS", "STAR", "OPEN_PAREN", "CLOSE_PAREN", "COMMA", "COLON", "SEMI_COLON", "POWER", "ASSIGN", "OPEN_BRACK", "CLOSE_BRACK", "OR_OP", "XOR", "AND_OP", "LEFT_SHIFT", "RIGHT_SHIFT", "ADD", "MINUS", "DIV", "MOD", "IDIV", "NOT_OP", "OPEN_BRACE", "CLOSE_BRACE", "LESS_THAN", "GREATER_THAN", "EQUALS", "GT_EQ", "LT_EQ", "NOT_EQ_1", "NOT_EQ_2", "AT", "ARROW", "ADD_ASSIGN", "SUB_ASSIGN", "MULT_ASSIGN", "AT_ASSIGN", "DIV_ASSIGN", "MOD_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", "XOR_ASSIGN", "LEFT_SHIFT_ASSIGN", "RIGHT_SHIFT_ASSIGN", "POWER_ASSIGN", "IDIV_ASSIGN", "SKIP_", "UNKNOWN_CHAR", "SHORT_STRING", "LONG_STRING", "LONG_STRING_ITEM", "LONG_STRING_CHAR", "STRING_ESCAPE_SEQ", "NON_ZERO_DIGIT", "DIGIT", "OCT_DIGIT", "HEX_DIGIT", "BIN_DIGIT", "POINT_FLOAT", "EXPONENT_FLOAT", "INT_PART", "FRACTION", "EXPONENT", "SHORT_BYTES", "LONG_BYTES", "LONG_BYTES_ITEM", "SHORT_BYTES_CHAR_NO_SINGLE_QUOTE", "SHORT_BYTES_CHAR_NO_DOUBLE_QUOTE", "LONG_BYTES_CHAR", "BYTES_ESCAPE_SEQ", "SPACES", "COMMENT", "LINE_JOINING", "ID_START", "ID_CONTINUE" ]; Python3Lexer.prototype.grammarFileName = "Python3.g4"; let CommonToken = require('antlr4/Token').CommonToken; let Python3Parser = require('./Python3Parser').Python3Parser; let old_lexer = Python3Lexer; Python3Lexer = function() { old_lexer.apply(this, arguments); this.reset.call(this); } Python3Lexer.prototype = Object.create(old_lexer.prototype); Python3Lexer.prototype.constructor = Python3Lexer; Python3Lexer.prototype.reset = function() { // A queue where extra tokens are pushed on (see the NEWLINE lexer rule). this.token_queue = []; // The stack that keeps track of the indentation level. this.indents = []; // The amount of opened braces, brackets and parenthesis. this.opened = 0; antlr4.Lexer.prototype.reset.call(this); }; Python3Lexer.prototype.emitToken = function(token) { this._token = token; this.token_queue.push(token); }; /** * Return the next token from the character stream and records this last * token in case it resides on the default channel. This recorded token * is used to determine when the lexer could possibly match a regex * literal. * */ Python3Lexer.prototype.nextToken = function() { // Check if the end-of-file is ahead and there are still some DEDENTS expected. if (this._input.LA(1) === Python3Parser.EOF && this.indents.length) { // Remove any trailing EOF tokens from our buffer. this.token_queue = this.token_queue.filter(function(val) { return val.type !== Python3Parser.EOF; }); // First emit an extra line break that serves as the end of the statement. this.emitToken(this.commonToken(Python3Parser.NEWLINE, "\n")); // Now emit as much DEDENT tokens as needed. while (this.indents.length) { this.emitToken(this.createDedent()); this.indents.pop(); } // Put the EOF back on the token stream. this.emitToken(this.commonToken(Python3Parser.EOF, "")); } let next = antlr4.Lexer.prototype.nextToken.call(this); return this.token_queue.length ? this.token_queue.shift() : next; }; Python3Lexer.prototype.createDedent = function() { return this.commonToken(Python3Parser.DEDENT, ""); } Python3Lexer.prototype.commonToken = function(type, text) { let stop = this.getCharIndex() - 1; let start = text.length ? stop - text.length + 1 : stop; return new CommonToken(this._tokenFactorySourcePair, type, antlr4.Lexer.DEFAULT_TOKEN_CHANNEL, start, stop); } // Calculates the indentation of the provided spaces, taking the // following rules into account: // // "Tabs are replaced (from left to right) by one to eight spaces // such that the total number of characters up to and including // the replacement is a multiple of eight [...]" // // -- https://docs.python.org/3.1/reference/lexical_analysis.html#indentation Python3Lexer.prototype.getIndentationCount = function(whitespace) { let count = 0; for (let i = 0; i < whitespace.length; i++) { if (whitespace[i] === '\t') { count += 8 - count % 8; } else { count++; } } return count; } Python3Lexer.prototype.atStartOfInput = function() { return this.getCharIndex() === 0; } Python3Lexer.prototype.action = function(localctx, ruleIndex, actionIndex) { switch (ruleIndex) { case 33: this.NEWLINE_action(localctx, actionIndex); break; case 46: this.OPEN_PAREN_action(localctx, actionIndex); break; case 47: this.CLOSE_PAREN_action(localctx, actionIndex); break; case 53: this.OPEN_BRACK_action(localctx, actionIndex); break; case 54: this.CLOSE_BRACK_action(localctx, actionIndex); break; case 66: this.OPEN_BRACE_action(localctx, actionIndex); break; case 67: this.CLOSE_BRACE_action(localctx, actionIndex); break; default: throw "No registered action for:" + ruleIndex; } }; Python3Lexer.prototype.NEWLINE_action = function(localctx , actionIndex) { switch (actionIndex) { case 0: let newLine = this.text.replace(/[^\r\n]+/g, ''); let spaces = this.text.replace(/[\r\n]+/g, ''); let next = this._input.LA(1); if (this.opened > 0 || next === 13 /* '\r' */ || next === 10 /* '\n' */ || next === 35 /* '#' */) { // If we're inside a list or on a blank line, ignore all indents, // dedents and line breaks. this.skip(); } else { this.emitToken(this.commonToken(Python3Parser.NEWLINE, newLine)); let indent = this.getIndentationCount(spaces); let previous = this.indents.length ? this.indents[this.indents.length - 1] : 0; if (indent === previous) { // skip indents of the same size as the present indent-size this.skip(); } else if (indent > previous) { this.indents.push(indent); this.emitToken(this.commonToken(Python3Parser.INDENT, spaces)); } else { // Possibly emit more than 1 DEDENT token. while (this.indents.length && this.indents[this.indents.length - 1] > indent) { this.emitToken(this.createDedent()); this.indents.pop(); } } } break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.OPEN_PAREN_action = function(localctx , actionIndex) { switch (actionIndex) { case 1: this.opened++; break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.CLOSE_PAREN_action = function(localctx , actionIndex) { switch (actionIndex) { case 2: this.opened--; break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.OPEN_BRACK_action = function(localctx , actionIndex) { switch (actionIndex) { case 3: this.opened++; break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.CLOSE_BRACK_action = function(localctx , actionIndex) { switch (actionIndex) { case 4: this.opened--; break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.OPEN_BRACE_action = function(localctx , actionIndex) { switch (actionIndex) { case 5: this.opened++; break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.CLOSE_BRACE_action = function(localctx , actionIndex) { switch (actionIndex) { case 6: this.opened--; break; default: throw "No registered action for:" + actionIndex; } }; Python3Lexer.prototype.sempred = function(localctx, ruleIndex, predIndex) { switch (ruleIndex) { case 33: return this.NEWLINE_sempred(localctx, predIndex); default: throw "No registered predicate for:" + ruleIndex; } }; Python3Lexer.prototype.NEWLINE_sempred = function(localctx, predIndex) { switch(predIndex) { case 0: return this.atStartOfInput(); default: throw "No predicate with index:" + predIndex; } }; exports.Python3Lexer = Python3Lexer; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Lexer.tokens ================================================ DEF=1 RETURN=2 RAISE=3 FROM=4 IMPORT=5 AS=6 GLOBAL=7 NONLOCAL=8 ASSERT=9 IF=10 ELIF=11 ELSE=12 WHILE=13 FOR=14 IN=15 TRY=16 FINALLY=17 WITH=18 EXCEPT=19 LAMBDA=20 OR=21 AND=22 NOT=23 IS=24 NONE=25 TRUE=26 FALSE=27 CLASS=28 YIELD=29 DEL=30 PASS=31 CONTINUE=32 BREAK=33 NEWLINE=34 NAME=35 STRING_LITERAL=36 BYTES_LITERAL=37 DECIMAL_INTEGER=38 OCT_INTEGER=39 HEX_INTEGER=40 BIN_INTEGER=41 FLOAT_NUMBER=42 IMAG_NUMBER=43 DOT=44 ELLIPSIS=45 STAR=46 OPEN_PAREN=47 CLOSE_PAREN=48 COMMA=49 COLON=50 SEMI_COLON=51 POWER=52 ASSIGN=53 OPEN_BRACK=54 CLOSE_BRACK=55 OR_OP=56 XOR=57 AND_OP=58 LEFT_SHIFT=59 RIGHT_SHIFT=60 ADD=61 MINUS=62 DIV=63 MOD=64 IDIV=65 NOT_OP=66 OPEN_BRACE=67 CLOSE_BRACE=68 LESS_THAN=69 GREATER_THAN=70 EQUALS=71 GT_EQ=72 LT_EQ=73 NOT_EQ_1=74 NOT_EQ_2=75 AT=76 ARROW=77 ADD_ASSIGN=78 SUB_ASSIGN=79 MULT_ASSIGN=80 AT_ASSIGN=81 DIV_ASSIGN=82 MOD_ASSIGN=83 AND_ASSIGN=84 OR_ASSIGN=85 XOR_ASSIGN=86 LEFT_SHIFT_ASSIGN=87 RIGHT_SHIFT_ASSIGN=88 POWER_ASSIGN=89 IDIV_ASSIGN=90 SKIP_=91 UNKNOWN_CHAR=92 'def'=1 'return'=2 'raise'=3 'from'=4 'import'=5 'as'=6 'global'=7 'nonlocal'=8 'assert'=9 'if'=10 'elif'=11 'else'=12 'while'=13 'for'=14 'in'=15 'try'=16 'finally'=17 'with'=18 'except'=19 'lambda'=20 'or'=21 'and'=22 'not'=23 'is'=24 'None'=25 'True'=26 'False'=27 'class'=28 'yield'=29 'del'=30 'pass'=31 'continue'=32 'break'=33 '.'=44 '...'=45 '*'=46 '('=47 ')'=48 ','=49 ':'=50 ';'=51 '**'=52 '='=53 '['=54 ']'=55 '|'=56 '^'=57 '&'=58 '<<'=59 '>>'=60 '+'=61 '-'=62 '/'=63 '%'=64 '//'=65 '~'=66 '{'=67 '}'=68 '<'=69 '>'=70 '=='=71 '>='=72 '<='=73 '<>'=74 '!='=75 '@'=76 '->'=77 '+='=78 '-='=79 '*='=80 '@='=81 '/='=82 '%='=83 '&='=84 '|='=85 '^='=86 '<<='=87 '>>='=88 '**='=89 '//='=90 ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Listener.js ================================================ // Generated from ./lang/python/Python3.g4 by ANTLR 4.7 // jshint ignore: start var antlr4 = require('antlr4/index'); // This class defines a complete listener for a parse tree produced by Python3Parser. function Python3Listener() { antlr4.tree.ParseTreeListener.call(this); return this; } Python3Listener.prototype = Object.create(antlr4.tree.ParseTreeListener.prototype); Python3Listener.prototype.constructor = Python3Listener; // Enter a parse tree produced by Python3Parser#single_input. Python3Listener.prototype.enterSingle_input = function(ctx) { }; // Exit a parse tree produced by Python3Parser#single_input. Python3Listener.prototype.exitSingle_input = function(ctx) { }; // Enter a parse tree produced by Python3Parser#file_input. Python3Listener.prototype.enterFile_input = function(ctx) { }; // Exit a parse tree produced by Python3Parser#file_input. Python3Listener.prototype.exitFile_input = function(ctx) { }; // Enter a parse tree produced by Python3Parser#eval_input. Python3Listener.prototype.enterEval_input = function(ctx) { }; // Exit a parse tree produced by Python3Parser#eval_input. Python3Listener.prototype.exitEval_input = function(ctx) { }; // Enter a parse tree produced by Python3Parser#decorator. Python3Listener.prototype.enterDecorator = function(ctx) { }; // Exit a parse tree produced by Python3Parser#decorator. Python3Listener.prototype.exitDecorator = function(ctx) { }; // Enter a parse tree produced by Python3Parser#decorators. Python3Listener.prototype.enterDecorators = function(ctx) { }; // Exit a parse tree produced by Python3Parser#decorators. Python3Listener.prototype.exitDecorators = function(ctx) { }; // Enter a parse tree produced by Python3Parser#decorated. Python3Listener.prototype.enterDecorated = function(ctx) { }; // Exit a parse tree produced by Python3Parser#decorated. Python3Listener.prototype.exitDecorated = function(ctx) { }; // Enter a parse tree produced by Python3Parser#funcdef. Python3Listener.prototype.enterFuncdef = function(ctx) { }; // Exit a parse tree produced by Python3Parser#funcdef. Python3Listener.prototype.exitFuncdef = function(ctx) { }; // Enter a parse tree produced by Python3Parser#parameters. Python3Listener.prototype.enterParameters = function(ctx) { }; // Exit a parse tree produced by Python3Parser#parameters. Python3Listener.prototype.exitParameters = function(ctx) { }; // Enter a parse tree produced by Python3Parser#typedargslist. Python3Listener.prototype.enterTypedargslist = function(ctx) { }; // Exit a parse tree produced by Python3Parser#typedargslist. Python3Listener.prototype.exitTypedargslist = function(ctx) { }; // Enter a parse tree produced by Python3Parser#tfpdef. Python3Listener.prototype.enterTfpdef = function(ctx) { }; // Exit a parse tree produced by Python3Parser#tfpdef. Python3Listener.prototype.exitTfpdef = function(ctx) { }; // Enter a parse tree produced by Python3Parser#varargslist. Python3Listener.prototype.enterVarargslist = function(ctx) { }; // Exit a parse tree produced by Python3Parser#varargslist. Python3Listener.prototype.exitVarargslist = function(ctx) { }; // Enter a parse tree produced by Python3Parser#vfpdef. Python3Listener.prototype.enterVfpdef = function(ctx) { }; // Exit a parse tree produced by Python3Parser#vfpdef. Python3Listener.prototype.exitVfpdef = function(ctx) { }; // Enter a parse tree produced by Python3Parser#stmt. Python3Listener.prototype.enterStmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#stmt. Python3Listener.prototype.exitStmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#simple_stmt. Python3Listener.prototype.enterSimple_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#simple_stmt. Python3Listener.prototype.exitSimple_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#small_stmt. Python3Listener.prototype.enterSmall_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#small_stmt. Python3Listener.prototype.exitSmall_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#expr_stmt. Python3Listener.prototype.enterExpr_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#expr_stmt. Python3Listener.prototype.exitExpr_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#testlist_star_expr. Python3Listener.prototype.enterTestlist_star_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#testlist_star_expr. Python3Listener.prototype.exitTestlist_star_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#augassign. Python3Listener.prototype.enterAugassign = function(ctx) { }; // Exit a parse tree produced by Python3Parser#augassign. Python3Listener.prototype.exitAugassign = function(ctx) { }; // Enter a parse tree produced by Python3Parser#del_stmt. Python3Listener.prototype.enterDel_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#del_stmt. Python3Listener.prototype.exitDel_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#pass_stmt. Python3Listener.prototype.enterPass_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#pass_stmt. Python3Listener.prototype.exitPass_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#flow_stmt. Python3Listener.prototype.enterFlow_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#flow_stmt. Python3Listener.prototype.exitFlow_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#break_stmt. Python3Listener.prototype.enterBreak_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#break_stmt. Python3Listener.prototype.exitBreak_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#continue_stmt. Python3Listener.prototype.enterContinue_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#continue_stmt. Python3Listener.prototype.exitContinue_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#return_stmt. Python3Listener.prototype.enterReturn_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#return_stmt. Python3Listener.prototype.exitReturn_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#yield_stmt. Python3Listener.prototype.enterYield_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#yield_stmt. Python3Listener.prototype.exitYield_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#raise_stmt. Python3Listener.prototype.enterRaise_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#raise_stmt. Python3Listener.prototype.exitRaise_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#import_stmt. Python3Listener.prototype.enterImport_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#import_stmt. Python3Listener.prototype.exitImport_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#import_name. Python3Listener.prototype.enterImport_name = function(ctx) { }; // Exit a parse tree produced by Python3Parser#import_name. Python3Listener.prototype.exitImport_name = function(ctx) { }; // Enter a parse tree produced by Python3Parser#import_from. Python3Listener.prototype.enterImport_from = function(ctx) { }; // Exit a parse tree produced by Python3Parser#import_from. Python3Listener.prototype.exitImport_from = function(ctx) { }; // Enter a parse tree produced by Python3Parser#import_as_name. Python3Listener.prototype.enterImport_as_name = function(ctx) { }; // Exit a parse tree produced by Python3Parser#import_as_name. Python3Listener.prototype.exitImport_as_name = function(ctx) { }; // Enter a parse tree produced by Python3Parser#dotted_as_name. Python3Listener.prototype.enterDotted_as_name = function(ctx) { }; // Exit a parse tree produced by Python3Parser#dotted_as_name. Python3Listener.prototype.exitDotted_as_name = function(ctx) { }; // Enter a parse tree produced by Python3Parser#import_as_names. Python3Listener.prototype.enterImport_as_names = function(ctx) { }; // Exit a parse tree produced by Python3Parser#import_as_names. Python3Listener.prototype.exitImport_as_names = function(ctx) { }; // Enter a parse tree produced by Python3Parser#dotted_as_names. Python3Listener.prototype.enterDotted_as_names = function(ctx) { }; // Exit a parse tree produced by Python3Parser#dotted_as_names. Python3Listener.prototype.exitDotted_as_names = function(ctx) { }; // Enter a parse tree produced by Python3Parser#dotted_name. Python3Listener.prototype.enterDotted_name = function(ctx) { }; // Exit a parse tree produced by Python3Parser#dotted_name. Python3Listener.prototype.exitDotted_name = function(ctx) { }; // Enter a parse tree produced by Python3Parser#global_stmt. Python3Listener.prototype.enterGlobal_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#global_stmt. Python3Listener.prototype.exitGlobal_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#nonlocal_stmt. Python3Listener.prototype.enterNonlocal_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#nonlocal_stmt. Python3Listener.prototype.exitNonlocal_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#assert_stmt. Python3Listener.prototype.enterAssert_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#assert_stmt. Python3Listener.prototype.exitAssert_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#compound_stmt. Python3Listener.prototype.enterCompound_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#compound_stmt. Python3Listener.prototype.exitCompound_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#if_stmt. Python3Listener.prototype.enterIf_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#if_stmt. Python3Listener.prototype.exitIf_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#while_stmt. Python3Listener.prototype.enterWhile_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#while_stmt. Python3Listener.prototype.exitWhile_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#for_stmt. Python3Listener.prototype.enterFor_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#for_stmt. Python3Listener.prototype.exitFor_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#try_stmt. Python3Listener.prototype.enterTry_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#try_stmt. Python3Listener.prototype.exitTry_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#with_stmt. Python3Listener.prototype.enterWith_stmt = function(ctx) { }; // Exit a parse tree produced by Python3Parser#with_stmt. Python3Listener.prototype.exitWith_stmt = function(ctx) { }; // Enter a parse tree produced by Python3Parser#with_item. Python3Listener.prototype.enterWith_item = function(ctx) { }; // Exit a parse tree produced by Python3Parser#with_item. Python3Listener.prototype.exitWith_item = function(ctx) { }; // Enter a parse tree produced by Python3Parser#except_clause. Python3Listener.prototype.enterExcept_clause = function(ctx) { }; // Exit a parse tree produced by Python3Parser#except_clause. Python3Listener.prototype.exitExcept_clause = function(ctx) { }; // Enter a parse tree produced by Python3Parser#suite. Python3Listener.prototype.enterSuite = function(ctx) { }; // Exit a parse tree produced by Python3Parser#suite. Python3Listener.prototype.exitSuite = function(ctx) { }; // Enter a parse tree produced by Python3Parser#test. Python3Listener.prototype.enterTest = function(ctx) { }; // Exit a parse tree produced by Python3Parser#test. Python3Listener.prototype.exitTest = function(ctx) { }; // Enter a parse tree produced by Python3Parser#test_nocond. Python3Listener.prototype.enterTest_nocond = function(ctx) { }; // Exit a parse tree produced by Python3Parser#test_nocond. Python3Listener.prototype.exitTest_nocond = function(ctx) { }; // Enter a parse tree produced by Python3Parser#lambdef. Python3Listener.prototype.enterLambdef = function(ctx) { }; // Exit a parse tree produced by Python3Parser#lambdef. Python3Listener.prototype.exitLambdef = function(ctx) { }; // Enter a parse tree produced by Python3Parser#lambdef_nocond. Python3Listener.prototype.enterLambdef_nocond = function(ctx) { }; // Exit a parse tree produced by Python3Parser#lambdef_nocond. Python3Listener.prototype.exitLambdef_nocond = function(ctx) { }; // Enter a parse tree produced by Python3Parser#or_test. Python3Listener.prototype.enterOr_test = function(ctx) { }; // Exit a parse tree produced by Python3Parser#or_test. Python3Listener.prototype.exitOr_test = function(ctx) { }; // Enter a parse tree produced by Python3Parser#and_test. Python3Listener.prototype.enterAnd_test = function(ctx) { }; // Exit a parse tree produced by Python3Parser#and_test. Python3Listener.prototype.exitAnd_test = function(ctx) { }; // Enter a parse tree produced by Python3Parser#not_test. Python3Listener.prototype.enterNot_test = function(ctx) { }; // Exit a parse tree produced by Python3Parser#not_test. Python3Listener.prototype.exitNot_test = function(ctx) { }; // Enter a parse tree produced by Python3Parser#comparison. Python3Listener.prototype.enterComparison = function(ctx) { }; // Exit a parse tree produced by Python3Parser#comparison. Python3Listener.prototype.exitComparison = function(ctx) { }; // Enter a parse tree produced by Python3Parser#comp_op. Python3Listener.prototype.enterComp_op = function(ctx) { }; // Exit a parse tree produced by Python3Parser#comp_op. Python3Listener.prototype.exitComp_op = function(ctx) { }; // Enter a parse tree produced by Python3Parser#star_expr. Python3Listener.prototype.enterStar_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#star_expr. Python3Listener.prototype.exitStar_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#expr. Python3Listener.prototype.enterExpr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#expr. Python3Listener.prototype.exitExpr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#xor_expr. Python3Listener.prototype.enterXor_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#xor_expr. Python3Listener.prototype.exitXor_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#and_expr. Python3Listener.prototype.enterAnd_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#and_expr. Python3Listener.prototype.exitAnd_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#shift_expr. Python3Listener.prototype.enterShift_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#shift_expr. Python3Listener.prototype.exitShift_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#arith_expr. Python3Listener.prototype.enterArith_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#arith_expr. Python3Listener.prototype.exitArith_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#term. Python3Listener.prototype.enterTerm = function(ctx) { }; // Exit a parse tree produced by Python3Parser#term. Python3Listener.prototype.exitTerm = function(ctx) { }; // Enter a parse tree produced by Python3Parser#factor. Python3Listener.prototype.enterFactor = function(ctx) { }; // Exit a parse tree produced by Python3Parser#factor. Python3Listener.prototype.exitFactor = function(ctx) { }; // Enter a parse tree produced by Python3Parser#power. Python3Listener.prototype.enterPower = function(ctx) { }; // Exit a parse tree produced by Python3Parser#power. Python3Listener.prototype.exitPower = function(ctx) { }; // Enter a parse tree produced by Python3Parser#atom. Python3Listener.prototype.enterAtom = function(ctx) { }; // Exit a parse tree produced by Python3Parser#atom. Python3Listener.prototype.exitAtom = function(ctx) { }; // Enter a parse tree produced by Python3Parser#testlist_comp. Python3Listener.prototype.enterTestlist_comp = function(ctx) { }; // Exit a parse tree produced by Python3Parser#testlist_comp. Python3Listener.prototype.exitTestlist_comp = function(ctx) { }; // Enter a parse tree produced by Python3Parser#trailer. Python3Listener.prototype.enterTrailer = function(ctx) { }; // Exit a parse tree produced by Python3Parser#trailer. Python3Listener.prototype.exitTrailer = function(ctx) { }; // Enter a parse tree produced by Python3Parser#subscriptlist. Python3Listener.prototype.enterSubscriptlist = function(ctx) { }; // Exit a parse tree produced by Python3Parser#subscriptlist. Python3Listener.prototype.exitSubscriptlist = function(ctx) { }; // Enter a parse tree produced by Python3Parser#subscript. Python3Listener.prototype.enterSubscript = function(ctx) { }; // Exit a parse tree produced by Python3Parser#subscript. Python3Listener.prototype.exitSubscript = function(ctx) { }; // Enter a parse tree produced by Python3Parser#sliceop. Python3Listener.prototype.enterSliceop = function(ctx) { }; // Exit a parse tree produced by Python3Parser#sliceop. Python3Listener.prototype.exitSliceop = function(ctx) { }; // Enter a parse tree produced by Python3Parser#exprlist. Python3Listener.prototype.enterExprlist = function(ctx) { }; // Exit a parse tree produced by Python3Parser#exprlist. Python3Listener.prototype.exitExprlist = function(ctx) { }; // Enter a parse tree produced by Python3Parser#testlist. Python3Listener.prototype.enterTestlist = function(ctx) { }; // Exit a parse tree produced by Python3Parser#testlist. Python3Listener.prototype.exitTestlist = function(ctx) { }; // Enter a parse tree produced by Python3Parser#dictorsetmaker. Python3Listener.prototype.enterDictorsetmaker = function(ctx) { }; // Exit a parse tree produced by Python3Parser#dictorsetmaker. Python3Listener.prototype.exitDictorsetmaker = function(ctx) { }; // Enter a parse tree produced by Python3Parser#classdef. Python3Listener.prototype.enterClassdef = function(ctx) { }; // Exit a parse tree produced by Python3Parser#classdef. Python3Listener.prototype.exitClassdef = function(ctx) { }; // Enter a parse tree produced by Python3Parser#arglist. Python3Listener.prototype.enterArglist = function(ctx) { }; // Exit a parse tree produced by Python3Parser#arglist. Python3Listener.prototype.exitArglist = function(ctx) { }; // Enter a parse tree produced by Python3Parser#argument. Python3Listener.prototype.enterArgument = function(ctx) { }; // Exit a parse tree produced by Python3Parser#argument. Python3Listener.prototype.exitArgument = function(ctx) { }; // Enter a parse tree produced by Python3Parser#comp_iter. Python3Listener.prototype.enterComp_iter = function(ctx) { }; // Exit a parse tree produced by Python3Parser#comp_iter. Python3Listener.prototype.exitComp_iter = function(ctx) { }; // Enter a parse tree produced by Python3Parser#comp_for. Python3Listener.prototype.enterComp_for = function(ctx) { }; // Exit a parse tree produced by Python3Parser#comp_for. Python3Listener.prototype.exitComp_for = function(ctx) { }; // Enter a parse tree produced by Python3Parser#comp_if. Python3Listener.prototype.enterComp_if = function(ctx) { }; // Exit a parse tree produced by Python3Parser#comp_if. Python3Listener.prototype.exitComp_if = function(ctx) { }; // Enter a parse tree produced by Python3Parser#yield_expr. Python3Listener.prototype.enterYield_expr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#yield_expr. Python3Listener.prototype.exitYield_expr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#yield_arg. Python3Listener.prototype.enterYield_arg = function(ctx) { }; // Exit a parse tree produced by Python3Parser#yield_arg. Python3Listener.prototype.exitYield_arg = function(ctx) { }; // Enter a parse tree produced by Python3Parser#str. Python3Listener.prototype.enterStr = function(ctx) { }; // Exit a parse tree produced by Python3Parser#str. Python3Listener.prototype.exitStr = function(ctx) { }; // Enter a parse tree produced by Python3Parser#number. Python3Listener.prototype.enterNumber = function(ctx) { }; // Exit a parse tree produced by Python3Parser#number. Python3Listener.prototype.exitNumber = function(ctx) { }; // Enter a parse tree produced by Python3Parser#integer. Python3Listener.prototype.enterInteger = function(ctx) { }; // Exit a parse tree produced by Python3Parser#integer. Python3Listener.prototype.exitInteger = function(ctx) { }; exports.Python3Listener = Python3Listener; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Parser.js ================================================ // Generated from ./lang/python/Python3.g4 by ANTLR 4.7 // jshint ignore: start var antlr4 = require('antlr4/index'); var Python3Listener = require('./Python3Listener').Python3Listener; var Python3Visitor = require('./Python3Visitor').Python3Visitor; var grammarFileName = "Python3.g4"; var serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964", "\u0003`\u0422\u0004\u0002\t\u0002\u0004\u0003\t\u0003\u0004\u0004\t", "\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007\t\u0007\u0004", "\b\t\b\u0004\t\t\t\u0004\n\t\n\u0004\u000b\t\u000b\u0004\f\t\f\u0004", "\r\t\r\u0004\u000e\t\u000e\u0004\u000f\t\u000f\u0004\u0010\t\u0010\u0004", "\u0011\t\u0011\u0004\u0012\t\u0012\u0004\u0013\t\u0013\u0004\u0014\t", "\u0014\u0004\u0015\t\u0015\u0004\u0016\t\u0016\u0004\u0017\t\u0017\u0004", "\u0018\t\u0018\u0004\u0019\t\u0019\u0004\u001a\t\u001a\u0004\u001b\t", "\u001b\u0004\u001c\t\u001c\u0004\u001d\t\u001d\u0004\u001e\t\u001e\u0004", "\u001f\t\u001f\u0004 \t \u0004!\t!\u0004\"\t\"\u0004#\t#\u0004$\t$\u0004", "%\t%\u0004&\t&\u0004\'\t\'\u0004(\t(\u0004)\t)\u0004*\t*\u0004+\t+\u0004", ",\t,\u0004-\t-\u0004.\t.\u0004/\t/\u00040\t0\u00041\t1\u00042\t2\u0004", "3\t3\u00044\t4\u00045\t5\u00046\t6\u00047\t7\u00048\t8\u00049\t9\u0004", ":\t:\u0004;\t;\u0004<\t<\u0004=\t=\u0004>\t>\u0004?\t?\u0004@\t@\u0004", "A\tA\u0004B\tB\u0004C\tC\u0004D\tD\u0004E\tE\u0004F\tF\u0004G\tG\u0004", "H\tH\u0004I\tI\u0004J\tJ\u0004K\tK\u0004L\tL\u0004M\tM\u0004N\tN\u0004", "O\tO\u0004P\tP\u0004Q\tQ\u0004R\tR\u0004S\tS\u0004T\tT\u0004U\tU\u0003", "\u0002\u0003\u0002\u0003\u0002\u0003\u0002\u0003\u0002\u0005\u0002\u00b0", "\n\u0002\u0003\u0003\u0003\u0003\u0007\u0003\u00b4\n\u0003\f\u0003\u000e", "\u0003\u00b7\u000b\u0003\u0003\u0003\u0003\u0003\u0003\u0004\u0003\u0004", "\u0007\u0004\u00bd\n\u0004\f\u0004\u000e\u0004\u00c0\u000b\u0004\u0003", "\u0004\u0003\u0004\u0003\u0005\u0003\u0005\u0003\u0005\u0003\u0005\u0005", "\u0005\u00c8\n\u0005\u0003\u0005\u0005\u0005\u00cb\n\u0005\u0003\u0005", "\u0003\u0005\u0003\u0006\u0006\u0006\u00d0\n\u0006\r\u0006\u000e\u0006", "\u00d1\u0003\u0007\u0003\u0007\u0003\u0007\u0005\u0007\u00d7\n\u0007", "\u0003\b\u0003\b\u0003\b\u0003\b\u0003\b\u0005\b\u00de\n\b\u0003\b\u0003", "\b\u0003\b\u0003\t\u0003\t\u0005\t\u00e5\n\t\u0003\t\u0003\t\u0003\n", "\u0003\n\u0003\n\u0005\n\u00ec\n\n\u0003\n\u0003\n\u0003\n\u0003\n\u0005", "\n\u00f2\n\n\u0007\n\u00f4\n\n\f\n\u000e\n\u00f7\u000b\n\u0003\n\u0003", "\n\u0003\n\u0005\n\u00fc\n\n\u0003\n\u0003\n\u0003\n\u0003\n\u0005\n", "\u0102\n\n\u0007\n\u0104\n\n\f\n\u000e\n\u0107\u000b\n\u0003\n\u0003", "\n\u0003\n\u0005\n\u010c\n\n\u0003\n\u0003\n\u0005\n\u0110\n\n\u0005", "\n\u0112\n\n\u0003\n\u0003\n\u0005\n\u0116\n\n\u0003\n\u0003\n\u0003", "\n\u0003\n\u0005\n\u011c\n\n\u0007\n\u011e\n\n\f\n\u000e\n\u0121\u000b", "\n\u0003\n\u0003\n\u0003\n\u0005\n\u0126\n\n\u0003\n\u0003\n\u0005\n", "\u012a\n\n\u0003\u000b\u0003\u000b\u0003\u000b\u0005\u000b\u012f\n\u000b", "\u0003\f\u0003\f\u0003\f\u0005\f\u0134\n\f\u0003\f\u0003\f\u0003\f\u0003", "\f\u0005\f\u013a\n\f\u0007\f\u013c\n\f\f\f\u000e\f\u013f\u000b\f\u0003", "\f\u0003\f\u0003\f\u0005\f\u0144\n\f\u0003\f\u0003\f\u0003\f\u0003\f", "\u0005\f\u014a\n\f\u0007\f\u014c\n\f\f\f\u000e\f\u014f\u000b\f\u0003", "\f\u0003\f\u0003\f\u0005\f\u0154\n\f\u0003\f\u0003\f\u0005\f\u0158\n", "\f\u0005\f\u015a\n\f\u0003\f\u0003\f\u0005\f\u015e\n\f\u0003\f\u0003", "\f\u0003\f\u0003\f\u0005\f\u0164\n\f\u0007\f\u0166\n\f\f\f\u000e\f\u0169", "\u000b\f\u0003\f\u0003\f\u0003\f\u0005\f\u016e\n\f\u0003\f\u0003\f\u0005", "\f\u0172\n\f\u0003\r\u0003\r\u0003\u000e\u0003\u000e\u0005\u000e\u0178", "\n\u000e\u0003\u000f\u0003\u000f\u0003\u000f\u0007\u000f\u017d\n\u000f", "\f\u000f\u000e\u000f\u0180\u000b\u000f\u0003\u000f\u0005\u000f\u0183", "\n\u000f\u0003\u000f\u0003\u000f\u0003\u0010\u0003\u0010\u0003\u0010", "\u0003\u0010\u0003\u0010\u0003\u0010\u0003\u0010\u0003\u0010\u0005\u0010", "\u018f\n\u0010\u0003\u0011\u0003\u0011\u0003\u0011\u0003\u0011\u0005", "\u0011\u0195\n\u0011\u0003\u0011\u0003\u0011\u0003\u0011\u0005\u0011", "\u019a\n\u0011\u0007\u0011\u019c\n\u0011\f\u0011\u000e\u0011\u019f\u000b", "\u0011\u0005\u0011\u01a1\n\u0011\u0003\u0012\u0003\u0012\u0005\u0012", "\u01a5\n\u0012\u0003\u0012\u0003\u0012\u0003\u0012\u0005\u0012\u01aa", "\n\u0012\u0007\u0012\u01ac\n\u0012\f\u0012\u000e\u0012\u01af\u000b\u0012", "\u0003\u0012\u0005\u0012\u01b2\n\u0012\u0003\u0013\u0003\u0013\u0003", "\u0014\u0003\u0014\u0003\u0014\u0003\u0015\u0003\u0015\u0003\u0016\u0003", "\u0016\u0003\u0016\u0003\u0016\u0003\u0016\u0005\u0016\u01c0\n\u0016", "\u0003\u0017\u0003\u0017\u0003\u0018\u0003\u0018\u0003\u0019\u0003\u0019", "\u0005\u0019\u01c8\n\u0019\u0003\u001a\u0003\u001a\u0003\u001b\u0003", "\u001b\u0003\u001b\u0003\u001b\u0005\u001b\u01d0\n\u001b\u0005\u001b", "\u01d2\n\u001b\u0003\u001c\u0003\u001c\u0005\u001c\u01d6\n\u001c\u0003", "\u001d\u0003\u001d\u0003\u001d\u0003\u001e\u0003\u001e\u0007\u001e\u01dd", "\n\u001e\f\u001e\u000e\u001e\u01e0\u000b\u001e\u0003\u001e\u0003\u001e", "\u0006\u001e\u01e4\n\u001e\r\u001e\u000e\u001e\u01e5\u0005\u001e\u01e8", "\n\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e\u0003\u001e", "\u0003\u001e\u0003\u001e\u0005\u001e\u01f1\n\u001e\u0003\u001f\u0003", "\u001f\u0003\u001f\u0005\u001f\u01f6\n\u001f\u0003 \u0003 \u0003 \u0005", " \u01fb\n \u0003!\u0003!\u0003!\u0007!\u0200\n!\f!\u000e!\u0203\u000b", "!\u0003!\u0005!\u0206\n!\u0003\"\u0003\"\u0003\"\u0007\"\u020b\n\"\f", "\"\u000e\"\u020e\u000b\"\u0003#\u0003#\u0003#\u0007#\u0213\n#\f#\u000e", "#\u0216\u000b#\u0003$\u0003$\u0003$\u0003$\u0007$\u021c\n$\f$\u000e", "$\u021f\u000b$\u0003%\u0003%\u0003%\u0003%\u0007%\u0225\n%\f%\u000e", "%\u0228\u000b%\u0003&\u0003&\u0003&\u0003&\u0005&\u022e\n&\u0003\'\u0003", "\'\u0003\'\u0003\'\u0003\'\u0003\'\u0003\'\u0003\'\u0005\'\u0238\n\'", "\u0003(\u0003(\u0003(\u0003(\u0003(\u0003(\u0003(\u0003(\u0003(\u0007", "(\u0243\n(\f(\u000e(\u0246\u000b(\u0003(\u0003(\u0003(\u0005(\u024b", "\n(\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0003)\u0005)\u0254\n", ")\u0003*\u0003*\u0003*\u0003*\u0003*\u0003*\u0003*\u0003*\u0003*\u0005", "*\u025f\n*\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0003+\u0006+\u0268", "\n+\r+\u000e+\u0269\u0003+\u0003+\u0003+\u0005+\u026f\n+\u0003+\u0003", "+\u0003+\u0005+\u0274\n+\u0003+\u0003+\u0003+\u0005+\u0279\n+\u0003", ",\u0003,\u0003,\u0003,\u0007,\u027f\n,\f,\u000e,\u0282\u000b,\u0003", ",\u0003,\u0003,\u0003-\u0003-\u0003-\u0005-\u028a\n-\u0003.\u0003.\u0003", ".\u0003.\u0005.\u0290\n.\u0005.\u0292\n.\u0003/\u0003/\u0003/\u0003", "/\u0006/\u0298\n/\r/\u000e/\u0299\u0003/\u0003/\u0005/\u029e\n/\u0003", "0\u00030\u00030\u00030\u00030\u00030\u00050\u02a6\n0\u00030\u00050\u02a9", "\n0\u00031\u00031\u00051\u02ad\n1\u00032\u00032\u00052\u02b1\n2\u0003", "2\u00032\u00032\u00033\u00033\u00053\u02b8\n3\u00033\u00033\u00033\u0003", "4\u00034\u00034\u00074\u02c0\n4\f4\u000e4\u02c3\u000b4\u00035\u0003", "5\u00035\u00075\u02c8\n5\f5\u000e5\u02cb\u000b5\u00036\u00036\u0003", "6\u00056\u02d0\n6\u00037\u00037\u00037\u00037\u00077\u02d6\n7\f7\u000e", "7\u02d9\u000b7\u00038\u00038\u00038\u00038\u00038\u00038\u00038\u0003", "8\u00038\u00038\u00038\u00038\u00038\u00058\u02e8\n8\u00039\u00059\u02eb", "\n9\u00039\u00039\u0003:\u0003:\u0003:\u0007:\u02f2\n:\f:\u000e:\u02f5", "\u000b:\u0003;\u0003;\u0003;\u0007;\u02fa\n;\f;\u000e;\u02fd\u000b;", "\u0003<\u0003<\u0003<\u0007<\u0302\n<\f<\u000e<\u0305\u000b<\u0003=", "\u0003=\u0003=\u0003=\u0003=\u0007=\u030c\n=\f=\u000e=\u030f\u000b=", "\u0003>\u0003>\u0003>\u0003>\u0003>\u0007>\u0316\n>\f>\u000e>\u0319", "\u000b>\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003?\u0003", "?\u0003?\u0003?\u0007?\u0326\n?\f?\u000e?\u0329\u000b?\u0003@\u0003", "@\u0003@\u0003@\u0003@\u0003@\u0003@\u0005@\u0332\n@\u0003A\u0003A\u0007", "A\u0336\nA\fA\u000eA\u0339\u000bA\u0003A\u0003A\u0005A\u033d\nA\u0003", "B\u0003B\u0003B\u0005B\u0342\nB\u0003B\u0003B\u0003B\u0005B\u0347\n", "B\u0003B\u0003B\u0003B\u0005B\u034c\nB\u0003B\u0003B\u0003B\u0003B\u0006", "B\u0352\nB\rB\u000eB\u0353\u0003B\u0003B\u0003B\u0003B\u0005B\u035a", "\nB\u0003C\u0003C\u0003C\u0003C\u0007C\u0360\nC\fC\u000eC\u0363\u000b", "C\u0003C\u0005C\u0366\nC\u0005C\u0368\nC\u0003D\u0003D\u0005D\u036c", "\nD\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0003D\u0005D\u0375\n", "D\u0003E\u0003E\u0003E\u0007E\u037a\nE\fE\u000eE\u037d\u000bE\u0003", "E\u0005E\u0380\nE\u0003F\u0003F\u0005F\u0384\nF\u0003F\u0003F\u0005", "F\u0388\nF\u0003F\u0005F\u038b\nF\u0005F\u038d\nF\u0003G\u0003G\u0005", "G\u0391\nG\u0003H\u0003H\u0003H\u0007H\u0396\nH\fH\u000eH\u0399\u000b", "H\u0003H\u0005H\u039c\nH\u0003I\u0003I\u0003I\u0007I\u03a1\nI\fI\u000e", "I\u03a4\u000bI\u0003I\u0005I\u03a7\nI\u0003J\u0003J\u0003J\u0003J\u0003", "J\u0003J\u0003J\u0003J\u0003J\u0007J\u03b2\nJ\fJ\u000eJ\u03b5\u000b", "J\u0003J\u0005J\u03b8\nJ\u0005J\u03ba\nJ\u0003J\u0003J\u0003J\u0003", "J\u0007J\u03c0\nJ\fJ\u000eJ\u03c3\u000bJ\u0003J\u0005J\u03c6\nJ\u0005", "J\u03c8\nJ\u0005J\u03ca\nJ\u0003K\u0003K\u0003K\u0003K\u0005K\u03d0", "\nK\u0003K\u0005K\u03d3\nK\u0003K\u0003K\u0003K\u0003L\u0003L\u0003", "L\u0007L\u03db\nL\fL\u000eL\u03de\u000bL\u0003L\u0003L\u0005L\u03e2", "\nL\u0003L\u0003L\u0003L\u0003L\u0007L\u03e8\nL\fL\u000eL\u03eb\u000b", "L\u0003L\u0003L\u0003L\u0005L\u03f0\nL\u0003L\u0003L\u0005L\u03f4\n", "L\u0003M\u0003M\u0005M\u03f8\nM\u0003M\u0003M\u0003M\u0003M\u0005M\u03fe", "\nM\u0003N\u0003N\u0005N\u0402\nN\u0003O\u0003O\u0003O\u0003O\u0003", "O\u0005O\u0409\nO\u0003P\u0003P\u0003P\u0005P\u040e\nP\u0003Q\u0003", "Q\u0005Q\u0412\nQ\u0003R\u0003R\u0003R\u0005R\u0417\nR\u0003S\u0003", "S\u0003T\u0003T\u0003T\u0005T\u041e\nT\u0003U\u0003U\u0003U\u0002\u0002", "V\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a", "\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~\u0080", "\u0082\u0084\u0086\u0088\u008a\u008c\u008e\u0090\u0092\u0094\u0096\u0098", "\u009a\u009c\u009e\u00a0\u00a2\u00a4\u00a6\u00a8\u0002\u0006\u0003\u0002", "P\\\u0003\u0002./\u0003\u0002&\'\u0003\u0002(+\u0002\u0492\u0002\u00af", "\u0003\u0002\u0002\u0002\u0004\u00b5\u0003\u0002\u0002\u0002\u0006\u00ba", "\u0003\u0002\u0002\u0002\b\u00c3\u0003\u0002\u0002\u0002\n\u00cf\u0003", "\u0002\u0002\u0002\f\u00d3\u0003\u0002\u0002\u0002\u000e\u00d8\u0003", "\u0002\u0002\u0002\u0010\u00e2\u0003\u0002\u0002\u0002\u0012\u0129\u0003", "\u0002\u0002\u0002\u0014\u012b\u0003\u0002\u0002\u0002\u0016\u0171\u0003", "\u0002\u0002\u0002\u0018\u0173\u0003\u0002\u0002\u0002\u001a\u0177\u0003", "\u0002\u0002\u0002\u001c\u0179\u0003\u0002\u0002\u0002\u001e\u018e\u0003", "\u0002\u0002\u0002 \u0190\u0003\u0002\u0002\u0002\"\u01a4\u0003\u0002", "\u0002\u0002$\u01b3\u0003\u0002\u0002\u0002&\u01b5\u0003\u0002\u0002", "\u0002(\u01b8\u0003\u0002\u0002\u0002*\u01bf\u0003\u0002\u0002\u0002", ",\u01c1\u0003\u0002\u0002\u0002.\u01c3\u0003\u0002\u0002\u00020\u01c5", "\u0003\u0002\u0002\u00022\u01c9\u0003\u0002\u0002\u00024\u01cb\u0003", "\u0002\u0002\u00026\u01d5\u0003\u0002\u0002\u00028\u01d7\u0003\u0002", "\u0002\u0002:\u01da\u0003\u0002\u0002\u0002<\u01f2\u0003\u0002\u0002", "\u0002>\u01f7\u0003\u0002\u0002\u0002@\u01fc\u0003\u0002\u0002\u0002", "B\u0207\u0003\u0002\u0002\u0002D\u020f\u0003\u0002\u0002\u0002F\u0217", "\u0003\u0002\u0002\u0002H\u0220\u0003\u0002\u0002\u0002J\u0229\u0003", "\u0002\u0002\u0002L\u0237\u0003\u0002\u0002\u0002N\u0239\u0003\u0002", "\u0002\u0002P\u024c\u0003\u0002\u0002\u0002R\u0255\u0003\u0002\u0002", "\u0002T\u0260\u0003\u0002\u0002\u0002V\u027a\u0003\u0002\u0002\u0002", "X\u0286\u0003\u0002\u0002\u0002Z\u028b\u0003\u0002\u0002\u0002\\\u029d", "\u0003\u0002\u0002\u0002^\u02a8\u0003\u0002\u0002\u0002`\u02ac\u0003", "\u0002\u0002\u0002b\u02ae\u0003\u0002\u0002\u0002d\u02b5\u0003\u0002", "\u0002\u0002f\u02bc\u0003\u0002\u0002\u0002h\u02c4\u0003\u0002\u0002", "\u0002j\u02cf\u0003\u0002\u0002\u0002l\u02d1\u0003\u0002\u0002\u0002", "n\u02e7\u0003\u0002\u0002\u0002p\u02ea\u0003\u0002\u0002\u0002r\u02ee", "\u0003\u0002\u0002\u0002t\u02f6\u0003\u0002\u0002\u0002v\u02fe\u0003", "\u0002\u0002\u0002x\u0306\u0003\u0002\u0002\u0002z\u0310\u0003\u0002", "\u0002\u0002|\u031a\u0003\u0002\u0002\u0002~\u0331\u0003\u0002\u0002", "\u0002\u0080\u0333\u0003\u0002\u0002\u0002\u0082\u0359\u0003\u0002\u0002", "\u0002\u0084\u035b\u0003\u0002\u0002\u0002\u0086\u0374\u0003\u0002\u0002", "\u0002\u0088\u0376\u0003\u0002\u0002\u0002\u008a\u038c\u0003\u0002\u0002", "\u0002\u008c\u038e\u0003\u0002\u0002\u0002\u008e\u0392\u0003\u0002\u0002", "\u0002\u0090\u039d\u0003\u0002\u0002\u0002\u0092\u03c9\u0003\u0002\u0002", "\u0002\u0094\u03cb\u0003\u0002\u0002\u0002\u0096\u03dc\u0003\u0002\u0002", "\u0002\u0098\u03fd\u0003\u0002\u0002\u0002\u009a\u0401\u0003\u0002\u0002", "\u0002\u009c\u0403\u0003\u0002\u0002\u0002\u009e\u040a\u0003\u0002\u0002", "\u0002\u00a0\u040f\u0003\u0002\u0002\u0002\u00a2\u0416\u0003\u0002\u0002", "\u0002\u00a4\u0418\u0003\u0002\u0002\u0002\u00a6\u041d\u0003\u0002\u0002", "\u0002\u00a8\u041f\u0003\u0002\u0002\u0002\u00aa\u00b0\u0007$\u0002", "\u0002\u00ab\u00b0\u0005\u001c\u000f\u0002\u00ac\u00ad\u0005L\'\u0002", "\u00ad\u00ae\u0007$\u0002\u0002\u00ae\u00b0\u0003\u0002\u0002\u0002", "\u00af\u00aa\u0003\u0002\u0002\u0002\u00af\u00ab\u0003\u0002\u0002\u0002", "\u00af\u00ac\u0003\u0002\u0002\u0002\u00b0\u0003\u0003\u0002\u0002\u0002", "\u00b1\u00b4\u0007$\u0002\u0002\u00b2\u00b4\u0005\u001a\u000e\u0002", "\u00b3\u00b1\u0003\u0002\u0002\u0002\u00b3\u00b2\u0003\u0002\u0002\u0002", "\u00b4\u00b7\u0003\u0002\u0002\u0002\u00b5\u00b3\u0003\u0002\u0002\u0002", "\u00b5\u00b6\u0003\u0002\u0002\u0002\u00b6\u00b8\u0003\u0002\u0002\u0002", "\u00b7\u00b5\u0003\u0002\u0002\u0002\u00b8\u00b9\u0007\u0002\u0002\u0003", "\u00b9\u0005\u0003\u0002\u0002\u0002\u00ba\u00be\u0005\u0090I\u0002", "\u00bb\u00bd\u0007$\u0002\u0002\u00bc\u00bb\u0003\u0002\u0002\u0002", "\u00bd\u00c0\u0003\u0002\u0002\u0002\u00be\u00bc\u0003\u0002\u0002\u0002", "\u00be\u00bf\u0003\u0002\u0002\u0002\u00bf\u00c1\u0003\u0002\u0002\u0002", "\u00c0\u00be\u0003\u0002\u0002\u0002\u00c1\u00c2\u0007\u0002\u0002\u0003", "\u00c2\u0007\u0003\u0002\u0002\u0002\u00c3\u00c4\u0007N\u0002\u0002", "\u00c4\u00ca\u0005D#\u0002\u00c5\u00c7\u00071\u0002\u0002\u00c6\u00c8", "\u0005\u0096L\u0002\u00c7\u00c6\u0003\u0002\u0002\u0002\u00c7\u00c8", "\u0003\u0002\u0002\u0002\u00c8\u00c9\u0003\u0002\u0002\u0002\u00c9\u00cb", "\u00072\u0002\u0002\u00ca\u00c5\u0003\u0002\u0002\u0002\u00ca\u00cb", "\u0003\u0002\u0002\u0002\u00cb\u00cc\u0003\u0002\u0002\u0002\u00cc\u00cd", "\u0007$\u0002\u0002\u00cd\t\u0003\u0002\u0002\u0002\u00ce\u00d0\u0005", "\b\u0005\u0002\u00cf\u00ce\u0003\u0002\u0002\u0002\u00d0\u00d1\u0003", "\u0002\u0002\u0002\u00d1\u00cf\u0003\u0002\u0002\u0002\u00d1\u00d2\u0003", "\u0002\u0002\u0002\u00d2\u000b\u0003\u0002\u0002\u0002\u00d3\u00d6\u0005", "\n\u0006\u0002\u00d4\u00d7\u0005\u0094K\u0002\u00d5\u00d7\u0005\u000e", "\b\u0002\u00d6\u00d4\u0003\u0002\u0002\u0002\u00d6\u00d5\u0003\u0002", "\u0002\u0002\u00d7\r\u0003\u0002\u0002\u0002\u00d8\u00d9\u0007\u0003", "\u0002\u0002\u00d9\u00da\u0007%\u0002\u0002\u00da\u00dd\u0005\u0010", "\t\u0002\u00db\u00dc\u0007O\u0002\u0002\u00dc\u00de\u0005^0\u0002\u00dd", "\u00db\u0003\u0002\u0002\u0002\u00dd\u00de\u0003\u0002\u0002\u0002\u00de", "\u00df\u0003\u0002\u0002\u0002\u00df\u00e0\u00074\u0002\u0002\u00e0", "\u00e1\u0005\\/\u0002\u00e1\u000f\u0003\u0002\u0002\u0002\u00e2\u00e4", "\u00071\u0002\u0002\u00e3\u00e5\u0005\u0012\n\u0002\u00e4\u00e3\u0003", "\u0002\u0002\u0002\u00e4\u00e5\u0003\u0002\u0002\u0002\u00e5\u00e6\u0003", "\u0002\u0002\u0002\u00e6\u00e7\u00072\u0002\u0002\u00e7\u0011\u0003", "\u0002\u0002\u0002\u00e8\u00eb\u0005\u0014\u000b\u0002\u00e9\u00ea\u0007", "7\u0002\u0002\u00ea\u00ec\u0005^0\u0002\u00eb\u00e9\u0003\u0002\u0002", "\u0002\u00eb\u00ec\u0003\u0002\u0002\u0002\u00ec\u00f5\u0003\u0002\u0002", "\u0002\u00ed\u00ee\u00073\u0002\u0002\u00ee\u00f1\u0005\u0014\u000b", "\u0002\u00ef\u00f0\u00077\u0002\u0002\u00f0\u00f2\u0005^0\u0002\u00f1", "\u00ef\u0003\u0002\u0002\u0002\u00f1\u00f2\u0003\u0002\u0002\u0002\u00f2", "\u00f4\u0003\u0002\u0002\u0002\u00f3\u00ed\u0003\u0002\u0002\u0002\u00f4", "\u00f7\u0003\u0002\u0002\u0002\u00f5\u00f3\u0003\u0002\u0002\u0002\u00f5", "\u00f6\u0003\u0002\u0002\u0002\u00f6\u0111\u0003\u0002\u0002\u0002\u00f7", "\u00f5\u0003\u0002\u0002\u0002\u00f8\u010f\u00073\u0002\u0002\u00f9", "\u00fb\u00070\u0002\u0002\u00fa\u00fc\u0005\u0014\u000b\u0002\u00fb", "\u00fa\u0003\u0002\u0002\u0002\u00fb\u00fc\u0003\u0002\u0002\u0002\u00fc", "\u0105\u0003\u0002\u0002\u0002\u00fd\u00fe\u00073\u0002\u0002\u00fe", "\u0101\u0005\u0014\u000b\u0002\u00ff\u0100\u00077\u0002\u0002\u0100", "\u0102\u0005^0\u0002\u0101\u00ff\u0003\u0002\u0002\u0002\u0101\u0102", "\u0003\u0002\u0002\u0002\u0102\u0104\u0003\u0002\u0002\u0002\u0103\u00fd", "\u0003\u0002\u0002\u0002\u0104\u0107\u0003\u0002\u0002\u0002\u0105\u0103", "\u0003\u0002\u0002\u0002\u0105\u0106\u0003\u0002\u0002\u0002\u0106\u010b", "\u0003\u0002\u0002\u0002\u0107\u0105\u0003\u0002\u0002\u0002\u0108\u0109", "\u00073\u0002\u0002\u0109\u010a\u00076\u0002\u0002\u010a\u010c\u0005", "\u0014\u000b\u0002\u010b\u0108\u0003\u0002\u0002\u0002\u010b\u010c\u0003", "\u0002\u0002\u0002\u010c\u0110\u0003\u0002\u0002\u0002\u010d\u010e\u0007", "6\u0002\u0002\u010e\u0110\u0005\u0014\u000b\u0002\u010f\u00f9\u0003", "\u0002\u0002\u0002\u010f\u010d\u0003\u0002\u0002\u0002\u010f\u0110\u0003", "\u0002\u0002\u0002\u0110\u0112\u0003\u0002\u0002\u0002\u0111\u00f8\u0003", "\u0002\u0002\u0002\u0111\u0112\u0003\u0002\u0002\u0002\u0112\u012a\u0003", "\u0002\u0002\u0002\u0113\u0115\u00070\u0002\u0002\u0114\u0116\u0005", "\u0014\u000b\u0002\u0115\u0114\u0003\u0002\u0002\u0002\u0115\u0116\u0003", "\u0002\u0002\u0002\u0116\u011f\u0003\u0002\u0002\u0002\u0117\u0118\u0007", "3\u0002\u0002\u0118\u011b\u0005\u0014\u000b\u0002\u0119\u011a\u0007", "7\u0002\u0002\u011a\u011c\u0005^0\u0002\u011b\u0119\u0003\u0002\u0002", "\u0002\u011b\u011c\u0003\u0002\u0002\u0002\u011c\u011e\u0003\u0002\u0002", "\u0002\u011d\u0117\u0003\u0002\u0002\u0002\u011e\u0121\u0003\u0002\u0002", "\u0002\u011f\u011d\u0003\u0002\u0002\u0002\u011f\u0120\u0003\u0002\u0002", "\u0002\u0120\u0125\u0003\u0002\u0002\u0002\u0121\u011f\u0003\u0002\u0002", "\u0002\u0122\u0123\u00073\u0002\u0002\u0123\u0124\u00076\u0002\u0002", "\u0124\u0126\u0005\u0014\u000b\u0002\u0125\u0122\u0003\u0002\u0002\u0002", "\u0125\u0126\u0003\u0002\u0002\u0002\u0126\u012a\u0003\u0002\u0002\u0002", "\u0127\u0128\u00076\u0002\u0002\u0128\u012a\u0005\u0014\u000b\u0002", "\u0129\u00e8\u0003\u0002\u0002\u0002\u0129\u0113\u0003\u0002\u0002\u0002", "\u0129\u0127\u0003\u0002\u0002\u0002\u012a\u0013\u0003\u0002\u0002\u0002", "\u012b\u012e\u0007%\u0002\u0002\u012c\u012d\u00074\u0002\u0002\u012d", "\u012f\u0005^0\u0002\u012e\u012c\u0003\u0002\u0002\u0002\u012e\u012f", "\u0003\u0002\u0002\u0002\u012f\u0015\u0003\u0002\u0002\u0002\u0130\u0133", "\u0005\u0018\r\u0002\u0131\u0132\u00077\u0002\u0002\u0132\u0134\u0005", "^0\u0002\u0133\u0131\u0003\u0002\u0002\u0002\u0133\u0134\u0003\u0002", "\u0002\u0002\u0134\u013d\u0003\u0002\u0002\u0002\u0135\u0136\u00073", "\u0002\u0002\u0136\u0139\u0005\u0018\r\u0002\u0137\u0138\u00077\u0002", "\u0002\u0138\u013a\u0005^0\u0002\u0139\u0137\u0003\u0002\u0002\u0002", "\u0139\u013a\u0003\u0002\u0002\u0002\u013a\u013c\u0003\u0002\u0002\u0002", "\u013b\u0135\u0003\u0002\u0002\u0002\u013c\u013f\u0003\u0002\u0002\u0002", "\u013d\u013b\u0003\u0002\u0002\u0002\u013d\u013e\u0003\u0002\u0002\u0002", "\u013e\u0159\u0003\u0002\u0002\u0002\u013f\u013d\u0003\u0002\u0002\u0002", "\u0140\u0157\u00073\u0002\u0002\u0141\u0143\u00070\u0002\u0002\u0142", "\u0144\u0005\u0018\r\u0002\u0143\u0142\u0003\u0002\u0002\u0002\u0143", "\u0144\u0003\u0002\u0002\u0002\u0144\u014d\u0003\u0002\u0002\u0002\u0145", "\u0146\u00073\u0002\u0002\u0146\u0149\u0005\u0018\r\u0002\u0147\u0148", "\u00077\u0002\u0002\u0148\u014a\u0005^0\u0002\u0149\u0147\u0003\u0002", "\u0002\u0002\u0149\u014a\u0003\u0002\u0002\u0002\u014a\u014c\u0003\u0002", "\u0002\u0002\u014b\u0145\u0003\u0002\u0002\u0002\u014c\u014f\u0003\u0002", "\u0002\u0002\u014d\u014b\u0003\u0002\u0002\u0002\u014d\u014e\u0003\u0002", "\u0002\u0002\u014e\u0153\u0003\u0002\u0002\u0002\u014f\u014d\u0003\u0002", "\u0002\u0002\u0150\u0151\u00073\u0002\u0002\u0151\u0152\u00076\u0002", "\u0002\u0152\u0154\u0005\u0018\r\u0002\u0153\u0150\u0003\u0002\u0002", "\u0002\u0153\u0154\u0003\u0002\u0002\u0002\u0154\u0158\u0003\u0002\u0002", "\u0002\u0155\u0156\u00076\u0002\u0002\u0156\u0158\u0005\u0018\r\u0002", "\u0157\u0141\u0003\u0002\u0002\u0002\u0157\u0155\u0003\u0002\u0002\u0002", "\u0157\u0158\u0003\u0002\u0002\u0002\u0158\u015a\u0003\u0002\u0002\u0002", "\u0159\u0140\u0003\u0002\u0002\u0002\u0159\u015a\u0003\u0002\u0002\u0002", "\u015a\u0172\u0003\u0002\u0002\u0002\u015b\u015d\u00070\u0002\u0002", "\u015c\u015e\u0005\u0018\r\u0002\u015d\u015c\u0003\u0002\u0002\u0002", "\u015d\u015e\u0003\u0002\u0002\u0002\u015e\u0167\u0003\u0002\u0002\u0002", "\u015f\u0160\u00073\u0002\u0002\u0160\u0163\u0005\u0018\r\u0002\u0161", "\u0162\u00077\u0002\u0002\u0162\u0164\u0005^0\u0002\u0163\u0161\u0003", "\u0002\u0002\u0002\u0163\u0164\u0003\u0002\u0002\u0002\u0164\u0166\u0003", "\u0002\u0002\u0002\u0165\u015f\u0003\u0002\u0002\u0002\u0166\u0169\u0003", "\u0002\u0002\u0002\u0167\u0165\u0003\u0002\u0002\u0002\u0167\u0168\u0003", "\u0002\u0002\u0002\u0168\u016d\u0003\u0002\u0002\u0002\u0169\u0167\u0003", "\u0002\u0002\u0002\u016a\u016b\u00073\u0002\u0002\u016b\u016c\u0007", "6\u0002\u0002\u016c\u016e\u0005\u0018\r\u0002\u016d\u016a\u0003\u0002", "\u0002\u0002\u016d\u016e\u0003\u0002\u0002\u0002\u016e\u0172\u0003\u0002", "\u0002\u0002\u016f\u0170\u00076\u0002\u0002\u0170\u0172\u0005\u0018", "\r\u0002\u0171\u0130\u0003\u0002\u0002\u0002\u0171\u015b\u0003\u0002", "\u0002\u0002\u0171\u016f\u0003\u0002\u0002\u0002\u0172\u0017\u0003\u0002", "\u0002\u0002\u0173\u0174\u0007%\u0002\u0002\u0174\u0019\u0003\u0002", "\u0002\u0002\u0175\u0178\u0005\u001c\u000f\u0002\u0176\u0178\u0005L", "\'\u0002\u0177\u0175\u0003\u0002\u0002\u0002\u0177\u0176\u0003\u0002", "\u0002\u0002\u0178\u001b\u0003\u0002\u0002\u0002\u0179\u017e\u0005\u001e", "\u0010\u0002\u017a\u017b\u00075\u0002\u0002\u017b\u017d\u0005\u001e", "\u0010\u0002\u017c\u017a\u0003\u0002\u0002\u0002\u017d\u0180\u0003\u0002", "\u0002\u0002\u017e\u017c\u0003\u0002\u0002\u0002\u017e\u017f\u0003\u0002", "\u0002\u0002\u017f\u0182\u0003\u0002\u0002\u0002\u0180\u017e\u0003\u0002", "\u0002\u0002\u0181\u0183\u00075\u0002\u0002\u0182\u0181\u0003\u0002", "\u0002\u0002\u0182\u0183\u0003\u0002\u0002\u0002\u0183\u0184\u0003\u0002", "\u0002\u0002\u0184\u0185\u0007$\u0002\u0002\u0185\u001d\u0003\u0002", "\u0002\u0002\u0186\u018f\u0005 \u0011\u0002\u0187\u018f\u0005&\u0014", "\u0002\u0188\u018f\u0005(\u0015\u0002\u0189\u018f\u0005*\u0016\u0002", "\u018a\u018f\u00056\u001c\u0002\u018b\u018f\u0005F$\u0002\u018c\u018f", "\u0005H%\u0002\u018d\u018f\u0005J&\u0002\u018e\u0186\u0003\u0002\u0002", "\u0002\u018e\u0187\u0003\u0002\u0002\u0002\u018e\u0188\u0003\u0002\u0002", "\u0002\u018e\u0189\u0003\u0002\u0002\u0002\u018e\u018a\u0003\u0002\u0002", "\u0002\u018e\u018b\u0003\u0002\u0002\u0002\u018e\u018c\u0003\u0002\u0002", "\u0002\u018e\u018d\u0003\u0002\u0002\u0002\u018f\u001f\u0003\u0002\u0002", "\u0002\u0190\u01a0\u0005\"\u0012\u0002\u0191\u0194\u0005$\u0013\u0002", "\u0192\u0195\u0005\u00a0Q\u0002\u0193\u0195\u0005\u0090I\u0002\u0194", "\u0192\u0003\u0002\u0002\u0002\u0194\u0193\u0003\u0002\u0002\u0002\u0195", "\u01a1\u0003\u0002\u0002\u0002\u0196\u0199\u00077\u0002\u0002\u0197", "\u019a\u0005\u00a0Q\u0002\u0198\u019a\u0005\"\u0012\u0002\u0199\u0197", "\u0003\u0002\u0002\u0002\u0199\u0198\u0003\u0002\u0002\u0002\u019a\u019c", "\u0003\u0002\u0002\u0002\u019b\u0196\u0003\u0002\u0002\u0002\u019c\u019f", "\u0003\u0002\u0002\u0002\u019d\u019b\u0003\u0002\u0002\u0002\u019d\u019e", "\u0003\u0002\u0002\u0002\u019e\u01a1\u0003\u0002\u0002\u0002\u019f\u019d", "\u0003\u0002\u0002\u0002\u01a0\u0191\u0003\u0002\u0002\u0002\u01a0\u019d", "\u0003\u0002\u0002\u0002\u01a1!\u0003\u0002\u0002\u0002\u01a2\u01a5", "\u0005^0\u0002\u01a3\u01a5\u0005p9\u0002\u01a4\u01a2\u0003\u0002\u0002", "\u0002\u01a4\u01a3\u0003\u0002\u0002\u0002\u01a5\u01ad\u0003\u0002\u0002", "\u0002\u01a6\u01a9\u00073\u0002\u0002\u01a7\u01aa\u0005^0\u0002\u01a8", "\u01aa\u0005p9\u0002\u01a9\u01a7\u0003\u0002\u0002\u0002\u01a9\u01a8", "\u0003\u0002\u0002\u0002\u01aa\u01ac\u0003\u0002\u0002\u0002\u01ab\u01a6", "\u0003\u0002\u0002\u0002\u01ac\u01af\u0003\u0002\u0002\u0002\u01ad\u01ab", "\u0003\u0002\u0002\u0002\u01ad\u01ae\u0003\u0002\u0002\u0002\u01ae\u01b1", "\u0003\u0002\u0002\u0002\u01af\u01ad\u0003\u0002\u0002\u0002\u01b0\u01b2", "\u00073\u0002\u0002\u01b1\u01b0\u0003\u0002\u0002\u0002\u01b1\u01b2", "\u0003\u0002\u0002\u0002\u01b2#\u0003\u0002\u0002\u0002\u01b3\u01b4", "\t\u0002\u0002\u0002\u01b4%\u0003\u0002\u0002\u0002\u01b5\u01b6\u0007", " \u0002\u0002\u01b6\u01b7\u0005\u008eH\u0002\u01b7\'\u0003\u0002\u0002", "\u0002\u01b8\u01b9\u0007!\u0002\u0002\u01b9)\u0003\u0002\u0002\u0002", "\u01ba\u01c0\u0005,\u0017\u0002\u01bb\u01c0\u0005.\u0018\u0002\u01bc", "\u01c0\u00050\u0019\u0002\u01bd\u01c0\u00054\u001b\u0002\u01be\u01c0", "\u00052\u001a\u0002\u01bf\u01ba\u0003\u0002\u0002\u0002\u01bf\u01bb", "\u0003\u0002\u0002\u0002\u01bf\u01bc\u0003\u0002\u0002\u0002\u01bf\u01bd", "\u0003\u0002\u0002\u0002\u01bf\u01be\u0003\u0002\u0002\u0002\u01c0+", "\u0003\u0002\u0002\u0002\u01c1\u01c2\u0007#\u0002\u0002\u01c2-\u0003", "\u0002\u0002\u0002\u01c3\u01c4\u0007\"\u0002\u0002\u01c4/\u0003\u0002", "\u0002\u0002\u01c5\u01c7\u0007\u0004\u0002\u0002\u01c6\u01c8\u0005\u0090", "I\u0002\u01c7\u01c6\u0003\u0002\u0002\u0002\u01c7\u01c8\u0003\u0002", "\u0002\u0002\u01c81\u0003\u0002\u0002\u0002\u01c9\u01ca\u0005\u00a0", "Q\u0002\u01ca3\u0003\u0002\u0002\u0002\u01cb\u01d1\u0007\u0005\u0002", "\u0002\u01cc\u01cf\u0005^0\u0002\u01cd\u01ce\u0007\u0006\u0002\u0002", "\u01ce\u01d0\u0005^0\u0002\u01cf\u01cd\u0003\u0002\u0002\u0002\u01cf", "\u01d0\u0003\u0002\u0002\u0002\u01d0\u01d2\u0003\u0002\u0002\u0002\u01d1", "\u01cc\u0003\u0002\u0002\u0002\u01d1\u01d2\u0003\u0002\u0002\u0002\u01d2", "5\u0003\u0002\u0002\u0002\u01d3\u01d6\u00058\u001d\u0002\u01d4\u01d6", "\u0005:\u001e\u0002\u01d5\u01d3\u0003\u0002\u0002\u0002\u01d5\u01d4", "\u0003\u0002\u0002\u0002\u01d67\u0003\u0002\u0002\u0002\u01d7\u01d8", "\u0007\u0007\u0002\u0002\u01d8\u01d9\u0005B\"\u0002\u01d99\u0003\u0002", "\u0002\u0002\u01da\u01e7\u0007\u0006\u0002\u0002\u01db\u01dd\t\u0003", "\u0002\u0002\u01dc\u01db\u0003\u0002\u0002\u0002\u01dd\u01e0\u0003\u0002", "\u0002\u0002\u01de\u01dc\u0003\u0002\u0002\u0002\u01de\u01df\u0003\u0002", "\u0002\u0002\u01df\u01e1\u0003\u0002\u0002\u0002\u01e0\u01de\u0003\u0002", "\u0002\u0002\u01e1\u01e8\u0005D#\u0002\u01e2\u01e4\t\u0003\u0002\u0002", "\u01e3\u01e2\u0003\u0002\u0002\u0002\u01e4\u01e5\u0003\u0002\u0002\u0002", "\u01e5\u01e3\u0003\u0002\u0002\u0002\u01e5\u01e6\u0003\u0002\u0002\u0002", "\u01e6\u01e8\u0003\u0002\u0002\u0002\u01e7\u01de\u0003\u0002\u0002\u0002", "\u01e7\u01e3\u0003\u0002\u0002\u0002\u01e8\u01e9\u0003\u0002\u0002\u0002", "\u01e9\u01f0\u0007\u0007\u0002\u0002\u01ea\u01f1\u00070\u0002\u0002", "\u01eb\u01ec\u00071\u0002\u0002\u01ec\u01ed\u0005@!\u0002\u01ed\u01ee", "\u00072\u0002\u0002\u01ee\u01f1\u0003\u0002\u0002\u0002\u01ef\u01f1", "\u0005@!\u0002\u01f0\u01ea\u0003\u0002\u0002\u0002\u01f0\u01eb\u0003", "\u0002\u0002\u0002\u01f0\u01ef\u0003\u0002\u0002\u0002\u01f1;\u0003", "\u0002\u0002\u0002\u01f2\u01f5\u0007%\u0002\u0002\u01f3\u01f4\u0007", "\b\u0002\u0002\u01f4\u01f6\u0007%\u0002\u0002\u01f5\u01f3\u0003\u0002", "\u0002\u0002\u01f5\u01f6\u0003\u0002\u0002\u0002\u01f6=\u0003\u0002", "\u0002\u0002\u01f7\u01fa\u0005D#\u0002\u01f8\u01f9\u0007\b\u0002\u0002", "\u01f9\u01fb\u0007%\u0002\u0002\u01fa\u01f8\u0003\u0002\u0002\u0002", "\u01fa\u01fb\u0003\u0002\u0002\u0002\u01fb?\u0003\u0002\u0002\u0002", "\u01fc\u0201\u0005<\u001f\u0002\u01fd\u01fe\u00073\u0002\u0002\u01fe", "\u0200\u0005<\u001f\u0002\u01ff\u01fd\u0003\u0002\u0002\u0002\u0200", "\u0203\u0003\u0002\u0002\u0002\u0201\u01ff\u0003\u0002\u0002\u0002\u0201", "\u0202\u0003\u0002\u0002\u0002\u0202\u0205\u0003\u0002\u0002\u0002\u0203", "\u0201\u0003\u0002\u0002\u0002\u0204\u0206\u00073\u0002\u0002\u0205", "\u0204\u0003\u0002\u0002\u0002\u0205\u0206\u0003\u0002\u0002\u0002\u0206", "A\u0003\u0002\u0002\u0002\u0207\u020c\u0005> \u0002\u0208\u0209\u0007", "3\u0002\u0002\u0209\u020b\u0005> \u0002\u020a\u0208\u0003\u0002\u0002", "\u0002\u020b\u020e\u0003\u0002\u0002\u0002\u020c\u020a\u0003\u0002\u0002", "\u0002\u020c\u020d\u0003\u0002\u0002\u0002\u020dC\u0003\u0002\u0002", "\u0002\u020e\u020c\u0003\u0002\u0002\u0002\u020f\u0214\u0007%\u0002", "\u0002\u0210\u0211\u0007.\u0002\u0002\u0211\u0213\u0007%\u0002\u0002", "\u0212\u0210\u0003\u0002\u0002\u0002\u0213\u0216\u0003\u0002\u0002\u0002", "\u0214\u0212\u0003\u0002\u0002\u0002\u0214\u0215\u0003\u0002\u0002\u0002", "\u0215E\u0003\u0002\u0002\u0002\u0216\u0214\u0003\u0002\u0002\u0002", "\u0217\u0218\u0007\t\u0002\u0002\u0218\u021d\u0007%\u0002\u0002\u0219", "\u021a\u00073\u0002\u0002\u021a\u021c\u0007%\u0002\u0002\u021b\u0219", "\u0003\u0002\u0002\u0002\u021c\u021f\u0003\u0002\u0002\u0002\u021d\u021b", "\u0003\u0002\u0002\u0002\u021d\u021e\u0003\u0002\u0002\u0002\u021eG", "\u0003\u0002\u0002\u0002\u021f\u021d\u0003\u0002\u0002\u0002\u0220\u0221", "\u0007\n\u0002\u0002\u0221\u0226\u0007%\u0002\u0002\u0222\u0223\u0007", "3\u0002\u0002\u0223\u0225\u0007%\u0002\u0002\u0224\u0222\u0003\u0002", "\u0002\u0002\u0225\u0228\u0003\u0002\u0002\u0002\u0226\u0224\u0003\u0002", "\u0002\u0002\u0226\u0227\u0003\u0002\u0002\u0002\u0227I\u0003\u0002", "\u0002\u0002\u0228\u0226\u0003\u0002\u0002\u0002\u0229\u022a\u0007\u000b", "\u0002\u0002\u022a\u022d\u0005^0\u0002\u022b\u022c\u00073\u0002\u0002", "\u022c\u022e\u0005^0\u0002\u022d\u022b\u0003\u0002\u0002\u0002\u022d", "\u022e\u0003\u0002\u0002\u0002\u022eK\u0003\u0002\u0002\u0002\u022f", "\u0238\u0005N(\u0002\u0230\u0238\u0005P)\u0002\u0231\u0238\u0005R*\u0002", "\u0232\u0238\u0005T+\u0002\u0233\u0238\u0005V,\u0002\u0234\u0238\u0005", "\u000e\b\u0002\u0235\u0238\u0005\u0094K\u0002\u0236\u0238\u0005\f\u0007", "\u0002\u0237\u022f\u0003\u0002\u0002\u0002\u0237\u0230\u0003\u0002\u0002", "\u0002\u0237\u0231\u0003\u0002\u0002\u0002\u0237\u0232\u0003\u0002\u0002", "\u0002\u0237\u0233\u0003\u0002\u0002\u0002\u0237\u0234\u0003\u0002\u0002", "\u0002\u0237\u0235\u0003\u0002\u0002\u0002\u0237\u0236\u0003\u0002\u0002", "\u0002\u0238M\u0003\u0002\u0002\u0002\u0239\u023a\u0007\f\u0002\u0002", "\u023a\u023b\u0005^0\u0002\u023b\u023c\u00074\u0002\u0002\u023c\u0244", "\u0005\\/\u0002\u023d\u023e\u0007\r\u0002\u0002\u023e\u023f\u0005^0", "\u0002\u023f\u0240\u00074\u0002\u0002\u0240\u0241\u0005\\/\u0002\u0241", "\u0243\u0003\u0002\u0002\u0002\u0242\u023d\u0003\u0002\u0002\u0002\u0243", "\u0246\u0003\u0002\u0002\u0002\u0244\u0242\u0003\u0002\u0002\u0002\u0244", "\u0245\u0003\u0002\u0002\u0002\u0245\u024a\u0003\u0002\u0002\u0002\u0246", "\u0244\u0003\u0002\u0002\u0002\u0247\u0248\u0007\u000e\u0002\u0002\u0248", "\u0249\u00074\u0002\u0002\u0249\u024b\u0005\\/\u0002\u024a\u0247\u0003", "\u0002\u0002\u0002\u024a\u024b\u0003\u0002\u0002\u0002\u024bO\u0003", "\u0002\u0002\u0002\u024c\u024d\u0007\u000f\u0002\u0002\u024d\u024e\u0005", "^0\u0002\u024e\u024f\u00074\u0002\u0002\u024f\u0253\u0005\\/\u0002\u0250", "\u0251\u0007\u000e\u0002\u0002\u0251\u0252\u00074\u0002\u0002\u0252", "\u0254\u0005\\/\u0002\u0253\u0250\u0003\u0002\u0002\u0002\u0253\u0254", "\u0003\u0002\u0002\u0002\u0254Q\u0003\u0002\u0002\u0002\u0255\u0256", "\u0007\u0010\u0002\u0002\u0256\u0257\u0005\u008eH\u0002\u0257\u0258", "\u0007\u0011\u0002\u0002\u0258\u0259\u0005\u0090I\u0002\u0259\u025a", "\u00074\u0002\u0002\u025a\u025e\u0005\\/\u0002\u025b\u025c\u0007\u000e", "\u0002\u0002\u025c\u025d\u00074\u0002\u0002\u025d\u025f\u0005\\/\u0002", "\u025e\u025b\u0003\u0002\u0002\u0002\u025e\u025f\u0003\u0002\u0002\u0002", "\u025fS\u0003\u0002\u0002\u0002\u0260\u0261\u0007\u0012\u0002\u0002", "\u0261\u0262\u00074\u0002\u0002\u0262\u0278\u0005\\/\u0002\u0263\u0264", "\u0005Z.\u0002\u0264\u0265\u00074\u0002\u0002\u0265\u0266\u0005\\/\u0002", "\u0266\u0268\u0003\u0002\u0002\u0002\u0267\u0263\u0003\u0002\u0002\u0002", "\u0268\u0269\u0003\u0002\u0002\u0002\u0269\u0267\u0003\u0002\u0002\u0002", "\u0269\u026a\u0003\u0002\u0002\u0002\u026a\u026e\u0003\u0002\u0002\u0002", "\u026b\u026c\u0007\u000e\u0002\u0002\u026c\u026d\u00074\u0002\u0002", "\u026d\u026f\u0005\\/\u0002\u026e\u026b\u0003\u0002\u0002\u0002\u026e", "\u026f\u0003\u0002\u0002\u0002\u026f\u0273\u0003\u0002\u0002\u0002\u0270", "\u0271\u0007\u0013\u0002\u0002\u0271\u0272\u00074\u0002\u0002\u0272", "\u0274\u0005\\/\u0002\u0273\u0270\u0003\u0002\u0002\u0002\u0273\u0274", "\u0003\u0002\u0002\u0002\u0274\u0279\u0003\u0002\u0002\u0002\u0275\u0276", "\u0007\u0013\u0002\u0002\u0276\u0277\u00074\u0002\u0002\u0277\u0279", "\u0005\\/\u0002\u0278\u0267\u0003\u0002\u0002\u0002\u0278\u0275\u0003", "\u0002\u0002\u0002\u0279U\u0003\u0002\u0002\u0002\u027a\u027b\u0007", "\u0014\u0002\u0002\u027b\u0280\u0005X-\u0002\u027c\u027d\u00073\u0002", "\u0002\u027d\u027f\u0005X-\u0002\u027e\u027c\u0003\u0002\u0002\u0002", "\u027f\u0282\u0003\u0002\u0002\u0002\u0280\u027e\u0003\u0002\u0002\u0002", "\u0280\u0281\u0003\u0002\u0002\u0002\u0281\u0283\u0003\u0002\u0002\u0002", "\u0282\u0280\u0003\u0002\u0002\u0002\u0283\u0284\u00074\u0002\u0002", "\u0284\u0285\u0005\\/\u0002\u0285W\u0003\u0002\u0002\u0002\u0286\u0289", "\u0005^0\u0002\u0287\u0288\u0007\b\u0002\u0002\u0288\u028a\u0005r:\u0002", "\u0289\u0287\u0003\u0002\u0002\u0002\u0289\u028a\u0003\u0002\u0002\u0002", "\u028aY\u0003\u0002\u0002\u0002\u028b\u0291\u0007\u0015\u0002\u0002", "\u028c\u028f\u0005^0\u0002\u028d\u028e\u0007\b\u0002\u0002\u028e\u0290", "\u0007%\u0002\u0002\u028f\u028d\u0003\u0002\u0002\u0002\u028f\u0290", "\u0003\u0002\u0002\u0002\u0290\u0292\u0003\u0002\u0002\u0002\u0291\u028c", "\u0003\u0002\u0002\u0002\u0291\u0292\u0003\u0002\u0002\u0002\u0292[", "\u0003\u0002\u0002\u0002\u0293\u029e\u0005\u001c\u000f\u0002\u0294\u0295", "\u0007$\u0002\u0002\u0295\u0297\u0007_\u0002\u0002\u0296\u0298\u0005", "\u001a\u000e\u0002\u0297\u0296\u0003\u0002\u0002\u0002\u0298\u0299\u0003", "\u0002\u0002\u0002\u0299\u0297\u0003\u0002\u0002\u0002\u0299\u029a\u0003", "\u0002\u0002\u0002\u029a\u029b\u0003\u0002\u0002\u0002\u029b\u029c\u0007", "`\u0002\u0002\u029c\u029e\u0003\u0002\u0002\u0002\u029d\u0293\u0003", "\u0002\u0002\u0002\u029d\u0294\u0003\u0002\u0002\u0002\u029e]\u0003", "\u0002\u0002\u0002\u029f\u02a5\u0005f4\u0002\u02a0\u02a1\u0007\f\u0002", "\u0002\u02a1\u02a2\u0005f4\u0002\u02a2\u02a3\u0007\u000e\u0002\u0002", "\u02a3\u02a4\u0005^0\u0002\u02a4\u02a6\u0003\u0002\u0002\u0002\u02a5", "\u02a0\u0003\u0002\u0002\u0002\u02a5\u02a6\u0003\u0002\u0002\u0002\u02a6", "\u02a9\u0003\u0002\u0002\u0002\u02a7\u02a9\u0005b2\u0002\u02a8\u029f", "\u0003\u0002\u0002\u0002\u02a8\u02a7\u0003\u0002\u0002\u0002\u02a9_", "\u0003\u0002\u0002\u0002\u02aa\u02ad\u0005f4\u0002\u02ab\u02ad\u0005", "d3\u0002\u02ac\u02aa\u0003\u0002\u0002\u0002\u02ac\u02ab\u0003\u0002", "\u0002\u0002\u02ada\u0003\u0002\u0002\u0002\u02ae\u02b0\u0007\u0016", "\u0002\u0002\u02af\u02b1\u0005\u0016\f\u0002\u02b0\u02af\u0003\u0002", "\u0002\u0002\u02b0\u02b1\u0003\u0002\u0002\u0002\u02b1\u02b2\u0003\u0002", "\u0002\u0002\u02b2\u02b3\u00074\u0002\u0002\u02b3\u02b4\u0005^0\u0002", "\u02b4c\u0003\u0002\u0002\u0002\u02b5\u02b7\u0007\u0016\u0002\u0002", "\u02b6\u02b8\u0005\u0016\f\u0002\u02b7\u02b6\u0003\u0002\u0002\u0002", "\u02b7\u02b8\u0003\u0002\u0002\u0002\u02b8\u02b9\u0003\u0002\u0002\u0002", "\u02b9\u02ba\u00074\u0002\u0002\u02ba\u02bb\u0005`1\u0002\u02bbe\u0003", "\u0002\u0002\u0002\u02bc\u02c1\u0005h5\u0002\u02bd\u02be\u0007\u0017", "\u0002\u0002\u02be\u02c0\u0005h5\u0002\u02bf\u02bd\u0003\u0002\u0002", "\u0002\u02c0\u02c3\u0003\u0002\u0002\u0002\u02c1\u02bf\u0003\u0002\u0002", "\u0002\u02c1\u02c2\u0003\u0002\u0002\u0002\u02c2g\u0003\u0002\u0002", "\u0002\u02c3\u02c1\u0003\u0002\u0002\u0002\u02c4\u02c9\u0005j6\u0002", "\u02c5\u02c6\u0007\u0018\u0002\u0002\u02c6\u02c8\u0005j6\u0002\u02c7", "\u02c5\u0003\u0002\u0002\u0002\u02c8\u02cb\u0003\u0002\u0002\u0002\u02c9", "\u02c7\u0003\u0002\u0002\u0002\u02c9\u02ca\u0003\u0002\u0002\u0002\u02ca", "i\u0003\u0002\u0002\u0002\u02cb\u02c9\u0003\u0002\u0002\u0002\u02cc", "\u02cd\u0007\u0019\u0002\u0002\u02cd\u02d0\u0005j6\u0002\u02ce\u02d0", "\u0005l7\u0002\u02cf\u02cc\u0003\u0002\u0002\u0002\u02cf\u02ce\u0003", "\u0002\u0002\u0002\u02d0k\u0003\u0002\u0002\u0002\u02d1\u02d7\u0005", "p9\u0002\u02d2\u02d3\u0005n8\u0002\u02d3\u02d4\u0005p9\u0002\u02d4\u02d6", "\u0003\u0002\u0002\u0002\u02d5\u02d2\u0003\u0002\u0002\u0002\u02d6\u02d9", "\u0003\u0002\u0002\u0002\u02d7\u02d5\u0003\u0002\u0002\u0002\u02d7\u02d8", "\u0003\u0002\u0002\u0002\u02d8m\u0003\u0002\u0002\u0002\u02d9\u02d7", "\u0003\u0002\u0002\u0002\u02da\u02e8\u0007G\u0002\u0002\u02db\u02e8", "\u0007H\u0002\u0002\u02dc\u02e8\u0007I\u0002\u0002\u02dd\u02e8\u0007", "J\u0002\u0002\u02de\u02e8\u0007K\u0002\u0002\u02df\u02e8\u0007L\u0002", "\u0002\u02e0\u02e8\u0007M\u0002\u0002\u02e1\u02e8\u0007\u0011\u0002", "\u0002\u02e2\u02e3\u0007\u0019\u0002\u0002\u02e3\u02e8\u0007\u0011\u0002", "\u0002\u02e4\u02e8\u0007\u001a\u0002\u0002\u02e5\u02e6\u0007\u001a\u0002", "\u0002\u02e6\u02e8\u0007\u0019\u0002\u0002\u02e7\u02da\u0003\u0002\u0002", "\u0002\u02e7\u02db\u0003\u0002\u0002\u0002\u02e7\u02dc\u0003\u0002\u0002", "\u0002\u02e7\u02dd\u0003\u0002\u0002\u0002\u02e7\u02de\u0003\u0002\u0002", "\u0002\u02e7\u02df\u0003\u0002\u0002\u0002\u02e7\u02e0\u0003\u0002\u0002", "\u0002\u02e7\u02e1\u0003\u0002\u0002\u0002\u02e7\u02e2\u0003\u0002\u0002", "\u0002\u02e7\u02e4\u0003\u0002\u0002\u0002\u02e7\u02e5\u0003\u0002\u0002", "\u0002\u02e8o\u0003\u0002\u0002\u0002\u02e9\u02eb\u00070\u0002\u0002", "\u02ea\u02e9\u0003\u0002\u0002\u0002\u02ea\u02eb\u0003\u0002\u0002\u0002", "\u02eb\u02ec\u0003\u0002\u0002\u0002\u02ec\u02ed\u0005r:\u0002\u02ed", "q\u0003\u0002\u0002\u0002\u02ee\u02f3\u0005t;\u0002\u02ef\u02f0\u0007", ":\u0002\u0002\u02f0\u02f2\u0005t;\u0002\u02f1\u02ef\u0003\u0002\u0002", "\u0002\u02f2\u02f5\u0003\u0002\u0002\u0002\u02f3\u02f1\u0003\u0002\u0002", "\u0002\u02f3\u02f4\u0003\u0002\u0002\u0002\u02f4s\u0003\u0002\u0002", "\u0002\u02f5\u02f3\u0003\u0002\u0002\u0002\u02f6\u02fb\u0005v<\u0002", "\u02f7\u02f8\u0007;\u0002\u0002\u02f8\u02fa\u0005v<\u0002\u02f9\u02f7", "\u0003\u0002\u0002\u0002\u02fa\u02fd\u0003\u0002\u0002\u0002\u02fb\u02f9", "\u0003\u0002\u0002\u0002\u02fb\u02fc\u0003\u0002\u0002\u0002\u02fcu", "\u0003\u0002\u0002\u0002\u02fd\u02fb\u0003\u0002\u0002\u0002\u02fe\u0303", "\u0005x=\u0002\u02ff\u0300\u0007<\u0002\u0002\u0300\u0302\u0005x=\u0002", "\u0301\u02ff\u0003\u0002\u0002\u0002\u0302\u0305\u0003\u0002\u0002\u0002", "\u0303\u0301\u0003\u0002\u0002\u0002\u0303\u0304\u0003\u0002\u0002\u0002", "\u0304w\u0003\u0002\u0002\u0002\u0305\u0303\u0003\u0002\u0002\u0002", "\u0306\u030d\u0005z>\u0002\u0307\u0308\u0007=\u0002\u0002\u0308\u030c", "\u0005z>\u0002\u0309\u030a\u0007>\u0002\u0002\u030a\u030c\u0005z>\u0002", "\u030b\u0307\u0003\u0002\u0002\u0002\u030b\u0309\u0003\u0002\u0002\u0002", "\u030c\u030f\u0003\u0002\u0002\u0002\u030d\u030b\u0003\u0002\u0002\u0002", "\u030d\u030e\u0003\u0002\u0002\u0002\u030ey\u0003\u0002\u0002\u0002", "\u030f\u030d\u0003\u0002\u0002\u0002\u0310\u0317\u0005|?\u0002\u0311", "\u0312\u0007?\u0002\u0002\u0312\u0316\u0005|?\u0002\u0313\u0314\u0007", "@\u0002\u0002\u0314\u0316\u0005|?\u0002\u0315\u0311\u0003\u0002\u0002", "\u0002\u0315\u0313\u0003\u0002\u0002\u0002\u0316\u0319\u0003\u0002\u0002", "\u0002\u0317\u0315\u0003\u0002\u0002\u0002\u0317\u0318\u0003\u0002\u0002", "\u0002\u0318{\u0003\u0002\u0002\u0002\u0319\u0317\u0003\u0002\u0002", "\u0002\u031a\u0327\u0005~@\u0002\u031b\u031c\u00070\u0002\u0002\u031c", "\u0326\u0005~@\u0002\u031d\u031e\u0007A\u0002\u0002\u031e\u0326\u0005", "~@\u0002\u031f\u0320\u0007B\u0002\u0002\u0320\u0326\u0005~@\u0002\u0321", "\u0322\u0007C\u0002\u0002\u0322\u0326\u0005~@\u0002\u0323\u0324\u0007", "N\u0002\u0002\u0324\u0326\u0005~@\u0002\u0325\u031b\u0003\u0002\u0002", "\u0002\u0325\u031d\u0003\u0002\u0002\u0002\u0325\u031f\u0003\u0002\u0002", "\u0002\u0325\u0321\u0003\u0002\u0002\u0002\u0325\u0323\u0003\u0002\u0002", "\u0002\u0326\u0329\u0003\u0002\u0002\u0002\u0327\u0325\u0003\u0002\u0002", "\u0002\u0327\u0328\u0003\u0002\u0002\u0002\u0328}\u0003\u0002\u0002", "\u0002\u0329\u0327\u0003\u0002\u0002\u0002\u032a\u032b\u0007?\u0002", "\u0002\u032b\u0332\u0005~@\u0002\u032c\u032d\u0007@\u0002\u0002\u032d", "\u0332\u0005~@\u0002\u032e\u032f\u0007D\u0002\u0002\u032f\u0332\u0005", "~@\u0002\u0330\u0332\u0005\u0080A\u0002\u0331\u032a\u0003\u0002\u0002", "\u0002\u0331\u032c\u0003\u0002\u0002\u0002\u0331\u032e\u0003\u0002\u0002", "\u0002\u0331\u0330\u0003\u0002\u0002\u0002\u0332\u007f\u0003\u0002\u0002", "\u0002\u0333\u0337\u0005\u0082B\u0002\u0334\u0336\u0005\u0086D\u0002", "\u0335\u0334\u0003\u0002\u0002\u0002\u0336\u0339\u0003\u0002\u0002\u0002", "\u0337\u0335\u0003\u0002\u0002\u0002\u0337\u0338\u0003\u0002\u0002\u0002", "\u0338\u033c\u0003\u0002\u0002\u0002\u0339\u0337\u0003\u0002\u0002\u0002", "\u033a\u033b\u00076\u0002\u0002\u033b\u033d\u0005~@\u0002\u033c\u033a", "\u0003\u0002\u0002\u0002\u033c\u033d\u0003\u0002\u0002\u0002\u033d\u0081", "\u0003\u0002\u0002\u0002\u033e\u0341\u00071\u0002\u0002\u033f\u0342", "\u0005\u00a0Q\u0002\u0340\u0342\u0005\u0084C\u0002\u0341\u033f\u0003", "\u0002\u0002\u0002\u0341\u0340\u0003\u0002\u0002\u0002\u0341\u0342\u0003", "\u0002\u0002\u0002\u0342\u0343\u0003\u0002\u0002\u0002\u0343\u035a\u0007", "2\u0002\u0002\u0344\u0346\u00078\u0002\u0002\u0345\u0347\u0005\u0084", "C\u0002\u0346\u0345\u0003\u0002\u0002\u0002\u0346\u0347\u0003\u0002", "\u0002\u0002\u0347\u0348\u0003\u0002\u0002\u0002\u0348\u035a\u00079", "\u0002\u0002\u0349\u034b\u0007E\u0002\u0002\u034a\u034c\u0005\u0092", "J\u0002\u034b\u034a\u0003\u0002\u0002\u0002\u034b\u034c\u0003\u0002", "\u0002\u0002\u034c\u034d\u0003\u0002\u0002\u0002\u034d\u035a\u0007F", "\u0002\u0002\u034e\u035a\u0007%\u0002\u0002\u034f\u035a\u0005\u00a6", "T\u0002\u0350\u0352\u0005\u00a4S\u0002\u0351\u0350\u0003\u0002\u0002", "\u0002\u0352\u0353\u0003\u0002\u0002\u0002\u0353\u0351\u0003\u0002\u0002", "\u0002\u0353\u0354\u0003\u0002\u0002\u0002\u0354\u035a\u0003\u0002\u0002", "\u0002\u0355\u035a\u0007/\u0002\u0002\u0356\u035a\u0007\u001b\u0002", "\u0002\u0357\u035a\u0007\u001c\u0002\u0002\u0358\u035a\u0007\u001d\u0002", "\u0002\u0359\u033e\u0003\u0002\u0002\u0002\u0359\u0344\u0003\u0002\u0002", "\u0002\u0359\u0349\u0003\u0002\u0002\u0002\u0359\u034e\u0003\u0002\u0002", "\u0002\u0359\u034f\u0003\u0002\u0002\u0002\u0359\u0351\u0003\u0002\u0002", "\u0002\u0359\u0355\u0003\u0002\u0002\u0002\u0359\u0356\u0003\u0002\u0002", "\u0002\u0359\u0357\u0003\u0002\u0002\u0002\u0359\u0358\u0003\u0002\u0002", "\u0002\u035a\u0083\u0003\u0002\u0002\u0002\u035b\u0367\u0005^0\u0002", "\u035c\u0368\u0005\u009cO\u0002\u035d\u035e\u00073\u0002\u0002\u035e", "\u0360\u0005^0\u0002\u035f\u035d\u0003\u0002\u0002\u0002\u0360\u0363", "\u0003\u0002\u0002\u0002\u0361\u035f\u0003\u0002\u0002\u0002\u0361\u0362", "\u0003\u0002\u0002\u0002\u0362\u0365\u0003\u0002\u0002\u0002\u0363\u0361", "\u0003\u0002\u0002\u0002\u0364\u0366\u00073\u0002\u0002\u0365\u0364", "\u0003\u0002\u0002\u0002\u0365\u0366\u0003\u0002\u0002\u0002\u0366\u0368", "\u0003\u0002\u0002\u0002\u0367\u035c\u0003\u0002\u0002\u0002\u0367\u0361", "\u0003\u0002\u0002\u0002\u0368\u0085\u0003\u0002\u0002\u0002\u0369\u036b", "\u00071\u0002\u0002\u036a\u036c\u0005\u0096L\u0002\u036b\u036a\u0003", "\u0002\u0002\u0002\u036b\u036c\u0003\u0002\u0002\u0002\u036c\u036d\u0003", "\u0002\u0002\u0002\u036d\u0375\u00072\u0002\u0002\u036e\u036f\u0007", "8\u0002\u0002\u036f\u0370\u0005\u0088E\u0002\u0370\u0371\u00079\u0002", "\u0002\u0371\u0375\u0003\u0002\u0002\u0002\u0372\u0373\u0007.\u0002", "\u0002\u0373\u0375\u0007%\u0002\u0002\u0374\u0369\u0003\u0002\u0002", "\u0002\u0374\u036e\u0003\u0002\u0002\u0002\u0374\u0372\u0003\u0002\u0002", "\u0002\u0375\u0087\u0003\u0002\u0002\u0002\u0376\u037b\u0005\u008aF", "\u0002\u0377\u0378\u00073\u0002\u0002\u0378\u037a\u0005\u008aF\u0002", "\u0379\u0377\u0003\u0002\u0002\u0002\u037a\u037d\u0003\u0002\u0002\u0002", "\u037b\u0379\u0003\u0002\u0002\u0002\u037b\u037c\u0003\u0002\u0002\u0002", "\u037c\u037f\u0003\u0002\u0002\u0002\u037d\u037b\u0003\u0002\u0002\u0002", "\u037e\u0380\u00073\u0002\u0002\u037f\u037e\u0003\u0002\u0002\u0002", "\u037f\u0380\u0003\u0002\u0002\u0002\u0380\u0089\u0003\u0002\u0002\u0002", "\u0381\u038d\u0005^0\u0002\u0382\u0384\u0005^0\u0002\u0383\u0382\u0003", "\u0002\u0002\u0002\u0383\u0384\u0003\u0002\u0002\u0002\u0384\u0385\u0003", "\u0002\u0002\u0002\u0385\u0387\u00074\u0002\u0002\u0386\u0388\u0005", "^0\u0002\u0387\u0386\u0003\u0002\u0002\u0002\u0387\u0388\u0003\u0002", "\u0002\u0002\u0388\u038a\u0003\u0002\u0002\u0002\u0389\u038b\u0005\u008c", "G\u0002\u038a\u0389\u0003\u0002\u0002\u0002\u038a\u038b\u0003\u0002", "\u0002\u0002\u038b\u038d\u0003\u0002\u0002\u0002\u038c\u0381\u0003\u0002", "\u0002\u0002\u038c\u0383\u0003\u0002\u0002\u0002\u038d\u008b\u0003\u0002", "\u0002\u0002\u038e\u0390\u00074\u0002\u0002\u038f\u0391\u0005^0\u0002", "\u0390\u038f\u0003\u0002\u0002\u0002\u0390\u0391\u0003\u0002\u0002\u0002", "\u0391\u008d\u0003\u0002\u0002\u0002\u0392\u0397\u0005p9\u0002\u0393", "\u0394\u00073\u0002\u0002\u0394\u0396\u0005p9\u0002\u0395\u0393\u0003", "\u0002\u0002\u0002\u0396\u0399\u0003\u0002\u0002\u0002\u0397\u0395\u0003", "\u0002\u0002\u0002\u0397\u0398\u0003\u0002\u0002\u0002\u0398\u039b\u0003", "\u0002\u0002\u0002\u0399\u0397\u0003\u0002\u0002\u0002\u039a\u039c\u0007", "3\u0002\u0002\u039b\u039a\u0003\u0002\u0002\u0002\u039b\u039c\u0003", "\u0002\u0002\u0002\u039c\u008f\u0003\u0002\u0002\u0002\u039d\u03a2\u0005", "^0\u0002\u039e\u039f\u00073\u0002\u0002\u039f\u03a1\u0005^0\u0002\u03a0", "\u039e\u0003\u0002\u0002\u0002\u03a1\u03a4\u0003\u0002\u0002\u0002\u03a2", "\u03a0\u0003\u0002\u0002\u0002\u03a2\u03a3\u0003\u0002\u0002\u0002\u03a3", "\u03a6\u0003\u0002\u0002\u0002\u03a4\u03a2\u0003\u0002\u0002\u0002\u03a5", "\u03a7\u00073\u0002\u0002\u03a6\u03a5\u0003\u0002\u0002\u0002\u03a6", "\u03a7\u0003\u0002\u0002\u0002\u03a7\u0091\u0003\u0002\u0002\u0002\u03a8", "\u03a9\u0005^0\u0002\u03a9\u03aa\u00074\u0002\u0002\u03aa\u03b9\u0005", "^0\u0002\u03ab\u03ba\u0005\u009cO\u0002\u03ac\u03ad\u00073\u0002\u0002", "\u03ad\u03ae\u0005^0\u0002\u03ae\u03af\u00074\u0002\u0002\u03af\u03b0", "\u0005^0\u0002\u03b0\u03b2\u0003\u0002\u0002\u0002\u03b1\u03ac\u0003", "\u0002\u0002\u0002\u03b2\u03b5\u0003\u0002\u0002\u0002\u03b3\u03b1\u0003", "\u0002\u0002\u0002\u03b3\u03b4\u0003\u0002\u0002\u0002\u03b4\u03b7\u0003", "\u0002\u0002\u0002\u03b5\u03b3\u0003\u0002\u0002\u0002\u03b6\u03b8\u0007", "3\u0002\u0002\u03b7\u03b6\u0003\u0002\u0002\u0002\u03b7\u03b8\u0003", "\u0002\u0002\u0002\u03b8\u03ba\u0003\u0002\u0002\u0002\u03b9\u03ab\u0003", "\u0002\u0002\u0002\u03b9\u03b3\u0003\u0002\u0002\u0002\u03ba\u03ca\u0003", "\u0002\u0002\u0002\u03bb\u03c7\u0005^0\u0002\u03bc\u03c8\u0005\u009c", "O\u0002\u03bd\u03be\u00073\u0002\u0002\u03be\u03c0\u0005^0\u0002\u03bf", "\u03bd\u0003\u0002\u0002\u0002\u03c0\u03c3\u0003\u0002\u0002\u0002\u03c1", "\u03bf\u0003\u0002\u0002\u0002\u03c1\u03c2\u0003\u0002\u0002\u0002\u03c2", "\u03c5\u0003\u0002\u0002\u0002\u03c3\u03c1\u0003\u0002\u0002\u0002\u03c4", "\u03c6\u00073\u0002\u0002\u03c5\u03c4\u0003\u0002\u0002\u0002\u03c5", "\u03c6\u0003\u0002\u0002\u0002\u03c6\u03c8\u0003\u0002\u0002\u0002\u03c7", "\u03bc\u0003\u0002\u0002\u0002\u03c7\u03c1\u0003\u0002\u0002\u0002\u03c8", "\u03ca\u0003\u0002\u0002\u0002\u03c9\u03a8\u0003\u0002\u0002\u0002\u03c9", "\u03bb\u0003\u0002\u0002\u0002\u03ca\u0093\u0003\u0002\u0002\u0002\u03cb", "\u03cc\u0007\u001e\u0002\u0002\u03cc\u03d2\u0007%\u0002\u0002\u03cd", "\u03cf\u00071\u0002\u0002\u03ce\u03d0\u0005\u0096L\u0002\u03cf\u03ce", "\u0003\u0002\u0002\u0002\u03cf\u03d0\u0003\u0002\u0002\u0002\u03d0\u03d1", "\u0003\u0002\u0002\u0002\u03d1\u03d3\u00072\u0002\u0002\u03d2\u03cd", "\u0003\u0002\u0002\u0002\u03d2\u03d3\u0003\u0002\u0002\u0002\u03d3\u03d4", "\u0003\u0002\u0002\u0002\u03d4\u03d5\u00074\u0002\u0002\u03d5\u03d6", "\u0005\\/\u0002\u03d6\u0095\u0003\u0002\u0002\u0002\u03d7\u03d8\u0005", "\u0098M\u0002\u03d8\u03d9\u00073\u0002\u0002\u03d9\u03db\u0003\u0002", "\u0002\u0002\u03da\u03d7\u0003\u0002\u0002\u0002\u03db\u03de\u0003\u0002", "\u0002\u0002\u03dc\u03da\u0003\u0002\u0002\u0002\u03dc\u03dd\u0003\u0002", "\u0002\u0002\u03dd\u03f3\u0003\u0002\u0002\u0002\u03de\u03dc\u0003\u0002", "\u0002\u0002\u03df\u03e1\u0005\u0098M\u0002\u03e0\u03e2\u00073\u0002", "\u0002\u03e1\u03e0\u0003\u0002\u0002\u0002\u03e1\u03e2\u0003\u0002\u0002", "\u0002\u03e2\u03f4\u0003\u0002\u0002\u0002\u03e3\u03e4\u00070\u0002", "\u0002\u03e4\u03e9\u0005^0\u0002\u03e5\u03e6\u00073\u0002\u0002\u03e6", "\u03e8\u0005\u0098M\u0002\u03e7\u03e5\u0003\u0002\u0002\u0002\u03e8", "\u03eb\u0003\u0002\u0002\u0002\u03e9\u03e7\u0003\u0002\u0002\u0002\u03e9", "\u03ea\u0003\u0002\u0002\u0002\u03ea\u03ef\u0003\u0002\u0002\u0002\u03eb", "\u03e9\u0003\u0002\u0002\u0002\u03ec\u03ed\u00073\u0002\u0002\u03ed", "\u03ee\u00076\u0002\u0002\u03ee\u03f0\u0005^0\u0002\u03ef\u03ec\u0003", "\u0002\u0002\u0002\u03ef\u03f0\u0003\u0002\u0002\u0002\u03f0\u03f4\u0003", "\u0002\u0002\u0002\u03f1\u03f2\u00076\u0002\u0002\u03f2\u03f4\u0005", "^0\u0002\u03f3\u03df\u0003\u0002\u0002\u0002\u03f3\u03e3\u0003\u0002", "\u0002\u0002\u03f3\u03f1\u0003\u0002\u0002\u0002\u03f4\u0097\u0003\u0002", "\u0002\u0002\u03f5\u03f7\u0005^0\u0002\u03f6\u03f8\u0005\u009cO\u0002", "\u03f7\u03f6\u0003\u0002\u0002\u0002\u03f7\u03f8\u0003\u0002\u0002\u0002", "\u03f8\u03fe\u0003\u0002\u0002\u0002\u03f9\u03fa\u0005^0\u0002\u03fa", "\u03fb\u00077\u0002\u0002\u03fb\u03fc\u0005^0\u0002\u03fc\u03fe\u0003", "\u0002\u0002\u0002\u03fd\u03f5\u0003\u0002\u0002\u0002\u03fd\u03f9\u0003", "\u0002\u0002\u0002\u03fe\u0099\u0003\u0002\u0002\u0002\u03ff\u0402\u0005", "\u009cO\u0002\u0400\u0402\u0005\u009eP\u0002\u0401\u03ff\u0003\u0002", "\u0002\u0002\u0401\u0400\u0003\u0002\u0002\u0002\u0402\u009b\u0003\u0002", "\u0002\u0002\u0403\u0404\u0007\u0010\u0002\u0002\u0404\u0405\u0005\u008e", "H\u0002\u0405\u0406\u0007\u0011\u0002\u0002\u0406\u0408\u0005f4\u0002", "\u0407\u0409\u0005\u009aN\u0002\u0408\u0407\u0003\u0002\u0002\u0002", "\u0408\u0409\u0003\u0002\u0002\u0002\u0409\u009d\u0003\u0002\u0002\u0002", "\u040a\u040b\u0007\f\u0002\u0002\u040b\u040d\u0005`1\u0002\u040c\u040e", "\u0005\u009aN\u0002\u040d\u040c\u0003\u0002\u0002\u0002\u040d\u040e", "\u0003\u0002\u0002\u0002\u040e\u009f\u0003\u0002\u0002\u0002\u040f\u0411", "\u0007\u001f\u0002\u0002\u0410\u0412\u0005\u00a2R\u0002\u0411\u0410", "\u0003\u0002\u0002\u0002\u0411\u0412\u0003\u0002\u0002\u0002\u0412\u00a1", "\u0003\u0002\u0002\u0002\u0413\u0414\u0007\u0006\u0002\u0002\u0414\u0417", "\u0005^0\u0002\u0415\u0417\u0005\u0090I\u0002\u0416\u0413\u0003\u0002", "\u0002\u0002\u0416\u0415\u0003\u0002\u0002\u0002\u0417\u00a3\u0003\u0002", "\u0002\u0002\u0418\u0419\t\u0004\u0002\u0002\u0419\u00a5\u0003\u0002", "\u0002\u0002\u041a\u041e\u0005\u00a8U\u0002\u041b\u041e\u0007,\u0002", "\u0002\u041c\u041e\u0007-\u0002\u0002\u041d\u041a\u0003\u0002\u0002", "\u0002\u041d\u041b\u0003\u0002\u0002\u0002\u041d\u041c\u0003\u0002\u0002", "\u0002\u041e\u00a7\u0003\u0002\u0002\u0002\u041f\u0420\t\u0005\u0002", "\u0002\u0420\u00a9\u0003\u0002\u0002\u0002\u0098\u00af\u00b3\u00b5\u00be", "\u00c7\u00ca\u00d1\u00d6\u00dd\u00e4\u00eb\u00f1\u00f5\u00fb\u0101\u0105", "\u010b\u010f\u0111\u0115\u011b\u011f\u0125\u0129\u012e\u0133\u0139\u013d", "\u0143\u0149\u014d\u0153\u0157\u0159\u015d\u0163\u0167\u016d\u0171\u0177", "\u017e\u0182\u018e\u0194\u0199\u019d\u01a0\u01a4\u01a9\u01ad\u01b1\u01bf", "\u01c7\u01cf\u01d1\u01d5\u01de\u01e5\u01e7\u01f0\u01f5\u01fa\u0201\u0205", "\u020c\u0214\u021d\u0226\u022d\u0237\u0244\u024a\u0253\u025e\u0269\u026e", "\u0273\u0278\u0280\u0289\u028f\u0291\u0299\u029d\u02a5\u02a8\u02ac\u02b0", "\u02b7\u02c1\u02c9\u02cf\u02d7\u02e7\u02ea\u02f3\u02fb\u0303\u030b\u030d", "\u0315\u0317\u0325\u0327\u0331\u0337\u033c\u0341\u0346\u034b\u0353\u0359", "\u0361\u0365\u0367\u036b\u0374\u037b\u037f\u0383\u0387\u038a\u038c\u0390", "\u0397\u039b\u03a2\u03a6\u03b3\u03b7\u03b9\u03c1\u03c5\u03c7\u03c9\u03cf", "\u03d2\u03dc\u03e1\u03e9\u03ef\u03f3\u03f7\u03fd\u0401\u0408\u040d\u0411", "\u0416\u041d"].join(""); var atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); }); var sharedContextCache = new antlr4.PredictionContextCache(); var literalNames = [ null, "'def'", "'return'", "'raise'", "'from'", "'import'", "'as'", "'global'", "'nonlocal'", "'assert'", "'if'", "'elif'", "'else'", "'while'", "'for'", "'in'", "'try'", "'finally'", "'with'", "'except'", "'lambda'", "'or'", "'and'", "'not'", "'is'", "'None'", "'True'", "'False'", "'class'", "'yield'", "'del'", "'pass'", "'continue'", "'break'", null, null, null, null, null, null, null, null, null, null, "'.'", "'...'", "'*'", "'('", "')'", "','", "':'", "';'", "'**'", "'='", "'['", "']'", "'|'", "'^'", "'&'", "'<<'", "'>>'", "'+'", "'-'", "'/'", "'%'", "'//'", "'~'", "'{'", "'}'", "'<'", "'>'", "'=='", "'>='", "'<='", "'<>'", "'!='", "'@'", "'->'", "'+='", "'-='", "'*='", "'@='", "'/='", "'%='", "'&='", "'|='", "'^='", "'<<='", "'>>='", "'**='", "'//='" ]; var symbolicNames = [ null, "DEF", "RETURN", "RAISE", "FROM", "IMPORT", "AS", "GLOBAL", "NONLOCAL", "ASSERT", "IF", "ELIF", "ELSE", "WHILE", "FOR", "IN", "TRY", "FINALLY", "WITH", "EXCEPT", "LAMBDA", "OR", "AND", "NOT", "IS", "NONE", "TRUE", "FALSE", "CLASS", "YIELD", "DEL", "PASS", "CONTINUE", "BREAK", "NEWLINE", "NAME", "STRING_LITERAL", "BYTES_LITERAL", "DECIMAL_INTEGER", "OCT_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER", "IMAG_NUMBER", "DOT", "ELLIPSIS", "STAR", "OPEN_PAREN", "CLOSE_PAREN", "COMMA", "COLON", "SEMI_COLON", "POWER", "ASSIGN", "OPEN_BRACK", "CLOSE_BRACK", "OR_OP", "XOR", "AND_OP", "LEFT_SHIFT", "RIGHT_SHIFT", "ADD", "MINUS", "DIV", "MOD", "IDIV", "NOT_OP", "OPEN_BRACE", "CLOSE_BRACE", "LESS_THAN", "GREATER_THAN", "EQUALS", "GT_EQ", "LT_EQ", "NOT_EQ_1", "NOT_EQ_2", "AT", "ARROW", "ADD_ASSIGN", "SUB_ASSIGN", "MULT_ASSIGN", "AT_ASSIGN", "DIV_ASSIGN", "MOD_ASSIGN", "AND_ASSIGN", "OR_ASSIGN", "XOR_ASSIGN", "LEFT_SHIFT_ASSIGN", "RIGHT_SHIFT_ASSIGN", "POWER_ASSIGN", "IDIV_ASSIGN", "SKIP_", "UNKNOWN_CHAR", "INDENT", "DEDENT" ]; var ruleNames = [ "single_input", "file_input", "eval_input", "decorator", "decorators", "decorated", "funcdef", "parameters", "typedargslist", "tfpdef", "varargslist", "vfpdef", "stmt", "simple_stmt", "small_stmt", "expr_stmt", "testlist_star_expr", "augassign", "del_stmt", "pass_stmt", "flow_stmt", "break_stmt", "continue_stmt", "return_stmt", "yield_stmt", "raise_stmt", "import_stmt", "import_name", "import_from", "import_as_name", "dotted_as_name", "import_as_names", "dotted_as_names", "dotted_name", "global_stmt", "nonlocal_stmt", "assert_stmt", "compound_stmt", "if_stmt", "while_stmt", "for_stmt", "try_stmt", "with_stmt", "with_item", "except_clause", "suite", "test", "test_nocond", "lambdef", "lambdef_nocond", "or_test", "and_test", "not_test", "comparison", "comp_op", "star_expr", "expr", "xor_expr", "and_expr", "shift_expr", "arith_expr", "term", "factor", "power", "atom", "testlist_comp", "trailer", "subscriptlist", "subscript", "sliceop", "exprlist", "testlist", "dictorsetmaker", "classdef", "arglist", "argument", "comp_iter", "comp_for", "comp_if", "yield_expr", "yield_arg", "str", "number", "integer" ]; function Python3Parser (input) { antlr4.Parser.call(this, input); this._interp = new antlr4.atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache); this.ruleNames = ruleNames; this.literalNames = literalNames; this.symbolicNames = symbolicNames; return this; } Python3Parser.prototype = Object.create(antlr4.Parser.prototype); Python3Parser.prototype.constructor = Python3Parser; Object.defineProperty(Python3Parser.prototype, "atn", { get : function() { return atn; } }); Python3Parser.EOF = antlr4.Token.EOF; Python3Parser.DEF = 1; Python3Parser.RETURN = 2; Python3Parser.RAISE = 3; Python3Parser.FROM = 4; Python3Parser.IMPORT = 5; Python3Parser.AS = 6; Python3Parser.GLOBAL = 7; Python3Parser.NONLOCAL = 8; Python3Parser.ASSERT = 9; Python3Parser.IF = 10; Python3Parser.ELIF = 11; Python3Parser.ELSE = 12; Python3Parser.WHILE = 13; Python3Parser.FOR = 14; Python3Parser.IN = 15; Python3Parser.TRY = 16; Python3Parser.FINALLY = 17; Python3Parser.WITH = 18; Python3Parser.EXCEPT = 19; Python3Parser.LAMBDA = 20; Python3Parser.OR = 21; Python3Parser.AND = 22; Python3Parser.NOT = 23; Python3Parser.IS = 24; Python3Parser.NONE = 25; Python3Parser.TRUE = 26; Python3Parser.FALSE = 27; Python3Parser.CLASS = 28; Python3Parser.YIELD = 29; Python3Parser.DEL = 30; Python3Parser.PASS = 31; Python3Parser.CONTINUE = 32; Python3Parser.BREAK = 33; Python3Parser.NEWLINE = 34; Python3Parser.NAME = 35; Python3Parser.STRING_LITERAL = 36; Python3Parser.BYTES_LITERAL = 37; Python3Parser.DECIMAL_INTEGER = 38; Python3Parser.OCT_INTEGER = 39; Python3Parser.HEX_INTEGER = 40; Python3Parser.BIN_INTEGER = 41; Python3Parser.FLOAT_NUMBER = 42; Python3Parser.IMAG_NUMBER = 43; Python3Parser.DOT = 44; Python3Parser.ELLIPSIS = 45; Python3Parser.STAR = 46; Python3Parser.OPEN_PAREN = 47; Python3Parser.CLOSE_PAREN = 48; Python3Parser.COMMA = 49; Python3Parser.COLON = 50; Python3Parser.SEMI_COLON = 51; Python3Parser.POWER = 52; Python3Parser.ASSIGN = 53; Python3Parser.OPEN_BRACK = 54; Python3Parser.CLOSE_BRACK = 55; Python3Parser.OR_OP = 56; Python3Parser.XOR = 57; Python3Parser.AND_OP = 58; Python3Parser.LEFT_SHIFT = 59; Python3Parser.RIGHT_SHIFT = 60; Python3Parser.ADD = 61; Python3Parser.MINUS = 62; Python3Parser.DIV = 63; Python3Parser.MOD = 64; Python3Parser.IDIV = 65; Python3Parser.NOT_OP = 66; Python3Parser.OPEN_BRACE = 67; Python3Parser.CLOSE_BRACE = 68; Python3Parser.LESS_THAN = 69; Python3Parser.GREATER_THAN = 70; Python3Parser.EQUALS = 71; Python3Parser.GT_EQ = 72; Python3Parser.LT_EQ = 73; Python3Parser.NOT_EQ_1 = 74; Python3Parser.NOT_EQ_2 = 75; Python3Parser.AT = 76; Python3Parser.ARROW = 77; Python3Parser.ADD_ASSIGN = 78; Python3Parser.SUB_ASSIGN = 79; Python3Parser.MULT_ASSIGN = 80; Python3Parser.AT_ASSIGN = 81; Python3Parser.DIV_ASSIGN = 82; Python3Parser.MOD_ASSIGN = 83; Python3Parser.AND_ASSIGN = 84; Python3Parser.OR_ASSIGN = 85; Python3Parser.XOR_ASSIGN = 86; Python3Parser.LEFT_SHIFT_ASSIGN = 87; Python3Parser.RIGHT_SHIFT_ASSIGN = 88; Python3Parser.POWER_ASSIGN = 89; Python3Parser.IDIV_ASSIGN = 90; Python3Parser.SKIP_ = 91; Python3Parser.UNKNOWN_CHAR = 92; Python3Parser.INDENT = 93; Python3Parser.DEDENT = 94; Python3Parser.RULE_single_input = 0; Python3Parser.RULE_file_input = 1; Python3Parser.RULE_eval_input = 2; Python3Parser.RULE_decorator = 3; Python3Parser.RULE_decorators = 4; Python3Parser.RULE_decorated = 5; Python3Parser.RULE_funcdef = 6; Python3Parser.RULE_parameters = 7; Python3Parser.RULE_typedargslist = 8; Python3Parser.RULE_tfpdef = 9; Python3Parser.RULE_varargslist = 10; Python3Parser.RULE_vfpdef = 11; Python3Parser.RULE_stmt = 12; Python3Parser.RULE_simple_stmt = 13; Python3Parser.RULE_small_stmt = 14; Python3Parser.RULE_expr_stmt = 15; Python3Parser.RULE_testlist_star_expr = 16; Python3Parser.RULE_augassign = 17; Python3Parser.RULE_del_stmt = 18; Python3Parser.RULE_pass_stmt = 19; Python3Parser.RULE_flow_stmt = 20; Python3Parser.RULE_break_stmt = 21; Python3Parser.RULE_continue_stmt = 22; Python3Parser.RULE_return_stmt = 23; Python3Parser.RULE_yield_stmt = 24; Python3Parser.RULE_raise_stmt = 25; Python3Parser.RULE_import_stmt = 26; Python3Parser.RULE_import_name = 27; Python3Parser.RULE_import_from = 28; Python3Parser.RULE_import_as_name = 29; Python3Parser.RULE_dotted_as_name = 30; Python3Parser.RULE_import_as_names = 31; Python3Parser.RULE_dotted_as_names = 32; Python3Parser.RULE_dotted_name = 33; Python3Parser.RULE_global_stmt = 34; Python3Parser.RULE_nonlocal_stmt = 35; Python3Parser.RULE_assert_stmt = 36; Python3Parser.RULE_compound_stmt = 37; Python3Parser.RULE_if_stmt = 38; Python3Parser.RULE_while_stmt = 39; Python3Parser.RULE_for_stmt = 40; Python3Parser.RULE_try_stmt = 41; Python3Parser.RULE_with_stmt = 42; Python3Parser.RULE_with_item = 43; Python3Parser.RULE_except_clause = 44; Python3Parser.RULE_suite = 45; Python3Parser.RULE_test = 46; Python3Parser.RULE_test_nocond = 47; Python3Parser.RULE_lambdef = 48; Python3Parser.RULE_lambdef_nocond = 49; Python3Parser.RULE_or_test = 50; Python3Parser.RULE_and_test = 51; Python3Parser.RULE_not_test = 52; Python3Parser.RULE_comparison = 53; Python3Parser.RULE_comp_op = 54; Python3Parser.RULE_star_expr = 55; Python3Parser.RULE_expr = 56; Python3Parser.RULE_xor_expr = 57; Python3Parser.RULE_and_expr = 58; Python3Parser.RULE_shift_expr = 59; Python3Parser.RULE_arith_expr = 60; Python3Parser.RULE_term = 61; Python3Parser.RULE_factor = 62; Python3Parser.RULE_power = 63; Python3Parser.RULE_atom = 64; Python3Parser.RULE_testlist_comp = 65; Python3Parser.RULE_trailer = 66; Python3Parser.RULE_subscriptlist = 67; Python3Parser.RULE_subscript = 68; Python3Parser.RULE_sliceop = 69; Python3Parser.RULE_exprlist = 70; Python3Parser.RULE_testlist = 71; Python3Parser.RULE_dictorsetmaker = 72; Python3Parser.RULE_classdef = 73; Python3Parser.RULE_arglist = 74; Python3Parser.RULE_argument = 75; Python3Parser.RULE_comp_iter = 76; Python3Parser.RULE_comp_for = 77; Python3Parser.RULE_comp_if = 78; Python3Parser.RULE_yield_expr = 79; Python3Parser.RULE_yield_arg = 80; Python3Parser.RULE_str = 81; Python3Parser.RULE_number = 82; Python3Parser.RULE_integer = 83; function Single_inputContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_single_input; return this; } Single_inputContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Single_inputContext.prototype.constructor = Single_inputContext; Single_inputContext.prototype.NEWLINE = function() { return this.getToken(Python3Parser.NEWLINE, 0); }; Single_inputContext.prototype.simple_stmt = function() { return this.getTypedRuleContext(Simple_stmtContext,0); }; Single_inputContext.prototype.compound_stmt = function() { return this.getTypedRuleContext(Compound_stmtContext,0); }; Single_inputContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSingle_input(this); } }; Single_inputContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSingle_input(this); } }; Single_inputContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSingle_input(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Single_inputContext = Single_inputContext; Python3Parser.prototype.single_input = function() { var localctx = new Single_inputContext(this, this._ctx, this.state); this.enterRule(localctx, 0, Python3Parser.RULE_single_input); try { this.state = 173; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NEWLINE: this.enterOuterAlt(localctx, 1); this.state = 168; this.match(Python3Parser.NEWLINE); break; case Python3Parser.RETURN: case Python3Parser.RAISE: case Python3Parser.FROM: case Python3Parser.IMPORT: case Python3Parser.GLOBAL: case Python3Parser.NONLOCAL: case Python3Parser.ASSERT: case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.YIELD: case Python3Parser.DEL: case Python3Parser.PASS: case Python3Parser.CONTINUE: case Python3Parser.BREAK: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 2); this.state = 169; this.simple_stmt(); break; case Python3Parser.DEF: case Python3Parser.IF: case Python3Parser.WHILE: case Python3Parser.FOR: case Python3Parser.TRY: case Python3Parser.WITH: case Python3Parser.CLASS: case Python3Parser.AT: this.enterOuterAlt(localctx, 3); this.state = 170; this.compound_stmt(); this.state = 171; this.match(Python3Parser.NEWLINE); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function File_inputContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_file_input; return this; } File_inputContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); File_inputContext.prototype.constructor = File_inputContext; File_inputContext.prototype.EOF = function() { return this.getToken(Python3Parser.EOF, 0); }; File_inputContext.prototype.NEWLINE = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.NEWLINE); } else { return this.getToken(Python3Parser.NEWLINE, i); } }; File_inputContext.prototype.stmt = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(StmtContext); } else { return this.getTypedRuleContext(StmtContext,i); } }; File_inputContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterFile_input(this); } }; File_inputContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitFile_input(this); } }; File_inputContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitFile_input(this); } else { return visitor.visitChildren(this); } }; Python3Parser.File_inputContext = File_inputContext; Python3Parser.prototype.file_input = function() { var localctx = new File_inputContext(this, this._ctx, this.state); this.enterRule(localctx, 2, Python3Parser.RULE_file_input); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 179; this._errHandler.sync(this); _la = this._input.LA(1); while((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << Python3Parser.DEF) | (1 << Python3Parser.RETURN) | (1 << Python3Parser.RAISE) | (1 << Python3Parser.FROM) | (1 << Python3Parser.IMPORT) | (1 << Python3Parser.GLOBAL) | (1 << Python3Parser.NONLOCAL) | (1 << Python3Parser.ASSERT) | (1 << Python3Parser.IF) | (1 << Python3Parser.WHILE) | (1 << Python3Parser.FOR) | (1 << Python3Parser.TRY) | (1 << Python3Parser.WITH) | (1 << Python3Parser.LAMBDA) | (1 << Python3Parser.NOT) | (1 << Python3Parser.NONE) | (1 << Python3Parser.TRUE) | (1 << Python3Parser.FALSE) | (1 << Python3Parser.CLASS) | (1 << Python3Parser.YIELD) | (1 << Python3Parser.DEL) | (1 << Python3Parser.PASS))) !== 0) || ((((_la - 32)) & ~0x1f) == 0 && ((1 << (_la - 32)) & ((1 << (Python3Parser.CONTINUE - 32)) | (1 << (Python3Parser.BREAK - 32)) | (1 << (Python3Parser.NEWLINE - 32)) | (1 << (Python3Parser.NAME - 32)) | (1 << (Python3Parser.STRING_LITERAL - 32)) | (1 << (Python3Parser.BYTES_LITERAL - 32)) | (1 << (Python3Parser.DECIMAL_INTEGER - 32)) | (1 << (Python3Parser.OCT_INTEGER - 32)) | (1 << (Python3Parser.HEX_INTEGER - 32)) | (1 << (Python3Parser.BIN_INTEGER - 32)) | (1 << (Python3Parser.FLOAT_NUMBER - 32)) | (1 << (Python3Parser.IMAG_NUMBER - 32)) | (1 << (Python3Parser.ELLIPSIS - 32)) | (1 << (Python3Parser.STAR - 32)) | (1 << (Python3Parser.OPEN_PAREN - 32)) | (1 << (Python3Parser.OPEN_BRACK - 32)) | (1 << (Python3Parser.ADD - 32)) | (1 << (Python3Parser.MINUS - 32)))) !== 0) || ((((_la - 66)) & ~0x1f) == 0 && ((1 << (_la - 66)) & ((1 << (Python3Parser.NOT_OP - 66)) | (1 << (Python3Parser.OPEN_BRACE - 66)) | (1 << (Python3Parser.AT - 66)))) !== 0)) { this.state = 177; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NEWLINE: this.state = 175; this.match(Python3Parser.NEWLINE); break; case Python3Parser.DEF: case Python3Parser.RETURN: case Python3Parser.RAISE: case Python3Parser.FROM: case Python3Parser.IMPORT: case Python3Parser.GLOBAL: case Python3Parser.NONLOCAL: case Python3Parser.ASSERT: case Python3Parser.IF: case Python3Parser.WHILE: case Python3Parser.FOR: case Python3Parser.TRY: case Python3Parser.WITH: case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.CLASS: case Python3Parser.YIELD: case Python3Parser.DEL: case Python3Parser.PASS: case Python3Parser.CONTINUE: case Python3Parser.BREAK: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: case Python3Parser.AT: this.state = 176; this.stmt(); break; default: throw new antlr4.error.NoViableAltException(this); } this.state = 181; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 182; this.match(Python3Parser.EOF); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Eval_inputContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_eval_input; return this; } Eval_inputContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Eval_inputContext.prototype.constructor = Eval_inputContext; Eval_inputContext.prototype.testlist = function() { return this.getTypedRuleContext(TestlistContext,0); }; Eval_inputContext.prototype.EOF = function() { return this.getToken(Python3Parser.EOF, 0); }; Eval_inputContext.prototype.NEWLINE = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.NEWLINE); } else { return this.getToken(Python3Parser.NEWLINE, i); } }; Eval_inputContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterEval_input(this); } }; Eval_inputContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitEval_input(this); } }; Eval_inputContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitEval_input(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Eval_inputContext = Eval_inputContext; Python3Parser.prototype.eval_input = function() { var localctx = new Eval_inputContext(this, this._ctx, this.state); this.enterRule(localctx, 4, Python3Parser.RULE_eval_input); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 184; this.testlist(); this.state = 188; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.NEWLINE) { this.state = 185; this.match(Python3Parser.NEWLINE); this.state = 190; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 191; this.match(Python3Parser.EOF); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function DecoratorContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_decorator; return this; } DecoratorContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); DecoratorContext.prototype.constructor = DecoratorContext; DecoratorContext.prototype.dotted_name = function() { return this.getTypedRuleContext(Dotted_nameContext,0); }; DecoratorContext.prototype.NEWLINE = function() { return this.getToken(Python3Parser.NEWLINE, 0); }; DecoratorContext.prototype.arglist = function() { return this.getTypedRuleContext(ArglistContext,0); }; DecoratorContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDecorator(this); } }; DecoratorContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDecorator(this); } }; DecoratorContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDecorator(this); } else { return visitor.visitChildren(this); } }; Python3Parser.DecoratorContext = DecoratorContext; Python3Parser.prototype.decorator = function() { var localctx = new DecoratorContext(this, this._ctx, this.state); this.enterRule(localctx, 6, Python3Parser.RULE_decorator); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 193; this.match(Python3Parser.AT); this.state = 194; this.dotted_name(); this.state = 200; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.OPEN_PAREN) { this.state = 195; this.match(Python3Parser.OPEN_PAREN); this.state = 197; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 52)) & ~0x1f) == 0 && ((1 << (_la - 52)) & ((1 << (Python3Parser.POWER - 52)) | (1 << (Python3Parser.OPEN_BRACK - 52)) | (1 << (Python3Parser.ADD - 52)) | (1 << (Python3Parser.MINUS - 52)) | (1 << (Python3Parser.NOT_OP - 52)) | (1 << (Python3Parser.OPEN_BRACE - 52)))) !== 0)) { this.state = 196; this.arglist(); } this.state = 199; this.match(Python3Parser.CLOSE_PAREN); } this.state = 202; this.match(Python3Parser.NEWLINE); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function DecoratorsContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_decorators; return this; } DecoratorsContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); DecoratorsContext.prototype.constructor = DecoratorsContext; DecoratorsContext.prototype.decorator = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(DecoratorContext); } else { return this.getTypedRuleContext(DecoratorContext,i); } }; DecoratorsContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDecorators(this); } }; DecoratorsContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDecorators(this); } }; DecoratorsContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDecorators(this); } else { return visitor.visitChildren(this); } }; Python3Parser.DecoratorsContext = DecoratorsContext; Python3Parser.prototype.decorators = function() { var localctx = new DecoratorsContext(this, this._ctx, this.state); this.enterRule(localctx, 8, Python3Parser.RULE_decorators); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 205; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 204; this.decorator(); this.state = 207; this._errHandler.sync(this); _la = this._input.LA(1); } while(_la===Python3Parser.AT); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function DecoratedContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_decorated; return this; } DecoratedContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); DecoratedContext.prototype.constructor = DecoratedContext; DecoratedContext.prototype.decorators = function() { return this.getTypedRuleContext(DecoratorsContext,0); }; DecoratedContext.prototype.classdef = function() { return this.getTypedRuleContext(ClassdefContext,0); }; DecoratedContext.prototype.funcdef = function() { return this.getTypedRuleContext(FuncdefContext,0); }; DecoratedContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDecorated(this); } }; DecoratedContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDecorated(this); } }; DecoratedContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDecorated(this); } else { return visitor.visitChildren(this); } }; Python3Parser.DecoratedContext = DecoratedContext; Python3Parser.prototype.decorated = function() { var localctx = new DecoratedContext(this, this._ctx, this.state); this.enterRule(localctx, 10, Python3Parser.RULE_decorated); try { this.enterOuterAlt(localctx, 1); this.state = 209; this.decorators(); this.state = 212; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.CLASS: this.state = 210; this.classdef(); break; case Python3Parser.DEF: this.state = 211; this.funcdef(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function FuncdefContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_funcdef; return this; } FuncdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); FuncdefContext.prototype.constructor = FuncdefContext; FuncdefContext.prototype.DEF = function() { return this.getToken(Python3Parser.DEF, 0); }; FuncdefContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; FuncdefContext.prototype.parameters = function() { return this.getTypedRuleContext(ParametersContext,0); }; FuncdefContext.prototype.suite = function() { return this.getTypedRuleContext(SuiteContext,0); }; FuncdefContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; FuncdefContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterFuncdef(this); } }; FuncdefContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitFuncdef(this); } }; FuncdefContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitFuncdef(this); } else { return visitor.visitChildren(this); } }; Python3Parser.FuncdefContext = FuncdefContext; Python3Parser.prototype.funcdef = function() { var localctx = new FuncdefContext(this, this._ctx, this.state); this.enterRule(localctx, 12, Python3Parser.RULE_funcdef); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 214; this.match(Python3Parser.DEF); this.state = 215; this.match(Python3Parser.NAME); this.state = 216; this.parameters(); this.state = 219; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ARROW) { this.state = 217; this.match(Python3Parser.ARROW); this.state = 218; this.test(); } this.state = 221; this.match(Python3Parser.COLON); this.state = 222; this.suite(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ParametersContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_parameters; return this; } ParametersContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ParametersContext.prototype.constructor = ParametersContext; ParametersContext.prototype.typedargslist = function() { return this.getTypedRuleContext(TypedargslistContext,0); }; ParametersContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterParameters(this); } }; ParametersContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitParameters(this); } }; ParametersContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitParameters(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ParametersContext = ParametersContext; Python3Parser.prototype.parameters = function() { var localctx = new ParametersContext(this, this._ctx, this.state); this.enterRule(localctx, 14, Python3Parser.RULE_parameters); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 224; this.match(Python3Parser.OPEN_PAREN); this.state = 226; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 35)) & ~0x1f) == 0 && ((1 << (_la - 35)) & ((1 << (Python3Parser.NAME - 35)) | (1 << (Python3Parser.STAR - 35)) | (1 << (Python3Parser.POWER - 35)))) !== 0)) { this.state = 225; this.typedargslist(); } this.state = 228; this.match(Python3Parser.CLOSE_PAREN); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TypedargslistContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_typedargslist; return this; } TypedargslistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); TypedargslistContext.prototype.constructor = TypedargslistContext; TypedargslistContext.prototype.tfpdef = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TfpdefContext); } else { return this.getTypedRuleContext(TfpdefContext,i); } }; TypedargslistContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; TypedargslistContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTypedargslist(this); } }; TypedargslistContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTypedargslist(this); } }; TypedargslistContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTypedargslist(this); } else { return visitor.visitChildren(this); } }; Python3Parser.TypedargslistContext = TypedargslistContext; Python3Parser.prototype.typedargslist = function() { var localctx = new TypedargslistContext(this, this._ctx, this.state); this.enterRule(localctx, 16, Python3Parser.RULE_typedargslist); var _la = 0; // Token type try { this.state = 295; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NAME: this.enterOuterAlt(localctx, 1); this.state = 230; this.tfpdef(); this.state = 233; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 231; this.match(Python3Parser.ASSIGN); this.state = 232; this.test(); } this.state = 243; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,12,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 235; this.match(Python3Parser.COMMA); this.state = 236; this.tfpdef(); this.state = 239; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 237; this.match(Python3Parser.ASSIGN); this.state = 238; this.test(); } } this.state = 245; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,12,this._ctx); } this.state = 271; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 246; this.match(Python3Parser.COMMA); this.state = 269; this._errHandler.sync(this); switch (this._input.LA(1)) { case Python3Parser.STAR: this.state = 247; this.match(Python3Parser.STAR); this.state = 249; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.NAME) { this.state = 248; this.tfpdef(); } this.state = 259; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,15,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 251; this.match(Python3Parser.COMMA); this.state = 252; this.tfpdef(); this.state = 255; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 253; this.match(Python3Parser.ASSIGN); this.state = 254; this.test(); } } this.state = 261; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,15,this._ctx); } this.state = 265; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 262; this.match(Python3Parser.COMMA); this.state = 263; this.match(Python3Parser.POWER); this.state = 264; this.tfpdef(); } break; case Python3Parser.POWER: this.state = 267; this.match(Python3Parser.POWER); this.state = 268; this.tfpdef(); break; case Python3Parser.CLOSE_PAREN: break; default: break; } } break; case Python3Parser.STAR: this.enterOuterAlt(localctx, 2); this.state = 273; this.match(Python3Parser.STAR); this.state = 275; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.NAME) { this.state = 274; this.tfpdef(); } this.state = 285; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,21,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 277; this.match(Python3Parser.COMMA); this.state = 278; this.tfpdef(); this.state = 281; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 279; this.match(Python3Parser.ASSIGN); this.state = 280; this.test(); } } this.state = 287; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,21,this._ctx); } this.state = 291; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 288; this.match(Python3Parser.COMMA); this.state = 289; this.match(Python3Parser.POWER); this.state = 290; this.tfpdef(); } break; case Python3Parser.POWER: this.enterOuterAlt(localctx, 3); this.state = 293; this.match(Python3Parser.POWER); this.state = 294; this.tfpdef(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TfpdefContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_tfpdef; return this; } TfpdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); TfpdefContext.prototype.constructor = TfpdefContext; TfpdefContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; TfpdefContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; TfpdefContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTfpdef(this); } }; TfpdefContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTfpdef(this); } }; TfpdefContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTfpdef(this); } else { return visitor.visitChildren(this); } }; Python3Parser.TfpdefContext = TfpdefContext; Python3Parser.prototype.tfpdef = function() { var localctx = new TfpdefContext(this, this._ctx, this.state); this.enterRule(localctx, 18, Python3Parser.RULE_tfpdef); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 297; this.match(Python3Parser.NAME); this.state = 300; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COLON) { this.state = 298; this.match(Python3Parser.COLON); this.state = 299; this.test(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function VarargslistContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_varargslist; return this; } VarargslistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); VarargslistContext.prototype.constructor = VarargslistContext; VarargslistContext.prototype.vfpdef = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(VfpdefContext); } else { return this.getTypedRuleContext(VfpdefContext,i); } }; VarargslistContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; VarargslistContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterVarargslist(this); } }; VarargslistContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitVarargslist(this); } }; VarargslistContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitVarargslist(this); } else { return visitor.visitChildren(this); } }; Python3Parser.VarargslistContext = VarargslistContext; Python3Parser.prototype.varargslist = function() { var localctx = new VarargslistContext(this, this._ctx, this.state); this.enterRule(localctx, 20, Python3Parser.RULE_varargslist); var _la = 0; // Token type try { this.state = 367; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NAME: this.enterOuterAlt(localctx, 1); this.state = 302; this.vfpdef(); this.state = 305; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 303; this.match(Python3Parser.ASSIGN); this.state = 304; this.test(); } this.state = 315; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,27,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 307; this.match(Python3Parser.COMMA); this.state = 308; this.vfpdef(); this.state = 311; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 309; this.match(Python3Parser.ASSIGN); this.state = 310; this.test(); } } this.state = 317; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,27,this._ctx); } this.state = 343; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 318; this.match(Python3Parser.COMMA); this.state = 341; this._errHandler.sync(this); switch (this._input.LA(1)) { case Python3Parser.STAR: this.state = 319; this.match(Python3Parser.STAR); this.state = 321; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.NAME) { this.state = 320; this.vfpdef(); } this.state = 331; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,30,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 323; this.match(Python3Parser.COMMA); this.state = 324; this.vfpdef(); this.state = 327; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 325; this.match(Python3Parser.ASSIGN); this.state = 326; this.test(); } } this.state = 333; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,30,this._ctx); } this.state = 337; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 334; this.match(Python3Parser.COMMA); this.state = 335; this.match(Python3Parser.POWER); this.state = 336; this.vfpdef(); } break; case Python3Parser.POWER: this.state = 339; this.match(Python3Parser.POWER); this.state = 340; this.vfpdef(); break; case Python3Parser.COLON: break; default: break; } } break; case Python3Parser.STAR: this.enterOuterAlt(localctx, 2); this.state = 345; this.match(Python3Parser.STAR); this.state = 347; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.NAME) { this.state = 346; this.vfpdef(); } this.state = 357; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,36,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 349; this.match(Python3Parser.COMMA); this.state = 350; this.vfpdef(); this.state = 353; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ASSIGN) { this.state = 351; this.match(Python3Parser.ASSIGN); this.state = 352; this.test(); } } this.state = 359; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,36,this._ctx); } this.state = 363; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 360; this.match(Python3Parser.COMMA); this.state = 361; this.match(Python3Parser.POWER); this.state = 362; this.vfpdef(); } break; case Python3Parser.POWER: this.enterOuterAlt(localctx, 3); this.state = 365; this.match(Python3Parser.POWER); this.state = 366; this.vfpdef(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function VfpdefContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_vfpdef; return this; } VfpdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); VfpdefContext.prototype.constructor = VfpdefContext; VfpdefContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; VfpdefContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterVfpdef(this); } }; VfpdefContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitVfpdef(this); } }; VfpdefContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitVfpdef(this); } else { return visitor.visitChildren(this); } }; Python3Parser.VfpdefContext = VfpdefContext; Python3Parser.prototype.vfpdef = function() { var localctx = new VfpdefContext(this, this._ctx, this.state); this.enterRule(localctx, 22, Python3Parser.RULE_vfpdef); try { this.enterOuterAlt(localctx, 1); this.state = 369; this.match(Python3Parser.NAME); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function StmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_stmt; return this; } StmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); StmtContext.prototype.constructor = StmtContext; StmtContext.prototype.simple_stmt = function() { return this.getTypedRuleContext(Simple_stmtContext,0); }; StmtContext.prototype.compound_stmt = function() { return this.getTypedRuleContext(Compound_stmtContext,0); }; StmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterStmt(this); } }; StmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitStmt(this); } }; StmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitStmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.StmtContext = StmtContext; Python3Parser.prototype.stmt = function() { var localctx = new StmtContext(this, this._ctx, this.state); this.enterRule(localctx, 24, Python3Parser.RULE_stmt); try { this.state = 373; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.RETURN: case Python3Parser.RAISE: case Python3Parser.FROM: case Python3Parser.IMPORT: case Python3Parser.GLOBAL: case Python3Parser.NONLOCAL: case Python3Parser.ASSERT: case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.YIELD: case Python3Parser.DEL: case Python3Parser.PASS: case Python3Parser.CONTINUE: case Python3Parser.BREAK: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 1); this.state = 371; this.simple_stmt(); break; case Python3Parser.DEF: case Python3Parser.IF: case Python3Parser.WHILE: case Python3Parser.FOR: case Python3Parser.TRY: case Python3Parser.WITH: case Python3Parser.CLASS: case Python3Parser.AT: this.enterOuterAlt(localctx, 2); this.state = 372; this.compound_stmt(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Simple_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_simple_stmt; return this; } Simple_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Simple_stmtContext.prototype.constructor = Simple_stmtContext; Simple_stmtContext.prototype.small_stmt = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Small_stmtContext); } else { return this.getTypedRuleContext(Small_stmtContext,i); } }; Simple_stmtContext.prototype.NEWLINE = function() { return this.getToken(Python3Parser.NEWLINE, 0); }; Simple_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSimple_stmt(this); } }; Simple_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSimple_stmt(this); } }; Simple_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSimple_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Simple_stmtContext = Simple_stmtContext; Python3Parser.prototype.simple_stmt = function() { var localctx = new Simple_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 26, Python3Parser.RULE_simple_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 375; this.small_stmt(); this.state = 380; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,40,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 376; this.match(Python3Parser.SEMI_COLON); this.state = 377; this.small_stmt(); } this.state = 382; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,40,this._ctx); } this.state = 384; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.SEMI_COLON) { this.state = 383; this.match(Python3Parser.SEMI_COLON); } this.state = 386; this.match(Python3Parser.NEWLINE); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Small_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_small_stmt; return this; } Small_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Small_stmtContext.prototype.constructor = Small_stmtContext; Small_stmtContext.prototype.expr_stmt = function() { return this.getTypedRuleContext(Expr_stmtContext,0); }; Small_stmtContext.prototype.del_stmt = function() { return this.getTypedRuleContext(Del_stmtContext,0); }; Small_stmtContext.prototype.pass_stmt = function() { return this.getTypedRuleContext(Pass_stmtContext,0); }; Small_stmtContext.prototype.flow_stmt = function() { return this.getTypedRuleContext(Flow_stmtContext,0); }; Small_stmtContext.prototype.import_stmt = function() { return this.getTypedRuleContext(Import_stmtContext,0); }; Small_stmtContext.prototype.global_stmt = function() { return this.getTypedRuleContext(Global_stmtContext,0); }; Small_stmtContext.prototype.nonlocal_stmt = function() { return this.getTypedRuleContext(Nonlocal_stmtContext,0); }; Small_stmtContext.prototype.assert_stmt = function() { return this.getTypedRuleContext(Assert_stmtContext,0); }; Small_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSmall_stmt(this); } }; Small_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSmall_stmt(this); } }; Small_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSmall_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Small_stmtContext = Small_stmtContext; Python3Parser.prototype.small_stmt = function() { var localctx = new Small_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 28, Python3Parser.RULE_small_stmt); try { this.state = 396; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 1); this.state = 388; this.expr_stmt(); break; case Python3Parser.DEL: this.enterOuterAlt(localctx, 2); this.state = 389; this.del_stmt(); break; case Python3Parser.PASS: this.enterOuterAlt(localctx, 3); this.state = 390; this.pass_stmt(); break; case Python3Parser.RETURN: case Python3Parser.RAISE: case Python3Parser.YIELD: case Python3Parser.CONTINUE: case Python3Parser.BREAK: this.enterOuterAlt(localctx, 4); this.state = 391; this.flow_stmt(); break; case Python3Parser.FROM: case Python3Parser.IMPORT: this.enterOuterAlt(localctx, 5); this.state = 392; this.import_stmt(); break; case Python3Parser.GLOBAL: this.enterOuterAlt(localctx, 6); this.state = 393; this.global_stmt(); break; case Python3Parser.NONLOCAL: this.enterOuterAlt(localctx, 7); this.state = 394; this.nonlocal_stmt(); break; case Python3Parser.ASSERT: this.enterOuterAlt(localctx, 8); this.state = 395; this.assert_stmt(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Expr_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_expr_stmt; return this; } Expr_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Expr_stmtContext.prototype.constructor = Expr_stmtContext; Expr_stmtContext.prototype.testlist_star_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Testlist_star_exprContext); } else { return this.getTypedRuleContext(Testlist_star_exprContext,i); } }; Expr_stmtContext.prototype.augassign = function() { return this.getTypedRuleContext(AugassignContext,0); }; Expr_stmtContext.prototype.yield_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Yield_exprContext); } else { return this.getTypedRuleContext(Yield_exprContext,i); } }; Expr_stmtContext.prototype.testlist = function() { return this.getTypedRuleContext(TestlistContext,0); }; Expr_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterExpr_stmt(this); } }; Expr_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitExpr_stmt(this); } }; Expr_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitExpr_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Expr_stmtContext = Expr_stmtContext; Python3Parser.prototype.expr_stmt = function() { var localctx = new Expr_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 30, Python3Parser.RULE_expr_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 398; this.testlist_star_expr(); this.state = 414; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.ADD_ASSIGN: case Python3Parser.SUB_ASSIGN: case Python3Parser.MULT_ASSIGN: case Python3Parser.AT_ASSIGN: case Python3Parser.DIV_ASSIGN: case Python3Parser.MOD_ASSIGN: case Python3Parser.AND_ASSIGN: case Python3Parser.OR_ASSIGN: case Python3Parser.XOR_ASSIGN: case Python3Parser.LEFT_SHIFT_ASSIGN: case Python3Parser.RIGHT_SHIFT_ASSIGN: case Python3Parser.POWER_ASSIGN: case Python3Parser.IDIV_ASSIGN: this.state = 399; this.augassign(); this.state = 402; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.YIELD: this.state = 400; this.yield_expr(); break; case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.state = 401; this.testlist(); break; default: throw new antlr4.error.NoViableAltException(this); } break; case Python3Parser.NEWLINE: case Python3Parser.SEMI_COLON: case Python3Parser.ASSIGN: this.state = 411; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.ASSIGN) { this.state = 404; this.match(Python3Parser.ASSIGN); this.state = 407; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.YIELD: this.state = 405; this.yield_expr(); break; case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.state = 406; this.testlist_star_expr(); break; default: throw new antlr4.error.NoViableAltException(this); } this.state = 413; this._errHandler.sync(this); _la = this._input.LA(1); } break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Testlist_star_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_testlist_star_expr; return this; } Testlist_star_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Testlist_star_exprContext.prototype.constructor = Testlist_star_exprContext; Testlist_star_exprContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; Testlist_star_exprContext.prototype.star_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Star_exprContext); } else { return this.getTypedRuleContext(Star_exprContext,i); } }; Testlist_star_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTestlist_star_expr(this); } }; Testlist_star_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTestlist_star_expr(this); } }; Testlist_star_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTestlist_star_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Testlist_star_exprContext = Testlist_star_exprContext; Python3Parser.prototype.testlist_star_expr = function() { var localctx = new Testlist_star_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 32, Python3Parser.RULE_testlist_star_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 418; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,47,this._ctx); switch(la_) { case 1: this.state = 416; this.test(); break; case 2: this.state = 417; this.star_expr(); break; } this.state = 427; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,49,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 420; this.match(Python3Parser.COMMA); this.state = 423; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,48,this._ctx); switch(la_) { case 1: this.state = 421; this.test(); break; case 2: this.state = 422; this.star_expr(); break; } } this.state = 429; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,49,this._ctx); } this.state = 431; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 430; this.match(Python3Parser.COMMA); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function AugassignContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_augassign; return this; } AugassignContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); AugassignContext.prototype.constructor = AugassignContext; AugassignContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterAugassign(this); } }; AugassignContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitAugassign(this); } }; AugassignContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitAugassign(this); } else { return visitor.visitChildren(this); } }; Python3Parser.AugassignContext = AugassignContext; Python3Parser.prototype.augassign = function() { var localctx = new AugassignContext(this, this._ctx, this.state); this.enterRule(localctx, 34, Python3Parser.RULE_augassign); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 433; _la = this._input.LA(1); if(!(((((_la - 78)) & ~0x1f) == 0 && ((1 << (_la - 78)) & ((1 << (Python3Parser.ADD_ASSIGN - 78)) | (1 << (Python3Parser.SUB_ASSIGN - 78)) | (1 << (Python3Parser.MULT_ASSIGN - 78)) | (1 << (Python3Parser.AT_ASSIGN - 78)) | (1 << (Python3Parser.DIV_ASSIGN - 78)) | (1 << (Python3Parser.MOD_ASSIGN - 78)) | (1 << (Python3Parser.AND_ASSIGN - 78)) | (1 << (Python3Parser.OR_ASSIGN - 78)) | (1 << (Python3Parser.XOR_ASSIGN - 78)) | (1 << (Python3Parser.LEFT_SHIFT_ASSIGN - 78)) | (1 << (Python3Parser.RIGHT_SHIFT_ASSIGN - 78)) | (1 << (Python3Parser.POWER_ASSIGN - 78)) | (1 << (Python3Parser.IDIV_ASSIGN - 78)))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Del_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_del_stmt; return this; } Del_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Del_stmtContext.prototype.constructor = Del_stmtContext; Del_stmtContext.prototype.DEL = function() { return this.getToken(Python3Parser.DEL, 0); }; Del_stmtContext.prototype.exprlist = function() { return this.getTypedRuleContext(ExprlistContext,0); }; Del_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDel_stmt(this); } }; Del_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDel_stmt(this); } }; Del_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDel_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Del_stmtContext = Del_stmtContext; Python3Parser.prototype.del_stmt = function() { var localctx = new Del_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 36, Python3Parser.RULE_del_stmt); try { this.enterOuterAlt(localctx, 1); this.state = 435; this.match(Python3Parser.DEL); this.state = 436; this.exprlist(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Pass_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_pass_stmt; return this; } Pass_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Pass_stmtContext.prototype.constructor = Pass_stmtContext; Pass_stmtContext.prototype.PASS = function() { return this.getToken(Python3Parser.PASS, 0); }; Pass_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterPass_stmt(this); } }; Pass_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitPass_stmt(this); } }; Pass_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitPass_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Pass_stmtContext = Pass_stmtContext; Python3Parser.prototype.pass_stmt = function() { var localctx = new Pass_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 38, Python3Parser.RULE_pass_stmt); try { this.enterOuterAlt(localctx, 1); this.state = 438; this.match(Python3Parser.PASS); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Flow_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_flow_stmt; return this; } Flow_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Flow_stmtContext.prototype.constructor = Flow_stmtContext; Flow_stmtContext.prototype.break_stmt = function() { return this.getTypedRuleContext(Break_stmtContext,0); }; Flow_stmtContext.prototype.continue_stmt = function() { return this.getTypedRuleContext(Continue_stmtContext,0); }; Flow_stmtContext.prototype.return_stmt = function() { return this.getTypedRuleContext(Return_stmtContext,0); }; Flow_stmtContext.prototype.raise_stmt = function() { return this.getTypedRuleContext(Raise_stmtContext,0); }; Flow_stmtContext.prototype.yield_stmt = function() { return this.getTypedRuleContext(Yield_stmtContext,0); }; Flow_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterFlow_stmt(this); } }; Flow_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitFlow_stmt(this); } }; Flow_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitFlow_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Flow_stmtContext = Flow_stmtContext; Python3Parser.prototype.flow_stmt = function() { var localctx = new Flow_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 40, Python3Parser.RULE_flow_stmt); try { this.state = 445; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.BREAK: this.enterOuterAlt(localctx, 1); this.state = 440; this.break_stmt(); break; case Python3Parser.CONTINUE: this.enterOuterAlt(localctx, 2); this.state = 441; this.continue_stmt(); break; case Python3Parser.RETURN: this.enterOuterAlt(localctx, 3); this.state = 442; this.return_stmt(); break; case Python3Parser.RAISE: this.enterOuterAlt(localctx, 4); this.state = 443; this.raise_stmt(); break; case Python3Parser.YIELD: this.enterOuterAlt(localctx, 5); this.state = 444; this.yield_stmt(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Break_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_break_stmt; return this; } Break_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Break_stmtContext.prototype.constructor = Break_stmtContext; Break_stmtContext.prototype.BREAK = function() { return this.getToken(Python3Parser.BREAK, 0); }; Break_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterBreak_stmt(this); } }; Break_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitBreak_stmt(this); } }; Break_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitBreak_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Break_stmtContext = Break_stmtContext; Python3Parser.prototype.break_stmt = function() { var localctx = new Break_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 42, Python3Parser.RULE_break_stmt); try { this.enterOuterAlt(localctx, 1); this.state = 447; this.match(Python3Parser.BREAK); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Continue_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_continue_stmt; return this; } Continue_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Continue_stmtContext.prototype.constructor = Continue_stmtContext; Continue_stmtContext.prototype.CONTINUE = function() { return this.getToken(Python3Parser.CONTINUE, 0); }; Continue_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterContinue_stmt(this); } }; Continue_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitContinue_stmt(this); } }; Continue_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitContinue_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Continue_stmtContext = Continue_stmtContext; Python3Parser.prototype.continue_stmt = function() { var localctx = new Continue_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 44, Python3Parser.RULE_continue_stmt); try { this.enterOuterAlt(localctx, 1); this.state = 449; this.match(Python3Parser.CONTINUE); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Return_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_return_stmt; return this; } Return_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Return_stmtContext.prototype.constructor = Return_stmtContext; Return_stmtContext.prototype.RETURN = function() { return this.getToken(Python3Parser.RETURN, 0); }; Return_stmtContext.prototype.testlist = function() { return this.getTypedRuleContext(TestlistContext,0); }; Return_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterReturn_stmt(this); } }; Return_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitReturn_stmt(this); } }; Return_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitReturn_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Return_stmtContext = Return_stmtContext; Python3Parser.prototype.return_stmt = function() { var localctx = new Return_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 46, Python3Parser.RULE_return_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 451; this.match(Python3Parser.RETURN); this.state = 453; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 452; this.testlist(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Yield_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_yield_stmt; return this; } Yield_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Yield_stmtContext.prototype.constructor = Yield_stmtContext; Yield_stmtContext.prototype.yield_expr = function() { return this.getTypedRuleContext(Yield_exprContext,0); }; Yield_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterYield_stmt(this); } }; Yield_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitYield_stmt(this); } }; Yield_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitYield_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Yield_stmtContext = Yield_stmtContext; Python3Parser.prototype.yield_stmt = function() { var localctx = new Yield_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 48, Python3Parser.RULE_yield_stmt); try { this.enterOuterAlt(localctx, 1); this.state = 455; this.yield_expr(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Raise_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_raise_stmt; return this; } Raise_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Raise_stmtContext.prototype.constructor = Raise_stmtContext; Raise_stmtContext.prototype.RAISE = function() { return this.getToken(Python3Parser.RAISE, 0); }; Raise_stmtContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; Raise_stmtContext.prototype.FROM = function() { return this.getToken(Python3Parser.FROM, 0); }; Raise_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterRaise_stmt(this); } }; Raise_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitRaise_stmt(this); } }; Raise_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitRaise_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Raise_stmtContext = Raise_stmtContext; Python3Parser.prototype.raise_stmt = function() { var localctx = new Raise_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 50, Python3Parser.RULE_raise_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 457; this.match(Python3Parser.RAISE); this.state = 463; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 458; this.test(); this.state = 461; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.FROM) { this.state = 459; this.match(Python3Parser.FROM); this.state = 460; this.test(); } } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Import_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_import_stmt; return this; } Import_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Import_stmtContext.prototype.constructor = Import_stmtContext; Import_stmtContext.prototype.import_name = function() { return this.getTypedRuleContext(Import_nameContext,0); }; Import_stmtContext.prototype.import_from = function() { return this.getTypedRuleContext(Import_fromContext,0); }; Import_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterImport_stmt(this); } }; Import_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitImport_stmt(this); } }; Import_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitImport_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Import_stmtContext = Import_stmtContext; Python3Parser.prototype.import_stmt = function() { var localctx = new Import_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 52, Python3Parser.RULE_import_stmt); try { this.state = 467; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.IMPORT: this.enterOuterAlt(localctx, 1); this.state = 465; this.import_name(); break; case Python3Parser.FROM: this.enterOuterAlt(localctx, 2); this.state = 466; this.import_from(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Import_nameContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_import_name; return this; } Import_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Import_nameContext.prototype.constructor = Import_nameContext; Import_nameContext.prototype.IMPORT = function() { return this.getToken(Python3Parser.IMPORT, 0); }; Import_nameContext.prototype.dotted_as_names = function() { return this.getTypedRuleContext(Dotted_as_namesContext,0); }; Import_nameContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterImport_name(this); } }; Import_nameContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitImport_name(this); } }; Import_nameContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitImport_name(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Import_nameContext = Import_nameContext; Python3Parser.prototype.import_name = function() { var localctx = new Import_nameContext(this, this._ctx, this.state); this.enterRule(localctx, 54, Python3Parser.RULE_import_name); try { this.enterOuterAlt(localctx, 1); this.state = 469; this.match(Python3Parser.IMPORT); this.state = 470; this.dotted_as_names(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Import_fromContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_import_from; return this; } Import_fromContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Import_fromContext.prototype.constructor = Import_fromContext; Import_fromContext.prototype.FROM = function() { return this.getToken(Python3Parser.FROM, 0); }; Import_fromContext.prototype.IMPORT = function() { return this.getToken(Python3Parser.IMPORT, 0); }; Import_fromContext.prototype.dotted_name = function() { return this.getTypedRuleContext(Dotted_nameContext,0); }; Import_fromContext.prototype.import_as_names = function() { return this.getTypedRuleContext(Import_as_namesContext,0); }; Import_fromContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterImport_from(this); } }; Import_fromContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitImport_from(this); } }; Import_fromContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitImport_from(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Import_fromContext = Import_fromContext; Python3Parser.prototype.import_from = function() { var localctx = new Import_fromContext(this, this._ctx, this.state); this.enterRule(localctx, 56, Python3Parser.RULE_import_from); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 472; this.match(Python3Parser.FROM); this.state = 485; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,58,this._ctx); switch(la_) { case 1: this.state = 476; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS) { this.state = 473; _la = this._input.LA(1); if(!(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 478; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 479; this.dotted_name(); break; case 2: this.state = 481; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 480; _la = this._input.LA(1); if(!(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } this.state = 483; this._errHandler.sync(this); _la = this._input.LA(1); } while(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS); break; } this.state = 487; this.match(Python3Parser.IMPORT); this.state = 494; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.STAR: this.state = 488; this.match(Python3Parser.STAR); break; case Python3Parser.OPEN_PAREN: this.state = 489; this.match(Python3Parser.OPEN_PAREN); this.state = 490; this.import_as_names(); this.state = 491; this.match(Python3Parser.CLOSE_PAREN); break; case Python3Parser.NAME: this.state = 493; this.import_as_names(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Import_as_nameContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_import_as_name; return this; } Import_as_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Import_as_nameContext.prototype.constructor = Import_as_nameContext; Import_as_nameContext.prototype.NAME = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.NAME); } else { return this.getToken(Python3Parser.NAME, i); } }; Import_as_nameContext.prototype.AS = function() { return this.getToken(Python3Parser.AS, 0); }; Import_as_nameContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterImport_as_name(this); } }; Import_as_nameContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitImport_as_name(this); } }; Import_as_nameContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitImport_as_name(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Import_as_nameContext = Import_as_nameContext; Python3Parser.prototype.import_as_name = function() { var localctx = new Import_as_nameContext(this, this._ctx, this.state); this.enterRule(localctx, 58, Python3Parser.RULE_import_as_name); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 496; this.match(Python3Parser.NAME); this.state = 499; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.AS) { this.state = 497; this.match(Python3Parser.AS); this.state = 498; this.match(Python3Parser.NAME); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Dotted_as_nameContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_dotted_as_name; return this; } Dotted_as_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Dotted_as_nameContext.prototype.constructor = Dotted_as_nameContext; Dotted_as_nameContext.prototype.dotted_name = function() { return this.getTypedRuleContext(Dotted_nameContext,0); }; Dotted_as_nameContext.prototype.AS = function() { return this.getToken(Python3Parser.AS, 0); }; Dotted_as_nameContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; Dotted_as_nameContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDotted_as_name(this); } }; Dotted_as_nameContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDotted_as_name(this); } }; Dotted_as_nameContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDotted_as_name(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Dotted_as_nameContext = Dotted_as_nameContext; Python3Parser.prototype.dotted_as_name = function() { var localctx = new Dotted_as_nameContext(this, this._ctx, this.state); this.enterRule(localctx, 60, Python3Parser.RULE_dotted_as_name); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 501; this.dotted_name(); this.state = 504; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.AS) { this.state = 502; this.match(Python3Parser.AS); this.state = 503; this.match(Python3Parser.NAME); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Import_as_namesContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_import_as_names; return this; } Import_as_namesContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Import_as_namesContext.prototype.constructor = Import_as_namesContext; Import_as_namesContext.prototype.import_as_name = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Import_as_nameContext); } else { return this.getTypedRuleContext(Import_as_nameContext,i); } }; Import_as_namesContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterImport_as_names(this); } }; Import_as_namesContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitImport_as_names(this); } }; Import_as_namesContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitImport_as_names(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Import_as_namesContext = Import_as_namesContext; Python3Parser.prototype.import_as_names = function() { var localctx = new Import_as_namesContext(this, this._ctx, this.state); this.enterRule(localctx, 62, Python3Parser.RULE_import_as_names); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 506; this.import_as_name(); this.state = 511; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,62,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 507; this.match(Python3Parser.COMMA); this.state = 508; this.import_as_name(); } this.state = 513; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,62,this._ctx); } this.state = 515; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 514; this.match(Python3Parser.COMMA); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Dotted_as_namesContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_dotted_as_names; return this; } Dotted_as_namesContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Dotted_as_namesContext.prototype.constructor = Dotted_as_namesContext; Dotted_as_namesContext.prototype.dotted_as_name = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Dotted_as_nameContext); } else { return this.getTypedRuleContext(Dotted_as_nameContext,i); } }; Dotted_as_namesContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDotted_as_names(this); } }; Dotted_as_namesContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDotted_as_names(this); } }; Dotted_as_namesContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDotted_as_names(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Dotted_as_namesContext = Dotted_as_namesContext; Python3Parser.prototype.dotted_as_names = function() { var localctx = new Dotted_as_namesContext(this, this._ctx, this.state); this.enterRule(localctx, 64, Python3Parser.RULE_dotted_as_names); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 517; this.dotted_as_name(); this.state = 522; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.COMMA) { this.state = 518; this.match(Python3Parser.COMMA); this.state = 519; this.dotted_as_name(); this.state = 524; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Dotted_nameContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_dotted_name; return this; } Dotted_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Dotted_nameContext.prototype.constructor = Dotted_nameContext; Dotted_nameContext.prototype.NAME = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.NAME); } else { return this.getToken(Python3Parser.NAME, i); } }; Dotted_nameContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDotted_name(this); } }; Dotted_nameContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDotted_name(this); } }; Dotted_nameContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDotted_name(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Dotted_nameContext = Dotted_nameContext; Python3Parser.prototype.dotted_name = function() { var localctx = new Dotted_nameContext(this, this._ctx, this.state); this.enterRule(localctx, 66, Python3Parser.RULE_dotted_name); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 525; this.match(Python3Parser.NAME); this.state = 530; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.DOT) { this.state = 526; this.match(Python3Parser.DOT); this.state = 527; this.match(Python3Parser.NAME); this.state = 532; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Global_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_global_stmt; return this; } Global_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Global_stmtContext.prototype.constructor = Global_stmtContext; Global_stmtContext.prototype.GLOBAL = function() { return this.getToken(Python3Parser.GLOBAL, 0); }; Global_stmtContext.prototype.NAME = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.NAME); } else { return this.getToken(Python3Parser.NAME, i); } }; Global_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterGlobal_stmt(this); } }; Global_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitGlobal_stmt(this); } }; Global_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitGlobal_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Global_stmtContext = Global_stmtContext; Python3Parser.prototype.global_stmt = function() { var localctx = new Global_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 68, Python3Parser.RULE_global_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 533; this.match(Python3Parser.GLOBAL); this.state = 534; this.match(Python3Parser.NAME); this.state = 539; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.COMMA) { this.state = 535; this.match(Python3Parser.COMMA); this.state = 536; this.match(Python3Parser.NAME); this.state = 541; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Nonlocal_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_nonlocal_stmt; return this; } Nonlocal_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Nonlocal_stmtContext.prototype.constructor = Nonlocal_stmtContext; Nonlocal_stmtContext.prototype.NONLOCAL = function() { return this.getToken(Python3Parser.NONLOCAL, 0); }; Nonlocal_stmtContext.prototype.NAME = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.NAME); } else { return this.getToken(Python3Parser.NAME, i); } }; Nonlocal_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterNonlocal_stmt(this); } }; Nonlocal_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitNonlocal_stmt(this); } }; Nonlocal_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitNonlocal_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Nonlocal_stmtContext = Nonlocal_stmtContext; Python3Parser.prototype.nonlocal_stmt = function() { var localctx = new Nonlocal_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 70, Python3Parser.RULE_nonlocal_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 542; this.match(Python3Parser.NONLOCAL); this.state = 543; this.match(Python3Parser.NAME); this.state = 548; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.COMMA) { this.state = 544; this.match(Python3Parser.COMMA); this.state = 545; this.match(Python3Parser.NAME); this.state = 550; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Assert_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_assert_stmt; return this; } Assert_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Assert_stmtContext.prototype.constructor = Assert_stmtContext; Assert_stmtContext.prototype.ASSERT = function() { return this.getToken(Python3Parser.ASSERT, 0); }; Assert_stmtContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; Assert_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterAssert_stmt(this); } }; Assert_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitAssert_stmt(this); } }; Assert_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitAssert_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Assert_stmtContext = Assert_stmtContext; Python3Parser.prototype.assert_stmt = function() { var localctx = new Assert_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 72, Python3Parser.RULE_assert_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 551; this.match(Python3Parser.ASSERT); this.state = 552; this.test(); this.state = 555; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 553; this.match(Python3Parser.COMMA); this.state = 554; this.test(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Compound_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_compound_stmt; return this; } Compound_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Compound_stmtContext.prototype.constructor = Compound_stmtContext; Compound_stmtContext.prototype.if_stmt = function() { return this.getTypedRuleContext(If_stmtContext,0); }; Compound_stmtContext.prototype.while_stmt = function() { return this.getTypedRuleContext(While_stmtContext,0); }; Compound_stmtContext.prototype.for_stmt = function() { return this.getTypedRuleContext(For_stmtContext,0); }; Compound_stmtContext.prototype.try_stmt = function() { return this.getTypedRuleContext(Try_stmtContext,0); }; Compound_stmtContext.prototype.with_stmt = function() { return this.getTypedRuleContext(With_stmtContext,0); }; Compound_stmtContext.prototype.funcdef = function() { return this.getTypedRuleContext(FuncdefContext,0); }; Compound_stmtContext.prototype.classdef = function() { return this.getTypedRuleContext(ClassdefContext,0); }; Compound_stmtContext.prototype.decorated = function() { return this.getTypedRuleContext(DecoratedContext,0); }; Compound_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterCompound_stmt(this); } }; Compound_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitCompound_stmt(this); } }; Compound_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitCompound_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Compound_stmtContext = Compound_stmtContext; Python3Parser.prototype.compound_stmt = function() { var localctx = new Compound_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 74, Python3Parser.RULE_compound_stmt); try { this.state = 565; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.IF: this.enterOuterAlt(localctx, 1); this.state = 557; this.if_stmt(); break; case Python3Parser.WHILE: this.enterOuterAlt(localctx, 2); this.state = 558; this.while_stmt(); break; case Python3Parser.FOR: this.enterOuterAlt(localctx, 3); this.state = 559; this.for_stmt(); break; case Python3Parser.TRY: this.enterOuterAlt(localctx, 4); this.state = 560; this.try_stmt(); break; case Python3Parser.WITH: this.enterOuterAlt(localctx, 5); this.state = 561; this.with_stmt(); break; case Python3Parser.DEF: this.enterOuterAlt(localctx, 6); this.state = 562; this.funcdef(); break; case Python3Parser.CLASS: this.enterOuterAlt(localctx, 7); this.state = 563; this.classdef(); break; case Python3Parser.AT: this.enterOuterAlt(localctx, 8); this.state = 564; this.decorated(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function If_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_if_stmt; return this; } If_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); If_stmtContext.prototype.constructor = If_stmtContext; If_stmtContext.prototype.IF = function() { return this.getToken(Python3Parser.IF, 0); }; If_stmtContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; If_stmtContext.prototype.suite = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SuiteContext); } else { return this.getTypedRuleContext(SuiteContext,i); } }; If_stmtContext.prototype.ELIF = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.ELIF); } else { return this.getToken(Python3Parser.ELIF, i); } }; If_stmtContext.prototype.ELSE = function() { return this.getToken(Python3Parser.ELSE, 0); }; If_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterIf_stmt(this); } }; If_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitIf_stmt(this); } }; If_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitIf_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.If_stmtContext = If_stmtContext; Python3Parser.prototype.if_stmt = function() { var localctx = new If_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 76, Python3Parser.RULE_if_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 567; this.match(Python3Parser.IF); this.state = 568; this.test(); this.state = 569; this.match(Python3Parser.COLON); this.state = 570; this.suite(); this.state = 578; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.ELIF) { this.state = 571; this.match(Python3Parser.ELIF); this.state = 572; this.test(); this.state = 573; this.match(Python3Parser.COLON); this.state = 574; this.suite(); this.state = 580; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 584; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ELSE) { this.state = 581; this.match(Python3Parser.ELSE); this.state = 582; this.match(Python3Parser.COLON); this.state = 583; this.suite(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function While_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_while_stmt; return this; } While_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); While_stmtContext.prototype.constructor = While_stmtContext; While_stmtContext.prototype.WHILE = function() { return this.getToken(Python3Parser.WHILE, 0); }; While_stmtContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; While_stmtContext.prototype.suite = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SuiteContext); } else { return this.getTypedRuleContext(SuiteContext,i); } }; While_stmtContext.prototype.ELSE = function() { return this.getToken(Python3Parser.ELSE, 0); }; While_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterWhile_stmt(this); } }; While_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitWhile_stmt(this); } }; While_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitWhile_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.While_stmtContext = While_stmtContext; Python3Parser.prototype.while_stmt = function() { var localctx = new While_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 78, Python3Parser.RULE_while_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 586; this.match(Python3Parser.WHILE); this.state = 587; this.test(); this.state = 588; this.match(Python3Parser.COLON); this.state = 589; this.suite(); this.state = 593; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ELSE) { this.state = 590; this.match(Python3Parser.ELSE); this.state = 591; this.match(Python3Parser.COLON); this.state = 592; this.suite(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function For_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_for_stmt; return this; } For_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); For_stmtContext.prototype.constructor = For_stmtContext; For_stmtContext.prototype.FOR = function() { return this.getToken(Python3Parser.FOR, 0); }; For_stmtContext.prototype.exprlist = function() { return this.getTypedRuleContext(ExprlistContext,0); }; For_stmtContext.prototype.IN = function() { return this.getToken(Python3Parser.IN, 0); }; For_stmtContext.prototype.testlist = function() { return this.getTypedRuleContext(TestlistContext,0); }; For_stmtContext.prototype.suite = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SuiteContext); } else { return this.getTypedRuleContext(SuiteContext,i); } }; For_stmtContext.prototype.ELSE = function() { return this.getToken(Python3Parser.ELSE, 0); }; For_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterFor_stmt(this); } }; For_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitFor_stmt(this); } }; For_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitFor_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.For_stmtContext = For_stmtContext; Python3Parser.prototype.for_stmt = function() { var localctx = new For_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 80, Python3Parser.RULE_for_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 595; this.match(Python3Parser.FOR); this.state = 596; this.exprlist(); this.state = 597; this.match(Python3Parser.IN); this.state = 598; this.testlist(); this.state = 599; this.match(Python3Parser.COLON); this.state = 600; this.suite(); this.state = 604; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ELSE) { this.state = 601; this.match(Python3Parser.ELSE); this.state = 602; this.match(Python3Parser.COLON); this.state = 603; this.suite(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Try_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_try_stmt; return this; } Try_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Try_stmtContext.prototype.constructor = Try_stmtContext; Try_stmtContext.prototype.TRY = function() { return this.getToken(Python3Parser.TRY, 0); }; Try_stmtContext.prototype.suite = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SuiteContext); } else { return this.getTypedRuleContext(SuiteContext,i); } }; Try_stmtContext.prototype.FINALLY = function() { return this.getToken(Python3Parser.FINALLY, 0); }; Try_stmtContext.prototype.except_clause = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Except_clauseContext); } else { return this.getTypedRuleContext(Except_clauseContext,i); } }; Try_stmtContext.prototype.ELSE = function() { return this.getToken(Python3Parser.ELSE, 0); }; Try_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTry_stmt(this); } }; Try_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTry_stmt(this); } }; Try_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTry_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Try_stmtContext = Try_stmtContext; Python3Parser.prototype.try_stmt = function() { var localctx = new Try_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 82, Python3Parser.RULE_try_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 606; this.match(Python3Parser.TRY); this.state = 607; this.match(Python3Parser.COLON); this.state = 608; this.suite(); this.state = 630; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.EXCEPT: this.state = 613; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 609; this.except_clause(); this.state = 610; this.match(Python3Parser.COLON); this.state = 611; this.suite(); this.state = 615; this._errHandler.sync(this); _la = this._input.LA(1); } while(_la===Python3Parser.EXCEPT); this.state = 620; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.ELSE) { this.state = 617; this.match(Python3Parser.ELSE); this.state = 618; this.match(Python3Parser.COLON); this.state = 619; this.suite(); } this.state = 625; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.FINALLY) { this.state = 622; this.match(Python3Parser.FINALLY); this.state = 623; this.match(Python3Parser.COLON); this.state = 624; this.suite(); } break; case Python3Parser.FINALLY: this.state = 627; this.match(Python3Parser.FINALLY); this.state = 628; this.match(Python3Parser.COLON); this.state = 629; this.suite(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function With_stmtContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_with_stmt; return this; } With_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); With_stmtContext.prototype.constructor = With_stmtContext; With_stmtContext.prototype.WITH = function() { return this.getToken(Python3Parser.WITH, 0); }; With_stmtContext.prototype.with_item = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(With_itemContext); } else { return this.getTypedRuleContext(With_itemContext,i); } }; With_stmtContext.prototype.suite = function() { return this.getTypedRuleContext(SuiteContext,0); }; With_stmtContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterWith_stmt(this); } }; With_stmtContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitWith_stmt(this); } }; With_stmtContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitWith_stmt(this); } else { return visitor.visitChildren(this); } }; Python3Parser.With_stmtContext = With_stmtContext; Python3Parser.prototype.with_stmt = function() { var localctx = new With_stmtContext(this, this._ctx, this.state); this.enterRule(localctx, 84, Python3Parser.RULE_with_stmt); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 632; this.match(Python3Parser.WITH); this.state = 633; this.with_item(); this.state = 638; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.COMMA) { this.state = 634; this.match(Python3Parser.COMMA); this.state = 635; this.with_item(); this.state = 640; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 641; this.match(Python3Parser.COLON); this.state = 642; this.suite(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function With_itemContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_with_item; return this; } With_itemContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); With_itemContext.prototype.constructor = With_itemContext; With_itemContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; With_itemContext.prototype.AS = function() { return this.getToken(Python3Parser.AS, 0); }; With_itemContext.prototype.expr = function() { return this.getTypedRuleContext(ExprContext,0); }; With_itemContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterWith_item(this); } }; With_itemContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitWith_item(this); } }; With_itemContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitWith_item(this); } else { return visitor.visitChildren(this); } }; Python3Parser.With_itemContext = With_itemContext; Python3Parser.prototype.with_item = function() { var localctx = new With_itemContext(this, this._ctx, this.state); this.enterRule(localctx, 86, Python3Parser.RULE_with_item); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 644; this.test(); this.state = 647; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.AS) { this.state = 645; this.match(Python3Parser.AS); this.state = 646; this.expr(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Except_clauseContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_except_clause; return this; } Except_clauseContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Except_clauseContext.prototype.constructor = Except_clauseContext; Except_clauseContext.prototype.EXCEPT = function() { return this.getToken(Python3Parser.EXCEPT, 0); }; Except_clauseContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; Except_clauseContext.prototype.AS = function() { return this.getToken(Python3Parser.AS, 0); }; Except_clauseContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; Except_clauseContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterExcept_clause(this); } }; Except_clauseContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitExcept_clause(this); } }; Except_clauseContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitExcept_clause(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Except_clauseContext = Except_clauseContext; Python3Parser.prototype.except_clause = function() { var localctx = new Except_clauseContext(this, this._ctx, this.state); this.enterRule(localctx, 88, Python3Parser.RULE_except_clause); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 649; this.match(Python3Parser.EXCEPT); this.state = 655; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 650; this.test(); this.state = 653; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.AS) { this.state = 651; this.match(Python3Parser.AS); this.state = 652; this.match(Python3Parser.NAME); } } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SuiteContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_suite; return this; } SuiteContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); SuiteContext.prototype.constructor = SuiteContext; SuiteContext.prototype.simple_stmt = function() { return this.getTypedRuleContext(Simple_stmtContext,0); }; SuiteContext.prototype.NEWLINE = function() { return this.getToken(Python3Parser.NEWLINE, 0); }; SuiteContext.prototype.INDENT = function() { return this.getToken(Python3Parser.INDENT, 0); }; SuiteContext.prototype.DEDENT = function() { return this.getToken(Python3Parser.DEDENT, 0); }; SuiteContext.prototype.stmt = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(StmtContext); } else { return this.getTypedRuleContext(StmtContext,i); } }; SuiteContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSuite(this); } }; SuiteContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSuite(this); } }; SuiteContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSuite(this); } else { return visitor.visitChildren(this); } }; Python3Parser.SuiteContext = SuiteContext; Python3Parser.prototype.suite = function() { var localctx = new SuiteContext(this, this._ctx, this.state); this.enterRule(localctx, 90, Python3Parser.RULE_suite); var _la = 0; // Token type try { this.state = 667; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.RETURN: case Python3Parser.RAISE: case Python3Parser.FROM: case Python3Parser.IMPORT: case Python3Parser.GLOBAL: case Python3Parser.NONLOCAL: case Python3Parser.ASSERT: case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.YIELD: case Python3Parser.DEL: case Python3Parser.PASS: case Python3Parser.CONTINUE: case Python3Parser.BREAK: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 1); this.state = 657; this.simple_stmt(); break; case Python3Parser.NEWLINE: this.enterOuterAlt(localctx, 2); this.state = 658; this.match(Python3Parser.NEWLINE); this.state = 659; this.match(Python3Parser.INDENT); this.state = 661; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 660; this.stmt(); this.state = 663; this._errHandler.sync(this); _la = this._input.LA(1); } while((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << Python3Parser.DEF) | (1 << Python3Parser.RETURN) | (1 << Python3Parser.RAISE) | (1 << Python3Parser.FROM) | (1 << Python3Parser.IMPORT) | (1 << Python3Parser.GLOBAL) | (1 << Python3Parser.NONLOCAL) | (1 << Python3Parser.ASSERT) | (1 << Python3Parser.IF) | (1 << Python3Parser.WHILE) | (1 << Python3Parser.FOR) | (1 << Python3Parser.TRY) | (1 << Python3Parser.WITH) | (1 << Python3Parser.LAMBDA) | (1 << Python3Parser.NOT) | (1 << Python3Parser.NONE) | (1 << Python3Parser.TRUE) | (1 << Python3Parser.FALSE) | (1 << Python3Parser.CLASS) | (1 << Python3Parser.YIELD) | (1 << Python3Parser.DEL) | (1 << Python3Parser.PASS))) !== 0) || ((((_la - 32)) & ~0x1f) == 0 && ((1 << (_la - 32)) & ((1 << (Python3Parser.CONTINUE - 32)) | (1 << (Python3Parser.BREAK - 32)) | (1 << (Python3Parser.NAME - 32)) | (1 << (Python3Parser.STRING_LITERAL - 32)) | (1 << (Python3Parser.BYTES_LITERAL - 32)) | (1 << (Python3Parser.DECIMAL_INTEGER - 32)) | (1 << (Python3Parser.OCT_INTEGER - 32)) | (1 << (Python3Parser.HEX_INTEGER - 32)) | (1 << (Python3Parser.BIN_INTEGER - 32)) | (1 << (Python3Parser.FLOAT_NUMBER - 32)) | (1 << (Python3Parser.IMAG_NUMBER - 32)) | (1 << (Python3Parser.ELLIPSIS - 32)) | (1 << (Python3Parser.STAR - 32)) | (1 << (Python3Parser.OPEN_PAREN - 32)) | (1 << (Python3Parser.OPEN_BRACK - 32)) | (1 << (Python3Parser.ADD - 32)) | (1 << (Python3Parser.MINUS - 32)))) !== 0) || ((((_la - 66)) & ~0x1f) == 0 && ((1 << (_la - 66)) & ((1 << (Python3Parser.NOT_OP - 66)) | (1 << (Python3Parser.OPEN_BRACE - 66)) | (1 << (Python3Parser.AT - 66)))) !== 0)); this.state = 665; this.match(Python3Parser.DEDENT); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TestContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_test; return this; } TestContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); TestContext.prototype.constructor = TestContext; TestContext.prototype.or_test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Or_testContext); } else { return this.getTypedRuleContext(Or_testContext,i); } }; TestContext.prototype.IF = function() { return this.getToken(Python3Parser.IF, 0); }; TestContext.prototype.ELSE = function() { return this.getToken(Python3Parser.ELSE, 0); }; TestContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; TestContext.prototype.lambdef = function() { return this.getTypedRuleContext(LambdefContext,0); }; TestContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTest(this); } }; TestContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTest(this); } }; TestContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTest(this); } else { return visitor.visitChildren(this); } }; Python3Parser.TestContext = TestContext; Python3Parser.prototype.test = function() { var localctx = new TestContext(this, this._ctx, this.state); this.enterRule(localctx, 92, Python3Parser.RULE_test); var _la = 0; // Token type try { this.state = 678; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 1); this.state = 669; this.or_test(); this.state = 675; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.IF) { this.state = 670; this.match(Python3Parser.IF); this.state = 671; this.or_test(); this.state = 672; this.match(Python3Parser.ELSE); this.state = 673; this.test(); } break; case Python3Parser.LAMBDA: this.enterOuterAlt(localctx, 2); this.state = 677; this.lambdef(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Test_nocondContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_test_nocond; return this; } Test_nocondContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Test_nocondContext.prototype.constructor = Test_nocondContext; Test_nocondContext.prototype.or_test = function() { return this.getTypedRuleContext(Or_testContext,0); }; Test_nocondContext.prototype.lambdef_nocond = function() { return this.getTypedRuleContext(Lambdef_nocondContext,0); }; Test_nocondContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTest_nocond(this); } }; Test_nocondContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTest_nocond(this); } }; Test_nocondContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTest_nocond(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Test_nocondContext = Test_nocondContext; Python3Parser.prototype.test_nocond = function() { var localctx = new Test_nocondContext(this, this._ctx, this.state); this.enterRule(localctx, 94, Python3Parser.RULE_test_nocond); try { this.state = 682; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 1); this.state = 680; this.or_test(); break; case Python3Parser.LAMBDA: this.enterOuterAlt(localctx, 2); this.state = 681; this.lambdef_nocond(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function LambdefContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_lambdef; return this; } LambdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); LambdefContext.prototype.constructor = LambdefContext; LambdefContext.prototype.LAMBDA = function() { return this.getToken(Python3Parser.LAMBDA, 0); }; LambdefContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; LambdefContext.prototype.varargslist = function() { return this.getTypedRuleContext(VarargslistContext,0); }; LambdefContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterLambdef(this); } }; LambdefContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitLambdef(this); } }; LambdefContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitLambdef(this); } else { return visitor.visitChildren(this); } }; Python3Parser.LambdefContext = LambdefContext; Python3Parser.prototype.lambdef = function() { var localctx = new LambdefContext(this, this._ctx, this.state); this.enterRule(localctx, 96, Python3Parser.RULE_lambdef); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 684; this.match(Python3Parser.LAMBDA); this.state = 686; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 35)) & ~0x1f) == 0 && ((1 << (_la - 35)) & ((1 << (Python3Parser.NAME - 35)) | (1 << (Python3Parser.STAR - 35)) | (1 << (Python3Parser.POWER - 35)))) !== 0)) { this.state = 685; this.varargslist(); } this.state = 688; this.match(Python3Parser.COLON); this.state = 689; this.test(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Lambdef_nocondContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_lambdef_nocond; return this; } Lambdef_nocondContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Lambdef_nocondContext.prototype.constructor = Lambdef_nocondContext; Lambdef_nocondContext.prototype.LAMBDA = function() { return this.getToken(Python3Parser.LAMBDA, 0); }; Lambdef_nocondContext.prototype.test_nocond = function() { return this.getTypedRuleContext(Test_nocondContext,0); }; Lambdef_nocondContext.prototype.varargslist = function() { return this.getTypedRuleContext(VarargslistContext,0); }; Lambdef_nocondContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterLambdef_nocond(this); } }; Lambdef_nocondContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitLambdef_nocond(this); } }; Lambdef_nocondContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitLambdef_nocond(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Lambdef_nocondContext = Lambdef_nocondContext; Python3Parser.prototype.lambdef_nocond = function() { var localctx = new Lambdef_nocondContext(this, this._ctx, this.state); this.enterRule(localctx, 98, Python3Parser.RULE_lambdef_nocond); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 691; this.match(Python3Parser.LAMBDA); this.state = 693; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 35)) & ~0x1f) == 0 && ((1 << (_la - 35)) & ((1 << (Python3Parser.NAME - 35)) | (1 << (Python3Parser.STAR - 35)) | (1 << (Python3Parser.POWER - 35)))) !== 0)) { this.state = 692; this.varargslist(); } this.state = 695; this.match(Python3Parser.COLON); this.state = 696; this.test_nocond(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Or_testContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_or_test; return this; } Or_testContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Or_testContext.prototype.constructor = Or_testContext; Or_testContext.prototype.and_test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(And_testContext); } else { return this.getTypedRuleContext(And_testContext,i); } }; Or_testContext.prototype.OR = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.OR); } else { return this.getToken(Python3Parser.OR, i); } }; Or_testContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterOr_test(this); } }; Or_testContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitOr_test(this); } }; Or_testContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitOr_test(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Or_testContext = Or_testContext; Python3Parser.prototype.or_test = function() { var localctx = new Or_testContext(this, this._ctx, this.state); this.enterRule(localctx, 100, Python3Parser.RULE_or_test); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 698; this.and_test(); this.state = 703; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.OR) { this.state = 699; this.match(Python3Parser.OR); this.state = 700; this.and_test(); this.state = 705; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function And_testContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_and_test; return this; } And_testContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); And_testContext.prototype.constructor = And_testContext; And_testContext.prototype.not_test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Not_testContext); } else { return this.getTypedRuleContext(Not_testContext,i); } }; And_testContext.prototype.AND = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTokens(Python3Parser.AND); } else { return this.getToken(Python3Parser.AND, i); } }; And_testContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterAnd_test(this); } }; And_testContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitAnd_test(this); } }; And_testContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitAnd_test(this); } else { return visitor.visitChildren(this); } }; Python3Parser.And_testContext = And_testContext; Python3Parser.prototype.and_test = function() { var localctx = new And_testContext(this, this._ctx, this.state); this.enterRule(localctx, 102, Python3Parser.RULE_and_test); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 706; this.not_test(); this.state = 711; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.AND) { this.state = 707; this.match(Python3Parser.AND); this.state = 708; this.not_test(); this.state = 713; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Not_testContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_not_test; return this; } Not_testContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Not_testContext.prototype.constructor = Not_testContext; Not_testContext.prototype.NOT = function() { return this.getToken(Python3Parser.NOT, 0); }; Not_testContext.prototype.not_test = function() { return this.getTypedRuleContext(Not_testContext,0); }; Not_testContext.prototype.comparison = function() { return this.getTypedRuleContext(ComparisonContext,0); }; Not_testContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterNot_test(this); } }; Not_testContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitNot_test(this); } }; Not_testContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitNot_test(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Not_testContext = Not_testContext; Python3Parser.prototype.not_test = function() { var localctx = new Not_testContext(this, this._ctx, this.state); this.enterRule(localctx, 104, Python3Parser.RULE_not_test); try { this.state = 717; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.NOT: this.enterOuterAlt(localctx, 1); this.state = 714; this.match(Python3Parser.NOT); this.state = 715; this.not_test(); break; case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 2); this.state = 716; this.comparison(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ComparisonContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_comparison; return this; } ComparisonContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ComparisonContext.prototype.constructor = ComparisonContext; ComparisonContext.prototype.star_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Star_exprContext); } else { return this.getTypedRuleContext(Star_exprContext,i); } }; ComparisonContext.prototype.comp_op = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Comp_opContext); } else { return this.getTypedRuleContext(Comp_opContext,i); } }; ComparisonContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterComparison(this); } }; ComparisonContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitComparison(this); } }; ComparisonContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitComparison(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ComparisonContext = ComparisonContext; Python3Parser.prototype.comparison = function() { var localctx = new ComparisonContext(this, this._ctx, this.state); this.enterRule(localctx, 106, Python3Parser.RULE_comparison); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 719; this.star_expr(); this.state = 725; this._errHandler.sync(this); _la = this._input.LA(1); while((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << Python3Parser.IN) | (1 << Python3Parser.NOT) | (1 << Python3Parser.IS))) !== 0) || ((((_la - 69)) & ~0x1f) == 0 && ((1 << (_la - 69)) & ((1 << (Python3Parser.LESS_THAN - 69)) | (1 << (Python3Parser.GREATER_THAN - 69)) | (1 << (Python3Parser.EQUALS - 69)) | (1 << (Python3Parser.GT_EQ - 69)) | (1 << (Python3Parser.LT_EQ - 69)) | (1 << (Python3Parser.NOT_EQ_1 - 69)) | (1 << (Python3Parser.NOT_EQ_2 - 69)))) !== 0)) { this.state = 720; this.comp_op(); this.state = 721; this.star_expr(); this.state = 727; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Comp_opContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_comp_op; return this; } Comp_opContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Comp_opContext.prototype.constructor = Comp_opContext; Comp_opContext.prototype.IN = function() { return this.getToken(Python3Parser.IN, 0); }; Comp_opContext.prototype.NOT = function() { return this.getToken(Python3Parser.NOT, 0); }; Comp_opContext.prototype.IS = function() { return this.getToken(Python3Parser.IS, 0); }; Comp_opContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterComp_op(this); } }; Comp_opContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitComp_op(this); } }; Comp_opContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitComp_op(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Comp_opContext = Comp_opContext; Python3Parser.prototype.comp_op = function() { var localctx = new Comp_opContext(this, this._ctx, this.state); this.enterRule(localctx, 108, Python3Parser.RULE_comp_op); try { this.state = 741; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,93,this._ctx); switch(la_) { case 1: this.enterOuterAlt(localctx, 1); this.state = 728; this.match(Python3Parser.LESS_THAN); break; case 2: this.enterOuterAlt(localctx, 2); this.state = 729; this.match(Python3Parser.GREATER_THAN); break; case 3: this.enterOuterAlt(localctx, 3); this.state = 730; this.match(Python3Parser.EQUALS); break; case 4: this.enterOuterAlt(localctx, 4); this.state = 731; this.match(Python3Parser.GT_EQ); break; case 5: this.enterOuterAlt(localctx, 5); this.state = 732; this.match(Python3Parser.LT_EQ); break; case 6: this.enterOuterAlt(localctx, 6); this.state = 733; this.match(Python3Parser.NOT_EQ_1); break; case 7: this.enterOuterAlt(localctx, 7); this.state = 734; this.match(Python3Parser.NOT_EQ_2); break; case 8: this.enterOuterAlt(localctx, 8); this.state = 735; this.match(Python3Parser.IN); break; case 9: this.enterOuterAlt(localctx, 9); this.state = 736; this.match(Python3Parser.NOT); this.state = 737; this.match(Python3Parser.IN); break; case 10: this.enterOuterAlt(localctx, 10); this.state = 738; this.match(Python3Parser.IS); break; case 11: this.enterOuterAlt(localctx, 11); this.state = 739; this.match(Python3Parser.IS); this.state = 740; this.match(Python3Parser.NOT); break; } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Star_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_star_expr; return this; } Star_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Star_exprContext.prototype.constructor = Star_exprContext; Star_exprContext.prototype.expr = function() { return this.getTypedRuleContext(ExprContext,0); }; Star_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterStar_expr(this); } }; Star_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitStar_expr(this); } }; Star_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitStar_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Star_exprContext = Star_exprContext; Python3Parser.prototype.star_expr = function() { var localctx = new Star_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 110, Python3Parser.RULE_star_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 744; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.STAR) { this.state = 743; this.match(Python3Parser.STAR); } this.state = 746; this.expr(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ExprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_expr; return this; } ExprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ExprContext.prototype.constructor = ExprContext; ExprContext.prototype.xor_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Xor_exprContext); } else { return this.getTypedRuleContext(Xor_exprContext,i); } }; ExprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterExpr(this); } }; ExprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitExpr(this); } }; ExprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitExpr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ExprContext = ExprContext; Python3Parser.prototype.expr = function() { var localctx = new ExprContext(this, this._ctx, this.state); this.enterRule(localctx, 112, Python3Parser.RULE_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 748; this.xor_expr(); this.state = 753; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.OR_OP) { this.state = 749; this.match(Python3Parser.OR_OP); this.state = 750; this.xor_expr(); this.state = 755; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Xor_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_xor_expr; return this; } Xor_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Xor_exprContext.prototype.constructor = Xor_exprContext; Xor_exprContext.prototype.and_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(And_exprContext); } else { return this.getTypedRuleContext(And_exprContext,i); } }; Xor_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterXor_expr(this); } }; Xor_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitXor_expr(this); } }; Xor_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitXor_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Xor_exprContext = Xor_exprContext; Python3Parser.prototype.xor_expr = function() { var localctx = new Xor_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 114, Python3Parser.RULE_xor_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 756; this.and_expr(); this.state = 761; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.XOR) { this.state = 757; this.match(Python3Parser.XOR); this.state = 758; this.and_expr(); this.state = 763; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function And_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_and_expr; return this; } And_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); And_exprContext.prototype.constructor = And_exprContext; And_exprContext.prototype.shift_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Shift_exprContext); } else { return this.getTypedRuleContext(Shift_exprContext,i); } }; And_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterAnd_expr(this); } }; And_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitAnd_expr(this); } }; And_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitAnd_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.And_exprContext = And_exprContext; Python3Parser.prototype.and_expr = function() { var localctx = new And_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 116, Python3Parser.RULE_and_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 764; this.shift_expr(); this.state = 769; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.AND_OP) { this.state = 765; this.match(Python3Parser.AND_OP); this.state = 766; this.shift_expr(); this.state = 771; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Shift_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_shift_expr; return this; } Shift_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Shift_exprContext.prototype.constructor = Shift_exprContext; Shift_exprContext.prototype.arith_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Arith_exprContext); } else { return this.getTypedRuleContext(Arith_exprContext,i); } }; Shift_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterShift_expr(this); } }; Shift_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitShift_expr(this); } }; Shift_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitShift_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Shift_exprContext = Shift_exprContext; Python3Parser.prototype.shift_expr = function() { var localctx = new Shift_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 118, Python3Parser.RULE_shift_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 772; this.arith_expr(); this.state = 779; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.LEFT_SHIFT || _la===Python3Parser.RIGHT_SHIFT) { this.state = 777; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.LEFT_SHIFT: this.state = 773; this.match(Python3Parser.LEFT_SHIFT); this.state = 774; this.arith_expr(); break; case Python3Parser.RIGHT_SHIFT: this.state = 775; this.match(Python3Parser.RIGHT_SHIFT); this.state = 776; this.arith_expr(); break; default: throw new antlr4.error.NoViableAltException(this); } this.state = 781; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Arith_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_arith_expr; return this; } Arith_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Arith_exprContext.prototype.constructor = Arith_exprContext; Arith_exprContext.prototype.term = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TermContext); } else { return this.getTypedRuleContext(TermContext,i); } }; Arith_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterArith_expr(this); } }; Arith_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitArith_expr(this); } }; Arith_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitArith_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Arith_exprContext = Arith_exprContext; Python3Parser.prototype.arith_expr = function() { var localctx = new Arith_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 120, Python3Parser.RULE_arith_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 782; this.term(); this.state = 789; this._errHandler.sync(this); _la = this._input.LA(1); while(_la===Python3Parser.ADD || _la===Python3Parser.MINUS) { this.state = 787; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.ADD: this.state = 783; this.match(Python3Parser.ADD); this.state = 784; this.term(); break; case Python3Parser.MINUS: this.state = 785; this.match(Python3Parser.MINUS); this.state = 786; this.term(); break; default: throw new antlr4.error.NoViableAltException(this); } this.state = 791; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TermContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_term; return this; } TermContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); TermContext.prototype.constructor = TermContext; TermContext.prototype.factor = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(FactorContext); } else { return this.getTypedRuleContext(FactorContext,i); } }; TermContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTerm(this); } }; TermContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTerm(this); } }; TermContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTerm(this); } else { return visitor.visitChildren(this); } }; Python3Parser.TermContext = TermContext; Python3Parser.prototype.term = function() { var localctx = new TermContext(this, this._ctx, this.state); this.enterRule(localctx, 122, Python3Parser.RULE_term); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 792; this.factor(); this.state = 805; this._errHandler.sync(this); _la = this._input.LA(1); while(((((_la - 46)) & ~0x1f) == 0 && ((1 << (_la - 46)) & ((1 << (Python3Parser.STAR - 46)) | (1 << (Python3Parser.DIV - 46)) | (1 << (Python3Parser.MOD - 46)) | (1 << (Python3Parser.IDIV - 46)) | (1 << (Python3Parser.AT - 46)))) !== 0)) { this.state = 803; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.STAR: this.state = 793; this.match(Python3Parser.STAR); this.state = 794; this.factor(); break; case Python3Parser.DIV: this.state = 795; this.match(Python3Parser.DIV); this.state = 796; this.factor(); break; case Python3Parser.MOD: this.state = 797; this.match(Python3Parser.MOD); this.state = 798; this.factor(); break; case Python3Parser.IDIV: this.state = 799; this.match(Python3Parser.IDIV); this.state = 800; this.factor(); break; case Python3Parser.AT: this.state = 801; this.match(Python3Parser.AT); this.state = 802; this.factor(); break; default: throw new antlr4.error.NoViableAltException(this); } this.state = 807; this._errHandler.sync(this); _la = this._input.LA(1); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function FactorContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_factor; return this; } FactorContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); FactorContext.prototype.constructor = FactorContext; FactorContext.prototype.factor = function() { return this.getTypedRuleContext(FactorContext,0); }; FactorContext.prototype.power = function() { return this.getTypedRuleContext(PowerContext,0); }; FactorContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterFactor(this); } }; FactorContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitFactor(this); } }; FactorContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitFactor(this); } else { return visitor.visitChildren(this); } }; Python3Parser.FactorContext = FactorContext; Python3Parser.prototype.factor = function() { var localctx = new FactorContext(this, this._ctx, this.state); this.enterRule(localctx, 124, Python3Parser.RULE_factor); try { this.state = 815; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.ADD: this.enterOuterAlt(localctx, 1); this.state = 808; this.match(Python3Parser.ADD); this.state = 809; this.factor(); break; case Python3Parser.MINUS: this.enterOuterAlt(localctx, 2); this.state = 810; this.match(Python3Parser.MINUS); this.state = 811; this.factor(); break; case Python3Parser.NOT_OP: this.enterOuterAlt(localctx, 3); this.state = 812; this.match(Python3Parser.NOT_OP); this.state = 813; this.factor(); break; case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 4); this.state = 814; this.power(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function PowerContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_power; return this; } PowerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); PowerContext.prototype.constructor = PowerContext; PowerContext.prototype.atom = function() { return this.getTypedRuleContext(AtomContext,0); }; PowerContext.prototype.trailer = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TrailerContext); } else { return this.getTypedRuleContext(TrailerContext,i); } }; PowerContext.prototype.factor = function() { return this.getTypedRuleContext(FactorContext,0); }; PowerContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterPower(this); } }; PowerContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitPower(this); } }; PowerContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitPower(this); } else { return visitor.visitChildren(this); } }; Python3Parser.PowerContext = PowerContext; Python3Parser.prototype.power = function() { var localctx = new PowerContext(this, this._ctx, this.state); this.enterRule(localctx, 126, Python3Parser.RULE_power); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 817; this.atom(); this.state = 821; this._errHandler.sync(this); _la = this._input.LA(1); while(((((_la - 44)) & ~0x1f) == 0 && ((1 << (_la - 44)) & ((1 << (Python3Parser.DOT - 44)) | (1 << (Python3Parser.OPEN_PAREN - 44)) | (1 << (Python3Parser.OPEN_BRACK - 44)))) !== 0)) { this.state = 818; this.trailer(); this.state = 823; this._errHandler.sync(this); _la = this._input.LA(1); } this.state = 826; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.POWER) { this.state = 824; this.match(Python3Parser.POWER); this.state = 825; this.factor(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function AtomContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_atom; return this; } AtomContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); AtomContext.prototype.constructor = AtomContext; AtomContext.prototype.yield_expr = function() { return this.getTypedRuleContext(Yield_exprContext,0); }; AtomContext.prototype.testlist_comp = function() { return this.getTypedRuleContext(Testlist_compContext,0); }; AtomContext.prototype.dictorsetmaker = function() { return this.getTypedRuleContext(DictorsetmakerContext,0); }; AtomContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; AtomContext.prototype.number = function() { return this.getTypedRuleContext(NumberContext,0); }; AtomContext.prototype.str = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(StrContext); } else { return this.getTypedRuleContext(StrContext,i); } }; AtomContext.prototype.NONE = function() { return this.getToken(Python3Parser.NONE, 0); }; AtomContext.prototype.TRUE = function() { return this.getToken(Python3Parser.TRUE, 0); }; AtomContext.prototype.FALSE = function() { return this.getToken(Python3Parser.FALSE, 0); }; AtomContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterAtom(this); } }; AtomContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitAtom(this); } }; AtomContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitAtom(this); } else { return visitor.visitChildren(this); } }; Python3Parser.AtomContext = AtomContext; Python3Parser.prototype.atom = function() { var localctx = new AtomContext(this, this._ctx, this.state); this.enterRule(localctx, 128, Python3Parser.RULE_atom); var _la = 0; // Token type try { this.state = 855; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.OPEN_PAREN: this.enterOuterAlt(localctx, 1); this.state = 828; this.match(Python3Parser.OPEN_PAREN); this.state = 831; this._errHandler.sync(this); switch (this._input.LA(1)) { case Python3Parser.YIELD: this.state = 829; this.yield_expr(); break; case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.state = 830; this.testlist_comp(); break; case Python3Parser.CLOSE_PAREN: break; default: break; } this.state = 833; this.match(Python3Parser.CLOSE_PAREN); break; case Python3Parser.OPEN_BRACK: this.enterOuterAlt(localctx, 2); this.state = 834; this.match(Python3Parser.OPEN_BRACK); this.state = 836; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 835; this.testlist_comp(); } this.state = 838; this.match(Python3Parser.CLOSE_BRACK); break; case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 3); this.state = 839; this.match(Python3Parser.OPEN_BRACE); this.state = 841; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 840; this.dictorsetmaker(); } this.state = 843; this.match(Python3Parser.CLOSE_BRACE); break; case Python3Parser.NAME: this.enterOuterAlt(localctx, 4); this.state = 844; this.match(Python3Parser.NAME); break; case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: this.enterOuterAlt(localctx, 5); this.state = 845; this.number(); break; case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: this.enterOuterAlt(localctx, 6); this.state = 847; this._errHandler.sync(this); _la = this._input.LA(1); do { this.state = 846; this.str(); this.state = 849; this._errHandler.sync(this); _la = this._input.LA(1); } while(_la===Python3Parser.STRING_LITERAL || _la===Python3Parser.BYTES_LITERAL); break; case Python3Parser.ELLIPSIS: this.enterOuterAlt(localctx, 7); this.state = 851; this.match(Python3Parser.ELLIPSIS); break; case Python3Parser.NONE: this.enterOuterAlt(localctx, 8); this.state = 852; this.match(Python3Parser.NONE); break; case Python3Parser.TRUE: this.enterOuterAlt(localctx, 9); this.state = 853; this.match(Python3Parser.TRUE); break; case Python3Parser.FALSE: this.enterOuterAlt(localctx, 10); this.state = 854; this.match(Python3Parser.FALSE); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Testlist_compContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_testlist_comp; return this; } Testlist_compContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Testlist_compContext.prototype.constructor = Testlist_compContext; Testlist_compContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; Testlist_compContext.prototype.comp_for = function() { return this.getTypedRuleContext(Comp_forContext,0); }; Testlist_compContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTestlist_comp(this); } }; Testlist_compContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTestlist_comp(this); } }; Testlist_compContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTestlist_comp(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Testlist_compContext = Testlist_compContext; Python3Parser.prototype.testlist_comp = function() { var localctx = new Testlist_compContext(this, this._ctx, this.state); this.enterRule(localctx, 130, Python3Parser.RULE_testlist_comp); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 857; this.test(); this.state = 869; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.FOR: this.state = 858; this.comp_for(); break; case Python3Parser.CLOSE_PAREN: case Python3Parser.COMMA: case Python3Parser.CLOSE_BRACK: this.state = 863; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,112,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 859; this.match(Python3Parser.COMMA); this.state = 860; this.test(); } this.state = 865; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,112,this._ctx); } this.state = 867; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 866; this.match(Python3Parser.COMMA); } break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TrailerContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_trailer; return this; } TrailerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); TrailerContext.prototype.constructor = TrailerContext; TrailerContext.prototype.arglist = function() { return this.getTypedRuleContext(ArglistContext,0); }; TrailerContext.prototype.subscriptlist = function() { return this.getTypedRuleContext(SubscriptlistContext,0); }; TrailerContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; TrailerContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTrailer(this); } }; TrailerContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTrailer(this); } }; TrailerContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTrailer(this); } else { return visitor.visitChildren(this); } }; Python3Parser.TrailerContext = TrailerContext; Python3Parser.prototype.trailer = function() { var localctx = new TrailerContext(this, this._ctx, this.state); this.enterRule(localctx, 132, Python3Parser.RULE_trailer); var _la = 0; // Token type try { this.state = 882; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.OPEN_PAREN: this.enterOuterAlt(localctx, 1); this.state = 871; this.match(Python3Parser.OPEN_PAREN); this.state = 873; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 52)) & ~0x1f) == 0 && ((1 << (_la - 52)) & ((1 << (Python3Parser.POWER - 52)) | (1 << (Python3Parser.OPEN_BRACK - 52)) | (1 << (Python3Parser.ADD - 52)) | (1 << (Python3Parser.MINUS - 52)) | (1 << (Python3Parser.NOT_OP - 52)) | (1 << (Python3Parser.OPEN_BRACE - 52)))) !== 0)) { this.state = 872; this.arglist(); } this.state = 875; this.match(Python3Parser.CLOSE_PAREN); break; case Python3Parser.OPEN_BRACK: this.enterOuterAlt(localctx, 2); this.state = 876; this.match(Python3Parser.OPEN_BRACK); this.state = 877; this.subscriptlist(); this.state = 878; this.match(Python3Parser.CLOSE_BRACK); break; case Python3Parser.DOT: this.enterOuterAlt(localctx, 3); this.state = 880; this.match(Python3Parser.DOT); this.state = 881; this.match(Python3Parser.NAME); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SubscriptlistContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_subscriptlist; return this; } SubscriptlistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); SubscriptlistContext.prototype.constructor = SubscriptlistContext; SubscriptlistContext.prototype.subscript = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(SubscriptContext); } else { return this.getTypedRuleContext(SubscriptContext,i); } }; SubscriptlistContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSubscriptlist(this); } }; SubscriptlistContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSubscriptlist(this); } }; SubscriptlistContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSubscriptlist(this); } else { return visitor.visitChildren(this); } }; Python3Parser.SubscriptlistContext = SubscriptlistContext; Python3Parser.prototype.subscriptlist = function() { var localctx = new SubscriptlistContext(this, this._ctx, this.state); this.enterRule(localctx, 134, Python3Parser.RULE_subscriptlist); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 884; this.subscript(); this.state = 889; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,117,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 885; this.match(Python3Parser.COMMA); this.state = 886; this.subscript(); } this.state = 891; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,117,this._ctx); } this.state = 893; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 892; this.match(Python3Parser.COMMA); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SubscriptContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_subscript; return this; } SubscriptContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); SubscriptContext.prototype.constructor = SubscriptContext; SubscriptContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; SubscriptContext.prototype.sliceop = function() { return this.getTypedRuleContext(SliceopContext,0); }; SubscriptContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSubscript(this); } }; SubscriptContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSubscript(this); } }; SubscriptContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSubscript(this); } else { return visitor.visitChildren(this); } }; Python3Parser.SubscriptContext = SubscriptContext; Python3Parser.prototype.subscript = function() { var localctx = new SubscriptContext(this, this._ctx, this.state); this.enterRule(localctx, 136, Python3Parser.RULE_subscript); var _la = 0; // Token type try { this.state = 906; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,122,this._ctx); switch(la_) { case 1: this.enterOuterAlt(localctx, 1); this.state = 895; this.test(); break; case 2: this.enterOuterAlt(localctx, 2); this.state = 897; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 896; this.test(); } this.state = 899; this.match(Python3Parser.COLON); this.state = 901; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 900; this.test(); } this.state = 904; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COLON) { this.state = 903; this.sliceop(); } break; } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function SliceopContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_sliceop; return this; } SliceopContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); SliceopContext.prototype.constructor = SliceopContext; SliceopContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; SliceopContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterSliceop(this); } }; SliceopContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitSliceop(this); } }; SliceopContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitSliceop(this); } else { return visitor.visitChildren(this); } }; Python3Parser.SliceopContext = SliceopContext; Python3Parser.prototype.sliceop = function() { var localctx = new SliceopContext(this, this._ctx, this.state); this.enterRule(localctx, 138, Python3Parser.RULE_sliceop); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 908; this.match(Python3Parser.COLON); this.state = 910; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 54)) & ~0x1f) == 0 && ((1 << (_la - 54)) & ((1 << (Python3Parser.OPEN_BRACK - 54)) | (1 << (Python3Parser.ADD - 54)) | (1 << (Python3Parser.MINUS - 54)) | (1 << (Python3Parser.NOT_OP - 54)) | (1 << (Python3Parser.OPEN_BRACE - 54)))) !== 0)) { this.state = 909; this.test(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ExprlistContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_exprlist; return this; } ExprlistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ExprlistContext.prototype.constructor = ExprlistContext; ExprlistContext.prototype.star_expr = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(Star_exprContext); } else { return this.getTypedRuleContext(Star_exprContext,i); } }; ExprlistContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterExprlist(this); } }; ExprlistContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitExprlist(this); } }; ExprlistContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitExprlist(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ExprlistContext = ExprlistContext; Python3Parser.prototype.exprlist = function() { var localctx = new ExprlistContext(this, this._ctx, this.state); this.enterRule(localctx, 140, Python3Parser.RULE_exprlist); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 912; this.star_expr(); this.state = 917; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,124,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 913; this.match(Python3Parser.COMMA); this.state = 914; this.star_expr(); } this.state = 919; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,124,this._ctx); } this.state = 921; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 920; this.match(Python3Parser.COMMA); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function TestlistContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_testlist; return this; } TestlistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); TestlistContext.prototype.constructor = TestlistContext; TestlistContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; TestlistContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterTestlist(this); } }; TestlistContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitTestlist(this); } }; TestlistContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitTestlist(this); } else { return visitor.visitChildren(this); } }; Python3Parser.TestlistContext = TestlistContext; Python3Parser.prototype.testlist = function() { var localctx = new TestlistContext(this, this._ctx, this.state); this.enterRule(localctx, 142, Python3Parser.RULE_testlist); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 923; this.test(); this.state = 928; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,126,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 924; this.match(Python3Parser.COMMA); this.state = 925; this.test(); } this.state = 930; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,126,this._ctx); } this.state = 932; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 931; this.match(Python3Parser.COMMA); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function DictorsetmakerContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_dictorsetmaker; return this; } DictorsetmakerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); DictorsetmakerContext.prototype.constructor = DictorsetmakerContext; DictorsetmakerContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; DictorsetmakerContext.prototype.comp_for = function() { return this.getTypedRuleContext(Comp_forContext,0); }; DictorsetmakerContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterDictorsetmaker(this); } }; DictorsetmakerContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitDictorsetmaker(this); } }; DictorsetmakerContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitDictorsetmaker(this); } else { return visitor.visitChildren(this); } }; Python3Parser.DictorsetmakerContext = DictorsetmakerContext; Python3Parser.prototype.dictorsetmaker = function() { var localctx = new DictorsetmakerContext(this, this._ctx, this.state); this.enterRule(localctx, 144, Python3Parser.RULE_dictorsetmaker); var _la = 0; // Token type try { this.state = 967; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,134,this._ctx); switch(la_) { case 1: this.enterOuterAlt(localctx, 1); this.state = 934; this.test(); this.state = 935; this.match(Python3Parser.COLON); this.state = 936; this.test(); this.state = 951; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.FOR: this.state = 937; this.comp_for(); break; case Python3Parser.COMMA: case Python3Parser.CLOSE_BRACE: this.state = 945; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,128,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 938; this.match(Python3Parser.COMMA); this.state = 939; this.test(); this.state = 940; this.match(Python3Parser.COLON); this.state = 941; this.test(); } this.state = 947; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,128,this._ctx); } this.state = 949; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 948; this.match(Python3Parser.COMMA); } break; default: throw new antlr4.error.NoViableAltException(this); } break; case 2: this.enterOuterAlt(localctx, 2); this.state = 953; this.test(); this.state = 965; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.FOR: this.state = 954; this.comp_for(); break; case Python3Parser.COMMA: case Python3Parser.CLOSE_BRACE: this.state = 959; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,131,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 955; this.match(Python3Parser.COMMA); this.state = 956; this.test(); } this.state = 961; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,131,this._ctx); } this.state = 963; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 962; this.match(Python3Parser.COMMA); } break; default: throw new antlr4.error.NoViableAltException(this); } break; } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ClassdefContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_classdef; return this; } ClassdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ClassdefContext.prototype.constructor = ClassdefContext; ClassdefContext.prototype.CLASS = function() { return this.getToken(Python3Parser.CLASS, 0); }; ClassdefContext.prototype.NAME = function() { return this.getToken(Python3Parser.NAME, 0); }; ClassdefContext.prototype.suite = function() { return this.getTypedRuleContext(SuiteContext,0); }; ClassdefContext.prototype.arglist = function() { return this.getTypedRuleContext(ArglistContext,0); }; ClassdefContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterClassdef(this); } }; ClassdefContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitClassdef(this); } }; ClassdefContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitClassdef(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ClassdefContext = ClassdefContext; Python3Parser.prototype.classdef = function() { var localctx = new ClassdefContext(this, this._ctx, this.state); this.enterRule(localctx, 146, Python3Parser.RULE_classdef); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 969; this.match(Python3Parser.CLASS); this.state = 970; this.match(Python3Parser.NAME); this.state = 976; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.OPEN_PAREN) { this.state = 971; this.match(Python3Parser.OPEN_PAREN); this.state = 973; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 20)) & ~0x1f) == 0 && ((1 << (_la - 20)) & ((1 << (Python3Parser.LAMBDA - 20)) | (1 << (Python3Parser.NOT - 20)) | (1 << (Python3Parser.NONE - 20)) | (1 << (Python3Parser.TRUE - 20)) | (1 << (Python3Parser.FALSE - 20)) | (1 << (Python3Parser.NAME - 20)) | (1 << (Python3Parser.STRING_LITERAL - 20)) | (1 << (Python3Parser.BYTES_LITERAL - 20)) | (1 << (Python3Parser.DECIMAL_INTEGER - 20)) | (1 << (Python3Parser.OCT_INTEGER - 20)) | (1 << (Python3Parser.HEX_INTEGER - 20)) | (1 << (Python3Parser.BIN_INTEGER - 20)) | (1 << (Python3Parser.FLOAT_NUMBER - 20)) | (1 << (Python3Parser.IMAG_NUMBER - 20)) | (1 << (Python3Parser.ELLIPSIS - 20)) | (1 << (Python3Parser.STAR - 20)) | (1 << (Python3Parser.OPEN_PAREN - 20)))) !== 0) || ((((_la - 52)) & ~0x1f) == 0 && ((1 << (_la - 52)) & ((1 << (Python3Parser.POWER - 52)) | (1 << (Python3Parser.OPEN_BRACK - 52)) | (1 << (Python3Parser.ADD - 52)) | (1 << (Python3Parser.MINUS - 52)) | (1 << (Python3Parser.NOT_OP - 52)) | (1 << (Python3Parser.OPEN_BRACE - 52)))) !== 0)) { this.state = 972; this.arglist(); } this.state = 975; this.match(Python3Parser.CLOSE_PAREN); } this.state = 978; this.match(Python3Parser.COLON); this.state = 979; this.suite(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ArglistContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_arglist; return this; } ArglistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ArglistContext.prototype.constructor = ArglistContext; ArglistContext.prototype.argument = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(ArgumentContext); } else { return this.getTypedRuleContext(ArgumentContext,i); } }; ArglistContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; ArglistContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterArglist(this); } }; ArglistContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitArglist(this); } }; ArglistContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitArglist(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ArglistContext = ArglistContext; Python3Parser.prototype.arglist = function() { var localctx = new ArglistContext(this, this._ctx, this.state); this.enterRule(localctx, 148, Python3Parser.RULE_arglist); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 986; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,137,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 981; this.argument(); this.state = 982; this.match(Python3Parser.COMMA); } this.state = 988; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,137,this._ctx); } this.state = 1009; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,141,this._ctx); switch(la_) { case 1: this.state = 989; this.argument(); this.state = 991; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 990; this.match(Python3Parser.COMMA); } break; case 2: this.state = 993; this.match(Python3Parser.STAR); this.state = 994; this.test(); this.state = 999; this._errHandler.sync(this); var _alt = this._interp.adaptivePredict(this._input,139,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { if(_alt===1) { this.state = 995; this.match(Python3Parser.COMMA); this.state = 996; this.argument(); } this.state = 1001; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,139,this._ctx); } this.state = 1005; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.COMMA) { this.state = 1002; this.match(Python3Parser.COMMA); this.state = 1003; this.match(Python3Parser.POWER); this.state = 1004; this.test(); } break; case 3: this.state = 1007; this.match(Python3Parser.POWER); this.state = 1008; this.test(); break; } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function ArgumentContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_argument; return this; } ArgumentContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); ArgumentContext.prototype.constructor = ArgumentContext; ArgumentContext.prototype.test = function(i) { if(i===undefined) { i = null; } if(i===null) { return this.getTypedRuleContexts(TestContext); } else { return this.getTypedRuleContext(TestContext,i); } }; ArgumentContext.prototype.comp_for = function() { return this.getTypedRuleContext(Comp_forContext,0); }; ArgumentContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterArgument(this); } }; ArgumentContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitArgument(this); } }; ArgumentContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitArgument(this); } else { return visitor.visitChildren(this); } }; Python3Parser.ArgumentContext = ArgumentContext; Python3Parser.prototype.argument = function() { var localctx = new ArgumentContext(this, this._ctx, this.state); this.enterRule(localctx, 150, Python3Parser.RULE_argument); var _la = 0; // Token type try { this.state = 1019; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,143,this._ctx); switch(la_) { case 1: this.enterOuterAlt(localctx, 1); this.state = 1011; this.test(); this.state = 1013; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.FOR) { this.state = 1012; this.comp_for(); } break; case 2: this.enterOuterAlt(localctx, 2); this.state = 1015; this.test(); this.state = 1016; this.match(Python3Parser.ASSIGN); this.state = 1017; this.test(); break; } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Comp_iterContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_comp_iter; return this; } Comp_iterContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Comp_iterContext.prototype.constructor = Comp_iterContext; Comp_iterContext.prototype.comp_for = function() { return this.getTypedRuleContext(Comp_forContext,0); }; Comp_iterContext.prototype.comp_if = function() { return this.getTypedRuleContext(Comp_ifContext,0); }; Comp_iterContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterComp_iter(this); } }; Comp_iterContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitComp_iter(this); } }; Comp_iterContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitComp_iter(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Comp_iterContext = Comp_iterContext; Python3Parser.prototype.comp_iter = function() { var localctx = new Comp_iterContext(this, this._ctx, this.state); this.enterRule(localctx, 152, Python3Parser.RULE_comp_iter); try { this.state = 1023; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.FOR: this.enterOuterAlt(localctx, 1); this.state = 1021; this.comp_for(); break; case Python3Parser.IF: this.enterOuterAlt(localctx, 2); this.state = 1022; this.comp_if(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Comp_forContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_comp_for; return this; } Comp_forContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Comp_forContext.prototype.constructor = Comp_forContext; Comp_forContext.prototype.FOR = function() { return this.getToken(Python3Parser.FOR, 0); }; Comp_forContext.prototype.exprlist = function() { return this.getTypedRuleContext(ExprlistContext,0); }; Comp_forContext.prototype.IN = function() { return this.getToken(Python3Parser.IN, 0); }; Comp_forContext.prototype.or_test = function() { return this.getTypedRuleContext(Or_testContext,0); }; Comp_forContext.prototype.comp_iter = function() { return this.getTypedRuleContext(Comp_iterContext,0); }; Comp_forContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterComp_for(this); } }; Comp_forContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitComp_for(this); } }; Comp_forContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitComp_for(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Comp_forContext = Comp_forContext; Python3Parser.prototype.comp_for = function() { var localctx = new Comp_forContext(this, this._ctx, this.state); this.enterRule(localctx, 154, Python3Parser.RULE_comp_for); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1025; this.match(Python3Parser.FOR); this.state = 1026; this.exprlist(); this.state = 1027; this.match(Python3Parser.IN); this.state = 1028; this.or_test(); this.state = 1030; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.IF || _la===Python3Parser.FOR) { this.state = 1029; this.comp_iter(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Comp_ifContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_comp_if; return this; } Comp_ifContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Comp_ifContext.prototype.constructor = Comp_ifContext; Comp_ifContext.prototype.IF = function() { return this.getToken(Python3Parser.IF, 0); }; Comp_ifContext.prototype.test_nocond = function() { return this.getTypedRuleContext(Test_nocondContext,0); }; Comp_ifContext.prototype.comp_iter = function() { return this.getTypedRuleContext(Comp_iterContext,0); }; Comp_ifContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterComp_if(this); } }; Comp_ifContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitComp_if(this); } }; Comp_ifContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitComp_if(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Comp_ifContext = Comp_ifContext; Python3Parser.prototype.comp_if = function() { var localctx = new Comp_ifContext(this, this._ctx, this.state); this.enterRule(localctx, 156, Python3Parser.RULE_comp_if); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1032; this.match(Python3Parser.IF); this.state = 1033; this.test_nocond(); this.state = 1035; this._errHandler.sync(this); _la = this._input.LA(1); if(_la===Python3Parser.IF || _la===Python3Parser.FOR) { this.state = 1034; this.comp_iter(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Yield_exprContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_yield_expr; return this; } Yield_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Yield_exprContext.prototype.constructor = Yield_exprContext; Yield_exprContext.prototype.YIELD = function() { return this.getToken(Python3Parser.YIELD, 0); }; Yield_exprContext.prototype.yield_arg = function() { return this.getTypedRuleContext(Yield_argContext,0); }; Yield_exprContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterYield_expr(this); } }; Yield_exprContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitYield_expr(this); } }; Yield_exprContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitYield_expr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Yield_exprContext = Yield_exprContext; Python3Parser.prototype.yield_expr = function() { var localctx = new Yield_exprContext(this, this._ctx, this.state); this.enterRule(localctx, 158, Python3Parser.RULE_yield_expr); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1037; this.match(Python3Parser.YIELD); this.state = 1039; this._errHandler.sync(this); _la = this._input.LA(1); if(((((_la - 4)) & ~0x1f) == 0 && ((1 << (_la - 4)) & ((1 << (Python3Parser.FROM - 4)) | (1 << (Python3Parser.LAMBDA - 4)) | (1 << (Python3Parser.NOT - 4)) | (1 << (Python3Parser.NONE - 4)) | (1 << (Python3Parser.TRUE - 4)) | (1 << (Python3Parser.FALSE - 4)) | (1 << (Python3Parser.NAME - 4)))) !== 0) || ((((_la - 36)) & ~0x1f) == 0 && ((1 << (_la - 36)) & ((1 << (Python3Parser.STRING_LITERAL - 36)) | (1 << (Python3Parser.BYTES_LITERAL - 36)) | (1 << (Python3Parser.DECIMAL_INTEGER - 36)) | (1 << (Python3Parser.OCT_INTEGER - 36)) | (1 << (Python3Parser.HEX_INTEGER - 36)) | (1 << (Python3Parser.BIN_INTEGER - 36)) | (1 << (Python3Parser.FLOAT_NUMBER - 36)) | (1 << (Python3Parser.IMAG_NUMBER - 36)) | (1 << (Python3Parser.ELLIPSIS - 36)) | (1 << (Python3Parser.STAR - 36)) | (1 << (Python3Parser.OPEN_PAREN - 36)) | (1 << (Python3Parser.OPEN_BRACK - 36)) | (1 << (Python3Parser.ADD - 36)) | (1 << (Python3Parser.MINUS - 36)) | (1 << (Python3Parser.NOT_OP - 36)) | (1 << (Python3Parser.OPEN_BRACE - 36)))) !== 0)) { this.state = 1038; this.yield_arg(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function Yield_argContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_yield_arg; return this; } Yield_argContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); Yield_argContext.prototype.constructor = Yield_argContext; Yield_argContext.prototype.FROM = function() { return this.getToken(Python3Parser.FROM, 0); }; Yield_argContext.prototype.test = function() { return this.getTypedRuleContext(TestContext,0); }; Yield_argContext.prototype.testlist = function() { return this.getTypedRuleContext(TestlistContext,0); }; Yield_argContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterYield_arg(this); } }; Yield_argContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitYield_arg(this); } }; Yield_argContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitYield_arg(this); } else { return visitor.visitChildren(this); } }; Python3Parser.Yield_argContext = Yield_argContext; Python3Parser.prototype.yield_arg = function() { var localctx = new Yield_argContext(this, this._ctx, this.state); this.enterRule(localctx, 160, Python3Parser.RULE_yield_arg); try { this.state = 1044; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.FROM: this.enterOuterAlt(localctx, 1); this.state = 1041; this.match(Python3Parser.FROM); this.state = 1042; this.test(); break; case Python3Parser.LAMBDA: case Python3Parser.NOT: case Python3Parser.NONE: case Python3Parser.TRUE: case Python3Parser.FALSE: case Python3Parser.NAME: case Python3Parser.STRING_LITERAL: case Python3Parser.BYTES_LITERAL: case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: case Python3Parser.FLOAT_NUMBER: case Python3Parser.IMAG_NUMBER: case Python3Parser.ELLIPSIS: case Python3Parser.STAR: case Python3Parser.OPEN_PAREN: case Python3Parser.OPEN_BRACK: case Python3Parser.ADD: case Python3Parser.MINUS: case Python3Parser.NOT_OP: case Python3Parser.OPEN_BRACE: this.enterOuterAlt(localctx, 2); this.state = 1043; this.testlist(); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function StrContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_str; return this; } StrContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); StrContext.prototype.constructor = StrContext; StrContext.prototype.STRING_LITERAL = function() { return this.getToken(Python3Parser.STRING_LITERAL, 0); }; StrContext.prototype.BYTES_LITERAL = function() { return this.getToken(Python3Parser.BYTES_LITERAL, 0); }; StrContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterStr(this); } }; StrContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitStr(this); } }; StrContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitStr(this); } else { return visitor.visitChildren(this); } }; Python3Parser.StrContext = StrContext; Python3Parser.prototype.str = function() { var localctx = new StrContext(this, this._ctx, this.state); this.enterRule(localctx, 162, Python3Parser.RULE_str); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1046; _la = this._input.LA(1); if(!(_la===Python3Parser.STRING_LITERAL || _la===Python3Parser.BYTES_LITERAL)) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function NumberContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_number; return this; } NumberContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); NumberContext.prototype.constructor = NumberContext; NumberContext.prototype.integer = function() { return this.getTypedRuleContext(IntegerContext,0); }; NumberContext.prototype.FLOAT_NUMBER = function() { return this.getToken(Python3Parser.FLOAT_NUMBER, 0); }; NumberContext.prototype.IMAG_NUMBER = function() { return this.getToken(Python3Parser.IMAG_NUMBER, 0); }; NumberContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterNumber(this); } }; NumberContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitNumber(this); } }; NumberContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitNumber(this); } else { return visitor.visitChildren(this); } }; Python3Parser.NumberContext = NumberContext; Python3Parser.prototype.number = function() { var localctx = new NumberContext(this, this._ctx, this.state); this.enterRule(localctx, 164, Python3Parser.RULE_number); try { this.state = 1051; this._errHandler.sync(this); switch(this._input.LA(1)) { case Python3Parser.DECIMAL_INTEGER: case Python3Parser.OCT_INTEGER: case Python3Parser.HEX_INTEGER: case Python3Parser.BIN_INTEGER: this.enterOuterAlt(localctx, 1); this.state = 1048; this.integer(); break; case Python3Parser.FLOAT_NUMBER: this.enterOuterAlt(localctx, 2); this.state = 1049; this.match(Python3Parser.FLOAT_NUMBER); break; case Python3Parser.IMAG_NUMBER: this.enterOuterAlt(localctx, 3); this.state = 1050; this.match(Python3Parser.IMAG_NUMBER); break; default: throw new antlr4.error.NoViableAltException(this); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; function IntegerContext(parser, parent, invokingState) { if(parent===undefined) { parent = null; } if(invokingState===undefined || invokingState===null) { invokingState = -1; } antlr4.ParserRuleContext.call(this, parent, invokingState); this.parser = parser; this.ruleIndex = Python3Parser.RULE_integer; return this; } IntegerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype); IntegerContext.prototype.constructor = IntegerContext; IntegerContext.prototype.DECIMAL_INTEGER = function() { return this.getToken(Python3Parser.DECIMAL_INTEGER, 0); }; IntegerContext.prototype.OCT_INTEGER = function() { return this.getToken(Python3Parser.OCT_INTEGER, 0); }; IntegerContext.prototype.HEX_INTEGER = function() { return this.getToken(Python3Parser.HEX_INTEGER, 0); }; IntegerContext.prototype.BIN_INTEGER = function() { return this.getToken(Python3Parser.BIN_INTEGER, 0); }; IntegerContext.prototype.enterRule = function(listener) { if(listener instanceof Python3Listener ) { listener.enterInteger(this); } }; IntegerContext.prototype.exitRule = function(listener) { if(listener instanceof Python3Listener ) { listener.exitInteger(this); } }; IntegerContext.prototype.accept = function(visitor) { if ( visitor instanceof Python3Visitor ) { return visitor.visitInteger(this); } else { return visitor.visitChildren(this); } }; Python3Parser.IntegerContext = IntegerContext; Python3Parser.prototype.integer = function() { var localctx = new IntegerContext(this, this._ctx, this.state); this.enterRule(localctx, 166, Python3Parser.RULE_integer); var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); this.state = 1053; _la = this._input.LA(1); if(!(((((_la - 38)) & ~0x1f) == 0 && ((1 << (_la - 38)) & ((1 << (Python3Parser.DECIMAL_INTEGER - 38)) | (1 << (Python3Parser.OCT_INTEGER - 38)) | (1 << (Python3Parser.HEX_INTEGER - 38)) | (1 << (Python3Parser.BIN_INTEGER - 38)))) !== 0))) { this._errHandler.recoverInline(this); } else { this._errHandler.reportMatch(this); this.consume(); } } catch (re) { if(re instanceof antlr4.error.RecognitionException) { localctx.exception = re; this._errHandler.reportError(this, re); this._errHandler.recover(this, re); } else { throw re; } } finally { this.exitRule(); } return localctx; }; exports.Python3Parser = Python3Parser; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Visitor.js ================================================ // Generated from ./lang/python/Python3.g4 by ANTLR 4.7 // jshint ignore: start var antlr4 = require('antlr4/index'); // This class defines a complete generic visitor for a parse tree produced by Python3Parser. function Python3Visitor() { antlr4.tree.ParseTreeVisitor.call(this); return this; } Python3Visitor.prototype = Object.create(antlr4.tree.ParseTreeVisitor.prototype); Python3Visitor.prototype.constructor = Python3Visitor; // Visit a parse tree produced by Python3Parser#single_input. Python3Visitor.prototype.visitSingle_input = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#file_input. Python3Visitor.prototype.visitFile_input = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#eval_input. Python3Visitor.prototype.visitEval_input = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#decorator. Python3Visitor.prototype.visitDecorator = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#decorators. Python3Visitor.prototype.visitDecorators = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#decorated. Python3Visitor.prototype.visitDecorated = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#funcdef. Python3Visitor.prototype.visitFuncdef = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#parameters. Python3Visitor.prototype.visitParameters = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#typedargslist. Python3Visitor.prototype.visitTypedargslist = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#tfpdef. Python3Visitor.prototype.visitTfpdef = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#varargslist. Python3Visitor.prototype.visitVarargslist = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#vfpdef. Python3Visitor.prototype.visitVfpdef = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#stmt. Python3Visitor.prototype.visitStmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#simple_stmt. Python3Visitor.prototype.visitSimple_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#small_stmt. Python3Visitor.prototype.visitSmall_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#expr_stmt. Python3Visitor.prototype.visitExpr_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#testlist_star_expr. Python3Visitor.prototype.visitTestlist_star_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#augassign. Python3Visitor.prototype.visitAugassign = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#del_stmt. Python3Visitor.prototype.visitDel_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#pass_stmt. Python3Visitor.prototype.visitPass_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#flow_stmt. Python3Visitor.prototype.visitFlow_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#break_stmt. Python3Visitor.prototype.visitBreak_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#continue_stmt. Python3Visitor.prototype.visitContinue_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#return_stmt. Python3Visitor.prototype.visitReturn_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#yield_stmt. Python3Visitor.prototype.visitYield_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#raise_stmt. Python3Visitor.prototype.visitRaise_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#import_stmt. Python3Visitor.prototype.visitImport_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#import_name. Python3Visitor.prototype.visitImport_name = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#import_from. Python3Visitor.prototype.visitImport_from = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#import_as_name. Python3Visitor.prototype.visitImport_as_name = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#dotted_as_name. Python3Visitor.prototype.visitDotted_as_name = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#import_as_names. Python3Visitor.prototype.visitImport_as_names = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#dotted_as_names. Python3Visitor.prototype.visitDotted_as_names = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#dotted_name. Python3Visitor.prototype.visitDotted_name = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#global_stmt. Python3Visitor.prototype.visitGlobal_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#nonlocal_stmt. Python3Visitor.prototype.visitNonlocal_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#assert_stmt. Python3Visitor.prototype.visitAssert_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#compound_stmt. Python3Visitor.prototype.visitCompound_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#if_stmt. Python3Visitor.prototype.visitIf_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#while_stmt. Python3Visitor.prototype.visitWhile_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#for_stmt. Python3Visitor.prototype.visitFor_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#try_stmt. Python3Visitor.prototype.visitTry_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#with_stmt. Python3Visitor.prototype.visitWith_stmt = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#with_item. Python3Visitor.prototype.visitWith_item = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#except_clause. Python3Visitor.prototype.visitExcept_clause = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#suite. Python3Visitor.prototype.visitSuite = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#test. Python3Visitor.prototype.visitTest = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#test_nocond. Python3Visitor.prototype.visitTest_nocond = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#lambdef. Python3Visitor.prototype.visitLambdef = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#lambdef_nocond. Python3Visitor.prototype.visitLambdef_nocond = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#or_test. Python3Visitor.prototype.visitOr_test = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#and_test. Python3Visitor.prototype.visitAnd_test = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#not_test. Python3Visitor.prototype.visitNot_test = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#comparison. Python3Visitor.prototype.visitComparison = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#comp_op. Python3Visitor.prototype.visitComp_op = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#star_expr. Python3Visitor.prototype.visitStar_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#expr. Python3Visitor.prototype.visitExpr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#xor_expr. Python3Visitor.prototype.visitXor_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#and_expr. Python3Visitor.prototype.visitAnd_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#shift_expr. Python3Visitor.prototype.visitShift_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#arith_expr. Python3Visitor.prototype.visitArith_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#term. Python3Visitor.prototype.visitTerm = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#factor. Python3Visitor.prototype.visitFactor = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#power. Python3Visitor.prototype.visitPower = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#atom. Python3Visitor.prototype.visitAtom = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#testlist_comp. Python3Visitor.prototype.visitTestlist_comp = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#trailer. Python3Visitor.prototype.visitTrailer = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#subscriptlist. Python3Visitor.prototype.visitSubscriptlist = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#subscript. Python3Visitor.prototype.visitSubscript = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#sliceop. Python3Visitor.prototype.visitSliceop = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#exprlist. Python3Visitor.prototype.visitExprlist = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#testlist. Python3Visitor.prototype.visitTestlist = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#dictorsetmaker. Python3Visitor.prototype.visitDictorsetmaker = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#classdef. Python3Visitor.prototype.visitClassdef = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#arglist. Python3Visitor.prototype.visitArglist = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#argument. Python3Visitor.prototype.visitArgument = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#comp_iter. Python3Visitor.prototype.visitComp_iter = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#comp_for. Python3Visitor.prototype.visitComp_for = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#comp_if. Python3Visitor.prototype.visitComp_if = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#yield_expr. Python3Visitor.prototype.visitYield_expr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#yield_arg. Python3Visitor.prototype.visitYield_arg = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#str. Python3Visitor.prototype.visitStr = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#number. Python3Visitor.prototype.visitNumber = function(ctx) { return this.visitChildren(ctx); }; // Visit a parse tree produced by Python3Parser#integer. Python3Visitor.prototype.visitInteger = function(ctx) { return this.visitChildren(ctx); }; exports.Python3Visitor = Python3Visitor; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/index.js ================================================ exports.Python3Lexer = require('./lang/python/Python3Lexer'); exports.Python3Listener = require('./lang/prpythonesto/Python3Listener'); exports.Python3Parser = require('./lang/python/Python3Parser'); exports.Python3Visitor = require('./lang/python/Python3Visitor'); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/index.ts ================================================ import {PythonWebWorkerMngr} from './web-worker/web-worker-manager'; export {PythonWebWorkerMngr}; declare var window: any; if (typeof window !== 'undefined') { window.biPythonParser = {PythonWebWorkerMngr}; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/parser/errors-listener.ts ================================================ import * as antlr4 from 'antlr4'; export interface IErrorAnnotation { row: number; column: number; text: string; type: string; } export class PythonErrorListener extends antlr4.error.ErrorListener { private readonly annotations: IErrorAnnotation[] = []; getErrors = () => this.annotations; syntaxError(recognizer, offendingSymbol, line, column, msg, e) { this.annotations.push({ row: line - 1, column, text: msg, type: 'error' }); } } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/parser/index.ts ================================================ import {Python3Parser} from '../../python-grammar/lang/python/Python3Parser'; import {createTokenizer} from '../tokenizer/index'; import {PythonErrorListener, IErrorAnnotation} from './errors-listener'; export const createParser = (input: string): any => { const tokens = createTokenizer(input); return new Python3Parser(tokens); }; export const getPythonErrors = (input: string) => { const parser = createParser(input); const listener = new PythonErrorListener(); parser.removeErrorListeners(); parser.addErrorListener(listener); parser.file_input(); return listener.getErrors(); }; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/parser/parser.spec.ts ================================================ import {expect} from 'chai'; import {getPythonErrors} from './'; describe('python parser', () => { it('should pass leagal code:', () => { const code = ` def greet(name): print ('Hello', name) greet('Jack') greet('Jill') greet('Bob') `; const errors = getPythonErrors(code); expect(errors).to.eqls([]); }); it('should handle indent error:', () => { const code = ` def greet(name): print ('Hello', name) greet('Jack') greet('Jill') greet('Bob') `; const errors = getPythonErrors(code); expect(errors.length).to.be.greaterThan(0); expect(errors[0]).to.eql({column: 0, row: 2, text: `missing INDENT at 'print'`, type: 'error'}); }); }); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/parser/types.ts ================================================ export interface ContextNode { children: Array; exception: any; invokingState: number; parentCtx: ContextNode; parser: any; ruleIndex: number; start: CommonToken; stop: CommonToken; } export interface Terminal { invokingState: number; parentCtx: ContextNode; symbol: CommonToken; } export interface CommonToken { channel: number; column: number; line: number; start: number; stop: number; source: any[]; tokenIndex: number; type: number; //token type from SqlBase.tokens text: string; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/tokenizer/index.ts ================================================ import antlr4 from 'antlr4'; import {Python3Lexer} from '../../python-grammar/lang/python/Python3Lexer'; import last from 'lodash/last'; import {CommonToken} from '../types/index'; export const createTokenizer = (input: string) => { const stream = new antlr4.InputStream(input); const lexer = new Python3Lexer(stream); const tokenizer = new antlr4.CommonTokenStream(lexer); return tokenizer; }; const generateTokens = (tokenizer: any) => { do { tokenizer.consume(); } while (last(tokenizer.tokens).type !== -1); return tokenizer.tokens as CommonToken[]; }; export function tokenize(input: string) { const tokenizer = createTokenizer(input); return generateTokens(tokenizer); } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/types/3rd-party.d.ts ================================================ declare module 'antlr4' { const _a: any; export = _a; } declare module 'tiny-worker' { export = Worker; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/types/index.ts ================================================ export type TokensMap = number; export interface CommonToken { channel: number; column: number; line: number; start: number; stop: number; source: any[]; tokenIndex: number; type: TokensMap; text: string; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/types.ts ================================================ import {WorkerFunctionsMap, RequestTypeToResponseTypeMap} from '../../../web-worker-infra/web-worker'; import {IErrorAnnotation} from '../parser/errors-listener'; export interface WorkerRequest { 'getErrors': string; } export interface WorkerResponse { 'errorsDone': IErrorAnnotation[]; } export interface RequestToResponseMap { 'getErrors': 'errorsDone'; } export const RequestToResponseMap: WorkerRqstToResposneMapType = { getErrors: 'errorsDone' }; export type WorkerRqstToResposneMapType = RequestTypeToResponseTypeMap; export type PythonWorkerFunctionsMap = WorkerFunctionsMap; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/web-worker-entry.ts ================================================ import webWorkerFunc from './web-worker'; /* tslint:disable */ webWorkerFunc(self as any); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/web-worker-manager.ts ================================================ import { WorkerRequest, RequestToResponseMap, WorkerResponse } from './types'; import {TypedWorkerManager} from '../../../web-worker-infra/web-worker-manager'; export class PythonWebWorkerMngr extends TypedWorkerManager { getErrors(pythonCode: string) { return this.sendMsg({type: 'getErrors', data: pythonCode}); } } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/web-worker.ts ================================================ import { WorkerRequest, RequestToResponseMap, WorkerResponse, PythonWorkerFunctionsMap } from './types'; import {getPythonErrors} from '../parser/index'; import {TypedWorkerFactory} from '../../../web-worker-infra/web-worker'; const functionMap: PythonWorkerFunctionsMap = { getErrors: getPythonErrors, }; const pythonWorker = TypedWorkerFactory(RequestToResponseMap, functionMap); export default pythonWorker; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/auto-format/index.ts ================================================ import SqlFormatter from 'sql-formatter/lib/languages/StandardSqlFormatter.js'; export const formatSql = (query: string) => new SqlFormatter().format(query); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/index.ts ================================================ import {BiSqlWebWorkerMngr} from './web-worker/web-worker-manager'; export {BiSqlWebWorkerMngrCtor, BiSqlWebWorkerMngr} from './web-worker/web-worker-manager'; declare var window: any; if (typeof window !== 'undefined') { window.biSqlParser = {BiSqlWebWorkerMngr}; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/parser/errors-listener.ts ================================================ import antlr4 from 'antlr4'; export interface IErrorAnnotation { row: number; column: number; text: string; type: string; } export class PrestoErrorListener extends antlr4.error.ErrorListener { private readonly annotations: IErrorAnnotation[] = []; getErrors = () => this.annotations; syntaxError(recognizer, offendingSymbol, line, column, msg, e) { this.annotations.push({ row: line - 1, column, text: msg, type: 'error' }); } } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/parser/index.ts ================================================ import antlr4 from 'antlr4'; import { SqlBaseParser } from '../../presto-grammar'; import { createTokenizer } from '../tokenizer/index'; import { PrestoListener } from './presto-listener'; import { PrestoErrorListener } from './errors-listener'; export const createParser = (input: string): any => { const tokens = createTokenizer(input); return new SqlBaseParser(tokens); }; export const createPrestoSyntaxTree = (input: string): any => { const parser = createParser(input); parser.removeErrorListeners(); return parser.multiStatement(); }; export const parsePrestoSql = (input: string) => { const tree = createPrestoSyntaxTree(input); const prestoListener = new PrestoListener(); antlr4.tree.ParseTreeWalker.DEFAULT.walk(prestoListener, tree); return prestoListener.parseResults(); }; export const getErrorsPrestoSql = (input: string) => { const parser = createParser(input); const listener = new PrestoErrorListener(); parser.removeErrorListeners(); parser.addErrorListener(listener); parser.multiStatement(); return listener.getErrors(); }; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/parser/parser.spec.ts ================================================ import {expect} from 'chai'; import {parsePrestoSql, getErrorsPrestoSql} from './'; describe('presto sql basic parser', () => { const defaultTestCase = `select foo,bar from table111 where foo = 'value'`; it('should get table name', () => { const results = parsePrestoSql(defaultTestCase); expect(results.tables).to.deep.equal(['table111']); }); it('should get *qualified* table name', () => { const testCase = `select foo,bar from catalog1.table1 where foo = 'value'`; const results = parsePrestoSql(testCase); expect(results.tables).to.deep.equal(['catalog1.table1']); }); it('should get column name', () => { const results = parsePrestoSql(defaultTestCase); expect(results.columns).to.deep.equal(['foo', 'bar']); }); it('should get column name, column is qualified name', () => { const results = parsePrestoSql('select foo.bar from sometable where base.col > 4'); expect(results.columns).to.deep.equal(['foo.bar', 'base.col']); }); it('should have no duplicates', () => { const testcase = `select foo,bar from table111 where foo = 'value' and bar = 'value'`; const results = parsePrestoSql(testcase); expect(results.strings).to.deep.equal([`'value'`]); }); it('should get subqueries', () => { const testcase = `WITH x AS (SELECT a, MAX(b) AS b FROM t GROUP BY a) SELECT a, b FROM x`; const results = parsePrestoSql(testcase); expect(results.subQueries).to.deep.equal(['x']); expect(results.tables).to.deep.equal(['t']); }); it('should get subqueries, sql not valid', () => { const testcase = `WITH x AS (SELECT a`; const results = parsePrestoSql(testcase); expect(results.subQueries).to.deep.equal(['x']); expect(results.columns).to.deep.equal(['a']); }); it('should parse multiple queries', () => { const testcase = `select foo from bar; select aa from bb;`; const results = parsePrestoSql(testcase); expect(results.tables).to.deep.equal(['bar', 'bb']); }); it('should parse alias table', () => { const testcase = `select foo from bar as b; select aa from aaa as a;`; const results = parsePrestoSql(testcase); expect(results.tableAlias).to.deep.equal(['b', 'a']); }); describe('string constants', () => { it('should get string constants', () => { const results = parsePrestoSql(defaultTestCase); expect(results.strings).to.deep.equal([`'value'`]); }); it('should get string constants 2', () => { const testcase = `select evid evid_open ,esi esi_open , uuid uuid_open , date_created date_open from users_38 where ((evid = 429)) and date_created between date '2017-03-01' and current_date`; const results = parsePrestoSql(testcase); expect(results.strings).to.deep.equal([`'2017-03-01'`]); }); }); }); describe('error annotation', () => { const testcase = ` select * from where a > 4 `; it('should get errors', () => { const errors = getErrorsPrestoSql(testcase); expect(errors.length).to.be.at.least(1); expect(errors[0].row).to.be.eq(1); expect(errors[0].text).to.contain('extraneous input \'where\' expecting'); }); it('should get errors, query with new lines', () => { const errors = getErrorsPrestoSql(`select * from b where a > 4; select foo from where a > 5; `); expect(errors.length).to.be.at.least(1); expect(errors[0].row).to.be.eq(7); expect(errors[0].text).to.contain('extraneous input \'where\' expecting'); }); }); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/parser/presto-listener.ts ================================================ import { SqlBaseListener } from '../../presto-grammar'; import { ContextNode, Terminal } from './types'; export class PrestoListener extends SqlBaseListener { private readonly strings: Set = new Set(); private readonly tables: Set = new Set(); private readonly columns: Set = new Set(); private readonly subQueries: Set = new Set(); private readonly tableAlias: Set = new Set(); private allowColumnReference = true; parseResults() { const strings = [...this.strings]; const columns = [...this.columns]; const subQueries = [...this.subQueries]; for (const sq of subQueries) { this.tables.delete(sq); } const tables = [...this.tables]; const tableAlias = [...this.tableAlias]; return { strings, tables, columns, subQueries, tableAlias }; } enterStringLiteral(ctx: ContextNode & { children: [Terminal] }) { this.strings.add(ctx.children[0].symbol.text); } enterTableName(ctx: ContextNode) { this.tables.add((ctx as any).qualifiedName().getText()); } enterColumnReference(ctx: ContextNode) { if (this.allowColumnReference) { this.columns.add(ctx.start.text); } } enterDereference(ctx: ContextNode) { this.columns.add((ctx as any).getText()); this.allowColumnReference = false; } exitDereference(ctx: ContextNode) { this.allowColumnReference = true; } enterNamedQuery(ctx: ContextNode) { this.subQueries.add((ctx as any).identifier().getText()); } enterAliasedRelation(ctx: any) { if (ctx.alias) { this.tableAlias.add(ctx.alias.getText()); } } enterSelectSingle(ctx: any) { const identifier = ctx.identifier(); if (identifier) { this.columns.add(identifier.getText()); } } enterTypeConstructor(ctx: any) { this.strings.add(ctx.STRING().getText()); } } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/parser/types.ts ================================================ export interface ContextNode { children: (ContextNode | Terminal)[]; exception: any; invokingState: number; parentCtx: ContextNode; parser: any; ruleIndex: number; start: CommonToken; stop: CommonToken; } export interface Terminal { invokingState: number; parentCtx: ContextNode; symbol: CommonToken; } export interface CommonToken { channel: number; column: number; line: number; start: number; stop: number; source: any[]; tokenIndex: number; type: number; //token type from SqlBase.tokens text: string; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/tokenizer/index.ts ================================================ import { TokensMap } from './tokensMap'; import antlr4 from 'antlr4'; import { SqlBaseLexer } from '../../presto-grammar'; import { last, mapValues } from 'lodash'; import { CommonToken } from '../types/index'; export const createTokenizer = (input: string) => { const stream = new antlr4.InputStream(input); const lexer = new SqlBaseLexer(stream); const tokenizer = new antlr4.CommonTokenStream(lexer); return tokenizer; }; const generateTokens = (tokenizer: any) => { do { tokenizer.consume(); } while (last(tokenizer.tokens).type !== -1); return tokenizer.tokens as CommonToken[]; }; export function tokenize(input: string) { const tokenizer = createTokenizer(input); return generateTokens(tokenizer); } export interface GetIdentifersResult { identifiers: string[]; strings: string[]; } const TokenTypeToPropNameMap = new Map([ [TokensMap.IDENTIFIER, 'identifiers'], [TokensMap.STRING, 'strings'], ]); export function getIdentifiers(tokens: CommonToken[]): GetIdentifersResult { const res = { identifiers: {}, strings: {} }; tokens.forEach((token) => { const prop = TokenTypeToPropNameMap.get(token.type); if (prop) { res[prop][token.text] = true; } }); return mapValues(res, (t) => Object.keys(t)) as any; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/tokenizer/tokenizer.spec.ts ================================================ import {expect} from 'chai'; import {tokenize, getIdentifiers} from './'; describe('presto sql tokenizer', () => { const testCase1 = `select foo,bar from table111 where bla = 'value'`; const testCase2 = `select foo,bar from table111 where foo = 'value'`; it('should return identifiers and strings', () => { const tokens = tokenize(testCase1); const identifersAndStrings = getIdentifiers(tokens); expect(identifersAndStrings.identifiers).to.eql(['foo', 'bar', 'table111', 'bla']); expect(identifersAndStrings.strings).to.eql([`'value'`]); }); it('should return a list without duplicates', () => { const tokens = tokenize(testCase2); const identifersAndStrings = getIdentifiers(tokens); expect(identifersAndStrings.identifiers).to.eql(['foo', 'bar', 'table111']); }); }); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/tokenizer/tokensMap.ts ================================================ export enum TokensMap { EOF = -1, T__0 = 1, T__1 = 2, T__2 = 3, T__3 = 4, T__4 = 5, T__5 = 6, T__6 = 7, T__7 = 8, T__8 = 9, SELECT = 10, FROM = 11, ADD = 12, AS = 13, ALL = 14, SOME = 15, ANY = 16, DISTINCT = 17, WHERE = 18, GROUP = 19, BY = 20, GROUPING = 21, SETS = 22, CUBE = 23, ROLLUP = 24, ORDER = 25, HAVING = 26, LIMIT = 27, AT = 28, OR = 29, AND = 30, IN = 31, NOT = 32, NO = 33, EXISTS = 34, BETWEEN = 35, LIKE = 36, IS = 37, NULL = 38, TRUE = 39, FALSE = 40, NULLS = 41, FIRST = 42, LAST = 43, ESCAPE = 44, ASC = 45, DESC = 46, SUBSTRING = 47, POSITION = 48, FOR = 49, TINYINT = 50, SMALLINT = 51, INTEGER = 52, DATE = 53, TIME = 54, TIMESTAMP = 55, INTERVAL = 56, YEAR = 57, MONTH = 58, DAY = 59, HOUR = 60, MINUTE = 61, SECOND = 62, ZONE = 63, CURRENT_DATE = 64, CURRENT_TIME = 65, CURRENT_TIMESTAMP = 66, LOCALTIME = 67, LOCALTIMESTAMP = 68, EXTRACT = 69, CASE = 70, WHEN = 71, THEN = 72, ELSE = 73, END = 74, JOIN = 75, CROSS = 76, OUTER = 77, INNER = 78, LEFT = 79, RIGHT = 80, FULL = 81, NATURAL = 82, USING = 83, ON = 84, FILTER = 85, OVER = 86, PARTITION = 87, RANGE = 88, ROWS = 89, UNBOUNDED = 90, PRECEDING = 91, FOLLOWING = 92, CURRENT = 93, ROW = 94, WITH = 95, RECURSIVE = 96, VALUES = 97, CREATE = 98, SCHEMA = 99, TABLE = 100, VIEW = 101, REPLACE = 102, INSERT = 103, DELETE = 104, INTO = 105, CONSTRAINT = 106, DESCRIBE = 107, GRANT = 108, REVOKE = 109, PRIVILEGES = 110, PUBLIC = 111, OPTION = 112, EXPLAIN = 113, ANALYZE = 114, FORMAT = 115, TYPE = 116, TEXT = 117, GRAPHVIZ = 118, LOGICAL = 119, DISTRIBUTED = 120, CAST = 121, TRY_CAST = 122, SHOW = 123, TABLES = 124, SCHEMAS = 125, CATALOGS = 126, COLUMNS = 127, COLUMN = 128, USE = 129, PARTITIONS = 130, FUNCTIONS = 131, DROP = 132, UNION = 133, EXCEPT = 134, INTERSECT = 135, TO = 136, SYSTEM = 137, BERNOULLI = 138, POISSONIZED = 139, TABLESAMPLE = 140, ALTER = 141, RENAME = 142, UNNEST = 143, ORDINALITY = 144, ARRAY = 145, MAP = 146, SET = 147, RESET = 148, SESSION = 149, DATA = 150, START = 151, TRANSACTION = 152, COMMIT = 153, ROLLBACK = 154, WORK = 155, ISOLATION = 156, LEVEL = 157, SERIALIZABLE = 158, REPEATABLE = 159, COMMITTED = 160, UNCOMMITTED = 161, READ = 162, WRITE = 163, ONLY = 164, CALL = 165, PREPARE = 166, DEALLOCATE = 167, EXECUTE = 168, INPUT = 169, OUTPUT = 170, CASCADE = 171, RESTRICT = 172, INCLUDING = 173, EXCLUDING = 174, PROPERTIES = 175, NORMALIZE = 176, NFD = 177, NFC = 178, NFKD = 179, NFKC = 180, IF = 181, NULLIF = 182, COALESCE = 183, EQ = 184, NEQ = 185, LT = 186, LTE = 187, GT = 188, GTE = 189, PLUS = 190, MINUS = 191, ASTERISK = 192, SLASH = 193, PERCENT = 194, CONCAT = 195, STRING = 196, BINARY_LITERAL = 197, INTEGER_VALUE = 198, DECIMAL_VALUE = 199, IDENTIFIER = 200, DIGIT_IDENTIFIER = 201, QUOTED_IDENTIFIER = 202, BACKQUOTED_IDENTIFIER = 203, TIME_WITH_TIME_ZONE = 204, TIMESTAMP_WITH_TIME_ZONE = 205, DOUBLE_PRECISION = 206, SIMPLE_COMMENT = 207, BRACKETED_COMMENT = 208, WS = 209, UNRECOGNIZED = 210, DELIMITER = 211, '.' = 1, '(' = 2, ',' = 3, ')' = 4, '?' = 5, '->' = 6, '[' = 7, ']' = 8, '=>' = 9, '=' = 184, '<' = 186, '<=' = 187, '>' = 188, '>=' = 189, '+' = 190, '-' = 191, '*' = 192, '/' = 193, '%' = 194, '||' = 195, } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/types/3rd-party.d.ts ================================================ declare module 'antlr4'; declare module 'tiny-worker' { export = Worker; } declare module 'sql-formatter/lib/languages/StandardSqlFormatter.js' { export interface SqlFormatterCfg { indent?: number; params?: Record } export default class StandardSqlFormatter { constructor(cfg?: SqlFormatterCfg); format(query: string): string; } } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/types/index.ts ================================================ import {TokensMap} from '../tokenizer/tokensMap'; export interface CommonToken { channel: number; column: number; line: number; start: number; stop: number; source: any[]; tokenIndex: number; type: TokensMap; //token type from SqlBase.tokens text: string; } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/types.ts ================================================ import {WorkerFunctionsMap, RequestTypeToResponseTypeMap} from '../../../web-worker-infra/web-worker'; import {IErrorAnnotation} from '../parser/errors-listener'; export interface SqlRequest { 'getIdentifiers': string, 'parse': string; 'getErrors': string; 'autoFormat': string; } export interface SqlResponse { 'getIdentifiersDone': {identifiers: string[]; strings: string[]}; 'parseDone': {strings: string[]; tables: string[]; subQueries: string[]; columns: string[]}; 'errorsDone': IErrorAnnotation[]; 'autoFormatDone': string; } export interface RequestToResponseMap { 'getIdentifiers': 'getIdentifiersDone'; 'parse': 'parseDone'; 'getErrors': 'errorsDone'; 'autoFormat': 'autoFormatDone'; } export const RequestToResponseMap: SqlRqstToResposneMapType = { getIdentifiers: 'getIdentifiersDone', parse: 'parseDone', getErrors: 'errorsDone', autoFormat: 'autoFormatDone' }; export type SqlRqstToResposneMapType = RequestTypeToResponseTypeMap; export type SqlWorkerFunctionsMap = WorkerFunctionsMap; ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/web-worker-entry.ts ================================================ import webWorkerFunc from './web-worker'; /* tslint:disable */ webWorkerFunc(self as any); ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/web-worker-manager.ts ================================================ import { SqlRequest, RequestToResponseMap, SqlResponse } from './types'; import {TypedWorkerManager} from '../../../web-worker-infra/web-worker-manager'; export type BiSqlWebWorkerMngrCtor = typeof BiSqlWebWorkerMngr; export class BiSqlWebWorkerMngr extends TypedWorkerManager { getIdentifiers(sqlQuery: string) { return this.sendMsg({type: 'getIdentifiers', data: sqlQuery}); } getErrors(sqlQuery: string) { return this.sendMsg({type: 'getErrors', data: sqlQuery}); } parse(sqlQuery: string) { return this.sendMsg({type: 'parse', data: sqlQuery}); } autoFormat(sqlQuery: string) { return this.sendMsg({type: 'autoFormat', data: sqlQuery}); } } ================================================ FILE: quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/web-worker.ts ================================================ import * as tokenizer from '../tokenizer'; import { SqlRequest, RequestToResponseMap, SqlResponse, SqlWorkerFunctionsMap } from './types'; import {getErrorsPrestoSql, parsePrestoSql} from '../parser/index'; import {TypedWorkerFactory} from '../../../web-worker-infra/web-worker'; import {formatSql} from '../auto-format'; const functionMap: SqlWorkerFunctionsMap = { getErrors: getErrorsPrestoSql, parse: parsePrestoSql, getIdentifiers: (query) => { const tokens = tokenizer.tokenize(query); return tokenizer.getIdentifiers(tokens); }, autoFormat: (query) => formatSql(query) }; const sqlWorker = TypedWorkerFactory(RequestToResponseMap, functionMap); export default sqlWorker; ================================================ FILE: quix-frontend/client/src/lib/runner/bootstrap.ts ================================================ import angular from 'angular'; import 'angular-resource'; import 'angular-sanitize'; import 'ng-csv'; import '../ui'; import '../code-editor'; import '../viz'; export default angular.module('bi.runner', [ 'ngResource', 'ngSanitize', 'ngCsv', 'bi.codeEditor', 'bi.ui', 'bi.viz' ]); ================================================ FILE: quix-frontend/client/src/lib/runner/config/index.ts ================================================ import {Config} from '../../core'; export const config = new Config<{ executeBaseUrl: string; apiBasePath: string; }>(); ================================================ FILE: quix-frontend/client/src/lib/runner/directives/index.ts ================================================ export {default as runner} from './runner/runner'; export {default as sqlRunner} from './sql-runner/sql-runner'; export {default as pythonRunner} from './python-runner/python-runner'; export {default as consoleResult} from './results/console/console-result'; ================================================ FILE: quix-frontend/client/src/lib/runner/directives/python-runner/python-runner-init.ts ================================================ import {last} from 'lodash'; import moment from 'moment'; import {Runner} from '../../services/runner-service'; import {RunnerComponentInstance} from '../runner/runner'; function initConsoleEvents(runner: Runner) { const state = runner.getState(); const events = runner.getEvents(); const id = 'console'; events.register('log', data => { data = {...data, timestamp: moment().format('HH:mm:ss')}; const fields = Object.keys(data); const values = [...fields.map(field => data[field])]; if (!state.getQueryById(id).getFields().length) { events.apply('fields', {id, fields}, {}); } events.apply('row', {id, values}, {}); return data; }); events .append('start', data => { events.apply('query-start', {id}, {}); events.apply('query-details', {id, code: 'console'}, {}); return data; }) .prepend('end', data => { state.getQueryById(id) && events.apply('query-end', {id}, {}); return data; }); } function initResultEvents(runner: Runner) { const state = runner.getState(); const events = runner.getEvents(); events.append('query-start', () => { state.setTotalNumOfQueries(state.getTotalNumOfQueries() + 1); }); events.register('query-details', data => { runner.getState().getQueryById(data.id).setTitle(data.id); return data; }); } function initRunnerComponent(runner: Runner, runnerComponentDeferred: Promise) { runner.on('finish', () => { return runnerComponentDeferred.then(runnerComponent => { if (runner.getTotalNumOfQueries() > 1) { runnerComponent.setCurrentQuery(last(runner.getQueries())); } }); }, true); } export default (runner: Runner, runnerComponentDeferred: Promise) => { initConsoleEvents(runner); initResultEvents(runner); initRunnerComponent(runner, runnerComponentDeferred); } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/python-runner/python-runner.html ================================================ ================================================ FILE: quix-frontend/client/src/lib/runner/directives/python-runner/python-runner.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; @import '../../../ui/assets/css/def/flex.def'; bi-python-runner { @include flex(column); width: 100%; flex-grow: 1; } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/python-runner/python-runner.ts ================================================ import './python-runner.scss'; import template from './python-runner.html'; import {CodeEditorInstance} from '../../../code-editor'; import {createNgModel, initNgScope, inject} from '../../../core'; import createRunner, {Runner} from '../../services/runner-service'; import {attachErrorHandler} from '../../services/syntax-valdator/syntax-validator-service'; import {initPythonWorker} from '../../services/workers/python-parser-worker'; import {RunnerComponentInstance} from '../runner/runner'; import initPythonRunner from './python-runner-init'; function initEditorComponentInstance(scope, editorComponentInstance: CodeEditorInstance, runnerComponentDeferred) { runnerComponentDeferred.then((runnerComponentInstance: RunnerComponentInstance) => { editorComponentInstance.addShortcut('Ctrl-Enter', 'Command-Enter', () => runnerComponentInstance.run(), scope); editorComponentInstance.getSelection() .on('select', text => { scope.vm.selection = text; scope.vm.runnerOptions.buttonText = 'Run selection'; }) .on('deselect', () => { scope.vm.selection = null; scope.vm.runnerOptions.buttonText = null; }); runnerComponentInstance.on('error', (rowNumber, msg) => editorComponentInstance.getAnnotator().showError(rowNumber, msg)); if (editorComponentInstance.getParams().hasParams()) { const code = editorComponentInstance.getParams().formatEmbed({runCustom: true}); createRunner('python', scope) .run(code) .on('finish', (runner: Runner) => { runner.getCurrentQuery().getResults().buffer.forEach(({k, o}) => { const options = JSON.parse(o); editorComponentInstance.getParams().overrideParam(k, {options}); }); }); } }); return editorComponentInstance; } function initRunnerComponentInstance(scope, runnerComponentInstance: RunnerComponentInstance, editorComponentDeferred) { editorComponentDeferred.then((editorComponentInstance: CodeEditorInstance) => { runnerComponentInstance.setRequestTransformer(() => { const params = editorComponentInstance.getParams(); const user = params.format(scope.vm.selection || scope.model.value); const autogenerated = params.formatEmbed(); return `${autogenerated}\n${user}`; }); }); return runnerComponentInstance; } function initRunner(runner: Runner, runnerComponentDeferred, editorComponentDeferred) { runner .on('success', () => editorComponentDeferred.then((editorComponentInstance: CodeEditorInstance) => editorComponentInstance.setValid(true)), true) .on('error', () => editorComponentDeferred.then((editorComponentInstance: CodeEditorInstance) => editorComponentInstance.setValid(false)), true); initPythonRunner(runner, runnerComponentDeferred); } export default () => { return { restrict: 'E', template, require: 'ngModel', scope: { runner: '=', version: '=', type: '=', bprOptions: '=', onEditorLoad: '&', onRunnerLoad: '&', onSave: '&', onRun: '&', onRunnerCreated: '&', onRunnerDestroyed: '&', onParamsShare: '&', downloadFileName: '&', readonly: '=' }, link: { pre(scope, element, attrs, ngModel) { const q = inject('$q'); const runnerComponentDeferred = q.defer(); const editorComponentDeferred = q.defer(); const componentInstances = inject('$q').all({ runnerComponentInstance: runnerComponentDeferred.promise, editorComponentInstance: editorComponentDeferred.promise, }); const modelConf = createNgModel(scope, ngModel) .formatWith(model => ({value: model})) .parseWith(({value}) => value) .watchDeep(true) .then(() => scope.vm.toggle(true)); initNgScope(scope) .withOptions('bprOptions', { focus: false, params: false, autoParams: true, customParams: true, showSyntaxErrors: true, fitContent: false, shareParams: false, autoRun: false, dateFormat: null, }) .withVM({ selection: null, runnerOptions: { buttonText: null }, hint: { run: { enabled: true } }, viz: { $init() { this.queries = this.createItemsVm({ type: null, setCurrent(type) { this.type = type; }, $init() { this.setCurrent('table'); } }); } } }) .withEvents({ onRunnerLoad(instance: RunnerComponentInstance) { runnerComponentDeferred.resolve(initRunnerComponentInstance(scope, instance, editorComponentDeferred.promise)); scope.onRunnerLoad({instance}); }, onEditorLoad(instance: CodeEditorInstance) { editorComponentDeferred.resolve(initEditorComponentInstance(scope, instance, runnerComponentDeferred.promise)); if (!scope.readonly && scope.options.showSyntaxErrors) { attachErrorHandler(initPythonWorker, instance, modelConf).catch(console.error) } scope.onEditorLoad({instance}); }, onRunnerCreated(runner: Runner) { initRunner(runner, runnerComponentDeferred.promise, editorComponentDeferred.promise); scope.vm.hint.run.toggle(false); scope.onRunnerCreated({runner}); }, onRunnerDestroyed(runner) { componentInstances.then(({editorComponentInstance}) => { editorComponentInstance.setValid(null); editorComponentInstance.getAnnotator().hideAll(); }); scope.vm.hint.run.toggle(true); scope.onRunnerDestroyed({runner}); }, onRun(runner) { scope.onRun({runner}); } }); scope.getCtrlKeyName = () => { return navigator.platform === 'MacIntel' ? 'Command' : 'Ctrl'; }; } } }; }; ================================================ FILE: quix-frontend/client/src/lib/runner/directives/results/console/console-result-testkit.ts ================================================ import { Testkit } from '../../../../../../test/e2e/driver'; const enum Hooks { Result = 'console-result-timestamp', ValueRow = 'console-result-value-row' } export class ConsoleResultTestkit extends Testkit { async getTimestampsCount() { return (await this.query.hooks(Hooks.Result)).length; } async getValueRowsCount() { return (await this.query.hooks(Hooks.ValueRow)).length; } } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/results/console/console-result.html ================================================
{{::row.timestamp}}
    {{::row.line}}
  
================================================ FILE: quix-frontend/client/src/lib/runner/directives/results/console/console-result.scss ================================================ @import '../../../../ui/assets/css/def/colors.def'; @import '../../../../ui/assets/css/def/flex.def'; bi-console-result { @include flex(column); height: 100%; padding: 15px; font-family: 'Courier'; font-size: 12px; color: $white; background-color: $darker-bg; overflow-y: auto; pre { white-space: nowrap; min-height: 17px; } bi-copy-to-clipboard { position: absolute; right: 0; top: 0; } .console-result-timestamp { position: relative; margin: 0 0 12px 0; &:not(:first-child) { margin: 10px 0; } &::after { content: ''; width: 100%; position: absolute; left: 0; top: 50%; z-index: 1; border-top: 1px solid lighten($darker-bg, 20); } .console-result-timestamp-value { $gap-width: 10px; font-size: 0.85em; padding: 1px $gap-width; position: relative; color: lighten($darker-bg, 80); background-color: lighten($darker-bg, 20); z-index: 2; margin-left: $gap-width + 20px; border-radius: 3px; &::before { content: ''; position: absolute; width: $gap-width; height: 100%; background-color: $darker-bg; z-index: 2; left: -$gap-width; } &::after { content: ''; position: absolute; width: $gap-width; height: 100%; background-color: $darker-bg; z-index: 2; right: -$gap-width; } } } } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/results/console/console-result.ts ================================================ import {IScope} from './console-types'; import template from './console-result.html'; import './console-result.scss'; export default () => { return { restrict: 'E', template, scope: { query: '<', }, link: { async pre(scope: IScope) { scope.isTimestampVisible = (timestamp, index, isFirst, isLast) => { return ( isFirst || isLast || scope.query.getResults().buffer[index - 1].timestamp !== timestamp ); }; scope.groupTextByTimestamp = (timestamp) => { return scope.query .getResults() .buffer.filter(r => r.timestamp === timestamp) .map(r => r.line) .join('\n'); }; }, }, }; }; ================================================ FILE: quix-frontend/client/src/lib/runner/directives/results/console/console-types.ts ================================================ import {IScope as ngIScope} from 'angular'; import {RunnerQuery} from '../../..'; export interface IScope extends ngIScope { query: RunnerQuery; } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/runner/runner.html ================================================
file_download
Elapsed time
timer {{vm.result.current.elapsedTime}}
Start time
access_time {{vm.result.current.startTime | biDate:'HH:mm'}}
Rows {{vm.result.current.getResults().bufferSize()}}
{{::query.getTitle()}}
close
sentiment_dissatisfied
No results
file_download
See downloaded file
{{::vm.result.csvFileName}}
warning
{{::query.getError().msg}}
error_outline
{{::options.type | biToHumanCase}} seems to be down at the moment
Please try again in 5 minutes
================================================ FILE: quix-frontend/client/src/lib/runner/directives/runner/runner.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; @import '../../../ui/assets/css/def/flex.def'; @import '../../../ui/assets/css/def/space.def'; bi-runner { @include flex(column); @include space-v__inner(15px !important); width: 100%; flex-grow: 1; overflow: hidden; editor, editor > * { @include flex(column); flex-grow: 1; } .br-run-toggle { min-width: 52px; } .br-custom-actions-toggle { margin-left: -1px; button { width: 30px; padding: 0; } } .br-download-action { width: 30px; padding: 7px; border-radius: 30px !important; } .br-download-action[disabled="disabled"] { i { color: $grey--600; } } .br-tabs { .br-tab { position: relative; max-width: 150px; height: 40px; margin-left: -1px; margin-bottom: -11px; padding: 5px 10px; flex-shrink: 3; line-height: 28px; color: $muted; border: 1px solid $grey--300; background-color: $grey--50; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; &.bi-active { color: $black; background-color: $white !important; border-bottom: $white; } &:hover { color: $black; background-color: $white; } } } .br-result { flex-basis: 300px; > *, result { display: flex; height: 300px; flex-direction: column; .bi-empty-state-content.bi-danger { white-space: pre-wrap; overflow-y: auto; } } &.br-result-with-tabs { margin-top: 10px !important; padding-top: 10px; border-top: 1px solid $grey--300; flex-basis: 311px; } } } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/runner/runner.ts ================================================ import {initNgScope, inject, srv} from '../../../core'; import {default as createRunner} from '../../services/runner-service'; import template from './runner.html'; import './runner.scss'; function downloadFile(url, fileName) { const a = window.document.createElement('A'); a.setAttribute('href', encodeURI(url)); a.setAttribute('type', 'text/csv'); a.setAttribute('target', '_blank'); a.setAttribute('rel', 'noopener noreferrer'); a.setAttribute('download', fileName); // needed for firefox window.document.body.appendChild(a); a.click(); window.document.body.removeChild(a); } function initRunner(scope, instance: RunnerComponentInstance, mode = 'stream') { scope.vm.runner.toggle(true); scope.runner = (scope.runner || createRunner(scope.options.type, scope, { version: scope.version, mode, executeBaseUrl: instance.getExecuteBaseUrl() }) .transformRequest(instance.getDataTransformer()) .transformResponse(instance.getResponseTransformer()) ) .on('queryCreated', (runner, query) => { if (!scope.vm.result.current) { scope.vm.result.setCurrent(query); } query.on('firstResultReceived', () => { scope.vm.result.toggle(true); }); query.on('error', (q, {message}) => { q.setErrorMessage(instance.getErrorTransformer()(runner, q, message)); if (message === 'Presto can\'t be reached, please try later. Underlying exception name is SocketTimeoutException') { scope.vm.result.queries.get(q).errorType = 'timeout'; } scope.vm.result.setCurrent(q); scope.vm.result.toggle(true); }, true); }, true) .on('downloadFile', (url, runner, query) => { downloadFile(url, scope.downloadFileName({query, runner}) || 'export.csv'); }) .on('finish', runner => { scope.vm.runner.toggle(false); if (!runner.getState().getStatus().killed) { scope.vm.result.toggle(true); } }, true); scope.onRunnerCreated({runner: scope.runner, component: instance}); return scope.runner; } function destroyRunner(scope) { kill(scope); scope.onRunnerDestroyed({runner: scope.runner}); scope.runner = null; } function destroyResult(scope) { scope.vm.result.toggle(false); scope.vm.result.reset(); } function destroy(scope) { destroyRunner(scope); destroyResult(scope); } function kill(scope, notify = false) { if (scope.runner) { scope.runner.kill(); if (notify) { scope.onRunnerKilled({runner: scope.runner}); } } scope.vm.runner.toggle(false); } function renderResult(scope, queryScope, query, tableFormatter, transclude) { if (!transclude.isSlotFilled('result')) { queryScope.options = scope.options; queryScope.query = query; queryScope.tableFormatter = tableFormatter; return inject('$compile')(` `)(queryScope); } return transclude((_, _scope) => _scope.query = query, null, 'result'); } export class RunnerComponentInstance extends srv.eventEmitter.EventEmitter { private user; private dataTransformer: Function; private responseTransformer: Function; private errorTransformer: Function = (runner, query, error) => error; private executeBaseUrl: string; constructor(private readonly scope) { super(); } run(mode: 'stream' | 'download' = 'stream') { return this.scope.events.onToggleRun(mode); } getDataTransformer() { return this.dataTransformer; } getResponseTransformer() { return this.responseTransformer; } getErrorTransformer() { return this.errorTransformer; } getExecuteBaseUrl() { return this.executeBaseUrl; } setRequestTransformer(fn: (code) => typeof code) { this.dataTransformer = fn; } setResponseTransformer(fn: (response) => typeof response) { this.responseTransformer = fn; } setErrorTransformer(fn: (runner, query, error) => typeof error) { this.errorTransformer = (runner, query, error) => fn(runner, query, error); } setExecuteBaseUrl(baseUrl: string) { this.executeBaseUrl = baseUrl; } setCurrentQuery(query) { this.scope.vm.result.setCurrent(query); } getCurrentQuery() { return this.scope.vm.result.current; } getUser() { return this.user; } setUser(user) { this.user = user; } load(runner) { destroy(this.scope); this.scope.runner = runner; initRunner(this.scope, this); } } export default () => { return { restrict: 'E', template, transclude: { editor: 'editor', actions: '?actions', result: '?result', runHint: '?runHint', controls: '?controls', stats: '?stats', }, scope: { data: '=', version: '=', runner: '<', brOptions: '<', onRun: '&', onRunnerCreated: '&', onRunnerKilled: '&', onRunnerDestroyed: '&', onLoad: '&', tableFormatter: '&', downloadFileName: '&', $state: '<' }, link: { pre(scope, element, attrs, ctrl, transclude) { const instance = new RunnerComponentInstance(scope); initNgScope(scope) .withOptions('brOptions', { type: 'presto', buttonText: 'Run', disableCustomActions: false, vizType: 'table', vizTypes: [], vizPicker: true, vizFilter: true, autoRun: false, showEditor: true, }, true) .withVM({ runner: {}, result: { csvFileName: null, $init() { this.current = null; this.queries = this.createItemsVm({ errorType: null }); }, setCurrent(query) { this.current = query; this.queries.get(query).toggle(true); this.csvFileName = scope.downloadFileName({query, runner: scope.runner}) || 'export.csv'; }, reset() { this.$init(); } }, tabs: { isEnabled() { return scope.vm.result.enabled && scope.runner.getTotalNumOfQueries() > 1; } }, customActions: { $init() { this.toggle(transclude.isSlotFilled('actions')); } }, stats: { enabled: true, }, }) .withEvents({ onSelectQuery(query) { scope.vm.result.setCurrent(query); scope.vm.stats.reload(); }, onToggleRun(mode) { if (scope.vm.runner.enabled) { kill(scope, true); } else { destroy(scope); const runner = initRunner(scope, instance, mode).run(scope.data, instance.getUser()); scope.onRun({runner}); return runner; } }, onCloseResult() { destroy(scope); } }) .withActions({ getCsvFields() { return scope.vm.result.current.getFields().map(field => field.name); }, getCsvRows() { const fields = scope.vm.result.current.getFields(); return scope.vm.result.current.getResults().buffer.map(row => fields.map(field => row[field.name])); } }); if (scope.runner) { initRunner(scope, instance); } scope.renderResult = (queryScope, query) => ({html: renderResult(scope, queryScope, query, scope.tableFormatter, transclude)}); scope.onLoad({instance}); if (scope.options.autoRun) { instance.run('stream'); } } } }; }; ================================================ FILE: quix-frontend/client/src/lib/runner/directives/sql-runner/sql-runner.html ================================================ ================================================ FILE: quix-frontend/client/src/lib/runner/directives/sql-runner/sql-runner.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; @import '../../../ui/assets/css/def/flex.def'; bi-sql-runner { @include flex(column); width: 100%; flex-grow: 1; } ================================================ FILE: quix-frontend/client/src/lib/runner/directives/sql-runner/sql-runner.ts ================================================ import './sql-runner.scss'; import template from './sql-runner.html'; import {CodeEditorInstance} from '../../../code-editor'; import {createNgModel, initNgScope, inject} from '../../../core'; import {setupCompleters} from '../../services/autocomplete/autocomplete-service'; import {attachErrorHandler, getParamsOffset} from '../../services/syntax-valdator/syntax-validator-service'; import {initSqlWorker} from '../../services/workers/sql-parser-worker'; import {RunnerComponentInstance} from '../runner/runner'; import {requestCredentials, isPermissionError} from '../../services/permissions/permissions-service'; import {config} from '../../config'; import { AUTO_PARAMS, AUTO_PARAM_TYPES } from '../../../code-editor/services/param-parser/param-types'; function renderActions(scope, editorComponentInstance, runnerComponentInstance, transclude: ng.ITranscludeFunction) { if (!transclude.isSlotFilled('actions')) { return inject('$compile')(`
  • file_download
    Run and download
`)(scope); } return transclude((_, s) => { s.editorComponentInstance = editorComponentInstance; s.runnerComponentInstance = runnerComponentInstance; }, null, 'actions'); } export default () => { return { restrict: 'E', template, require: 'ngModel', transclude: { actions: '?actions', controls: '?controls', stats: '?stats', }, scope: { version: '=', type: '=', runner: '=', bsrOptions: '=', onEditorLoad: '&', onRunnerLoad: '&', onSave: '&', onRun: '&', onRunnerCreated: '&', onRunnerDestroyed: '&', onParamsShare: '&', tableFormatter: '&', downloadFileName: '&', readonly: '=', $state: '<', autocompleteDbFetchers: '<' }, link: { pre(scope, element, attrs, ngModel, transclude) { let editorInstance: CodeEditorInstance, runnerInstance: RunnerComponentInstance; const deferredEditor = inject('$q').defer(); const modelConf = createNgModel(scope, ngModel) .formatWith(model => ({value: model})) .parseWith(({value}) => value) .watchDeep(true) .then(() => scope.vm.toggle(true)); initNgScope(scope) .withOptions('bsrOptions', { focus: false, params: false, autoParams: true, customParams: true, useAutocomplete: true, showSyntaxErrors: true, promptOnPermissionError: true, disableCustomActions: false, fitContent: false, shareParams: false, autoRun: false, dateFormat: null, }) .withVM({ selection: null, password: null, runnerOptions: { buttonText: null }, hint: { run: { enabled: true } }, viz: { $init() { this.queries = this.createItemsVm({ type: null, setCurrent(type) { this.type = type; }, $init() { this.setCurrent('table'); } }); } } }) .withEvents({ onRunnerLoad(instance: RunnerComponentInstance) { runnerInstance = instance; runnerInstance.setRequestTransformer(() => editorInstance.getParams().format(scope.vm.selection || scope.model.value)); runnerInstance.setErrorTransformer((runner, query, msg) => { if (isPermissionError(msg) && scope.options.promptOnPermissionError) { requestCredentials(scope, runnerInstance).then(() => runnerInstance.run()); } else { const match = msg.match(/^line (\d+)\:\d+/); if (match) { const queryOffset: number = runner.getQueries().reduce((res, _query) => { if (_query !== query) { res += _query.meta('numOfRows'); } return res; }, getParamsOffset(editorInstance)); const rowNumber = queryOffset + parseInt(match[1], 10) + (editorInstance.getSelection().getOffset() as number); msg = msg.replace(/^(line )(\d+)(\:\d+)/, `$1${rowNumber}$3`); editorInstance.getAnnotator().showError(rowNumber, msg); } } return msg; }); scope.onRunnerLoad({instance}); }, onEditorLoad(instance: CodeEditorInstance) { editorInstance = instance; deferredEditor.resolve(instance); editorInstance.addShortcut('Ctrl-Enter', 'Command-Enter', () => runnerInstance.run(), scope); editorInstance.getSelection() .on('select', text => { scope.vm.selection = text; scope.vm.runnerOptions.buttonText = 'Run selection'; }) .on('deselect', () => { scope.vm.selection = null; scope.vm.runnerOptions.buttonText = null; }); if (scope.options.params) { editorInstance.addLiveCompleter('$', prefix => { let completions = []; const params = editorInstance.getParams(); if (scope.options.autoParams) { completions = [ ...completions, ...AUTO_PARAMS .map(name => ({name, meta: AUTO_PARAM_TYPES[name]})) .map(({name, meta}) => ({ caption: name, value: params.getParser().getSerializer().serialize({ match: null, key: name, type: null, value: null, isAutoParam: true, isKeyOnlyParam: false, options: null }), meta, completer: { insertMatch(editor) { editor.insert(name); editorInstance.getParams().addAutoParam(name); } } })) ]; } if (scope.options.customParams) { completions = [ ...completions, ...params.getParams().filter(({isAutoParam}) => !isAutoParam).map(({key, type, value}) => { return { caption: key, value: params.getParser().getSerializer().serialize({ match: null, key, type, value, isAutoParam: false, isKeyOnlyParam: true, options: null }), meta: type }; }) ]; } return completions; }); } runnerInstance.on('error', (rowNumber, msg) => editorInstance.getAnnotator().showError(rowNumber, msg)); if (!scope.readonly && scope.options.useAutocomplete) { setupCompleters(editorInstance, scope.type, config.get().apiBasePath, scope.autocompleteDbFetchers).catch(console.error); } if (!scope.readonly && scope.options.showSyntaxErrors) { attachErrorHandler(initSqlWorker, editorInstance, modelConf).catch(console.error); } scope.onEditorLoad({instance}); }, onRunnerCreated(runner) { runner .on('success', () => deferredEditor.promise.then((editor: CodeEditorInstance) => editor.setValid(true), true)) .on('error', () => deferredEditor.promise.then((editor: CodeEditorInstance) => editor.setValid(false), true)); runner.getEvents().register('query-details', data => { const code = data && data.code || ''; const lines = code.trim().split('\n'); runner.getCurrentQuery().meta('numOfRows', lines.length); runner.getCurrentQuery().setTitle(lines[0] ? lines[0].replace('--', '').trim() : 'query'); return data; }); scope.vm.hint.run.toggle(false); scope.onRunnerCreated({runner}); }, onRunnerDestroyed(runner) { deferredEditor.promise.then(() => { editorInstance.setValid(null); editorInstance.getAnnotator().hideAll(); }); scope.vm.hint.run.toggle(true); scope.onRunnerDestroyed({runner}); }, onRun(runner) { scope.onRun({runner}); }, onRunAndDownload() { runnerInstance.run('download'); } }); scope.renderActions = () => ({html: renderActions(scope, editorInstance, runnerInstance, transclude)}); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/runner/index.ts ================================================ import ngApp from './bootstrap'; import init from './init'; init(ngApp); export {default as createRunner, Runner} from './services/runner-service'; export {default as RunnerQuery} from './services/runner-query'; export {config} from './config'; ================================================ FILE: quix-frontend/client/src/lib/runner/init.ts ================================================ import {forEach} from 'lodash'; import * as directives from './directives'; function toDirectiveName(name: string) { return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`; } export default function init(ngApp: angular.IModule) { forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any)); } ================================================ FILE: quix-frontend/client/src/lib/runner/services/autocomplete/autocomplete-service.ts ================================================ import { CodeEditorInstance } from '../../../code-editor'; // import { ICompleterItem as AceCompletion } from '../../../code-editor/services/code-editor-completer'; import { SqlAutocompleter } from "../../../sql-autocomplete/adapter/sql-autocomplete-adapter"; import { highlightAndScore } from "./highlight-and-score"; // import { BiSqlWebWorkerMngr } from '../../../language-parsers/sql-parser'; // import { initSqlWorker } from '../workers/sql-parser-worker'; import { getKeywordsCompletions, getQueryAndCursorPositionFromEditor, getSuggestions, isSearchInObject, } from './autocomplete-utils'; import { IDbInfoConfig } from '../../../sql-autocomplete/db-info'; // import { DbInfoService } from '../../../sql-autocomplete/db-info'; import { evaluateContextFromPosition, QueryContext, } from '../../../sql-autocomplete/sql-context-evaluator'; import { IEditSession } from 'brace'; import { setupOldCompleter } from './old-autocomplete-service'; /* tslint:disable:no-shadowed-variable */ export async function setupCompleters( editorInstance: CodeEditorInstance, type: string, apiBasePath = '', dbInfoService?: IDbInfoConfig ) { // in order to run locally comment out if (!dbInfoService) { setupOldCompleter(editorInstance, type, apiBasePath); return; } // dbInfoService = dbInfoService ?? new DbInfoService(type, apiBasePath); const sqlAutocompleter = new SqlAutocompleter(dbInfoService, type); editorInstance.setLiveAutocompletion(true); const keywordsCompletions = getKeywordsCompletions(); const completerFn = async (prefix: string, session: IEditSession) => { const { query, position } = getQueryAndCursorPositionFromEditor( editorInstance, session ); const queryContext: QueryContext = evaluateContextFromPosition( query, position ); const searchInObject = await isSearchInObject(queryContext, sqlAutocompleter) let autocompletionSuggestions = await getSuggestions(queryContext, keywordsCompletions, sqlAutocompleter, searchInObject); if (prefix) { autocompletionSuggestions = highlightAndScore( autocompletionSuggestions, queryContext, searchInObject ) } return autocompletionSuggestions.sort((a, b) => a.value.localeCompare(b.value)); }; editorInstance.addOnDemandCompleter(/[\w.]+/, completerFn as any, { acceptEmptyString: true, }); // editorInstance.addOnDemandCompleter(/[\s]+/, completerFn as any); } ================================================ FILE: quix-frontend/client/src/lib/runner/services/autocomplete/autocomplete-utils.ts ================================================ /* tslint:disable:no-bitwise */ import { IEditSession } from 'brace'; import { CodeEditorInstance } from '../../../code-editor'; import { ICompleterItem } from '../../../code-editor/services/code-editor-completer'; import { reservedPrestoWords } from '../../../sql-autocomplete/languge/reserved-words'; import { ContextType } from '../../../sql-autocomplete/sql-context-evaluator/types'; let keywords: ICompleterItem[]; export const getKeywordsCompletions = (): ICompleterItem[] => { // TODO: FIND A WAY TO FETCH KEYWORDS FROM ANTLR GRAMMAR keywords = keywords ?? reservedPrestoWords.map((keyword) => makeCompletionItem(keyword, 'keyword') ); return keywords; }; /** * create an array of bitmaps. * if ((bit j of array[i]) === 1) means that the character i*31 + j should be marked in UI * * @param {number | number[]} start * @param {number} length * @returns {number[]} */ export const createMatchMask = ( start: number | number[], length: number ): number[] => { const res = []; start = Array.isArray(start) ? start : [start]; start.forEach((startElement) => { for (let i = startElement; i < startElement + length; i++) { const index = i % 31; const offset = i - 31 * index; res[index] = res[index] || 0; res[index] = res[index] | (1 << offset); } }); return res; }; export async function getSuggestions(queryContext, keywordsCompletions, sqlAutocompleter, searchInObject) { if (queryContext.contextType === ContextType.Undefined) { return keywordsCompletions.filter(obj => obj.value.toLowerCase().includes(queryContext.prefix.toLowerCase())); } return searchInObject ? sqlAutocompleter.getCompletionItemsFromQueryContextColumn( queryContext ) : sqlAutocompleter.getCompletionItemsFromQueryContext( queryContext ); } export async function isSearchInObject(queryContext, sqlAutocompleter) { if (queryContext.contextType === ContextType.Column && queryContext.prefix) { const completions = await sqlAutocompleter.getCompletionItemsFromQueryContext( queryContext ) const filteredCompletions = completions.filter(c => c.value.toLowerCase().includes(queryContext.prefix)); return filteredCompletions.length === 0; } return false } export function createCaption(str: string) { const maxCaptionLength = 60; const maxSubCaptionLength = 57; if (str.length > maxCaptionLength) { return str.substring(0, maxSubCaptionLength) + "..."; } return str; } export const makeCompletionItem = ( value: string, meta: string, caption?: string, matchMask?: number[], score?: number ): ICompleterItem => { const completer = { value, meta, ...(caption ? { caption } : {}), ...(matchMask ? { matchMask } : {}), ...(score ? { score } : {}), }; return completer; }; export const getQueryAndCursorPositionFromEditor = ( editorInstance: CodeEditorInstance, session: IEditSession ) => { let query: string = session .getDocument() .getAllLines() .join('\n'); let position: number = session .getDocument() .positionToIndex(session.selection.getCursor(), 0); if (editorInstance.getParams().hasParams()) { const tempQuery = query.slice(0, position) + '@REPLACE_ME@' + query.slice(position); query = editorInstance.getParams().format(tempQuery); position = query.indexOf('@REPLACE_ME@'); query = query.replace('@REPLACE_ME@', ''); } return { query, position }; }; export const findAllIndexOf = (haystack: string, needle: string) => { const indexes: number[] = []; if (needle === '') { return indexes; } haystack = haystack.toLowerCase(); needle = needle.toLowerCase(); let index = 0; while (index !== -1) { index = haystack.indexOf(needle, index); if (index !== -1) { indexes.push(index); index++; } } return indexes; }; ================================================ FILE: quix-frontend/client/src/lib/runner/services/autocomplete/highlight-and-score.ts ================================================ import { createCaption, createMatchMask, findAllIndexOf, } from './autocomplete-utils'; import { findColumnPathForPrefix } from "../../../sql-autocomplete/adapter/sql-autocomplete-adapter-utills"; import { ICompleterItem as AceCompletion } from '../../../code-editor/services/code-editor-completer'; import { QueryContext } from '../../../sql-autocomplete/sql-context-evaluator'; const PERFECT_SCORE = 10000; export function highlightAndScore( autocompletionSuggestions, queryContext, searchInObject ) { const lowerCasedPrefix = queryContext.prefix.trim().toLowerCase(); return searchInObject ? enrichCompletionForObject(queryContext.prefix, autocompletionSuggestions, queryContext, lowerCasedPrefix) : enrichCompletionItem(autocompletionSuggestions, lowerCasedPrefix); } function enrichCompletionItemAfterDotObject(all: AceCompletion[]): AceCompletion[] { const indexes = [0]; return all.map(completionItem => ({ ...completionItem, matchMask: createMatchMask(indexes, 0), score: PERFECT_SCORE, })); } function enrichCompletionForObject(prefix: string, autocompletionSuggestions: any, queryContext: QueryContext, lowerCasedPrefix: string) { return prefix.endsWith('.') ? enrichCompletionItemAfterDotObject(autocompletionSuggestions) : enrichCompletionItemInObjectSearch(autocompletionSuggestions, queryContext, lowerCasedPrefix); } function enrichCompletionItemInObjectSearch(all: AceCompletion[], queryContext: QueryContext, prefix: string): AceCompletion[] { return all.reduce((resultArr, completionItem) => { const columnPathForPrefix = findColumnPathForPrefix(queryContext.tables, prefix.split('.')).slice(0, -1); const lastDotIndex = findLastDotIndex(columnPathForPrefix); const startOfSearch = lastDotIndex >= 0 ? columnPathForPrefix.slice(0, lastDotIndex + 1) : columnPathForPrefix; const searchPart = columnPathForPrefix.replace(startOfSearch, ''); const indexes = findAllIndexOf(completionItem.caption, searchPart); updateCompletionItem(completionItem, indexes, searchPart, resultArr); return resultArr; }, []); } function enrichCompletionItem(all: AceCompletion[], lowerCasedPrefix: string): AceCompletion[] { return all.reduce((resultArr, completionItem) => { const indexes = findAllIndexOf(completionItem.value, lowerCasedPrefix); updateCompletionItem(completionItem, indexes, lowerCasedPrefix, resultArr); return resultArr; }, []); } function updateCompletionItem( completionItem: AceCompletion, indexes: number[], searchPart: string, resultArr: AceCompletion[] ): void { if (indexes.length > 0) { completionItem.matchMask = createMatchMask( indexes, searchPart.length ); completionItem.score = PERFECT_SCORE - indexes[0]; resultArr.push(completionItem); } completionItem.caption = createCaption(completionItem.caption || completionItem.value); } export function findLastDotIndex(prefix: string): number { return prefix.lastIndexOf('.'); } ================================================ FILE: quix-frontend/client/src/lib/runner/services/autocomplete/old-autocomplete-service.ts ================================================ import {CodeEditorInstance} from '../../../code-editor'; import {ICompleterItem as AceCompletion} from '../../../code-editor/services/code-editor-completer'; import {BiSqlWebWorkerMngr} from '../../../language-parsers/sql-parser'; import {DbInfo} from '../db/db-service'; import {initSqlWorker} from '../workers/sql-parser-worker'; import {createMatchMask, makeCompletionItem} from './autocomplete-utils'; const sqlContextGroups = ['subQueries', 'tableAlias', 'strings', 'tables', 'columns']; let sqlParser: BiSqlWebWorkerMngr; let keywords: Promise; // All Completions let tables: Promise; async function getTablesCompletions(dbInfoService: DbInfo): Promise { keywords = keywords || dbInfoService.fetchAllKeywords(); const completions = await keywords; return completions.filter(completion => completion.meta === 'table'); } /* tslint:disable:no-shadowed-variable */ export async function setupOldCompleter(editorInstance: CodeEditorInstance, type: string, apiBasePath = '') { sqlParser = await initSqlWorker(); const dbInfoService = new DbInfo(type, apiBasePath); keywords = keywords || dbInfoService.fetchAllKeywords(); tables = tables || getTablesCompletions(dbInfoService); editorInstance.addOnDemandCompleter(/[\w.]+/, ((prefix, session) => { let contextCompletions: Promise; if (sqlParser) { const text = session.getDocument().getAllLines().join('\n'); contextCompletions = sqlParser.parse(text) .then(parseResults => sqlContextGroups.reduce((sum, groupName) => sum.concat(parseResults[groupName] .map(item => makeCompletionItem(item, groupName))), [])); } else { contextCompletions = Promise.resolve([]); } return Promise.all([tables, contextCompletions]) .then(([tableCompletions, contextCompletions]) => { let all = contextCompletions.concat(tableCompletions); if (prefix) { all = all.reduce((resultArr: AceCompletion[], completion) => { const index = completion.value.indexOf(prefix); if (index !== -1) { completion.matchMask = createMatchMask(index, prefix.length); resultArr.push(completion); } return resultArr; }, []); } return all; }); }) as any, {acceptEmptyString: true}); } ================================================ FILE: quix-frontend/client/src/lib/runner/services/db/db-service.ts ================================================ 'use strict'; import {inject} from '../../../core'; import angular from 'angular'; export interface IAutocomplete { value: string; meta: string; } export interface IDbNode { name: string; type: string; children: IDbNode[]; } export class DbInfo { private readonly $http: angular.IHttpService = inject('$http'); constructor(private readonly type: string, private readonly apiBasePath = '') {} fetchAllKeywords(): Promise { return this.$http({ url: `${this.apiBasePath}/api/autocomplete/${this.type}`, method: 'GET' }) .then(({data}) => data) .catch(e => console.log(e)) as any; } fetchSchema(): Promise { return this.$http({ url: `${this.apiBasePath}/api/db/${this.type}/explore`, method: 'GET' }) .then(({data}) => data) .catch(e => []) as any; } } ================================================ FILE: quix-frontend/client/src/lib/runner/services/permissions/permissions-service.ts ================================================ import {confirm} from '../../../../lib/ui'; import {RunnerComponentInstance} from '../../directives/runner/runner'; const PERMISSION_ERROR_PATTERNS = [ 'permission denied', 'permission was denied', 'you do not have permission', 'under the current security context', 'Login failed. The login is from an untrusted domain and cannot be used with Windows authentication' ]; export const isPermissionError = (msg: string) => { return PERMISSION_ERROR_PATTERNS.some(pattern => msg.indexOf(pattern) !== -1); } export const requestCredentials = (scope, runnerInstance: RunnerComponentInstance) => { const user = runnerInstance.getUser(); if (!user) { throw new Error('To use promptOnPermissionError please call runnerComponentInstance.setUser(user)'); } user.getPermission().deelevate(); return confirm({ title: `Permission denied`, actionType: 'neutral', icon: 'gpp_bad', yes: 'Submit', resolveOnEnter: true, html: `
Please enter your password to access restricted data
` }, scope, {model: {password: null}}).then(({model}) => { user.getPermission().elevate(model.password); }); } ================================================ FILE: quix-frontend/client/src/lib/runner/services/runner-event.ts ================================================ export default class RunnerEvent { private readonly handlers = []; private readonly status = { callCount: 0 }; constructor (private readonly name, private readonly options = {dontDigest: false}) { } public getName() { return this.name; } public getOptions() { return this.options; } public append(handler) { this.handlers.push(handler); } public prepend(handler) { this.handlers.unshift(handler); } public apply(data, meta) { this.status.callCount++; this.handlers.every(handler => { data = handler(data, meta, this.status); // break if data is false if (data === false) { return false; } return true; }); } } ================================================ FILE: quix-frontend/client/src/lib/runner/services/runner-events.ts ================================================ import {values} from 'lodash'; import RunnerEvent from './runner-event'; export default class RunnerEvents { private readonly handlers: {[eventName: string]: RunnerEvent} = {}; constructor(private readonly runner) { } public register(eventName, handler, options = {dontDigest: false}) { const event = this.handlers[eventName] = new RunnerEvent(eventName, options); event.append(handler); return this; } public getRegisteredEvents(): RunnerEvent[] { return values(this.handlers); } public append(eventName, handler): RunnerEvents { this.handlers[eventName].append(handler); return this; } public prepend(eventName, handler): RunnerEvents { this.handlers[eventName].prepend(handler); return this; } public apply(eventName, data, meta): RunnerEvents { if (this.runner.getState().getStatus().killed) { return; } this.handlers[eventName].apply(data, meta); return this; } } ================================================ FILE: quix-frontend/client/src/lib/runner/services/runner-query.ts ================================================ import {zipObject} from 'lodash'; import moment from 'moment'; import {srv, inject} from '../../core'; export interface IField { name: string; title?: string; } export interface IError { msg: string; details: Object; } export interface ITime { elapsed: string; started: number; interval; } export interface IStatus { running: boolean; success: boolean; finished: boolean; error: boolean; killed: boolean; } function getFieldName(field: string, fieldNames: Record) { fieldNames[field] = fieldNames[field] || 0; return field + `${fieldNames[field]++ ? `_${fieldNames[field]}` : ''}`; } function startDurationCount(): ITime { const res: ITime = { elapsed: '00:00', started: Date.now(), interval: null }; res.interval = inject('$interval')(() => { const now = moment(); res.elapsed = now.subtract(res.started).format('mm:ss'); }, 1000); return res; } function stopDurationCount(time) { inject('$interval').cancel(time.interval); } export default class RunnerQuery extends srv.eventEmitter.EventEmitter { private details = {}; private readonly metadata = {}; private title; private _fields: IField[] = []; private _rawFields: string[] = []; private readonly _results = new srv.collections.BufferedCollection().setChunkSize(20); private fastForwardPromise = null; private error: IError; private stats: {[key: string]: any}; private time: ITime = { elapsed: null, started: null, interval: null }; private readonly status: IStatus = { running: false, success: false, finished: false, error: false, killed: false }; constructor(private readonly id, private readonly index) { super(); } public meta(name, value?) { if (value) { this.metadata[name] = value; return this; } return this.metadata[name]; } public setDetails(details) { this.details = details; return this; } public getDetails() { return this.details; } public get results(): any { return this.getResults(); } public get fields(): IField[] { return this.getFields(); } public get running(): boolean { return this.status.running; } public get success(): boolean { return this.status.success; } public get finished(): boolean { return this.status.finished; } public get elapsedTime(): string { return this.getTime().elapsed; } public get startTime(): number { return this.getTime().started; } public getId(): string { return this.id; } public getIndex(): number { return this.index; } public getResults(): any { return this._results; } public getFields(): IField[] { return this._fields; } public getRawFields(): string[] { return this._rawFields; } public getError(): IError { return this.error; } public getTime(): ITime { return this.time; } public getTitle() { return this.title; } public setTitle(title: string): RunnerQuery { this.title = title; return this; } public setFields(fields: string[]): RunnerQuery { const fieldNames = {}; this._fields = fields.map(name => ({ name: getFieldName(name, fieldNames), })); this._rawFields = this._fields.map(({name}) => name); return this; } public addRow(row): Object { this._results.feed(zipObject(this._rawFields, row)); if (this.getResults().bufferSize() === 1) { this.fire('firstResultReceived', this); } else if (this.getResults().bufferSize() === 2) { this.fire('moreResultReceived', this); } // Fast-forward slow rows if (this._results.size() < this._results.getChunkSize()) { this.fastForwardPromise = this.fastForwardPromise ? this.fastForwardPromise.then(() => { if (this._results.size() < this._results.getChunkSize()) { return this._results.more(); } }) : this._results.more(); } return this; } public setError(error): RunnerQuery { this.error = error; this.fire('error', this, error); return this; } public setErrorMessage(msg) { this.error.msg = msg; } public getStats() { return this.stats; } public setStats(stats: {[key: string]: any}) { this.stats = stats; } public start(): RunnerQuery { this._results.fetch(); this.status.running = true; this.status.success = true; this.time = startDurationCount(); return this; } public end(): RunnerQuery { this._results.seal(); this.status.running = false; this.status.finished = true; stopDurationCount(this.time); this.fire('finish', this); return this; } } ================================================ FILE: quix-frontend/client/src/lib/runner/services/runner-service.ts ================================================ import {inject, srv} from '../../core'; import {RunnerSocket} from './runner-socket'; import RunnerEvents from './runner-events'; import RunnerState from './runner-state'; import RunnerQuery from './runner-query'; import {RunnerType} from '../typings/runner-types'; import { config } from '../config'; function initSocket(socket: RunnerSocket, events: RunnerEvents, transformers, scope, log: boolean = false) { events.getRegisteredEvents().forEach(event => { const eventName = event.getName(); socket.on(eventName, ({data, meta}) => { if (log) { /* tslint:disable-next-line:no-console */ console.log(eventName, data, meta); } if (event.getOptions().dontDigest) { events.apply(eventName, data, meta); } else { scope.$apply(() => { events.apply(eventName, data, meta); }); } }); }); socket.transformResponse(transformers.response); } function sendSocketData(socket, code, user, transformers, mode = 'stream') { const session: any = {mode}; if (user && user.getPermission() && user.getPermission().isElevated()) { session['user.password'] = user.getPermission().getPassword(); } socket.on('open', async () => { code = await transformers.request(code); socket.send({ event: 'execute', data: {code, session} }); }); } export class Runner extends srv.eventEmitter.EventEmitter { private readonly mode: string; private readonly version: number; private readonly executeBaseUrl: string; private socket: RunnerSocket; private readonly events: RunnerEvents; private readonly state = new RunnerState(); private code = null; private logEvents: boolean = false; private keepAliveInterval; private numOfRetries = 0; private readonly transformers = { request: request => request, response: response => response }; constructor(private readonly type: RunnerType, private readonly scope, options) { super(); this.mode = options.mode; this.version = options.version || 1; this.executeBaseUrl = options.executeBaseUrl; this.events = new RunnerEvents(this); this.events .register('start', data => { this.getState() .setId(data.id) .setTotalNumOfQueries(data.numOfQueries); this.fire('start', this); return data; }) .register('end', data => { this.finish(); return data; }) .register('query-start', (data) => { this.getState() .startQuery(data.id); this.stream('queryCreated', this, this.getState().getCurrentQuery()); return data; }); this.getEvents().register('query-download', (data) => { if (data.url) { this.fire('downloadFile', `${this.executeBaseUrl}${data.url}`, this, this.getCurrentQuery()); } }) .register('query-end', data => { this.getCurrentQuery().setStats(data.statistics); this.getState().endQuery(data.id); return data; }) .register('percentage', (data, meta, status) => { const totalQueries = this.getTotalNumOfQueries(); const percentagePerQuery = 100 / totalQueries; const totalQueriesUntilNow = this.getState().getQueries().length - 1; const percentageUntilNow = totalQueriesUntilNow * percentagePerQuery; const thisQueryPercentage = data.percentage * percentagePerQuery / 100; this.getState() .setProgress(Math.round(percentageUntilNow + thisQueryPercentage)) .setSuccessStatus(true); if (status.callCount === 1) { this.fire('success', this, this.getCurrentQuery()); } return data; }) .register('error', (data) => { if (!this.getState().getCurrentQuery()) { // error happened in a very early stage of execution, some events need to be simulated this.events .apply('start', {id: 1}, {}) .apply('query-start', {id: 1}, {}) .apply('query-end', {id: 1}, {}); } const query = this.getState() .setErrorStatus(true) .getCurrentQuery().setError(data); this.fire('error', this, data, query); return data; }) .register('fields', data => { const query = data.id ? this.getState().getQueryById(data.id) : this.getState().getCurrentQuery(); query.setFields(data.fields); return data; }) .register('row', (data, meta, status) => { const query = data.id ? this.getState().getQueryById(data.id) : this.getState().getCurrentQuery(); query.addRow(data.values); if (status.callCount === 1) { this.fire('firstResultReceived', this); } else if (status.callCount === 2) { this.fire('moreResultReceived', this); } return data; }, {dontDigest: true}); } protected log(value: boolean) { this.logEvents = value; } protected start() { this.getState().setRunningStatus(true); if (this.numOfRetries === 0) { this.getState().startDurationCount(); this.keepAliveInterval = inject('$interval')(() => this.getSocket().send({ event: 'ping' }), 15 * 1000); } } protected finish() { inject('$interval').cancel(this.keepAliveInterval); this.getSocket().close(); this.getState() .setRunningStatus(false) .setFinishedStatus(true) .stopDurationCount(); this.getState().getQueries().forEach(query => { if (!query.finished) { this.getState().endQuery(query.getId()); } }); this.fire('finish', this); } public getScope() { return this.scope; } public getSocket() { return this.socket; } public getEvents() { return this.events; } public getState() { return this.state; } public getQueries(): RunnerQuery[] { return this.getState().getQueries(); } public getTotalNumOfQueries(): number { return this.getState().getTotalNumOfQueries(); } public getCurrentQuery(): RunnerQuery { return this.getState().getCurrentQuery(); } public getMode(): string { return this.mode; } public get error() { return this.getState().getError(); } public get progress() { return this.getState().getProgress(); } public get elapsedTime() { return this.getState().getTime().elapsed; } public get running() { return this.getState().getStatus().running; } public getCode() { return this.code; } public transformRequest(transformer): Runner { this.transformers.request = transformer || this.transformers.request; return this; } public transformResponse(transformer): Runner { this.transformers.response = transformer || this.transformers.response; return this; } public run(code, user?): Runner { this.socket = new RunnerSocket(this.type, this.version, this.executeBaseUrl); this.code = code; initSocket(this.socket, this.events, this.transformers, this.scope, this.logEvents); sendSocketData(this.socket, code, user, this.transformers, this.mode); this.socket.on('close', () => { if (this.getState().getStatus().finished) { return; } const connectionId = this.getState().getId(); if ( this.numOfRetries < 10 && (!connectionId || ( this.getQueries().length === 1 && !this.getCurrentQuery().getResults().bufferSize() )) ) { this.numOfRetries++; this.run(code, user); return; } this.getScope().$apply(() => { this.getEvents().apply('error', { message: this.getConnectionErrorMessage(connectionId), }, {}); this.finish(); }); }); this.start(); return this; } public kill() { this.getState().setKilledStatus(true); if (!this.running) { return; } this.finish(); } getConnectionErrorMessage(connectionId) { return `Connection failed after (${this.numOfRetries}) retries, please rerun your query manually. This is most likely a transient network error and not a problem with the ${inject('$filter')('biToHumanCase')(this.type)} engine. ------------------------------------------------------------------------------------------------- Connection ID: ${connectionId} Connection start time: ${inject('$filter')('biDate')(this.getState().getTime().started, 'seconds')} Connection elapsed time: ${this.getState().getTime().elapsed} ------------------------------------------------------------------------------------------------- ${this.getCurrentQuery() ? `Query ID: ${this.getCurrentQuery().getId()}` : ''} ${this.getCurrentQuery() ? `Query start time: ${inject('$filter')('biDate')(this.getCurrentQuery().getTime().started, 'seconds')}` : ``} ${this.getCurrentQuery() ? `Query elapsed time: ${this.getCurrentQuery().getTime().elapsed}` : ``} ${this.getCurrentQuery() ? `Fetched rows: ${this.getCurrentQuery().getResults().bufferSize()}` : ``} ` } } export default function create(type: RunnerType, scope, { mode = 'stream', version = null, executeBaseUrl = config.get().executeBaseUrl, } = { mode: 'stream', version: null, executeBaseUrl: config.get().executeBaseUrl, }) { if (!executeBaseUrl) { throw new Error('Missing execute url definition'); } return new Runner(type, scope, {mode, version, executeBaseUrl}); } ================================================ FILE: quix-frontend/client/src/lib/runner/services/runner-socket.ts ================================================ import {srv} from '../../core'; import {RunnerType} from '../typings/runner-types'; function attachProtocol(url: string) { if (url.startsWith('http://')) { return url.replace('http://', 'ws://'); } if (url.startsWith('https://')) { return url.replace('https://', 'wss://'); } return (window.location.protocol === 'https:' ? 'wss:' : 'ws:') + url; } function getEndpoint(type: string, version: number) { return `/api/v${version}/execute/${type}`; } export class RunnerSocket extends srv.Socket { private readonly transformers = { response: response => response }; constructor ( type: RunnerType = 'sql', version: number = null, baseUrl = '', url: string = `${baseUrl}${getEndpoint(type, version)}` ) { super(attachProtocol(url)); this.on('event', (socket, eventName = '__unknown__', data) => { this.fire(eventName, this.transformers.response(data), data.payload); }); } public send(payload): RunnerSocket { super.send(payload); return this; } public transformResponse(transformer): RunnerSocket { this.transformers.response = transformer; return this; } } ================================================ FILE: quix-frontend/client/src/lib/runner/services/runner-state.ts ================================================ import moment from 'moment'; import {last, find} from 'lodash'; import {inject} from '../../core'; import {default as RunnerQuery, IStatus, ITime, IField} from './runner-query'; // no actual runner logic should be handled here, just setters/getters export default class State { private readonly state = { id: null, queries: [], progress: 0, totalNumOfQueries: 0, status: { running: false, success: false, finished: false, error: false, killed: false } as IStatus, time: { elapsed: '00:00', started: null, interval: null } as ITime }; public getId(): string { return this.state.id; } public setId(id): State { this.state.id = id; return this; } public getFields(): IField[] { return this.state.queries.length && this.getCurrentQuery().getFields(); } public getResults() { return this.state.queries.length && this.getCurrentQuery().getResults(); } public getError() { return this.state.queries.length && this.getCurrentQuery().getError(); } public hasQueries(): boolean { return !!this.getQueries().length; } public getQueries(): RunnerQuery[] { return this.state.queries; } public getCurrentQuery(): RunnerQuery { // if (!this.state.queries.length) { // throw 'Runner.state: there are 0 queries in the pool'; // } return last(this.state.queries); } public getQueryById(id): RunnerQuery { return find(this.state.queries, query => query.getId() === id); } public startQuery(id): State { this.state.queries.push(new RunnerQuery(id, this.state.queries.length).start()); return this; } public endQuery(id): State { this.getQueryById(id).end(); return this; } public getTotalNumOfQueries() { return this.state.totalNumOfQueries; } public setTotalNumOfQueries(num) { return this.state.totalNumOfQueries = num; } public getProgress(): number { return this.state.progress; } public setProgress(progress): State { this.state.progress = progress; return this; } public getStatus(): IStatus { return this.state.status; } public startDurationCount() { this.state.time.started = Date.now(); this.state.time.interval = inject('$interval')(() => { const now = moment(); this.state.time.elapsed = now.subtract(this.state.time.started).format('mm:ss'); }, 1000); return this; } public stopDurationCount() { inject('$interval').cancel(this.state.time.interval); return this; } public getTime(): ITime { return this.state.time; } public setRunningStatus(value: boolean): State { this.state.status.running = value; return this; } public setSuccessStatus(value: boolean): State { this.state.status.success = value; return this; } public setFinishedStatus(value: boolean): State { this.state.status.finished = value; return this; } public setErrorStatus(value: boolean): State { this.state.status.error = value; return this; } public setKilledStatus(value: boolean): State { this.state.status.killed = value; return this; } } ================================================ FILE: quix-frontend/client/src/lib/runner/services/syntax-valdator/syntax-validator-service.ts ================================================ import {IErrorAnnotation} from '../../../language-parsers/sql-parser/parser/errors-listener'; import {CodeEditorInstance} from '../../../code-editor'; import {ModelConf} from '../../../core/ang/srv/ng-model/ng-model'; export interface HasGetErrorsMethod { getErrors(s: string): Promise; } export function getParamsOffset(editorInstance: CodeEditorInstance) { if (editorInstance.getParams().hasParams()) { const locked = editorInstance.getLockedRange(); return (locked[locked.length - 1][1] as number) + 1; /* casting because of tslint... */ } return 0; } export const attachErrorHandler = async (initWorker: () => Promise, editorInstance: CodeEditorInstance, modelConf: ModelConf) => { const worker = await initWorker(); modelConf.watchWith(({value}) => { worker.getErrors(editorInstance.getParams().format(value)) .then(errors => { editorInstance.getAnnotator().hideAll(); if (errors.length) { const e = errors[0]; const offset = getParamsOffset(editorInstance); editorInstance.getAnnotator().showError(e.row + offset + 1, e.text); } }).catch(e => null); }); }; ================================================ FILE: quix-frontend/client/src/lib/runner/services/workers/python-parser-worker.ts ================================================ import {PythonWebWorkerMngr} from '../../../language-parsers/python-parser'; const workerUrl = 'https://static.parastorage.com/unpkg-semver/bi-python-parser/web-worker.bundle.js'; let pythonParserPromise: Promise; export const initPythonWorker = async (): Promise => { pythonParserPromise = pythonParserPromise || PythonWebWorkerMngr.createFromUrl(workerUrl, 86400); return pythonParserPromise; }; ================================================ FILE: quix-frontend/client/src/lib/runner/services/workers/sql-parser-worker.ts ================================================ import {BiSqlWebWorkerMngr} from '../../../language-parsers/sql-parser'; const workerUrl = 'https://static.parastorage.com/unpkg/@wix/bi-sql-parser@1.0.43/dist/statics/web-worker.bundle.min.js'; let sqlParserPromise: Promise; export const initSqlWorker = async (): Promise => { sqlParserPromise = sqlParserPromise || BiSqlWebWorkerMngr.createFromUrl(workerUrl, 86400); return sqlParserPromise; }; ================================================ FILE: quix-frontend/client/src/lib/runner/typings/angular-promise.d.ts ================================================ /// import * as angular from 'angular'; declare module 'angular' { export interface IPromise { then(successCallback: (promiseValue: T) => PromiseLike | TResult, errorCallback?: (reason: any) => TResult2, notifyCallback?: (state: any) => any): IPromise; catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; } } ================================================ FILE: quix-frontend/client/src/lib/runner/typings/runner-types.ts ================================================ export type RunnerType = 'sql' | 'python' | 'native'; ================================================ FILE: quix-frontend/client/src/lib/runner/typings/types.d.ts ================================================ declare module '*.scss'; declare module '*.html'; interface DedicatedWorkerGlobalScope {} interface Promise { finally(finallyCallback: () => any): Promise; /* lets pretend we have this in es6, makes it comptabile with ng.Ipromise */ } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/sql-autocomplete-adapter-utills.ts ================================================ import { findLastDotIndex } from "../../runner/services/autocomplete/highlight-and-score"; import { Column } from "../db-info"; import { TableInfo } from "../sql-context-evaluator"; import { trinoToJs } from "./trinoToJs" interface ObjectChild { name: string; dataType: any; } export function getObjectChildren(obj: Record, parentName = ''): ObjectChild[] { const children: ObjectChild[] = []; for (const key in obj) { const childName = parentName ? `${parentName}.${key}` : key; if (typeof obj[key] === 'object' && obj[key] !== null) { children.push({ name: childName, dataType: obj[key] }); children.push(...getObjectChildren(obj[key], childName)); } else { children.push({ name: childName, dataType: obj[key] }); } } return children; } export function findColumnPathForPrefix(tables: TableInfo[], brokenPrefix: string[]): string { const relevantPrefixes: string[] = []; for (const table of tables) { for (const column of table.columns) { let found = false; let gotRelevantPartOfPrefix = false; let currentPrefix = ''; brokenPrefix.forEach(item => { if (found) { currentPrefix += item + '.'; } if (typeof column === 'object' && !gotRelevantPartOfPrefix && item === column.name) { found = true; gotRelevantPartOfPrefix = true; currentPrefix += item + '.'; } }); if (currentPrefix) { relevantPrefixes.push(currentPrefix); } } } if (relevantPrefixes.length === 0) { return ''; // No relevant prefixes found } // Find the longest relevant prefix let longestPrefix = relevantPrefixes[0]; for (const prefix of relevantPrefixes) { if (prefix.length > longestPrefix.length) { longestPrefix = prefix; } } return longestPrefix } function getAllChildrenOfTables(tables: TableInfo[]) { const allChildren = []; for (const extractedTable of tables) { const { columns } = extractedTable; (columns.filter(c => typeof c === 'object') as Column[]) .forEach(({ name, dataType }) => { if (typeof dataType === 'string') { dataType = trinoToJs(dataType, 0); } if (typeof dataType === 'object') { allChildren.push(...getObjectChildren(dataType, name)); } }); } return allChildren; } export function getSearchCompletion(tables: TableInfo[], prefix: string | undefined): any { if (!prefix.includes('.')) { return []; } const columnPathForPrefix = findColumnPathForPrefix(tables, prefix.split('.')).slice(0, -1); if (!columnPathForPrefix) { return [] } const filteredChildren = getAllChildrenOfTables(tables).filter(byPrefix(columnPathForPrefix)); const prefixUntilLastDot = extractPrefixUntilLastDot(columnPathForPrefix); const completionArray = filteredChildren.map(({ name, dataType }) => ({ value: name, meta: typeof dataType === 'object' ? 'row' : dataType, caption: name.slice(prefixUntilLastDot.length + 1) })); return completionArray; } function byPrefix(relevantPartOfPrefix: string) { return ({ name }) => { const startOfSearch = findLastDotIndex(relevantPartOfPrefix) >= 0 ? relevantPartOfPrefix.slice(0, findLastDotIndex(relevantPartOfPrefix) + 1) : relevantPartOfPrefix; const searchPart = relevantPartOfPrefix.replace(startOfSearch, '') const parts = name.toLowerCase().split('.'); if (parts.length <= 1) { return false } const substringAfterFirstDot = parts.slice(1).join('.'); const criteria = doesSubstringMatchInHierarchy(substringAfterFirstDot, searchPart.toLowerCase()); const filterIfInDifferentColumn = name.startsWith(relevantPartOfPrefix.split('.')[0]); return name.includes(startOfSearch) && substringAfterFirstDot.includes(searchPart.toLowerCase()) && criteria && filterIfInDifferentColumn; }; } export function getNextLevel(tables: TableInfo[], prefix: string | undefined): any { const columnPathForPrefix = findColumnPathForPrefix(tables, prefix.split('.')).slice(0, -1); const siblings = getAllChildrenOfTables(tables).filter(({ name }) => { const dotCount = name.split('.').length - 1; return name.startsWith(columnPathForPrefix) && dotCount === columnPathForPrefix.split('.').length - 1; }); return siblings.map(({ name, dataType }) => ({ value: prefix.replace(columnPathForPrefix, '') + name, meta: typeof dataType === 'object' ? 'row' : dataType, caption: name.slice(columnPathForPrefix.length) })); } function doesSubstringMatchInHierarchy(substringAfterFirstDot, searchPart) { const lastDotIndex = findLastDotIndex(substringAfterFirstDot); return lastDotIndex >= 0 ? substringAfterFirstDot.substring(lastDotIndex + 1).includes(searchPart) : substringAfterFirstDot.includes(searchPart); } function extractPrefixUntilLastDot(inputString: string) { const lastDotIndex = findLastDotIndex(inputString); return lastDotIndex >= 0 ? inputString.substring(0, lastDotIndex) : inputString } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/sql-autocomplete-adapter.ts ================================================ import { uniqBy } from 'lodash'; import { ICompleterItem } from '../../code-editor/services/code-editor-completer'; import { IAutocompleter } from './types'; import { ContextType, QueryContext, TableInfo, TableType, } from '../sql-context-evaluator'; import { getNextLevel, getSearchCompletion } from "./sql-autocomplete-adapter-utills"; import { trinoToJs } from "./trinoToJs"; import { IDbInfoConfig } from '../db-info'; import { BaseEntity, Column } from '../db-info/types'; interface ComplexCompleterItem extends ICompleterItem { dataType?: string | object } export class SqlAutocompleter implements IAutocompleter { private prefix: string; private lastCompleters: ICompleterItem[] = []; constructor( private readonly config: IDbInfoConfig, private readonly type?: string ) { this.config.preFetch(this.type); } // methods /** * Extract columns and tables from the queryContext * @param {QueryContext} queryContext * @return {ICompleterItem[]} */ public async getCompletionItemsFromQueryContext(queryContext: QueryContext) { const { contextType, tables, prefix } = queryContext; switch (contextType) { case ContextType.Column: return this.getQueryContextColumns(tables); case ContextType.Table: const tablesCompleters = this.getQueryContextTables(tables); if (prefix !== this.prefix) { const [dbEntitiesCompleters, dbCompleters] = await Promise.all([ this.getEntitiesCompletersFromDbBasedOnPrefix(prefix), this.searchEntitiesFromDb(prefix), ]); this.lastCompleters = [...dbEntitiesCompleters, ...dbCompleters]; } this.prefix = prefix; return [...this.lastCompleters, ...tablesCompleters]; default: return []; } } public async getCompletionItemsFromQueryContextColumn(queryContext: QueryContext) { switch (queryContext.contextType) { case ContextType.Column: return this.translateAndGetQueryContextColumns(queryContext.tables, queryContext.prefix); default: return []; } } public async translateAndGetQueryContextColumns(tables: TableInfo[], prefix?: string) { const extractedTables = await this.extractColumnsFromTable(tables); if (prefix.endsWith('.')) { return getNextLevel(extractedTables, prefix); } return getSearchCompletion(extractedTables, prefix); } private async extractColumnsFromTable(tables: TableInfo[]) { const tablesPromises: Promise[] = []; for (const table of tables) { tablesPromises.push(this.extractTableColumns(table)); } return Promise.all(tablesPromises); } /** * Extract the tables from the queryContext * @param {TableInfo[]} tables * @return {ICompleterItem[]} */ private getQueryContextTables(tables: TableInfo[]) { return tables.map((table) => this.createCompleterItem(table.name, 'table')); } /** * Extract the columns from the queryContext * @param {TableInfo[]} tables * @return {Promise} */ private async getQueryContextColumns(tables: TableInfo[]) { const extractedTables = await this.extractColumnsFromTable(tables); const result: ComplexCompleterItem[] = []; for (const extractedTable of extractedTables) { const { name, alias, columns } = extractedTable; const includeTablePrefix = tables.length > 1; columns.forEach((column) => { if (typeof column === 'object' && typeof column.dataType === 'string') { column.dataType = trinoToJs(column.dataType, 0); } let meta: string | undefined; if (typeof column === 'object' && 'dataType' in column) { const objectInTrino = 'row'; meta = typeof column.dataType === 'object' ? objectInTrino : column.dataType; } const getColumnDisplayName = (inputColumn: Column | string) => { return inputColumn instanceof Object ? inputColumn.name : inputColumn; }; let value: string; if (alias) { value = `${alias}.${getColumnDisplayName(column)}`; } else if (includeTablePrefix) { value = `${name}.${getColumnDisplayName(column)}`; } else { value = getColumnDisplayName(column); } if (typeof column === 'string') { result.push({ value: column, meta: 'column' }); if (alias || extractedTable.name) { const prefix = alias || extractedTable.name; result.push({ value: `${prefix}.${column}`, meta: 'column' }); } } else { result.push({ meta, value }); result.push({ meta, value: column instanceof Object ? column.name : column }); } }); } return uniqBy(result, (obj) => `${obj.meta}-${obj.value}-${obj.caption}` ) } /** * Extract the columns from the table * @param {TableInfo} table * @return {Promise} */ private async extractTableColumns(table: TableInfo) { const tablesToExtract = [...table.tableRefs]; if (table.type === TableType.External) { tablesToExtract.push(table.name); } const columnsByTablesPromises: Promise[] = []; for (const tableFullName of tablesToExtract) { const [catalog, schema, tableName] = tableFullName.split('.'); columnsByTablesPromises.push( this.config.getColumnsByTable(catalog, schema, tableName, this.type) ); } const columnsByTables = await Promise.all(columnsByTablesPromises); for (const columnsByTable of columnsByTables) { table.columns.push(...columnsByTable); } return table; } private createCompleterItem(value: string, meta: string): ICompleterItem { return { value, meta }; } private async getEntitiesCompletersFromDbBasedOnPrefix(prefix: string) { const prefixArray = prefix.split('.') || []; prefixArray.pop(); prefix = prefixArray.join('.'); let entities: BaseEntity[] = []; switch (prefixArray.length) { case 0: entities = await this.config.getCatalogs(this.type); break; case 1: entities = await this.config.getSchemasByCatalog(prefix, this.type); break; case 2: entities = await this.config.getTablesBySchema( prefixArray[0], prefixArray[1], this.type ); break; default: entities = []; } return entities.map((entity) => this.createCompleterItem( prefix ? `${prefix}.${entity.name}` : entity.name, entity.type ) ); } private async searchEntitiesFromDb( prefix: string ): Promise { const allCompleters = []; if (prefix?.length > 1) { const schemaCompleters: Set = new Set(); const tableCompleters: Set = new Set(); const dbTree = await this.config.getCatalogs(this.type); dbTree.forEach((catalog) => { catalog.children.forEach((schema) => { if (schema.name.indexOf(prefix) !== -1) { schemaCompleters.add(`${catalog.name}.${schema.name}`); } schema.children.forEach((table) => { if (table.name.indexOf(prefix) !== -1) { tableCompleters.add( `${catalog.name}.${schema.name}.${table.name}` ); } }); }); }); [...schemaCompleters].forEach((completer) => allCompleters.push(this.createCompleterItem(completer, 'schema')) ); [...tableCompleters].forEach((completer) => allCompleters.push(this.createCompleterItem(completer, 'table')) ); } return allCompleters; } } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/expected-results.ts ================================================ import { makeCompletionItem } from '../../../../runner/services/autocomplete/autocomplete-utils'; export const expectedResult = { empty: [], twoColumns: [ makeCompletionItem('col1', 'column'), makeCompletionItem('col2', 'column'), ], twoColumnsWithAlias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblAlias1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblAlias1.col2', 'column'), ], twoColumnsWithNameAndAlias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), makeCompletionItem('tblAlias1.col1', 'column'), makeCompletionItem('tblAlias1.col2', 'column'), ], twoColumnsWithAliasAfter: [ makeCompletionItem('col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblAlias1.col1', 'column'), makeCompletionItem('tblAlias1.col2', 'column'), ], twoColumnsWithNameAfter: [ makeCompletionItem('col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('tblName1.col2', 'column'), ], twoColumnsWithName: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), ], twoColumnsWithTwoAliases: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblAlias1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblAlias1.col2', 'column'), makeCompletionItem('tblAlias2.col1', 'column'), makeCompletionItem('tblAlias2.col2', 'column'), ], fourColumnsWithTwoAliases: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblAlias1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblAlias1.col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('tblAlias2.col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('tblAlias2.col4', 'column'), ], fourColumnsWithNameAndAlias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('tblAlias1.col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('tblAlias1.col4', 'column'), ], fourColumnsWith1Alias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('tblAlias1.col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('tblAlias1.col4', 'column'), ], fourColumnsWith1Name: [ makeCompletionItem('col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('tblName1.col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('tblName1.col4', 'column'), ], sixColumnsWithName1: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('col5', 'column'), makeCompletionItem('col6', 'column'), ], sixColumnsWithNameAndAlias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('tblAlias1.col3', 'column'), makeCompletionItem('tblAlias1.col4', 'column'), ], sixColumnsWithNameAnd2Alias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), makeCompletionItem('col3', 'column'), makeCompletionItem('tblAlias1.col3', 'column'), makeCompletionItem('col4', 'column'), makeCompletionItem('tblAlias1.col4', 'column'), makeCompletionItem('tblAlias2.col3', 'column'), makeCompletionItem('tblAlias2.col4', 'column'), ], tableRefsColumnsAndExtColumns: [ makeCompletionItem('tblName1.col1_of_tblRef1', 'varchar'), makeCompletionItem('col1_of_tblRef1', 'varchar'), makeCompletionItem('tblName1.col2_of_tblRef1', 'varchar'), makeCompletionItem('col2_of_tblRef1', 'varchar'), makeCompletionItem('tblName1.col1_of_tblRef2', 'varchar'), makeCompletionItem('col1_of_tblRef2', 'varchar'), makeCompletionItem('tblName1.col2_of_tblRef2', 'varchar'), makeCompletionItem('col2_of_tblRef2', 'varchar'), makeCompletionItem('col1', 'column'), makeCompletionItem('tblName1.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName1.col2', 'column'), makeCompletionItem('ctl1.schm1.extTbl1.col1_of_extTbl1', 'varchar'), makeCompletionItem('col1_of_extTbl1', 'varchar'), makeCompletionItem('ctl1.schm1.extTbl1.col2_of_extTbl1', 'varchar'), makeCompletionItem('col2_of_extTbl1', 'varchar'), ], threeTbl1Wtwithcolumns12AndTblRef1Ext1ExtwithAlias: [ makeCompletionItem('col1', 'column'), makeCompletionItem('tblName2.col1', 'column'), makeCompletionItem('col2', 'column'), makeCompletionItem('tblName2.col2', 'column'), makeCompletionItem('tblName2.col1_of_tblRef1', 'varchar'), makeCompletionItem('col1_of_tblRef1', 'varchar'), makeCompletionItem('tblName2.col2_of_tblRef1', 'varchar'), makeCompletionItem('col2_of_tblRef1', 'varchar'), makeCompletionItem('ctl1.schm1.extTbl1.col1_of_extTbl1', 'varchar'), makeCompletionItem('col1_of_extTbl1', 'varchar'), makeCompletionItem('ctl1.schm1.extTbl1.col2_of_extTbl1', 'varchar'), makeCompletionItem('col2_of_extTbl1', 'varchar'), makeCompletionItem('tblAlias1.col1_of_extTbl1', 'varchar'), makeCompletionItem('tblAlias1.col2_of_extTbl1', 'varchar'), ], }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/get-completion-Items.spec.ts ================================================ import { testInputQueryContext } from './test-inputs/input-query-context'; import { expectedResult } from './expected-results'; import { ContextType } from '../../../sql-context-evaluator/types'; import { runAdapterGetCompletersTest } from '../test-utils/tests-utils'; describe('when reciving queryContext', () => { runAdapterGetCompletersTest( 1, testInputQueryContext[ContextType.Column].empty, expectedResult.empty ); runAdapterGetCompletersTest( 2, testInputQueryContext[ContextType.Column].nestedTable, expectedResult.twoColumns ); runAdapterGetCompletersTest( 3, testInputQueryContext[ContextType.Column].nestedTableWithAlias, expectedResult.twoColumnsWithAlias ); runAdapterGetCompletersTest( 4, testInputQueryContext[ContextType.Column].withTable, expectedResult.twoColumnsWithName ); runAdapterGetCompletersTest( 5, testInputQueryContext[ContextType.Column] .twoTables1Nested1NestedWithAliasSameColumns, expectedResult.twoColumnsWithAliasAfter ); runAdapterGetCompletersTest( 6, testInputQueryContext[ContextType.Column] .twoTables1NestedWithAlias1NestedWithAlias2SameColumns, expectedResult.twoColumnsWithTwoAliases ); runAdapterGetCompletersTest( 7, testInputQueryContext[ContextType.Column] .twoTables1NestedWithAlias1NestedWithAlias2, expectedResult.fourColumnsWithTwoAliases ); runAdapterGetCompletersTest( 8, testInputQueryContext[ContextType.Column].twoTables1Nested1NestedWithAlias, expectedResult.fourColumnsWith1Alias ); runAdapterGetCompletersTest( 9, testInputQueryContext[ContextType.Column].twoTables1Nested1WtSameColumns, expectedResult.twoColumnsWithNameAfter ); runAdapterGetCompletersTest( 10, testInputQueryContext[ContextType.Column].twoTables1Nested1Wt, expectedResult.fourColumnsWith1Name ); runAdapterGetCompletersTest( 11, testInputQueryContext[ContextType.Column] .twoTables1Wt1WithAlias1NestedSameColumns, expectedResult.twoColumnsWithNameAndAlias ); runAdapterGetCompletersTest( 12, testInputQueryContext[ContextType.Column].twoTables1Wt1NestedWithAlias, expectedResult.fourColumnsWithNameAndAlias ); runAdapterGetCompletersTest( 13, testInputQueryContext[ContextType.Column] .threeTables1WtWith2Columns2NestedWith2Columns, expectedResult.sixColumnsWithName1 ); runAdapterGetCompletersTest( 14, testInputQueryContext[ContextType.Column] .threeTables1WtWith2Columns121NestedWithColumns341NestedWithColumns34AndAlias, expectedResult.sixColumnsWithNameAndAlias ); runAdapterGetCompletersTest( 15, testInputQueryContext[ContextType.Column] .threeTables1WtWith2Columns121NestedWithColumns34Alias1NestedWithColumns34Alias2, expectedResult.sixColumnsWithNameAnd2Alias ); runAdapterGetCompletersTest( 16, testInputQueryContext[ContextType.Column] .threeTables1Ext1WtColumns121Wt2Refs, expectedResult.tableRefsColumnsAndExtColumns ); runAdapterGetCompletersTest( 17, testInputQueryContext[ContextType.Column].threeTables2Ext1Wt1Refs2Columns, expectedResult.threeTbl1Wtwithcolumns12AndTblRef1Ext1ExtwithAlias ); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/test-inputs/input-query-context.ts ================================================ import { BasicQueryContextOption } from '../../../../sql-context-evaluator/tests/result-options/utils'; import { ContextType, QueryContext, TableInfo, } from '../../../../sql-context-evaluator/types'; import { testTable } from './input-table'; export const createQueryContextObject = ( contextType: ContextType.Column | ContextType.Table | ContextType.Undefined, tables: TableInfo[], queryContext?: QueryContext ) => { return { ...queryContext, contextType: contextType, tables: tables, } as QueryContext; }; export const testInputQueryContext: BasicQueryContextOption = { [ContextType.Column]: { empty: createQueryContextObject(ContextType.Column, []), nestedTable: createQueryContextObject(ContextType.Column, [ testTable.nested.unnamedWith2Columns12, ]), nestedTableWithAlias: createQueryContextObject(ContextType.Column, [ testTable.nested.unnamedWith2Columns12AndAlias, ]), withTable: createQueryContextObject(ContextType.Column, [ testTable.withTable.namedWith2Columns12, ]), twoTables1Nested1NestedWithAliasSameColumns: createQueryContextObject( ContextType.Column, [ testTable.nested.unnamedWith2Columns12, testTable.nested.unnamedWith2Columns12AndAlias, ] ), twoTables1NestedWithAlias1NestedWithAlias2SameColumns: createQueryContextObject( ContextType.Column, [ testTable.nested.unnamedWith2Columns12AndAlias, testTable.nested.unnamedWith2Columns12AndAlias2, ] ), twoTables1NestedWithAlias1NestedWithAlias2: createQueryContextObject( ContextType.Column, [ testTable.nested.unnamedWith2Columns12AndAlias, testTable.nested.unnamedWith2Columns34AndAlias2, ] ), twoTables1Nested1NestedWithAlias: createQueryContextObject( ContextType.Column, [ testTable.nested.unnamedWith2Columns12, testTable.nested.unnamedWith2Columns34AndAlias, ] ), twoTables1Nested1WtSameColumns: createQueryContextObject( ContextType.Column, [ testTable.nested.unnamedWith2Columns12, testTable.withTable.namedWith2Columns12, ] ), twoTables1Nested1Wt: createQueryContextObject(ContextType.Column, [ testTable.nested.unnamedWith2Columns12, testTable.withTable.namedWith2Columns34, ]), twoTables1Wt1WithAlias1NestedSameColumns: createQueryContextObject( ContextType.Column, [ testTable.withTable.namedWith2Columns12, testTable.nested.unnamedWith2Columns12AndAlias, ] ), twoTables1Wt1NestedWithAlias: createQueryContextObject(ContextType.Column, [ testTable.withTable.namedWith2Columns12, testTable.nested.unnamedWith2Columns34AndAlias, ]), threeTables1WtWith2Columns2NestedWith2Columns: createQueryContextObject( ContextType.Column, [ testTable.withTable.namedWith2Columns12, testTable.nested.unnamedWith2Columns34, testTable.nested.unnamedWith2Columns56, ] ), threeTables1WtWith2Columns121NestedWithColumns341NestedWithColumns34AndAlias: createQueryContextObject( ContextType.Column, [ testTable.withTable.namedWith2Columns12, testTable.nested.unnamedWith2Columns34, testTable.nested.unnamedWith2Columns34AndAlias, ] ), threeTables1WtWith2Columns121NestedWithColumns34Alias1NestedWithColumns34Alias2: createQueryContextObject( ContextType.Column, [ testTable.withTable.namedWith2Columns12, testTable.nested.unnamedWith2Columns34AndAlias, testTable.nested.unnamedWith2Columns34AndAlias2, ] ), threeTables1Ext1WtColumns121Wt2Refs: createQueryContextObject( ContextType.Column, [ testTable.withTable.namedWith2TblRefs, testTable.withTable.namedWith2Columns12, testTable.external.ext, ] ), threeTables2Ext1Wt1Refs2Columns: createQueryContextObject( ContextType.Column, [ testTable.withTable.named2With1TblRef1And2Columns12, testTable.external.ext, testTable.external.extWithAlias, ] ), }, [ContextType.Table]: {}, }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/test-inputs/input-table.ts ================================================ import { TableType } from '../../../../sql-context-evaluator/types'; import { createNewTableInfoObj } from '../../../../sql-context-evaluator/utils'; export const testTable = { nested: { emptyUnnamed: createNewTableInfoObj({ type: TableType.Nested, }), unnamedWith2Columns12: createNewTableInfoObj({ type: TableType.Nested, columns: ['col1', 'col2'], }), unnamedWith2Columns34: createNewTableInfoObj({ type: TableType.Nested, columns: ['col3', 'col4'], }), unnamedWith2Columns56: createNewTableInfoObj({ type: TableType.Nested, columns: ['col5', 'col6'], }), unnamedWith2Columns12AndAlias: createNewTableInfoObj({ type: TableType.Nested, columns: ['col1', 'col2'], alias: 'tblAlias1', }), unnamedWith2Columns12AndAlias2: createNewTableInfoObj({ type: TableType.Nested, columns: ['col1', 'col2'], alias: 'tblAlias2', }), unnamedWith2Columns34AndAlias: createNewTableInfoObj({ type: TableType.Nested, columns: ['col3', 'col4'], alias: 'tblAlias1', }), unnamedWith2Columns34AndAlias2: createNewTableInfoObj({ type: TableType.Nested, columns: ['col3', 'col4'], alias: 'tblAlias2', }), unnamedWith1TableRef1: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], }), unnamedWith1TableRef2: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], }), unnamedWith1TblRef1And2Columns12: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], columns: ['col1', 'col2'], }), unnamedWith1TblRef2And2Columns12: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], columns: ['col1', 'col2'], }), unnamedWith2TblRefs: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1', 'ctl2.schm2.tblRef2'], }), unnamedWith1TblRef1And2Columns12AndAlias: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], columns: ['col1', 'col2'], alias: 'tblAlias1', }), unnamedWith1TblRef2And2Columns12AndAlias: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], columns: ['col1', 'col2'], alias: 'tblAlias1', }), unnamedWith1TblRef1And2Columns12AndAlias2: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], columns: ['col1', 'col2'], alias: 'tblAlias2', }), unnamedWith1TblRef2And2Columns12AndAlias2: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], columns: ['col1', 'col2'], alias: 'tblAlias2', }), }, withTable: { namedWith2Columns12: createNewTableInfoObj({ type: TableType.Nested, name: 'tblName1', columns: ['col1', 'col2'], }), namedWith2Columns34: createNewTableInfoObj({ type: TableType.Nested, name: 'tblName1', columns: ['col3', 'col4'], }), namedWithTblRef1: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], name: 'tblName1', }), namedWithTblRef2: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], name: 'tblName1', }), namedWith1TblRef1And2Columns12: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], columns: ['col1', 'col2'], name: 'tblName1', }), namedWith1TblRef2And2Columns12: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], columns: ['col1', 'col2'], name: 'tblName1', }), named2With1TblRef1And2Columns12: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1'], columns: ['col1', 'col2'], name: 'tblName2', }), named2With1TblRef2And2Columns12: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef2'], columns: ['col1', 'col2'], name: 'tblName2', }), namedWith2TblRefs: createNewTableInfoObj({ type: TableType.Nested, tableRefs: ['ctl1.schm1.tblRef1', 'ctl2.schm2.tblRef2'], name: 'tblName1', }), }, external: { ext: createNewTableInfoObj({ name: 'ctl1.schm1.extTbl1', }), extWithAlias: createNewTableInfoObj({ name: 'ctl1.schm1.extTbl1', alias: 'tblAlias1', }), extWithAlias2: createNewTableInfoObj({ name: 'ctl1.schm1.extTbl1', alias: 'tblAlias2', }), }, }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/test-utils/mock-db-config.ts ================================================ import { Catalog, Column, IDbInfoConfig, Schema, Table, } from '../../../db-info/types'; export class MockDbInfoService implements IDbInfoConfig { preFetch() { return; } public async getColumnsByTable( catalog: string, schema: string, table: string ) { return [ this.createColumn(`col1_of_${table}`), this.createColumn(`col2_of_${table}`), ]; } public async getTablesBySchema(catalog: string, schema: string) { return [ this.createTable(`tbl1_of_${schema}`), this.createTable(`tbl2_of_${schema}`), ]; } public async getSchemasByCatalog(catalog: string) { return [ this.createSchema(`schm1_of_${catalog}`), this.createSchema(`schm2_of_${catalog}`), ]; } public async getCatalogs() { return [this.createCatalog('catalog1')]; } public async search(type: string, prefix: string) { return []; } private createColumn = (name: string): Column => { return { name: name, type: 'column', dataType: 'varchar' } as Column; }; private createTable = (name: string): Table => { return { name: name, type: 'table', children: [this.createColumn('col1'), this.createColumn('col2')], }; }; private createSchema = (name: string): Schema => { return { name: name, type: 'schema', children: [this.createTable('tbl1'), this.createTable('tbl2')], }; }; private createCatalog = (name: string): Catalog => { return { name: name, type: 'catalog', children: [this.createSchema('schm1')], }; }; } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/test-utils/test-getCompletionItemsFromQueryContext.spec.ts ================================================ import { DbInfoService } from "../../../../sql-autocomplete/db-info"; import { ContextType, QueryContext, TableType } from "../../../sql-context-evaluator"; import { SqlAutocompleter } from '../../sql-autocomplete-adapter'; import {expect} from 'chai'; import { MockDbInfoService } from "./mock-db-config"; describe('testing autoComplete for nested objects: ', () => { const config = new MockDbInfoService(); const completer = new SqlAutocompleter(config); const queryContext = { prefix : '', contextType: ContextType.Column, tables : [ { type: TableType.External, name: 'catalog0.schema0.TVAndSports', alias: "", selectAll : false, tableRefs: [], columns : [ { name: 'TV', dataType: 'row(movies row(action row(The_Dark_Knight varchar,The_Avengers varchar,Die_Hard varchar), comedy row(The_Hangover varchar, The_Hangover2 varchar)), tvSeries row(sopranos varchar, The_wire varchar))' }, { name: 'sports', dataType: 'row(team row(basketball varchar, baseball varchar, soccer varchar), individual row(tennis varchar, racketBall varchar))' }, ] }, { type: TableType.External, name: 'catalog1.schema1.foodAndcountries', alias: 'aliasName', selectAll : false, tableRefs: [], columns : [ { name: 'food', dataType: 'row(fastFood row(mcDonalds row(hamBurger varchar,mcflurry varchar,french_fries varchar), asain row(sushi varchar, wok varchar)), local row(falafel varchar, hummus varchar))' }, { name: 'countries', dataType: 'row(israel row(telAviv varchar, jerusalem varchar, ramatGan varchar), USA row(NYC varchar, california varchar))' }, ] } ], } it('should return first level of nested object',async () => { queryContext.prefix= 'catalog0.schema0.TVAndSports.TV.' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [ { value: 'catalog0.schema0.TVAndSports.TV.movies', meta: 'row' , caption: 'movies' }, { value: 'catalog0.schema0.TVAndSports.TV.tvSeries', meta: 'row' , caption: 'tvSeries' }, ] ); }); it('should return second level of nested object',async () => { queryContext.prefix= 'catalog0.schema0.TVAndSports.TV.movies.' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [ { value: 'catalog0.schema0.TVAndSports.TV.movies.action', meta: 'row' , caption: 'action' }, { value: 'catalog0.schema0.TVAndSports.TV.movies.comedy', meta: 'row' , caption: 'comedy' }, ] ); }); it('should return all options that include the letter d from the second layer and above',async () => { queryContext.prefix= 'catalog0.schema0.TVAndSports.TV.movies.d' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [ { value: 'TV.movies.action.The_Dark_Knight', meta: 'varchar' , caption: 'action.The_Dark_Knight' }, { value: 'TV.movies.action.Die_Hard', meta: 'varchar' , caption: 'action.Die_Hard' }, { value: 'TV.movies.comedy', meta: 'row' , caption: 'comedy' }, ] ); }); it('should return second level of nested object but value begins with alias',async () => { queryContext.prefix= 'aliasName.foodAndcountries.food.' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [ { value: 'aliasName.foodAndcountries.food.fastFood', meta: 'row' , caption: 'fastFood' }, { value: 'aliasName.foodAndcountries.food.local', meta: 'row' , caption: 'local' }, ] ); }); it('should return options that include prefix rry in food column',async () => { queryContext.prefix= 'aliasName.foodAndcountries.food.rry' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [ { value: 'food.fastFood.mcDonalds.mcflurry', meta: 'varchar' , caption: 'fastFood.mcDonalds.mcflurry' }, ] ); }); it('should return options that include prefix rryyyy in food column',async () => { queryContext.prefix= 'aliasName.foodAndcountries.food.rryyyy' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [] ); }); it('should return options that include prefix Gan in from 2nd layer and higher',async () => { queryContext.prefix= 'foodAndcountries.countries.Gan' const completers = await getCompletions(queryContext , completer); expect(completers).to.deep.equal( [ { value: 'countries.israel.ramatGan', meta: 'varchar' , caption: 'israel.ramatGan' }, ] ); }); }); async function getCompletions(queryContext: QueryContext , completer: SqlAutocompleter) { return completer.getCompletionItemsFromQueryContextColumn( queryContext ); } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/test-utils/tests-utils.ts ================================================ import { expect } from 'chai'; import { ICompleterItem } from '../../../../code-editor/services/code-editor-completer'; import { QueryContext, } from '../../../sql-context-evaluator'; import { SqlAutocompleter } from '../../sql-autocomplete-adapter'; import { MockDbInfoService } from './mock-db-config'; export const runAdapterGetCompletersTest = ( testnumber: number, queryContext: QueryContext, expected: ICompleterItem[] ) => { const config = new MockDbInfoService(); const autocomp = new SqlAutocompleter(config); it(`test #${testnumber} should return comleters = ${expected}`, async () => { const completers = await autocomp.getCompletionItemsFromQueryContext(queryContext); expect(completers).to.be.deep.equal(expected); }); } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/trinoToJs.spec.ts ================================================ import {expect} from 'chai'; import { trinoToJs } from './trinoToJs'; describe.only('testing trinoToJs function usecase: ', () => { it('should translate a simple row to a js object', () => { const path = 'row(aa varchar)'; expect(trinoToJs(path, 0)).to.deep.equal({ aa: 'varchar' }); //length after change of vars }); it('should translate a simple nested row to a nested js object', () => { const path = 'row(a varchar, b row(a varchar))'; expect(trinoToJs(path, 0)).to.deep.equal({ a: 'varchar', b: { a: 'varchar' } }); }); it('should translate the multilayered row to a js object', () => { const path = 'row(a varchar, b row(c varchar), d e, f row(g row(h row(i varchar))))'; const expected = { a: 'varchar', b: { c: 'varchar' }, d: 'e', f: { g: { h: { i: 'varchar' } } } }; expect(trinoToJs(path, 0)).to.deep.equal(expected); }); it('should translate a row with multiple data structures', () => { const path = 'row(a map(a,a), b row(c varchar), d array(asdasd,asdsd,sdsd), f row(g row(h row(i array(irrelevant,info,rmation)))))'; expect(trinoToJs(path, 0)).to.deep.equal({ a: 'map', b: { c: 'varchar' }, d: 'array', f: {g: {h: { i: 'array'}}} }); }); it('should return an empty input when given an empty one', () => { const path = ''; expect(trinoToJs(path, 0)).to.deep.equal(''); }); it('should parse the nested map and return "map"', () => { const path = 'map(row(a varchar, b bigint), row(c double, d boolean))'; expect(trinoToJs(path, 0)).to.deep.equal('map'); }); it('should parse the nested array and return "array"', () => { const path = 'array(row(a varchar, b map(c integer, d boolean)), row(e double, f map(g varchar, h array(integer))))'; expect(trinoToJs(path, 0)).to.deep.equal('array'); }); it('should fail because of invalid data structure', () => { const path = 'row(a hello(a,b))'; try { expect(trinoToJs(path, 0)).to.deep.equal({}); } catch (error) { expect(error.message).to.equal('Error at index: hello'); } }); it('should fail because of invalid char in key', () => { const path = 'row(a@b row(a,b))'; try { expect(trinoToJs(path, 0)).to.deep.equal({}); } catch (error) { expect(error.message).to.equal('Error at index: 5, illegal key value'); } }); it('should fail because of invalid comma', () => { const path = 'row(a , row(a,b))'; try { expect(trinoToJs(path, 0)).to.deep.equal({}); } catch (error) { expect(error.message).to.equal('Error at index: ow(a , type expected before comma'); } }); it('should return a simple string when given one', () => { const path = 'a varchar'; expect(trinoToJs(path, 0)).to.deep.equal('a varchar'); }); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/trinoToJs.ts ================================================ const enum StartingOptions { Row = 'row(', Map = 'map(', Array = 'array(', TimeStamp = 'timestamp(', } const enum SpecialCharacters { OpenParenthesis = '(', ClosedParenthesis = ')', Comma = ',', Space = ' ', } export function trinoToJs(trinoObjectAsString: string, index: number): object|string { if (trinoObjectAsString.startsWith(StartingOptions.Row , index)) { return processRow(trinoObjectAsString, index + StartingOptions.Row.length); } if (trinoObjectAsString.startsWith(StartingOptions.Map, index )) { return 'map'; } if ( trinoObjectAsString.startsWith(StartingOptions.Array, index ) ) { return 'array'; } return trinoObjectAsString; } export function processRow(trinoObjectAsString: string, index: number): object { const finalObject: object = {}; let key = ""; let value = ""; let objectToInsert; let isFirstWord = true; const LENGTH_OF_SUBSTRING = 5; while (index <= trinoObjectAsString.length) { switch (trinoObjectAsString.charAt(index)) { case SpecialCharacters.OpenParenthesis: { const start = findBeginningOfWord(trinoObjectAsString, index); const result = handleStartingOptions(trinoObjectAsString, start, index); objectToInsert = result.objectToInsert; finalObject[key] = result.type; index = result.newIndex; break; } case SpecialCharacters.ClosedParenthesis: { validateKey(key, index); finalObject[key] = objectToInsert || value; return finalObject; } case SpecialCharacters.Comma: { if (value === "") { throw new Error(`Error at index: ${trinoObjectAsString.substring(index-LENGTH_OF_SUBSTRING,index)}, type expected before comma`); } finalObject[key] = objectToInsert || value; key = ""; value = ""; objectToInsert = undefined; isFirstWord = true; break; } case SpecialCharacters.Space: { isFirstWord = trinoObjectAsString[index-1] === SpecialCharacters.Comma; break; } default: { const charIndex = trinoObjectAsString.charAt(index); if (isFirstWord) { key += charIndex; validateKey(key, index); } else { value += charIndex; } } } index++; } return {}; } function findBeginningOfWord(str: string, index: number): number { while (index > 0 && str[index] !== SpecialCharacters.Space) { index--; } return index; } function handleStartingOptions(trinoObjectAsString: string, start: number, end: number) { let objectToInsert; let newIndex = end; const rowLength = 3; const lengthOfSubstring = 5; switch (getOperator(trinoObjectAsString, start, end)) { case StartingOptions.Row: { objectToInsert = trinoToJs(trinoObjectAsString, end - rowLength); newIndex = findClosingParentheses(trinoObjectAsString, end); break; } case StartingOptions.Map: { newIndex = findClosingParentheses(trinoObjectAsString, end); return { objectToInsert, type: "map", newIndex }; } case StartingOptions.Array: { newIndex = findClosingParentheses(trinoObjectAsString, end); return { objectToInsert, type: "array", newIndex }; } case StartingOptions.TimeStamp: { newIndex = findClosingParentheses(trinoObjectAsString, end); return { objectToInsert, type: "timeStamp", newIndex }; } default : { throw new Error(`Error at index: ${trinoObjectAsString.substring(end-lengthOfSubstring,end)}`); } } return { objectToInsert, newIndex }; } function validateKey(key: string, indexInOriginalString: number) { const forbiddenChars = /^[^!@#$%^&*(),.:;\s\n]+$/; if (!forbiddenChars.test(key)) { throw new Error(`Error at index: ${indexInOriginalString}, illegal key value`); } } function getOperator(trinoObjectAsString: string, start: number , end: number) { return trinoObjectAsString.substring(start+1, end+1); //we are in middle of string start is ' ' } function findClosingParentheses(trinoObjectAsString: string, counter: number): number { let parenthesis = 0; for (let i = counter; i < trinoObjectAsString.length; i++) { if (trinoObjectAsString.charAt(i) === SpecialCharacters.OpenParenthesis) { parenthesis++; } if (trinoObjectAsString.charAt(i) === SpecialCharacters.ClosedParenthesis) { parenthesis--; } if (parenthesis === 0) { return i } } return -1; } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/adapter/types.ts ================================================ import { QueryContext } from '../sql-context-evaluator/types'; export type IContextEvaluator = (input: string, position: number) => any; export interface IAutocompleter { getCompletionItemsFromQueryContext(queryContext: QueryContext): any; } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/db-info/db-info-service.ts ================================================ import { CacheProps, Catalog, Column, IDbInfoConfig, Schema, Table, } from './types'; import axios from 'axios'; export class DbInfoService implements IDbInfoConfig { private readonly cache = new Map(); constructor( private readonly type: string, private readonly apiBasePath: string ) {} preFetch = async (type: string = this.type) => { this.addCacheTypeEntry(type); if (!this.cache.get(type).catalogs) { const response = await axios.get( `${this.apiBasePath}/api/db/${type}/explore` ); this.cache.set(type, response.data); } }; getCatalogs = async (type: string = this.type): Promise => { await this.preFetch(type); return this.cache[type]; }; getSchemasByCatalog = async ( catalog: string, type?: string ): Promise => { const catalogs: Catalog[] = await this.getCatalogs(type); const catalogData: Catalog | undefined = catalogs.find( (currCatalog) => currCatalog.name === catalog ); return catalogData?.children || []; }; getTablesBySchema = async ( catalog: string, schema: string, type?: string ): Promise => { const catalogSchemas: Schema[] = await this.getSchemasByCatalog( catalog, type ); const schemaData: Schema | undefined = catalogSchemas.find( (catalogSchema) => catalogSchema.name === schema ); return schemaData?.children || []; }; getColumnsByTable = async ( catalog: string, schema: string, table: string, type: string = this.type ): Promise => { const query = `${encodeURIComponent(catalog)}/${encodeURIComponent( schema )}/${encodeURIComponent(table)}`; this.addCacheTypeEntry(type); if (this.cache.get(type).tables[query]) { return this.cache.get(type).tables[query]; } const response = await axios.get( `${this.apiBasePath}/api/db/${type}/explore/${query}` ); const tableData: Table = response.data; this.cache.get(type).tables[query] = (tableData?.children || []).map( (column) => ({ ...column, }) ); return this.cache.get(type).tables[query]; }; search = async ( prefix: string, type: string = this.type ): Promise => { return axios .get(`${this.apiBasePath}/api/db/${type}/search`, { params: { q: prefix }, }) .then((response) => response.data); }; private readonly addCacheTypeEntry = (type: string) => { if (!this.cache.has(type)) { const newCacheProp: CacheProps = { catalogs: [], tables: {} }; this.cache.set(type, newCacheProp); } }; } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/db-info/index.ts ================================================ import { DbInfoService } from './db-info-service'; import { IDbInfoConfig, Catalog, Schema, Table, Column } from './types'; export { DbInfoService, IDbInfoConfig, Catalog, Schema, Table, Column }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/db-info/types.ts ================================================ export interface BaseEntity { name: string; type: string; } export interface Column extends BaseEntity { dataType: object | string; } export interface NestedColumn extends Column { dataType: object; } export interface Table extends BaseEntity { children: Column[]; } export interface Schema extends BaseEntity { children: Table[]; } export interface Catalog extends BaseEntity { children: Schema[]; } export interface CacheProps { catalogs: Catalog[]; tables: { [key: string]: Column[] }; } export interface IDbInfoConfig { getColumnsByTable( catalog: string, schema: string, table: string, type?: string ): Promise; getTablesBySchema( catalog: string, schema: string, type?: string ): Promise; getSchemasByCatalog(catalog: string, type?: string): Promise; getCatalogs(type?: string): Promise; search(prefix: string, type?: string): Promise; preFetch(type?: string): any; } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/languge/reserved-words.ts ================================================ export const reservedPrestoWords = [ 'ALTER', 'ALTER COLUMN', 'ALTER TABLE', 'AND', 'AS', 'BETWEEN', 'BY', 'CASE', 'CAST', 'CONSTRAINT', 'CREATE', 'CROSS', 'CROSS APPLY', 'CROSS JOIN', 'CUBE', 'CURRENT_DATE', 'CURRENT_PATH', 'CURRENT_ROLE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'DEALLOCATE', 'DELETE', 'DELETE FROM', 'DESCRIBE', 'DISTINCT', 'DROP', 'ELSE', 'END', 'ESCAPE', 'EXCEPT', 'EXECUTE', 'EXISTS', 'EXTRACT', 'FALSE', 'FOR', 'FROM', 'FULL', // 'GROUP', 'GROUP BY', 'GROUPING', 'HAVING', 'IN', 'INNER', 'INNER JOIN', 'INSERT', 'INSERT INTO', 'INTERSECT', 'INTO', 'IS', 'JOIN', 'LEFT', 'LEFT JOIN', 'LEFT OUTER JOIN', 'LIKE', 'LIMIT', 'LOCALTIME', 'LOCALTIMESTAMP', 'NATURAL', 'NORMALIZE', 'NOT', 'NULL', 'ON', 'OR', // 'ORDER', 'ORDER BY', // 'OUTER', 'OUTER APPLY', 'OUTER JOIN', 'PREPARE', 'RECURSIVE', 'RIGHT', 'RIGHT JOIN', 'RIGHT OUTER JOIN', 'ROLLUP', 'SELECT', 'SET', 'SET CURRENT SCHEMA', 'SET SCHEMA', 'TABLE', 'THEN', 'TRUE', 'UESCAPE', 'UNION', 'UNION ALL', 'UNNEST', 'UPDATE', 'USING', 'VALUES', 'WHEN', 'WHERE', 'WITH', 'XOR', ]; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/context-evaluator.ts ================================================ import * as antlr4 from 'antlr4'; import { PrestoContextListener } from './presto-context-listener'; import { ContextType, QueryContext, TableInfo } from './types'; import { getTableInfoFromRelationNode } from './tree-analyzer'; import { analyzeNamedQueryNode } from './with-clause-analyzer'; import { createPrestoSyntaxTree } from '../../language-parsers/sql-parser/parser'; /** * Takes query and identifier and returns the context of the given identifier in the query. * * @param {string} input sql query * @param {string} identifier to evaluate * * @returns {QueryContext} the evaluated context. */ export const evaluateContext = ( input: string, identifier: string ): QueryContext => { const prestoSyntaxTree = createPrestoSyntaxTree(input); return getContextFromSyntaxTree(prestoSyntaxTree, identifier); }; /** * Takes antlr syntax tree and identifier and returns the context of the given identifier in the tree. * * @param {any} tree antlr syntax tree * @param {string} identifier to evaluate * * @returns {QueryContext} the evaluated context type and the tables info that defines the query. */ const getContextFromSyntaxTree = ( tree: any, identifier: string ): QueryContext => { const prestoContextListener = new PrestoContextListener(); prestoContextListener.setIdentifier(identifier); antlr4.tree.ParseTreeWalker.DEFAULT.walk(prestoContextListener, tree); const contextType = prestoContextListener.getContextType(); const queryTables: TableInfo[] = contextType === ContextType.Column ? evaluateQueryTablesInfo( prestoContextListener.getQuerySpecificationNode() ) : []; const withTablesInfo: TableInfo[] = evaluateWithTablesInfo( prestoContextListener.getWithNodes() ); const tables: TableInfo[] = mergeAndFilterResults( contextType, queryTables, withTablesInfo, identifier ); return { contextType, tables, }; }; /** * Takes querySpecificationNode and evaluate all is 'relation' childrens. * Creates for each relation TableInfo that defines the relation properties. * * @param {any} querySpecificationNode antlr tree node * * @returns {TableInfo[]} TableInfo array. */ const evaluateQueryTablesInfo = (querySpecificationNode: any): TableInfo[] => { return querySpecificationNode ?.relation() .reduce((accumulator: TableInfo[], relationNode: any) => { accumulator.push(...getTableInfoFromRelationNode(relationNode)); return accumulator; }, []); }; /** * Takes array of namedQueryNodes and creates TableInfo that defines the * WITH table properties for each namedQueryNode. * * @param {any[]} namedQueries array of antlr tree node * * @returns {TableInfo[]} TableInfo array. */ const evaluateWithTablesInfo = (namedQueries: any[]): TableInfo[] => { return namedQueries.reduce((accumulator: TableInfo[], withNode: any) => { return accumulator.concat(analyzeNamedQueryNode(withNode)); }, []); }; /** * Takes 2 TableInfo array, one of regular query and one for the WITH tables * and merge them according to the context type. * During the merge, all the regular tables and the table references are replaced with their * corresponding WITH tables, if exists one. * * @param {ContextType} contextType * @param {TableInfo[]} queryTablesInfo * @param {TableInfo[]} withTablesInfo * @param {string} identifier * * @returns {TableInfo[]} a new TableInfo array with the results of the merge and filter. */ const mergeAndFilterResults = ( contextType: ContextType, queryTablesInfo: TableInfo[], withTablesInfo: TableInfo[], identifier: string ): TableInfo[] => { const mergedTableInfoResults: TableInfo[] = []; const withTablesMap = new Map( withTablesInfo.map((table) => { if (table.name !== identifier && table.alias !== identifier) { return [table.name, table]; } }) ); queryTablesInfo.forEach((table: TableInfo) => { if (table.name !== identifier && table.alias !== identifier) { let currentTable: TableInfo = table; if (table.name && withTablesMap.has(table.name)) { currentTable = withTablesMap.get(table.name); if (table.alias) { currentTable.alias = table.alias; } withTablesMap.delete(table.name); } mergedTableInfoResults.push(currentTable); if (currentTable.tableRefs.length > 0) { replaceTableRefsAndWithTables(currentTable, withTablesMap); } } }); if (contextType === ContextType.Table) { mergedTableInfoResults.push(...withTablesMap.values()); } return mergedTableInfoResults; }; /** * Replace all the table references of a given TableInfo with their * corresponding WITH tables info, if exists one. * For each such table, replaces the references and adds the columns of * the WITH table to the given table recursively. * * @param {TableInfo} table * @param {Map} withMap */ const replaceTableRefsAndWithTables = ( table: TableInfo, withMap: Map ) => { const newTableRefs: string[] = []; let tableRefsChanged: boolean = false; table.tableRefs.forEach((tableRef: string) => { if (withMap.has(tableRef)) { tableRefsChanged = true; const withTable = withMap.get(tableRef); newTableRefs.push(...withTable.tableRefs); table.columns.push(...withTable.columns); } else { newTableRefs.push(tableRef); } }); if (tableRefsChanged) { table.tableRefs = newTableRefs; replaceTableRefsAndWithTables(table, withMap); } table.selectAll = table.tableRefs.length > 0; }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/index.ts ================================================ import { evaluateContextFromPosition } from './position-evaluator'; import { evaluateContext } from './context-evaluator'; import { QueryContext, TableInfo, ContextType, TableType } from './types'; export { evaluateContextFromPosition }; export { evaluateContext }; export { QueryContext }; export { TableInfo }; export { ContextType }; export { TableType }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/position-evaluator.ts ================================================ import { evaluateContext } from './context-evaluator'; import { QueryContext } from './types'; /** * Takes query and position and returns the context of the given position in the query * * @param {string} input sql query * @param {number} position to evaluate * * @returns {QueryContext} the evaluated context */ export const evaluateContextFromPosition = ( input: string, position: number ): QueryContext => { const identifier = 'AUTOCOMPLETE_HERE'; const query = createQueryToEvaluate(input, position, identifier); const prefix = getPrefixByPosition(input, position); return { ...evaluateContext(query, identifier), prefix }; }; /** * Replace the nearest word to the given position in the input with the identifier * * @param {string} input * @param {number} position where to insert * @param {string} identifier string to be inserted * * @returns {string} the input after replacement */ const createQueryToEvaluate = ( input: string, position: number, identifier: string ): string => { return position > 0 && position < input.length + 1 ? removeLastPrefix(input.slice(0, position)) + ' ' + identifier + ' ' + input.slice(position) : input; }; /** * Removes the last word in the string matches the format (a-z 0-9 .) * * @param {string} input * * @returns {string} the input after removal */ const removeLastPrefix = (input: string): string => { const parts = input.match(/([\w._]+)|([\s,()=<>'`":;/*!@#$%^&+-]+)/g); if (parts[parts.length - 1].match(/([\w._]+)/)) { parts.pop(); } return parts.join(''); }; /** * @param {string} input * @param {number} position * * @returns {string} the nearest prefix that matches the format (a-z 0-9 .) before the given postion */ const getPrefixByPosition = (input: string, position: number): string => { return input .slice(0, position) .split(/[\s,()=<>'`":;*!@#$%^&+-]+/) .pop(); }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/presto-context-listener.ts ================================================ import { SqlBaseListener, SqlBaseParser, } from '../../language-parsers/presto-grammar'; import { ContextType } from './types'; /** * A listener to parse an Antlr4 syntax tree for presto grammar. * To use the listener first set an identifier and than use the DEFAULT.walk method in Antlr4. * The listener collects data that defines the query context based on the identifier location in the tree. * * @extends {SqlBaseListener} Auto-generated listener by Antlr4 for presto grammar */ export class PrestoContextListener extends SqlBaseListener { private identifier: string; private nodeFound: any; private contextType: ContextType; private insidePrestoWithFlag: boolean; private missingJoin: boolean = false; private missingBy: boolean = false; private readonly withNodes: any[] = []; setIdentifier(value: string) { this.identifier = value; } /** * @returns {any[]} an array of NamedQueryNode (which defines WITH table) that collected * during the 'walk' over the Antlr4 tree. */ getWithNodes(): any[] { return this.withNodes; } /** * @returns {any} the tree node that matches the identifier during the 'walk' over the Antlr4 tree. */ getNodeFound(): any { return this.nodeFound; } /** * The context type is evaluated based on the node found during the 'walk' over the Antlr4 tree. * * @returns {ContextType} context type */ getContextType(): ContextType { return (this.nodeFound && this.contextType) ?? ContextType.Undefined; } /** * Using the node found (which indicates the position to evaluate the context) finds * the next querySpecificationNode up the tree. * * @returns {any} querySpecificationNode */ getQuerySpecificationNode(): any { let currentNode = this.nodeFound; let querySpecificationNode: any; while (currentNode && !querySpecificationNode) { switch (currentNode.ruleIndex) { case SqlBaseParser.RULE_querySpecification: querySpecificationNode = currentNode; break; case SqlBaseParser.RULE_queryNoWith: querySpecificationNode = currentNode .queryTerm() .queryPrimary() .querySpecification(); break; default: currentNode = currentNode.parentCtx; } } return querySpecificationNode; } enterUnquotedIdentifier(ctx: any) { if (ctx.getText() === this.identifier) { this.nodeFound = ctx; if (this.insidePrestoWithFlag) { this.withNodes.pop(); } } } enterColumnReference(_ctx: any) { if (!this.nodeFound && !this.missingBy) { this.contextType = ContextType.Column; } } exitColumnReference(_ctx: any) { if (!this.nodeFound) { this.contextType = ContextType.Undefined; } this.missingBy = false; } enterSelectSingle(_ctx: any) { if (!this.nodeFound) { this.contextType = ContextType.Column; } } exitSelectSingle(_ctx: any) { if (!this.nodeFound) { this.contextType = ContextType.Undefined; } } enterJoinCriteria(_ctx: any) { if (!this.nodeFound) { this.contextType = ContextType.Column; } } exitJoinCriteria(_ctx: any) { if (!this.nodeFound) { this.contextType = ContextType.Undefined; } } enterJoinType(ctx: any) { if (!this.nodeFound) { this.missingJoin = this.missingChildrenExists( ctx.parentCtx, SqlBaseParser.JOIN ); } } enterGroupBy(ctx: any) { if (!this.nodeFound) { this.missingBy = this.missingChildrenExists( ctx.parentCtx, SqlBaseParser.BY ); } } enterSortItem(ctx: any) { if (!this.nodeFound) { this.missingBy = this.missingChildrenExists( ctx.parentCtx, SqlBaseParser.BY ); } } enterTableName(_ctx: any) { if (!this.nodeFound && !this.missingJoin) { this.contextType = ContextType.Table; } } exitTableName(_ctx: any) { if (!this.nodeFound) { this.contextType = ContextType.Undefined; } this.missingJoin = false; } enterPresto_with(_ctx: any) { this.insidePrestoWithFlag = true; } exitPresto_with(_ctx: any) { this.insidePrestoWithFlag = false; } enterNamedQuery(ctx: any) { if (this.insidePrestoWithFlag) { this.withNodes.push(ctx); } } missingChildrenExists(ctx: any, symbolType: any) { return ( ctx.children.find( (child: any) => child .getText() .toLowerCase() .indexOf('missing') !== -1 && child.symbol.type === symbolType ) !== undefined ); } } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/basic-queries.spec.ts ================================================ import { ContextType } from '../../types'; import { basicResult } from '../result-options/basic-results'; import { runQueryTest } from './utils'; describe('Presto sql context evaluator: When receiving a basic query', () => { runQueryTest('', basicResult[ContextType.Undefined].zeroTables); runQueryTest(' ', basicResult[ContextType.Undefined].zeroTables); runQueryTest('SELECT 1', basicResult[ContextType.Undefined].zeroTables); runQueryTest('SE|LECT 1', basicResult[ContextType.Undefined].zeroTables); runQueryTest('SELECT| 1', basicResult[ContextType.Undefined].zeroTables); runQueryTest('SELECT 1|', basicResult[ContextType.Column].zeroTables); describe('and cursor after "SELECT" keyword', () => { runQueryTest( 'SELECT foo,| FROM table1 WHERE foo = "value"', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT |, foo FROM table1 WHERE foo = "value"', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT |, foo FROM table1, table2 as tbl2 WHERE foo = "value"', basicResult[ContextType.Column].twoExternalTablesAndAlias ); runQueryTest( 'SELECT |, foo FROM table1, table2, table3 WHERE foo = "value"', basicResult[ContextType.Column].threeExternalTables ); runQueryTest( 'SELECT |, foo FROM (table1), table2 as tbl2 WHERE foo = "value"', basicResult[ContextType.Column].twoExternalTablesAndAlias ); runQueryTest( 'SELECT foo,| FROM (((table1))) WHERE foo = "value"', basicResult[ContextType.Column].oneExternalTable ); }); describe('and the cursor is after "FROM" keyword', () => { runQueryTest( 'SELECT foo, bar FROM | WHERE foo = "value"', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT foo, bar FROM table1,| WHERE foo = "value"', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT foo, bar FROM table1,|,table2 WHERE foo = "value"', basicResult[ContextType.Table].zeroTables ); }); describe('with comments in it', () => { runQueryTest( '/* comment */ SELECT foo,| FROM table1 WHERE foo = "value"', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar /* comment */ FROM | WHERE foo = "value"', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT foo, bar FROM table1 GROUP BY | /* comment */', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 /* comment */ WHERE |', basicResult[ContextType.Column].twoExternalTables ); }); describe('and cursor after "GROUP BY" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 GROUP BY |', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 GROUP BY |', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 as tbl2 GROUP BY |', basicResult[ContextType.Column].twoExternalTablesAndAlias ); runQueryTest( 'SELECT foo, bar FROM table1, table2 as tbl2 GROUP |', basicResult[ContextType.Undefined].zeroTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 as tbl2 GROUP B|', basicResult[ContextType.Undefined].zeroTables ); }); describe('and cursor after "ORDER BY" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 ORDER BY |', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 ORDER BY |', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 as tbl2 ORDER BY |', basicResult[ContextType.Column].twoExternalTablesAndAlias ); runQueryTest( 'SELECT foo, bar FROM table1, table2 as tbl2 ORDER |', basicResult[ContextType.Undefined].zeroTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 as tbl2 ORDER B|', basicResult[ContextType.Undefined].zeroTables ); }); describe('and cursor after "WHERE" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 WHERE |', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE |', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=|', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE |=bar', basicResult[ContextType.Column].twoExternalTables ); }); describe('and cursor after "WHERE NOT" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 WHERE NOT |', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE NOT |', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE NOT foo=|', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE NOT |=bar', basicResult[ContextType.Column].twoExternalTables ); }); describe('and cursor after "WHERE ... AND" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 WHERE foo=1 AND |', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND |', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE | AND foo=1', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND bar=|', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND |=bar', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE NOT foo=1 AND |=bar', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND NOT |=bar', basicResult[ContextType.Column].twoExternalTables ); }); describe('and cursor after "WHERE ... OR" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 WHERE foo=1 OR |', basicResult[ContextType.Column].oneExternalTable ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR |', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE | OR foo=1', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR bar=|', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR |=bar', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE NOT foo=1 OR |=bar', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR NOT |=bar', basicResult[ContextType.Column].twoExternalTables ); }); describe('and cursor after "HAVING" keyword', () => { runQueryTest( 'SELECT foo, bar FROM table1 HAVING |', basicResult[ContextType.Column].oneExternalTable ); }); describe('and cursor inside function keyword', () => { ['MIN', 'MAX', 'COUNT', 'AVG', 'SUM'].forEach((keyword) => { describe(`=> ${keyword}`, () => { runQueryTest( `SELECT ${keyword}(| FROM table1`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT ${keyword}(|) FROM table1`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT ${keyword}(|, bar FROM table1`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT ${keyword}(|), bar FROM table1`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT ${keyword}(|, bar FROM table1, table2`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT ${keyword}(|), bar FROM table1, table2`, basicResult[ContextType.Column].twoExternalTables ); }); }); }); describe('and cursor inside "CASE" keyword after "SELECT" keyword', () => { runQueryTest( `SELECT foo, CASE WHEN | THEN 'something' ELSE 'something else' END AS goo FROM table1;`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT foo, CASE WHEN bar=1 THEN | ELSE 'something else' END AS goo FROM table1;`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT foo, CASE WHEN bar=1 THEN 'something' ELSE | END AS goo FROM table1;`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT foo, CASE WHEN | THEN 'something' ELSE 'something else' END AS goo FROM table1, table2, table3;`, basicResult[ContextType.Column].threeExternalTables ); }); describe('and cursor inside "CASE" keyword after "ORDER BY" keyword', () => { runQueryTest( `SELECT column1, column2 FROM table1, table2 ORDER BY (CASE WHEN | IS NULL THEN foo ELSE bar END);`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT column1, column2 FROM table1, table2 ORDER BY (CASE WHEN foo IS NULL THEN | ELSE bar END);`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT column1, column2 FROM table1, table2 ORDER BY (CASE WHEN foo IS NULL THEN bar ELSE | END);`, basicResult[ContextType.Column].twoExternalTables ); }); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/join-queries.spec.ts ================================================ import { ContextType } from '../../types'; import { basicResult } from '../result-options/basic-results'; import { runQueryTest } from './utils'; describe('Presto sql context evaluator: When receiving "JOIN" query', () => { describe('and cursor after "SELECT"', () => { runQueryTest( `SELECT | FROM table1 INNER JOIN table2 ON table1.uuid=table2.uuid;`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT table1.OrderID, | FROM (table1 INNER JOIN table2 ON table1.CustomerID = table2.CustomerID INNER JOIN table3 ON table1.ShipperID = table3.ShipperID);`, basicResult[ContextType.Column].threeExternalTables ); runQueryTest( `SELECT table1.OrderID, | FROM ((table1 INNER JOIN table2 ON table1.CustomerID = table2.CustomerID) INNER JOIN table3 ON table1.ShipperID = table3.ShipperID);`, basicResult[ContextType.Column].threeExternalTables ); }); describe('and cursor after "ON"', () => { runQueryTest( `SELECT table1.a, table2.b FROM table1 INNER JOIN table2 ON |;`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT table1.a, table2.b FROM table1 INNER JOIN table2 ON table1.uuid=|;`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT table1.a, table2.b FROM table1 INNER JOIN table2 ON |=table2.uuid;`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT table1.a, table2.b, table3.c FROM ((table1 INNER JOIN table2 ON table1.CustomerID = table2.CustomerID) INNER JOIN table3 ON |);`, basicResult[ContextType.Column].threeExternalTables ); }); describe('and cursor after "USING"', () => { /* * TODO : if the cursor after "USING" the correct result is only the columns that appear in both tables. */ runQueryTest( `SELECT table1.a, table2.b FROM table1 INNER JOIN table2 USING (|;`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT table1.a, table2.b FROM table1 INNER JOIN table2 USING (|);`, basicResult[ContextType.Column].twoExternalTables ); runQueryTest( `SELECT table1.a, table2.b, table3.c FROM ((table1 INNER JOIN table2 USING (CustomerID)) INNER JOIN table3 USING (|));`, basicResult[ContextType.Column].threeExternalTables ); }); describe('and cursor after "JOIN"', () => { runQueryTest( `SELECT table1.a, table1.b FROM table1 INNER JOIN |`, basicResult[ContextType.Table].zeroTables ); runQueryTest( `SELECT table1.a, table2.b FROM ((table1 INNER JOIN table2 ON table1.CustomerID = table2.CustomerID) INNER JOIN |`, basicResult[ContextType.Table].zeroTables ); }); describe('while typing "JOIN"', () => { runQueryTest( `SELECT table1.a, table1.b FROM table1 INNER |`, basicResult[ContextType.Undefined].zeroTables ); runQueryTest( `SELECT table1.a, table1.b FROM table1 LEFT |`, basicResult[ContextType.Undefined].zeroTables ); runQueryTest( `SELECT table1.a, table1.b FROM table1 RIGHT |`, basicResult[ContextType.Undefined].zeroTables ); runQueryTest( `SELECT table1.a, table1.b FROM table1 OUTER |`, basicResult[ContextType.Undefined].zeroTables ); runQueryTest( `SELECT table1.a, table1.b FROM table1 INNER JOI|`, basicResult[ContextType.Undefined].zeroTables ); }); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/nested-queries.spec.ts ================================================ import { ContextType } from '../../types'; import { nestedResult } from '../result-options/nested-results'; import { basicResult } from '../result-options/basic-results'; import { runQueryTest } from './utils'; describe('Presto sql context evaluator: When receiving a nested query', () => { describe('and the cursor is outside the nested query', () => { describe('after "SELECT" keyword', () => { runQueryTest( 'SELECT | FROM (SELECT a, b FROM A, B)', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT | FROM (SELECT C.a, D.b FROM A as C, B as D)', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT | FROM (SELECT a, b FROM A, B) tbl1', nestedResult[ContextType.Column].oneNestedWithAlias ); runQueryTest( 'SELECT | FROM table1, (SELECT a, b FROM A, B)', nestedResult[ContextType.Column].oneExtOneNested ); runQueryTest( 'SELECT | FROM table1, (SELECT a, b FROM A, B) tbl2', nestedResult[ContextType.Column].oneExtOneNestedWithAlias ); runQueryTest( 'SELECT | FROM table1, (SELECT * FROM A, B) tbl2', nestedResult[ContextType.Column].oneExtOneNestedWithAliasAndRefs ); runQueryTest( 'SELECT | FROM table1, (SELECT * FROM A, B)', nestedResult[ContextType.Column].oneExtOneNestedAndRefs ); runQueryTest( 'SELECT | FROM (SELECT * FROM A, B) tbl1, (SELECT a, b FROM B, C)', nestedResult[ContextType.Column].twoNestedOneWithRefsAndAlias ); }); describe('after "FROM" keyword', () => { runQueryTest( 'SELECT * FROM (SELECT a, b FROM A, B), |', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT * FROM (SELECT a, b FROM A, B) tbl1, |', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT * FROM table1, (SELECT a, b FROM A, B), | ', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT * FROM table1, (SELECT a, b FROM A, B) tbl2, |', basicResult[ContextType.Table].zeroTables ); runQueryTest( 'SELECT * FROM table1, (SELECT * FROM A, B), |', basicResult[ContextType.Table].zeroTables ); }); }); describe('and the cursor is inside the nested query after "SELECT" keyword', () => { runQueryTest( 'SELECT FROM (SELECT | FROM table1, table2)', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT FROM (SELECT | FROM table1, table2) tbl1', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT FROM table1, (SELECT | FROM table1, table2)', basicResult[ContextType.Column].twoExternalTables ); runQueryTest( 'SELECT FROM table1, (SELECT | FROM table1, table2) tbl2', basicResult[ContextType.Column].twoExternalTables ); }); describe('that define a column', () => { runQueryTest( 'SELECT | FROM (SELECT *, (SELECT id FROM table2 WHERE table1.id = table2.id) as foo FROM table1)', nestedResult[ContextType.Column].oneNestedWithRefAndColumn ); // TODO: Add the functionality to get 'column' autocomplete from an external table // inside a nested query that comes after SELECT keyword. // In that case we expect to get two external tables -> ['table1', 'table2'] // runQueryTest( // 'SELECT *, (SELECT id FROM table2 WHERE table1.id = |) as foo FROM table1', // basicResult[ContextType.Column].twoExternalTables // ); }); describe('(double nested)', () => { describe('and the cursor is outside both nested query after "SELECT" keyword', () => { runQueryTest( 'SELECT | FROM (SELECT * FROM (SELECT count(c) a, b FROM A, B))', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT | FROM (SELECT * FROM (SELECT foo.a, bar.b FROM foo, bar))', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT | FROM (SELECT * FROM (SELECT A.a, D.b FROM A, B as D))', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT | FROM (SELECT * FROM (SELECT count(c) a, b FROM A, B)) tbl1', nestedResult[ContextType.Column].oneNestedWithAlias ); runQueryTest( 'SELECT | FROM table1, (SELECT * FROM (SELECT count(c) a, b FROM A, B)) tbl2', nestedResult[ContextType.Column].oneExtOneNestedWithAlias ); runQueryTest( 'SELECT | FROM table1, (SELECT a, b FROM (SELECT * FROM A, B)) tbl2', nestedResult[ContextType.Column].oneExtOneNestedWithAlias ); runQueryTest( 'SELECT | FROM table1, (SELECT * FROM (SELECT * FROM A, B)) tbl2', nestedResult[ContextType.Column].oneExtOneNestedWithAliasAndRefs ); runQueryTest( 'SELECT | FROM table1, (SELECT * FROM (SELECT * FROM A, B) tbl3) tbl2', nestedResult[ContextType.Column].oneExtOneNestedWithAliasAndRefs ); }); describe('and the cursor is inside the first nested query after "SELECT" keyword', () => { runQueryTest( 'SELECT FROM (SELECT | FROM (SELECT count(c) a, b FROM A, B))', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT FROM (SELECT | FROM (SELECT count(c) a, b FROM A, B)) tbl1', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT FROM table1, (SELECT | FROM (SELECT count(c) a, b FROM A, B)) tbl2', nestedResult[ContextType.Column].oneNested ); runQueryTest( 'SELECT FROM table1, (SELECT | FROM (SELECT count(c) a, b FROM A, B) tbl1)', nestedResult[ContextType.Column].oneNestedWithAlias ); runQueryTest( 'SELECT FROM table1, (SELECT | FROM (SELECT * FROM A, B))', nestedResult[ContextType.Column].oneNestedWithRefs ); runQueryTest( 'SELECT FROM table1, (SELECT | FROM (SELECT * FROM A, B) tbl1)', nestedResult[ContextType.Column].oneNestedWithAliasAndRefs ); }); describe('and the cursor is inside the seconed nested query after "SELECT" keyword', () => { runQueryTest( 'SELECT FROM (SELECT FROM (SELECT | FROM table1, table2))', basicResult[ContextType.Column].twoExternalTables ); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/union-queries.spec.ts ================================================ import { ContextType } from '../../types'; import { basicResult } from '../result-options/basic-results'; import { nestedResult } from '../result-options/nested-results'; import { runQueryTest } from './utils'; describe('Presto sql context evaluator: When receiving "UNION" query', () => { describe('and cursor after "SELECT"', () => { runQueryTest( `SELECT a, b, | FROM table1 UNION SELECT a, b, c FROM table2;`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT a, b, c FROM table2 UNION SELECT a, b, | FROM table1;`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT FROM table2 UNION SELECT a, b, | FROM table1;`, basicResult[ContextType.Column].oneExternalTable ); }); describe('with nested quary', () => { describe('And cursor after "SELECT"', () => { runQueryTest( `SELECT | FROM ( SELECT a, b FROM table1 UNION SELECT a, b FROM table2)`, nestedResult[ContextType.Column].oneNested ); runQueryTest( `SELECT | FROM ( SELECT a, b FROM table1 UNION SELECT a, b FROM table2) as tbl1`, nestedResult[ContextType.Column].oneNestedWithAlias ); runQueryTest( `SELECT * FROM ( SELECT a, | FROM table1 UNION SELECT a, b FROM table2) `, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT * FROM ( SELECT a, b FROM table2 UNION SELECT | FROM table1)`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `SELECT | FROM ( SELECT * FROM table1 UNION SELECT * FROM table2)`, nestedResult[ContextType.Column].oneNestedWithOneRef ); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/utils.ts ================================================ import { expect } from 'chai'; import { evaluateContextFromPosition } from '../../position-evaluator'; import { QueryContext } from '../../types'; export interface TestCase { input: string; expected: QueryContext; } const getContext = (input: string) => { return evaluateContextFromPosition( input.replace('|', ''), input.indexOf('|') ); }; export const runQueryTest = ( input: TestCase | TestCase[] | string, expected?: QueryContext ): void => { const tests = typeof input === 'string' ? [{ input, expected }] : input instanceof Array ? input : [input]; tests.forEach((test: TestCase) => { it(`it should return contextType ${test.expected.contextType} and ${test.expected.tables.length} table info. input: '${test.input}'`, () => { const results: QueryContext = getContext(test.input); expect(results) .to.have.property('contextType') .to.be.equal(test.expected.contextType); expect(results) .to.have.property('tables') .deep.equal(test.expected.tables); }); }); }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/with-queries.spec.ts ================================================ import { ContextType, TableType } from '../../types'; import { runQueryTest } from './utils'; import { withResult } from '../result-options/with-results'; import { basicResult } from '../result-options/basic-results'; import { nestedResult } from '../result-options/nested-results'; describe('Presto sql context evaluator: When receiving "WITH" query', () => { describe('and cursor outside the "WITH"', () => { describe('after "SELECT" keyword', () => { runQueryTest( 'WITH table1(foo1, bar1) as (SELECT a, b FROM users) SELECT | FROM table1', withResult[ContextType.Column].oneWithTable ); runQueryTest( 'WITH table1 as (SELECT foo1, bar1 FROM users) SELECT | FROM table1', withResult[ContextType.Column].oneWithTable ); runQueryTest( 'WITH table1 as (SELECT users.foo1, users.bar1 FROM users) SELECT | FROM table1', withResult[ContextType.Column].oneWithTable ); runQueryTest( 'WITH table1 as (SELECT tblOne.foo1, tblTwo.bar1 FROM tblOne, tblTwo) SELECT | FROM table1', withResult[ContextType.Column].oneWithTable ); runQueryTest( 'WITH table1 as (SELECT foo1, bar1 FROM users) SELECT | FROM table1 as tbl1', withResult[ContextType.Column].oneWithTableAliased ); runQueryTest( 'WITH table1 as (SELECT * FROM externalTable) SELECT | FROM table1', withResult[ContextType.Column].oneWithTableAndRef ); runQueryTest( 'WITH table1 as (SELECT foo1, bar1 FROM users) SELECT | FROM table1, table2', withResult[ContextType.Column].oneWithOneExternalTables ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2 as (SELECT foo2, bar2 FROM products) SELECT | FROM table1, table2`, withResult[ContextType.Column].twoWithTables ); runQueryTest( `WITH table1 as (SELECT foo1, fo.bar1 FROM users as fo), table2 as (SELECT products.foo2, st.bar2 FROM products, stores as st) SELECT | FROM table1, table2`, withResult[ContextType.Column].twoWithTables ); describe('(nested query)', () => { runQueryTest( `WITH table1 as (SELECT * FROM (SELECT * FROM externalTable)) SELECT | FROM table1`, withResult[ContextType.Column].oneWithTableAndRef ); runQueryTest( `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM externalTable)) SELECT | FROM table1`, withResult[ContextType.Column].oneWithTable ); runQueryTest( `WITH table2 as (SELECT * FROM externalTable), table1 as (SELECT * FROM table2) SELECT | FROM table1`, withResult[ContextType.Column].oneWithTableWithNameAndOneRef ); runQueryTest( `WITH table2 as (SELECT * FROM externalTable), table3 as (SELECT * FROM table2), table1 as (SELECT * FROM table3) SELECT | FROM table1`, withResult[ContextType.Column].oneWithTableAndRef ); }); }); describe('after "FROM" keyword', () => { runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users) SELECT foo1 FROM |`, withResult[ContextType.Table].oneWithTable ); runQueryTest( `WITH table1 as (SELECT * FROM externalTable) SELECT foo FROM |`, withResult[ContextType.Table].oneWithTableAndRef ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2(foo2, bar2) as (SELECT c, d FROM products) SELECT foo1, b FROM |`, withResult[ContextType.Table].twoWithTables ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2(foo2, bar2) as (SELECT c, d FROM products) SELECT foo1, b FROM table3, |`, withResult[ContextType.Table].twoWithTables ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2(foo2, bar2) as (SELECT c, d FROM products) SELECT foo1, b FROM |, table3`, withResult[ContextType.Table].twoWithTables ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2(foo2, bar2) as (SELECT c, d FROM products) SELECT foo1, b FROM table3, |, table4`, withResult[ContextType.Table].twoWithTables ); describe('(nested query)', () => { runQueryTest( `WITH table1 as (SELECT * FROM (SELECT * FROM externalTable)) SELECT a FROM |`, withResult[ContextType.Table].oneWithTableAndRef ); runQueryTest( `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM externalTable)) SELECT a FROM |`, withResult[ContextType.Table].oneWithTable ); }); }); }); describe('and cursor inside the "WITH"', () => { describe('after "SELECT" keyword', () => { runQueryTest( `WITH table2 as (SELECT foo1, | FROM table1) SELECT foo1 FROM table2`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2(foo2, bar2) as (SELECT | FROM table1) SELECT foo1 FROM table1`, withResult[ContextType.Column].oneWithTable ); runQueryTest( `WITH table2 as (SELECT foo1, bar1 FROM users), table3(foo2, bar2) as (SELECT | FROM table1) SELECT foo1 FROM table2`, basicResult[ContextType.Column].oneExternalTable ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table3(foo2, bar2) as (SELECT | FROM table1, table2) SELECT foo1 FROM table3`, withResult[ContextType.Column].oneWithOneExternalTables ); describe('(nested query)', () => { runQueryTest( `WITH table2 as (SELECT * FROM (SELECT * FROM table1)), table3(foo3, bar3) as (SELECT | FROM (SELECT * FROM table2)) SELECT foo1 FROM table3`, nestedResult[ContextType.Column].oneNestedWithOneRef ); runQueryTest( `WITH table2 as (SELECT * FROM (SELECT a, b FROM table1)), table3(foo3, bar3) as (SELECT | FROM (SELECT * FROM table2)) SELECT foo1 FROM table3`, nestedResult[ContextType.Column].oneNested ); }); }); describe('after "FROM" keyword', () => { runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM |) SELECT foo1 FROM table1`, basicResult[ContextType.Table].zeroTables ); runQueryTest( `WITH table1 as (SELECT foo1, bar1 FROM users), table2(foo2, bar2) as (SELECT c, d FROM |) SELECT foo1 FROM table1`, withResult[ContextType.Table].oneWithTable ); describe('(nested query)', () => { runQueryTest( `WITH table1 as (SELECT * FROM (SELECT * FROM externalTable)), table2(foo2, bar2) as (SELECT c, d FROM |) SELECT foo1 FROM table1`, withResult[ContextType.Table].oneWithTableAndRef ); runQueryTest( `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM users)), table2(foo2, bar2) as (SELECT c, d FROM |) SELECT foo1 FROM table1`, withResult[ContextType.Table].oneWithTable ); runQueryTest( `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM users)), table2(foo2, bar2) as (SELECT c, d FROM |) SELECT foo1 FROM table1`, withResult[ContextType.Table].oneWithTable ); }); }); }); }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/basic-results.ts ================================================ import { ContextType } from '../../types'; import { BasicQueryContextOption, testTable } from './utils'; export const basicResult: BasicQueryContextOption = { [ContextType.Undefined]: { zeroTables: { contextType: ContextType.Undefined, tables: [], }, }, [ContextType.Column]: { zeroTables: { contextType: ContextType.Column, tables: [], }, oneExternalTable: { contextType: ContextType.Column, tables: [testTable.external.table1], }, twoExternalTables: { contextType: ContextType.Column, tables: [testTable.external.table1, testTable.external.table2], }, twoExternalTablesAndAlias: { contextType: ContextType.Column, tables: [ testTable.external.table1, { ...testTable.external.table2, alias: 'tbl2' }, ], }, threeExternalTables: { contextType: ContextType.Column, tables: [ testTable.external.table1, testTable.external.table2, testTable.external.table3, ], }, }, [ContextType.Table]: { zeroTables: { contextType: ContextType.Table, tables: [], }, }, }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/nested-results.ts ================================================ import { ContextType } from '../../types'; import { BasicQueryContextOption, testTable } from './utils'; export const nestedResult: BasicQueryContextOption = { [ContextType.Column]: { oneNested: { contextType: ContextType.Column, tables: [testTable.nested.unnamedWithColumns], }, oneNestedWithRefs: { contextType: ContextType.Column, tables: [ { ...testTable.nested.unnamed, columns: [], tableRefs: ['A', 'B'], selectAll: true, }, ], }, oneNestedWithOneRef: { contextType: ContextType.Column, tables: [ { ...testTable.nested.unnamed, tableRefs: ['table1'], selectAll: true }, ], }, oneNestedWithRefAndColumn: { contextType: ContextType.Column, tables: [ { ...testTable.nested.unnamed, columns: ['foo'], tableRefs: ['table1'], selectAll: true, }, ], }, oneNestedWithAlias: { contextType: ContextType.Column, tables: [{ ...testTable.nested.unnamedWithColumns, alias: 'tbl1' }], }, oneNestedWithAliasAndRefs: { contextType: ContextType.Column, tables: [ { ...testTable.nested.unnamed, alias: 'tbl1', tableRefs: ['A', 'B'], selectAll: true, }, ], }, oneExtOneNested: { contextType: ContextType.Column, tables: [testTable.external.table1, testTable.nested.unnamedWithColumns], }, oneExtOneNestedWithAlias: { contextType: ContextType.Column, tables: [ testTable.external.table1, { ...testTable.nested.unnamedWithColumns, alias: 'tbl2' }, ], }, oneExtOneNestedWithAliasAndRefs: { contextType: ContextType.Column, tables: [ testTable.external.table1, { ...testTable.nested.unnamed, alias: 'tbl2', tableRefs: ['A', 'B'], selectAll: true, }, ], }, oneExtOneNestedAndRefs: { contextType: ContextType.Column, tables: [ testTable.external.table1, { ...testTable.nested.unnamed, tableRefs: ['A', 'B'], selectAll: true }, ], }, twoNestedOneWithRefsAndAlias: { contextType: ContextType.Column, tables: [ { ...testTable.nested.unnamed, alias: 'tbl1', tableRefs: ['A', 'B'], selectAll: true, }, testTable.nested.unnamedWithColumns, ], }, }, }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/utils.ts ================================================ import { TableType, ContextType, QueryContext } from '../../types'; import { createNewTableInfoObj } from '../../utils'; export type BasicQueryContextOption = { [key in ContextType]?: Record; }; export const testTable = { nested: { unnamed: createNewTableInfoObj({ type: TableType.Nested, }), unnamedWithColumns: createNewTableInfoObj({ type: TableType.Nested, columns: ['a', 'b'], }), table1: createNewTableInfoObj({ name: 'table1', type: TableType.Nested, columns: ['foo1', 'bar1'], }), table1WithRef: createNewTableInfoObj({ name: 'table1', type: TableType.Nested, tableRefs: ['externalTable'], selectAll: true, }), table2: createNewTableInfoObj({ name: 'table2', type: TableType.Nested, columns: ['foo2', 'bar2'], }), }, external: { table1: createNewTableInfoObj({ name: 'table1', type: TableType.External, }), table2: createNewTableInfoObj({ name: 'table2', type: TableType.External, }), table3: createNewTableInfoObj({ name: 'table3', type: TableType.External, }), }, }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/with-results.ts ================================================ import { ContextType } from '../../types'; import { BasicQueryContextOption } from '../result-options/utils'; import { testTable } from './utils'; export const withResult: BasicQueryContextOption = { [ContextType.Column]: { oneWithTable: { contextType: ContextType.Column, tables: [testTable.nested.table1], }, oneWithTableWithNameAndOneRef: { contextType: ContextType.Column, tables: [testTable.nested.table1WithRef], }, oneWithTableAliased: { contextType: ContextType.Column, tables: [{ ...testTable.nested.table1, alias: 'tbl1' }], }, oneWithTableAndRef: { contextType: ContextType.Column, tables: [testTable.nested.table1WithRef], }, twoWithTables: { contextType: ContextType.Column, tables: [testTable.nested.table1, testTable.nested.table2], }, oneWithOneExternalTables: { contextType: ContextType.Column, tables: [testTable.nested.table1, testTable.external.table2], }, }, [ContextType.Table]: { oneWithTable: { contextType: ContextType.Table, tables: [testTable.nested.table1], }, oneWithTableAndRef: { contextType: ContextType.Table, tables: [testTable.nested.table1WithRef], }, twoWithTables: { contextType: ContextType.Table, tables: [testTable.nested.table1, testTable.nested.table2], }, }, }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tree-analyzer.ts ================================================ import { QueryDetails, TableInfo, TableType } from './types'; import { createNewTableInfoObj } from './utils'; /** * Recuresive function which takes a relationNode and returns a TableInfo array * that defines the relation properties considering sub-relations. * * @param {any} relationNode * * @returns {TableInfo[]} TableInfo array */ export const getTableInfoFromRelationNode = ( relationNode: any ): TableInfo[] => { if (relationNode.relation) { // when using 'JOIN' keyword -> split and analyze all sub-relations return relationNode .relation() ?.reduce((accumulator: TableInfo[], subRelation: any) => { return accumulator.concat(...getTableInfoFromRelationNode(subRelation)); }, []); } const aliasedRelationNode = relationNode.sampledRelation().aliasedRelation(); const relationPrimaryNode = aliasedRelationNode.relationPrimary(); if (relationPrimaryNode.relation) { // dealing with nested parentheses, for example: SELECT * FROM ((some_table)) return getTableInfoFromRelationNode(relationPrimaryNode.relation()); } const currentTableInfo: TableInfo = createNewTableInfoObj({ name: relationPrimaryNode.qualifiedName && relationPrimaryNode.qualifiedName()?.getText(), type: relationPrimaryNode.query ? TableType.Nested : TableType.External, alias: aliasedRelationNode.identifier && aliasedRelationNode.identifier()?.getText(), }); if (currentTableInfo.type === TableType.Nested && relationPrimaryNode.query) { // evaluate the nested query and merge it with the currentTableInfo const nestedQueryDetails: QueryDetails = getQueryDetailsFromQuerySpecificationNode( getNextQuerySpecificationNode(relationNode) ); aggregateQueryDetailsAndTableInfo(nestedQueryDetails, currentTableInfo); } return [currentTableInfo]; }; /** * Recuresive function which takes a querySpecificationNode and returns a QueryDetails * that defines all the query properties considering tables and columns. * * @param {any} querySpecificationNode * * @returns {QueryDetails} query properties */ export const getQueryDetailsFromQuerySpecificationNode = ( querySpecificationNode: any ): QueryDetails => { const tables: TableInfo[] = []; const columns: string[] = []; let selectAll: boolean = false; // evaluate all relations after FROM clause querySpecificationNode ?.relation() .forEach((relation: any) => tables.push(...getTableInfoFromRelationNode(relation)) ); const prefixToReplace = createRegexNameFilter(tables); // evaluate all columns after SELECT clause querySpecificationNode ?.selectItem() .forEach((selectItem: any) => selectItem.ASTERISK ? (selectAll = true) : columns.push( selectItem.identifier() ? selectItem.identifier().getText() : selectItem.getText().replace(prefixToReplace, '') ) ); return { tables, columns, selectAll }; }; /** * Takes TableInfo array and creates a RegExp to match all tables aliases/names in the given array. * * @param {TableInfo[]} tables * * @returns {RegExp} Regular expression of all tables aliases/names */ const createRegexNameFilter = (tables: TableInfo[]): RegExp => { const tablesNames = tables.reduce((names, table) => { const name = table.alias || table.name; if (name) { names.push(name); } return names; }, []); return tablesNames.length > 0 ? new RegExp(`^(${tablesNames.join('|')})\\.`, 'g') : undefined; }; /** * Takes QueryDetails and aggregates it into a given TableInfo. * * @param {QueryDetails} queryDetails * @param {TableInfo} tableInfo * * @return {void} */ export const aggregateQueryDetailsAndTableInfo = ( queryDetails: QueryDetails, tableInfo: TableInfo ): void => { queryDetails.tables.forEach((table: TableInfo) => { if (queryDetails.selectAll) { if (table.type === TableType.External) { tableInfo.selectAll = true; tableInfo.tableRefs.push(table.name); } else if (table.type === TableType.Nested) { tableInfo.selectAll = tableInfo.selectAll || table.selectAll; tableInfo.tableRefs.push(...table.tableRefs); tableInfo.columns.push(...table.columns); } } }); tableInfo.columns.push(...queryDetails.columns); }; /** * Takes any Antlr4 tree node and advances it to the next QuerySpecificationNode down the tree. * * @param {any} currentNode * * @return {any} querySpecificationNode */ export const getNextQuerySpecificationNode = (currentNode: any): any => { if (!(currentNode?.children?.length > 0)) { return null; } let nextNode: any = currentNode; nextNode = nextNode?.sampledRelation ? nextNode.sampledRelation() : nextNode; nextNode = nextNode?.aliasedRelation ? nextNode.aliasedRelation() : nextNode; nextNode = nextNode?.relationPrimary ? nextNode.relationPrimary() : nextNode; nextNode = nextNode?.query ? nextNode.query() : nextNode; nextNode = nextNode?.queryNoWith ? nextNode.queryNoWith() : nextNode; nextNode = nextNode?.queryTerm ? nextNode.queryTerm() : nextNode; // when use 'UNION' keyword -> analyze the first table nextNode = nextNode?.queryTerm ? nextNode.queryTerm()[0] : nextNode; nextNode = nextNode?.queryPrimary ? nextNode.queryPrimary() : nextNode; return nextNode?.querySpecification ? nextNode.querySpecification() : nextNode !== currentNode ? getNextQuerySpecificationNode(nextNode) : null; }; ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/types.ts ================================================ import { Column } from "../db-info"; export enum TableType { External = 'External', Nested = 'Nested', } export interface QueryDetails { columns: string[]; selectAll?: boolean; tables: TableInfo[]; } export interface TableInfo { type: TableType; name: string; alias: string; columns: (Column | string)[]; tableRefs: string[]; selectAll: boolean; } export enum ContextType { Table = 'Table', Column = 'Column', Undefined = 'Undefined', } export interface QueryContext { contextType: ContextType; tables: TableInfo[]; prefix?: string; } ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/utils.ts ================================================ import { TableInfo, TableType } from './types'; export const createNewTableInfoObj = ( tableInfo?: Partial ): TableInfo => ({ type: TableType.External, name: undefined, alias: undefined, columns: [], tableRefs: [], selectAll: false, ...tableInfo, }); ================================================ FILE: quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/with-clause-analyzer.ts ================================================ import { aggregateQueryDetailsAndTableInfo, getQueryDetailsFromQuerySpecificationNode, getNextQuerySpecificationNode, } from './tree-analyzer'; import { QueryDetails, TableInfo, TableType } from './types'; import { createNewTableInfoObj } from './utils'; /** * Takes NamedQueryNode (which defines WITH table) and analyzes its properties using the tree-analyzer. * * @param {any} namedQueryNode * * @returns {TableInfo} the WITH table details as table info */ export const analyzeNamedQueryNode = (namedQueryNode: any): TableInfo => { const currentTableInfo: TableInfo = createNewTableInfoObj({ name: getWithClauseName(namedQueryNode), type: TableType.Nested, columns: getColumnAliases(namedQueryNode), }); if (currentTableInfo.columns.length === 0) { const queryDetails: QueryDetails = getQueryDetailsFromQuerySpecificationNode( getNextQuerySpecificationNode(namedQueryNode) ); aggregateQueryDetailsAndTableInfo(queryDetails, currentTableInfo); } return currentTableInfo; }; /** * @param {any} namedQueryNode * * @returns {string} name */ const getWithClauseName = (namedQueryNode: any): string => { return namedQueryNode.identifier().getText(); }; /** * In cases where the column names are defined along with the table name, an array of columns names will be returned. * For example: WITH foo(bar, goo) as (SELECT a, b FROM c) * * @param {any} namedQueryNode * * @returns {string[]} columns names */ const getColumnAliases = (namedQueryNode: any): string[] => { const columnsAlias: string[] = []; if (namedQueryNode.columnAliases) { namedQueryNode .columnAliases() ?.identifier() ?.forEach((identifier: any) => { columnsAlias.push(identifier.getText()); }); } return columnsAlias; }; ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016-present ZeroTurnaround LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. attributed to https://github.com/zeroturnaround/sql-formatter ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/core/Formatter.ts ================================================ import includes from 'lodash/includes'; import trimEnd from 'lodash/trimEnd'; import tokenTypes from './tokenTypes'; import Indentation from './Indentation'; import InlineBlock from './InlineBlock'; import Params from './Params'; import Tokenizer from './Tokenizer'; export interface Cfg { indent?: string; params?: Params; } export default class Formatter { private readonly cfg: Cfg; private readonly indentation: Indentation; private readonly inlineBlock: InlineBlock; private readonly params: Params; private readonly tokenizer: Tokenizer; private previousReservedWord: any; private index: number; private tokens: any[]; /** * @param {Object} cfg * @param {Object} cfg.indent * @param {Object} cfg.params * @param {Tokenizer} tokenizer */ constructor(cfg, tokenizer) { this.cfg = cfg || {}; this.indentation = new Indentation(this.cfg.indent); this.inlineBlock = new InlineBlock(); this.params = new Params(this.cfg.params); this.tokenizer = tokenizer; this.previousReservedWord = {}; this.tokens = []; this.index = 0; } /** * Formats whitespaces in a SQL string to make it easier to read. * * @param {String} query The SQL query string * @return {String} formatted query */ format(query) { this.tokens = this.tokenizer.tokenize(query); const formattedQuery = this.getFormattedQueryFromTokens(); return formattedQuery.trim(); } getFormattedQueryFromTokens() { let formattedQuery = ''; this.tokens.forEach((token, index) => { this.index = index; if (token.type === tokenTypes.WHITESPACE) { // ignore (we do our own whitespace formatting) } else if (token.type === tokenTypes.LINE_COMMENT) { formattedQuery = this.formatLineComment(token, formattedQuery); } else if (token.type === tokenTypes.BLOCK_COMMENT) { formattedQuery = this.formatBlockComment(token, formattedQuery); } else if (token.type === tokenTypes.RESERVED_TOPLEVEL) { formattedQuery = this.formatToplevelReservedWord(token, formattedQuery); this.previousReservedWord = token; } else if (token.type === tokenTypes.RESERVED_NEWLINE) { formattedQuery = this.formatNewlineReservedWord(token, formattedQuery); this.previousReservedWord = token; } else if (token.type === tokenTypes.RESERVED) { formattedQuery = this.formatWithSpaces(token, formattedQuery); this.previousReservedWord = token; } else if (token.type === tokenTypes.OPEN_PAREN) { formattedQuery = this.formatOpeningParentheses(token, formattedQuery); } else if (token.type === tokenTypes.CLOSE_PAREN) { formattedQuery = this.formatClosingParentheses(token, formattedQuery); } else if (token.type === tokenTypes.PLACEHOLDER) { formattedQuery = this.formatPlaceholder(token, formattedQuery); } else if (token.value === ',') { formattedQuery = this.formatComma(token, formattedQuery); } else if (token.value === ':') { formattedQuery = this.formatWithSpaceAfter(token, formattedQuery); } else if (token.value === '.') { formattedQuery = this.formatWithoutSpaces(token, formattedQuery); } else if (token.value === ';') { formattedQuery = this.formatQuerySeparator(token, formattedQuery); } else { formattedQuery = this.formatWithSpaces(token, formattedQuery); } }); return formattedQuery; } formatLineComment(token, query: string) { return this.addNewline(query + token.value); } formatBlockComment(token, query: string) { return this.addNewline(this.addNewline(query) + this.indentComment(token.value)); } indentComment(comment) { return comment.replace(/\n/g, '\n' + this.indentation.getIndent()); } formatToplevelReservedWord(token, query) { this.indentation.decreaseTopLevel(); query = this.addNewline(query); this.indentation.increaseToplevel(); query += this.equalizeWhitespace(token.value); return this.addNewline(query); } formatNewlineReservedWord(token, query) { return this.addNewline(query) + this.equalizeWhitespace(token.value) + ' '; } // Replace any sequence of whitespace characters with single space equalizeWhitespace(string) { return string.replace(/\s+/g, ' '); } // Opening parentheses increase the block indent level and start a new line formatOpeningParentheses(token, query) { // Take out the preceding space unless there was whitespace there in the original query // or another opening parens or line comment const preserveWhitespaceFor = [tokenTypes.WHITESPACE, tokenTypes.OPEN_PAREN, tokenTypes.LINE_COMMENT]; if (!includes(preserveWhitespaceFor, this.previousToken().type)) { query = trimEnd(query); } query += token.value; this.inlineBlock.beginIfPossible(this.tokens, this.index); if (!this.inlineBlock.isActive()) { this.indentation.increaseBlockLevel(); query = this.addNewline(query); } return query; } // Closing parentheses decrease the block indent level formatClosingParentheses(token, query) { if (this.inlineBlock.isActive()) { this.inlineBlock.end(); return this.formatWithSpaceAfter(token, query); } this.indentation.decreaseBlockLevel(); return this.formatWithSpaces(token, this.addNewline(query)); } formatPlaceholder(token, query) { return query + this.params.get(token) + ' '; } // Commas start a new line (unless within inline parentheses or SQL "LIMIT" clause) formatComma(token, query) { query = this.trimTrailingWhitespace(query) + token.value + ' '; if (this.inlineBlock.isActive()) { return query; } if (/^LIMIT$/i.test(this.previousReservedWord.value)) { return query; } return this.addNewline(query); } formatWithSpaceAfter(token, query) { return this.trimTrailingWhitespace(query) + token.value + ' '; } formatWithoutSpaces(token, query) { return this.trimTrailingWhitespace(query) + token.value; } formatWithSpaces(token, query) { return query + token.value + ' '; } formatQuerySeparator(token, query) { return this.trimTrailingWhitespace(query) + token.value + '\n'; } addNewline(query) { return trimEnd(query) + '\n' + this.indentation.getIndent(); } trimTrailingWhitespace(query) { if (this.previousNonWhitespaceToken().type === tokenTypes.LINE_COMMENT) { return trimEnd(query) + '\n'; } return trimEnd(query); } previousNonWhitespaceToken() { let n = 1; while (this.previousToken(n).type === tokenTypes.WHITESPACE) { n++; } return this.previousToken(n); } previousToken(offset = 1) { return this.tokens[this.index - offset] || {}; } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/core/Indentation.ts ================================================ import repeat from 'lodash/repeat'; import last from 'lodash/last'; const INDENT_TYPE_TOP_LEVEL = 'top-level'; const INDENT_TYPE_BLOCK_LEVEL = 'block-level'; /** * Manages indentation levels. * * There are two types of indentation levels: * * - BLOCK_LEVEL : increased by open-parenthesis * - TOP_LEVEL : increased by RESERVED_TOPLEVEL words */ export default class Indentation { private readonly indent: string; private readonly indentTypes: string[]; /** * @param {String} indent Indent value, default is " " (2 spaces) */ constructor(indent) { this.indent = indent || ' '; this.indentTypes = []; } /** * Returns current indentation string. * @return {String} */ getIndent() { return repeat(this.indent, this.indentTypes.length); } /** * Increases indentation by one top-level indent. */ increaseToplevel() { this.indentTypes.push(INDENT_TYPE_TOP_LEVEL); } /** * Increases indentation by one block-level indent. */ increaseBlockLevel() { this.indentTypes.push(INDENT_TYPE_BLOCK_LEVEL); } /** * Decreases indentation by one top-level indent. * Does nothing when the previous indent is not top-level. */ decreaseTopLevel() { if (last(this.indentTypes) === INDENT_TYPE_TOP_LEVEL) { this.indentTypes.pop(); } } /** * Decreases indentation by one block-level indent. * If there are top-level indents within the block-level indent, * throws away these as well. */ decreaseBlockLevel() { while (this.indentTypes.length > 0) { const type = this.indentTypes.pop(); if (type !== INDENT_TYPE_TOP_LEVEL) { break; } } } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/core/InlineBlock.ts ================================================ import tokenTypes from './tokenTypes'; const INLINE_MAX_LENGTH = 50; /** * Bookkeeper for inline blocks. * * Inline blocks are parenthized expressions that are shorter than INLINE_MAX_LENGTH. * These blocks are formatted on a single line, unlike longer parenthized * expressions where open-parenthesis causes newline and increase of indentation. */ export default class InlineBlock { private level: number; constructor() { this.level = 0; } /** * Begins inline block when lookahead through upcoming tokens determines * that the block would be smaller than INLINE_MAX_LENGTH. * @param {Object[]} tokens Array of all tokens * @param {Number} index Current token position */ beginIfPossible(tokens, index) { if (this.level === 0 && this.isInlineBlock(tokens, index)) { this.level = 1; } else if (this.level > 0) { this.level++; } else { this.level = 0; } } /** * Finishes current inline block. * There might be several nested ones. */ end() { this.level--; } /** * True when inside an inline block * @return {Boolean} */ isActive() { return this.level > 0; } // Check if this should be an inline parentheses block // Examples are "NOW()", "COUNT(*)", "int(10)", key(`somecolumn`), DECIMAL(7,2) isInlineBlock(tokens, index) { let length = 0; let level = 0; for (let i = index; i < tokens.length; i++) { const token = tokens[i]; length += token.value.length; // Overran max length if (length > INLINE_MAX_LENGTH) { return false; } if (token.type === tokenTypes.OPEN_PAREN) { level++; } else if (token.type === tokenTypes.CLOSE_PAREN) { level--; if (level === 0) { return true; } } if (this.isForbiddenToken(token)) { return false; } } return false; } // Reserved words that cause newlines, comments and semicolons // are not allowed inside inline parentheses block isForbiddenToken({type, value}) { return ( type === tokenTypes.RESERVED_TOPLEVEL || type === tokenTypes.RESERVED_NEWLINE || type === tokenTypes.LINE_COMMENT || type === tokenTypes.BLOCK_COMMENT || value === ';' ); } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/core/Params.ts ================================================ /** * Handles placeholder replacement with given params. */ export default class Params { private readonly params: any; private index: number; /** * @param {Object} params */ constructor(params) { this.params = params; this.index = 0; } /** * Returns param value that matches given placeholder with param key. * @param {Object} token * @param {String} token.key Placeholder key * @param {String} token.value Placeholder value * @return {String} param or token.value when params are missing */ get({key, value}) { if (!this.params) { return value; } if (key) { return this.params[key]; } return this.params[this.index++]; } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/core/Tokenizer.ts ================================================ import isEmpty from 'lodash/isEmpty'; import escapeRegExp from 'lodash/escapeRegExp'; import tokenTypes from './tokenTypes'; export default class Tokenizer { private readonly WHITESPACE_REGEX: RegExp; private readonly NUMBER_REGEX: RegExp; private readonly OPERATOR_REGEX: RegExp; private readonly BLOCK_COMMENT_REGEX: RegExp; private readonly LINE_COMMENT_REGEX: RegExp; private readonly RESERVED_TOPLEVEL_REGEX: RegExp; private readonly RESERVED_NEWLINE_REGEX: RegExp; private readonly RESERVED_PLAIN_REGEX: RegExp; private readonly WORD_REGEX: RegExp; private readonly STRING_REGEX: RegExp; private readonly OPEN_PAREN_REGEX: RegExp; private readonly CLOSE_PAREN_REGEX: RegExp; private readonly INDEXED_PLACEHOLDER_REGEX: RegExp | false; private readonly IDENT_NAMED_PLACEHOLDER_REGEX: RegExp | false; private readonly STRING_NAMED_PLACEHOLDER_REGEX: RegExp | false; // private readonly SPECIAL_TOKENS: RegExp | false = false; private readonly upperCase: boolean = false; /** * @param {Object} cfg * @param {String[]} cfg.reservedWords Reserved words in SQL * @param {String[]} cfg.reservedToplevelWords Words that are set to new line separately * @param {String[]} cfg.reservedNewlineWords Words that are set to newline * @param {String[]} cfg.stringTypes String types to enable: "", '', ``, [], N'' * @param {String[]} cfg.openParens Opening parentheses to enable, like (, [ * @param {String[]} cfg.closeParens Closing parentheses to enable, like ), ] * @param {String[]} cfg.indexedPlaceholderTypes Prefixes for indexed placeholders, like ? * @param {String[]} cfg.namedPlaceholderTypes Prefixes for named placeholders, like @ and : * @param {String[]} cfg.lineCommentTypes Line comments to enable, like # and -- * @param {String[]} cfg.specialWordChars Special chars that can be found inside of words, like @ and # * @param {boolean} cfg.upperCase */ constructor(cfg: any) { this.WHITESPACE_REGEX = /^(\s+)/; this.NUMBER_REGEX = /^((-\s*)?[0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)\b/; this.OPERATOR_REGEX = /^(!=|<>|==|<=|>=|!<|!>|\|\||::|->>|->|~~\*|~~|!~~\*|!~~|~\*|!~\*|!~|.)/; this.BLOCK_COMMENT_REGEX = /^(\/\*[^]*?(?:\*\/|$))/; this.LINE_COMMENT_REGEX = this.createLineCommentRegex(cfg.lineCommentTypes); this.RESERVED_TOPLEVEL_REGEX = this.createReservedWordRegex(cfg.reservedToplevelWords); this.RESERVED_NEWLINE_REGEX = this.createReservedWordRegex(cfg.reservedNewlineWords); this.RESERVED_PLAIN_REGEX = this.createReservedWordRegex(cfg.reservedWords); this.WORD_REGEX = this.createWordRegex(cfg.specialWordChars); this.STRING_REGEX = this.createStringRegex(cfg.stringTypes); this.OPEN_PAREN_REGEX = this.createParenRegex(cfg.openParens); this.CLOSE_PAREN_REGEX = this.createParenRegex(cfg.closeParens); this.INDEXED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.indexedPlaceholderTypes, '[0-9]*'); this.IDENT_NAMED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.namedPlaceholderTypes, '[a-zA-Z0-9._$]+'); this.STRING_NAMED_PLACEHOLDER_REGEX = this.createPlaceholderRegex( cfg.namedPlaceholderTypes, this.createStringPattern(cfg.stringTypes), ); this.upperCase = !!cfg.upperCase; } createLineCommentRegex(lineCommentTypes) { return new RegExp(`^((?:${lineCommentTypes.map(c => escapeRegExp(c)).join('|')}).*?(?:\n|$))`); } createReservedWordRegex(reservedWords) { const reservedWordsPattern = reservedWords.join('|').replace(/ /g, '\\s+'); return new RegExp(`^(${reservedWordsPattern})\\b`, 'i'); } createWordRegex(specialChars = []) { return new RegExp(`^([\\w${specialChars.join('')}]+)`); } createStringRegex(stringTypes) { return new RegExp('^(' + this.createStringPattern(stringTypes) + ')'); } // This enables the following string patterns: // 1. backtick quoted string using `` to escape // 2. square bracket quoted string (SQL Server) using ]] to escape // 3. double quoted string using "" or \" to escape // 4. single quoted string using '' or \' to escape // 5. national character quoted string using N'' or N\' to escape createStringPattern(stringTypes) { const patterns = { '``': '((`[^`]*($|`))+)', '[]': '((\\[[^\\]]*($|\\]))(\\][^\\]]*($|\\]))*)', '""': '(("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)', "''": "(('[^'\\\\]*(?:\\\\.[^'\\\\]*)*('|$))+)", "N''": "((N'[^N'\\\\]*(?:\\\\.[^N'\\\\]*)*('|$))+)", }; return stringTypes.map(t => patterns[t]).join('|'); } createParenRegex(parens) { return new RegExp('^(' + parens.map(p => this.escapeParen(p)).join('|') + ')', 'i'); } escapeParen(paren) { if (paren.length === 1) { // A single punctuation character return escapeRegExp(paren); } // longer word return '\\b' + paren + '\\b'; } createPlaceholderRegex(types, pattern) { if (isEmpty(types)) { return false; } const typesRegex = types.map(escapeRegExp).join('|'); return new RegExp(`^((?:${typesRegex})(?:${pattern}))`); } /** * Takes a SQL string and breaks it into tokens. * Each token is an object with type and value. * * @param {String} input The SQL string * @return {Object[]} tokens An array of tokens. * @return {String} token.type * @return {String} token.value */ tokenize(input) { const tokens = []; let token; // Keep processing the string until it is empty while (input.length) { // Get the next token and the token type token = this.getNextToken(input, token); // Advance the string input = input.substring(token.value.length); tokens.push(token); } return tokens; } getNextToken(input, previousToken) { return ( this.getWhitespaceToken(input) || this.getCommentToken(input) || this.getStringToken(input) || this.getOpenParenToken(input) || this.getCloseParenToken(input) || this.getPlaceholderToken(input) || this.getNumberToken(input) || this.getReservedWordToken(input, previousToken) || this.getWordToken(input) || this.getOperatorToken(input) ); } getWhitespaceToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.WHITESPACE, regex: this.WHITESPACE_REGEX, }); } getCommentToken(input) { return this.getLineCommentToken(input) || this.getBlockCommentToken(input); } getLineCommentToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.LINE_COMMENT, regex: this.LINE_COMMENT_REGEX, }); } getBlockCommentToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.BLOCK_COMMENT, regex: this.BLOCK_COMMENT_REGEX, }); } getStringToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.STRING, regex: this.STRING_REGEX, }); } getOpenParenToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.OPEN_PAREN, regex: this.OPEN_PAREN_REGEX, }); } getCloseParenToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.CLOSE_PAREN, regex: this.CLOSE_PAREN_REGEX, }); } getPlaceholderToken(input) { return ( this.getIdentNamedPlaceholderToken(input) || this.getStringNamedPlaceholderToken(input) || this.getIndexedPlaceholderToken(input) ); } getIdentNamedPlaceholderToken(input) { return this.getPlaceholderTokenWithKey({ input, regex: this.IDENT_NAMED_PLACEHOLDER_REGEX, parseKey: v => v.slice(1), }); } getStringNamedPlaceholderToken(input) { return this.getPlaceholderTokenWithKey({ input, regex: this.STRING_NAMED_PLACEHOLDER_REGEX, parseKey: v => this.getEscapedPlaceholderKey({key: v.slice(2, -1), quoteChar: v.slice(-1)}), }); } getIndexedPlaceholderToken(input) { return this.getPlaceholderTokenWithKey({ input, regex: this.INDEXED_PLACEHOLDER_REGEX, parseKey: v => v.slice(1), }); } getPlaceholderTokenWithKey({input, regex, parseKey}) { const token = this.getTokenOnFirstMatch({input, regex, type: tokenTypes.PLACEHOLDER}); if (token) { token.key = parseKey(token.value); } return token; } getEscapedPlaceholderKey({key, quoteChar}) { return key.replace(new RegExp(escapeRegExp('\\') + quoteChar, 'g'), quoteChar); } // Decimal, binary, or hex numbers getNumberToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.NUMBER, regex: this.NUMBER_REGEX, }); } // Punctuation and symbols getOperatorToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.OPERATOR, regex: this.OPERATOR_REGEX, }); } getReservedWordToken(input, previousToken) { // A reserved word cannot be preceded by a "." // this makes it so in "mytable.from", "from" is not considered a reserved word if (previousToken && previousToken.value && previousToken.value === '.') { return; } return ( this.getToplevelReservedToken(input) || this.getNewlineReservedToken(input) || this.getPlainReservedToken(input) ); } getToplevelReservedToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.RESERVED_TOPLEVEL, regex: this.RESERVED_TOPLEVEL_REGEX, }); } getNewlineReservedToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.RESERVED_NEWLINE, regex: this.RESERVED_NEWLINE_REGEX, }); } getPlainReservedToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.RESERVED, regex: this.RESERVED_PLAIN_REGEX, }); } getWordToken(input) { return this.getTokenOnFirstMatch({ input, type: tokenTypes.WORD, regex: this.WORD_REGEX, }); } getTokenOnFirstMatch({input, type, regex}): any { const matches = input.match(regex); if (matches) { let value: string = matches[1]; if ( this.upperCase && (type === tokenTypes.RESERVED || type === tokenTypes.RESERVED_TOPLEVEL || type === tokenTypes.RESERVED_NEWLINE) ) { value = value.toLocaleUpperCase(); } return {type, value}; } } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/core/tokenTypes.ts ================================================ /** * Constants for token types */ export default { WHITESPACE: 'whitespace', WORD: 'word', STRING: 'string', RESERVED: 'reserved', RESERVED_TOPLEVEL: 'reserved-toplevel', RESERVED_NEWLINE: 'reserved-newline', OPERATOR: 'operator', OPEN_PAREN: 'open-paren', CLOSE_PAREN: 'close-paren', LINE_COMMENT: 'line-comment', BLOCK_COMMENT: 'block-comment', NUMBER: 'number', PLACEHOLDER: 'placeholder', }; ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/index.ts ================================================ import QuixSqlFormatter from './languages/SqlWithQuixVarFormmater'; export {QuixSqlFormatter}; ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/languages/SqlWithQuixVarFormmater.ts ================================================ import Formatter from '../core/Formatter'; import Tokenizer from '../core/Tokenizer'; import {tokenizerConf} from './StandardSqlFormatter'; const reservedWords = [ 'ALTER', 'AND', 'AS', 'BETWEEN', 'BY', 'CASE', 'CAST', 'CONSTRAINT', 'CREATE', 'CROSS', 'CUBE', 'CURRENT_DATE', 'CURRENT_PATH', 'CURRENT_ROLE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'DEALLOCATE', 'DELETE', 'DESCRIBE', 'DISTINCT', 'DROP', 'ELSE', 'END', 'ESCAPE', 'EXCEPT', 'EXECUTE', 'EXISTS', 'EXTRACT', 'FALSE', 'FOR', 'FROM', 'FULL', 'GROUP', 'GROUPING', 'HAVING', 'IN', 'INNER', 'INSERT', 'INTERSECT', 'INTO', 'IS', 'JOIN', 'LEFT', 'LIKE', 'LOCALTIME', 'LOCALTIMESTAMP', 'NATURAL', 'NORMALIZE', 'NOT', 'NULL', 'ON', 'OR', 'ORDER', 'OUTER', 'PREPARE', 'RECURSIVE', 'RIGHT', 'ROLLUP', 'SELECT', 'TABLE', 'THEN', 'TRUE', 'UESCAPE', 'UNION', 'UNNEST', 'USING', 'VALUES', 'WHEN', 'WHERE', 'WITH', ]; const reservedToplevelWords = [ 'ALTER COLUMN', 'ALTER TABLE', 'DELETE FROM', 'EXCEPT', 'FROM', 'GROUP BY', 'HAVING', 'INSERT INTO', 'INSERT', 'INTERSECT', 'LIMIT', 'ORDER BY', 'SELECT', 'SET CURRENT SCHEMA', 'SET SCHEMA', 'SET', 'UNION ALL', 'UNION', 'UPDATE', 'VALUES', 'WHERE', ]; const reservedNewlineWords = [ 'AND', 'CROSS APPLY', 'CROSS JOIN', 'ELSE', 'INNER JOIN', 'JOIN', 'LEFT JOIN', 'LEFT OUTER JOIN', 'OR', 'OUTER APPLY', 'OUTER JOIN', 'RIGHT JOIN', 'RIGHT OUTER JOIN', 'WHEN', 'XOR', ]; const newTokenizerConf = { ...tokenizerConf, namedPlaceholderTypes: tokenizerConf.namedPlaceholderTypes.concat(['$']), reservedNewlineWords, reservedToplevelWords, reservedWords, }; export default class QuixSqlFormatter { private readonly cfg: any; private tokenizer: any; /** * @param {Object} cfg Different set of configurations */ constructor(cfg = {}) { this.cfg = cfg; } /** * Format the whitespace in a Standard SQL string to make it easier to read * * @param {String} query The Standard SQL string * @return {String} formatted string */ format(query) { if (!this.tokenizer) { this.tokenizer = new Tokenizer({...newTokenizerConf, upperCase: this.cfg.upperCase}); } return new Formatter(this.cfg, this.tokenizer).format(query); } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/languages/StandardSqlFormatter.ts ================================================ import Formatter from '../core/Formatter'; import Tokenizer from '../core/Tokenizer'; const reservedWords = [ 'ACCESSIBLE', 'ACTION', 'AGAINST', 'AGGREGATE', 'ALGORITHM', 'ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AS', 'ASC', 'AUTOCOMMIT', 'AUTO_INCREMENT', 'BACKUP', 'BEGIN', 'BETWEEN', 'BINLOG', 'BOTH', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED', 'CHARACTER SET', 'CHARSET', 'CHECK', 'CHECKSUM', 'COLLATE', 'COLLATION', 'COLUMN', 'COLUMNS', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPRESSED', 'CONCURRENT', 'CONSTRAINT', 'CONTAINS', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY', 'DAY_HOUR', 'DAY_MINUTE', 'DAY_SECOND', 'DEFAULT', 'DEFINER', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DO', 'DROP', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', 'ELSE', 'ENCLOSED', 'END', 'ENGINE', 'ENGINES', 'ENGINE_TYPE', 'ESCAPE', 'ESCAPED', 'EVENTS', 'EXEC', 'EXECUTE', 'EXISTS', 'EXPLAIN', 'EXTENDED', 'FAST', 'FETCH', 'FIELDS', 'FILE', 'FIRST', 'FIXED', 'FLUSH', 'FOR', 'FORCE', 'FOREIGN', 'FULL', 'FULLTEXT', 'FUNCTION', 'GLOBAL', 'GRANT', 'GRANTS', 'GROUP_CONCAT', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', 'HOUR', 'HOUR_MINUTE', 'HOUR_SECOND', 'IDENTIFIED', 'IF', 'IFNULL', 'IGNORE', 'IN', 'INDEX', 'INDEXES', 'INFILE', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', 'INTERVAL', 'INTO', 'INVOKER', 'IS', 'ISOLATION', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', 'LEVEL', 'LIKE', 'LINEAR', 'LINES', 'LOAD', 'LOCAL', 'LOCK', 'LOCKS', 'LOGS', 'LOW_PRIORITY', 'MARIA', 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE', 'MATCH', 'MAX_CONNECTIONS_PER_HOUR', 'MAX_QUERIES_PER_HOUR', 'MAX_ROWS', 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', 'MODIFY', 'MONTH', 'MRG_MYISAM', 'MYISAM', 'NAMES', 'NATURAL', 'NOT', 'NOW()', 'NULL', 'OFFSET', 'ON DELETE', 'ON UPDATE', 'ON', 'ONLY', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OUTFILE', 'PACK_KEYS', 'PAGE', 'PARTIAL', 'PARTITION', 'PARTITIONS', 'PASSWORD', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE', 'PROCESS', 'PROCESSLIST', 'PURGE', 'QUICK', 'RAID0', 'RAID_CHUNKS', 'RAID_CHUNKSIZE', 'RAID_TYPE', 'RANGE', 'READ', 'READ_ONLY', 'READ_WRITE', 'REFERENCES', 'REGEXP', 'RELOAD', 'RENAME', 'REPAIR', 'REPEATABLE', 'REPLACE', 'REPLICATION', 'RESET', 'RESTORE', 'RESTRICT', 'RETURN', 'RETURNS', 'REVOKE', 'RLIKE', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SECOND', 'SECURITY', 'SEPARATOR', 'SERIALIZABLE', 'SESSION', 'SHARE', 'SHOW', 'SHUTDOWN', 'SLAVE', 'SONAME', 'SOUNDS', 'SQL', 'SQL_AUTO_IS_NULL', 'SQL_BIG_RESULT', 'SQL_BIG_SELECTS', 'SQL_BIG_TABLES', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_CALC_FOUND_ROWS', 'SQL_LOG_BIN', 'SQL_LOG_OFF', 'SQL_LOG_UPDATE', 'SQL_LOW_PRIORITY_UPDATES', 'SQL_MAX_JOIN_SIZE', 'SQL_NO_CACHE', 'SQL_QUOTE_SHOW_CREATE', 'SQL_SAFE_UPDATES', 'SQL_SELECT_LIMIT', 'SQL_SLAVE_SKIP_COUNTER', 'SQL_SMALL_RESULT', 'SQL_WARNINGS', 'START', 'STARTING', 'STATUS', 'STOP', 'STORAGE', 'STRAIGHT_JOIN', 'STRING', 'STRIPED', 'SUPER', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TO', 'TRAILING', 'TRANSACTIONAL', 'TRUE', 'TRUNCATE', 'TYPE', 'TYPES', 'UNCOMMITTED', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'USAGE', 'USE', 'USING', 'VARIABLES', 'VIEW', 'WHEN', 'WITH', 'WORK', 'WRITE', 'YEAR_MONTH', ]; const reservedToplevelWords = [ 'ADD', 'AFTER', 'ALTER COLUMN', 'ALTER TABLE', 'DELETE FROM', 'EXCEPT', 'FETCH FIRST', 'FROM', 'GROUP BY', 'GO', 'HAVING', 'INSERT INTO', 'INSERT', 'INTERSECT', 'LIMIT', 'MODIFY', 'ORDER BY', 'SELECT', 'SET CURRENT SCHEMA', 'SET SCHEMA', 'SET', 'UNION ALL', 'UNION', 'UPDATE', 'VALUES', 'WHERE', ]; const reservedNewlineWords = [ 'AND', 'CROSS APPLY', 'CROSS JOIN', 'ELSE', 'INNER JOIN', 'JOIN', 'LEFT JOIN', 'LEFT OUTER JOIN', 'OR', 'OUTER APPLY', 'OUTER JOIN', 'RIGHT JOIN', 'RIGHT OUTER JOIN', 'WHEN', 'XOR', ]; let tokenizer; export const tokenizerConf = { reservedWords, reservedToplevelWords, reservedNewlineWords, stringTypes: [`""`, "N''", "''", '``', '[]'], openParens: ['(', 'CASE'], closeParens: [')', 'END'], indexedPlaceholderTypes: ['?'], namedPlaceholderTypes: ['@', ':'], lineCommentTypes: ['#', '--'], }; export default class StandardSqlFormatter { private readonly cfg: any; /** * @param {Object} cfg Different set of configurations */ constructor(cfg) { this.cfg = cfg; } /** * Format the whitespace in a Standard SQL string to make it easier to read * * @param {String} query The Standard SQL string * @return {String} formatted string */ format(query) { if (!tokenizer) { tokenizer = new Tokenizer(tokenizerConf); } return new Formatter(this.cfg, tokenizer).format(query); } } ================================================ FILE: quix-frontend/client/src/lib/sql-formatter/sqlFormatter.ts ================================================ import StandardSqlFormatter from './languages/StandardSqlFormatter'; import QuixSqlFormatter from './languages/SqlWithQuixVarFormmater'; export interface Cfg { language?: 'sql' | 'quixsql'; params?: Record | string[]; indent?: string; upperCase?: boolean; } export default { /** * Format whitespaces in a query to make it easier to read. * * @param {String} query * @param {Object} cfg * @param {String} cfg.language Query language, default is Standard SQL * @param {String} cfg.indent Characters used for indentation, default is " " (2 spaces) * @param {Object} cfg.params Collection of params for placeholder replacement * @return {String} */ format: (query, cfg: Cfg = {}) => { switch (cfg.language) { case 'sql': case undefined: return new StandardSqlFormatter(cfg).format(query); case 'quixsql': return new QuixSqlFormatter(cfg).format(query); default: throw Error(`Unsupported SQL dialect: ${cfg.language}`); } }, }; ================================================ FILE: quix-frontend/client/src/lib/store/index.ts ================================================ export {default as createStore, Store, StoreOptions, IBranch, dispatch, dispatchAndLog, logAndDispatch, ReduxStore, sessionId} from './services/store'; export {StoreCache, Cache, Request} from './services/store-cache'; export {combineReducers} from 'redux'; ================================================ FILE: quix-frontend/client/src/lib/store/services/store-cache.ts ================================================ import {isEqual, uniqueId} from 'lodash'; import {inject} from '../../core'; import {Store} from './store'; export class Request { private promise; private args; private id; private shouldHandleRequest(args: any[]) { return !this.promise || !isEqual(this.args, args); } private shouldHandleResponse(requestId) { return requestId === this.id; } private clear() { this.promise = this.args = null; } private createRequest(id: string, args, fetch: Function, onSuccess: Function, onError: Function) { return fetch(...args) .then(res => { if (!this.shouldHandleResponse(id)) { return inject('$q').reject(); } delete res.$promise; delete res.$resolved; return onSuccess(res, ...args); }) .catch(e => { onError({...e.data, status: e.status}, ...args); return null; }) .finally(() => this.shouldHandleResponse(id) && this.clear()); } do(args: any[], fetch: Function, onSuccess: Function, onError: Function) { if (!this.shouldHandleRequest(args)) { return this.promise; } this.id = uniqueId(); this.args = args; this.promise = this.createRequest(this.id, args, fetch, onSuccess, onError); return this.promise; } } export class Cache { protected cacher: Function; protected getter: Function; protected catcher: Function; private fetcher: Function; private readonly request = new Request(); protected getCache(...args) { // abstract } protected setCache(...args) { // abstract } protected setError(...args) { // abstract } private fetchAndSetCache(...args): ng.IPromise { return this.request.do(args, this.fetcher, (...arg) => this.setCache(...arg), (...arg) => this.setError(...arg)); } cacheWith(cacher: Function): Cache { this.cacher = cacher; return this; } getWith(getter: Function): Cache { this.getter = getter; return this; } fetchWith(fetcher: Function): Cache { this.fetcher = fetcher; return this; } catchWith(catcher: Function): Cache { this.catcher = catcher; return this; } /** * Returns cached value if exists, otherwise fetches and sets a new value */ get(...args): ng.IPromise { return inject('$q').when((this.getCache(...args) as any) || this.fetchAndSetCache(...args)); } /** * Fetches and sets a new value */ fetch(...args): ng.IPromise { return this.fetchAndSetCache(...args); } } export class StoreCache extends Cache { constructor(private readonly store: Store, private readonly branch: string) { super(); } protected getCache(...args): T { const state = this.store.getState(this.branch); return this.getter ? this.getter(state, ...args) : state; } protected setCache(...args): ng.IPromise { const action = this.cacher(...args); if (!action) { return; } return this.store.dispatch(action).then(() => this.getCache()); } protected setError(...args): ng.IPromise { const action = this.catcher && this.catcher(...args); if (!action) { return; } return this.store.dispatch(action); } } ================================================ FILE: quix-frontend/client/src/lib/store/services/store-logger.ts ================================================ import {inject, srv, utils} from '../../core'; import {toast} from '../../ui'; const {injector} = srv; function onError(error) { toast.showToast({text: 'Action failed', cancel: 'close', type: 'error'}, 3000); return inject('$q').reject(error); } const toScalaEvent = (eventName: string, data: object) => ({name: eventName, data: utils.stripDollars(data)}); const toNodeAction = (eventName: string, data: object) => ({type: eventName, ...utils.stripDollars(data)}); export type ServerFrameworkType = 'Scala' | 'Node'; export default class StoreLogger { private resource; private readonly transform; constructor(endpoint, private readonly sessionId = null, server: ServerFrameworkType = 'Scala' ) { injector.on('ready', () => { this.resource = inject('$resource')(endpoint, {sessionId: '@sessionId'}, {events: {method: 'POST'}}); }); this.transform = server === 'Scala' ? toScalaEvent : toNodeAction; } log(eventName, data) { return this.resource.events({sessionId: this.sessionId}, [this.transform(eventName, data)]).$promise.catch(onError); } bulk() { const resource = this.resource; const self = this; return { events: [], add(eventName, data) { this.events.push(self.transform(eventName, data)); return this; }, log() { return resource.events({sessionId: this.sessionId}, this.events).$promise.catch(onError); } }; } } ================================================ FILE: quix-frontend/client/src/lib/store/services/store.ts ================================================ import { isArray, find, pull, forEach, get, assign, chain as _ } from 'lodash'; import { utils, inject } from '../../core'; import StoreLogger, { ServerFrameworkType } from './store-logger'; import * as Redux from 'redux'; import { uuid } from '../../core/utils'; const { scope: scopeUtils } = utils; export type IBranch = ( fn: (reducer: Redux.Reducer, ...middleware: Redux.Middleware[]) => void ) => void; export type ReduxStore = Redux.Store; export interface IBranches { [key: string]: IBranch; } function getLogParams({ type, ...action }) { delete (action as any).$log; delete (action as any).$defer; delete (action as any).$next; return [type, action]; } function logAction(logger, action) { return logger.log(...getLogParams(action)); } function logBulkAction(logger, ...actions) { logger = logger.bulk(); actions.forEach((action) => logger.add(...getLogParams(action))); return logger.log(); } const handleReactions = (store: Store, reactions: any[]) => { reactions.forEach((reaction: any) => store.dispatch(reaction)); }; function resolveActions( action, promises = [], res = null, deferred = null, isBulk = false ) { const $q = inject('$q'); deferred = deferred || $q.defer(); isBulk = isBulk || isArray(action); res = res || (isArray(action) ? action : [action]); if (action.then) { const promise = { promise: action, action: null }; promises.push(promise); promise.promise.then( (actn) => { promise.action = actn; resolveActions(actn, promises, res, deferred, isBulk); }, () => deferred.reject() ); } else { let promise = find(promises, { action }); if (promise) { pull(promises, promise); } else { promise = { promise: action, action }; } res = _(res) .map((item) => (item === promise.promise ? promise.action : item)) .flattenDeep() .value(); if (isArray(action)) { action.forEach((actn) => resolveActions(actn, promises, res, deferred, isBulk) ); } if (promises.length === 0) { deferred.resolve({ actions: res, isBulk }); } } return deferred.promise; } function logMiddleware(logger) { /** * @param actions array of action definitions * * @return Promise */ return (store) => (next) => (actions) => { const $q = inject('$q'); const { $log, $bulk, $defer } = actions; const action = actions[0]; let res = !$bulk && !$defer ? next(action) : action; if ($log) { res = $bulk ? logBulkAction(logger, ...actions) : logAction(logger, action); if ($defer && !$bulk) { res.then(() => next(action)); } } return $q.when(res).then((data) => { if (data && data.reactions) { handleReactions(store, data.reactions); } return action; }); }; } function promiseMiddleware(biStore) { return (store) => (next) => (action) => { const { $log = false, $defer = false } = action; const res = resolveActions(action).then(({ actions, isBulk }) => { if (!actions.length) { return; } actions.$log = $log; actions.$defer = $defer; actions.$bulk = isBulk; if (isBulk && !$defer) { actions.forEach((actn) => biStore.dispatch(actn)); } return next(actions).then((result) => { if (isBulk && $defer) { actions.forEach((actn) => biStore.dispatch(actn)); } return result; }); }); if (!action.then) { assign(res, isArray(action) ? action[0] : action); } return res; }; } // allow inversion of control function functionMiddleware(biStore) { return (store) => (next) => (action) => { if (typeof action === 'function') { return action(biStore)((action as any).$next); } return next(action); }; } function initBranches(branches: IBranches) { const reducers = {}; const branchMiddlewares = []; forEach(branches, (branch, name) => { branch((reducer, ...middleware) => { reducers[name] = reducer; if (middleware.length) { branchMiddlewares.push(...middleware); } }); }); return { reducers, middlewares: branchMiddlewares }; } /** * Dispatch an action * * @param action * - single action * - array of actions or promises (nesting supported) * - promise resolved with any of the above */ export const dispatch = (storeDispatch) => (action) => { if (!(action as any).$next) { (action as any).$next = (actn) => dispatch(actn); } return storeDispatch(action); }; /** * Same as dispatch() but also logs the action to server */ export const dispatchAndLog = (storeDispatch) => (action: T): Promise => { (action as any).$log = true; if (!(action as any).$next) { (action as any).$next = (actn) => dispatchAndLog(storeDispatch)(actn); } return dispatch(storeDispatch)(action); }; /** * Same as dispatchAndLog() but dispatching is deferred until after logging the action to server */ export const logAndDispatch = (storeDispatch) => (action: T): Promise => { (action as any).$defer = true; (action as any).$next = (actn) => logAndDispatch(storeDispatch)(actn); return dispatchAndLog(storeDispatch)(action); }; export interface StoreOptions { logUrl?: string; server?: ServerFrameworkType; } const defaultStoreOptions: StoreOptions = { logUrl: '', server: 'Scala', }; export const sessionId = uuid(); export class Store { private readonly store: ReduxStore; logger: StoreLogger; private readonly options: StoreOptions; constructor(branches: IBranches, options: StoreOptions = {}) { this.options = { ...defaultStoreOptions, ...options }; const { reducers, middlewares } = initBranches(branches); const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || Redux.compose; this.logger = new StoreLogger( this.options.logUrl, sessionId, this.options.server ); this.store = Redux.createStore( Redux.combineReducers(reducers), composeEnhancers( Redux.applyMiddleware( ...[ functionMiddleware(this), promiseMiddleware(this), logMiddleware(this.logger), ...middlewares, ] ) ) ); this.dispatch = dispatch(this.store.dispatch); this.dispatchAndLog = dispatchAndLog(this.store.dispatch); this.logAndDispatch = logAndDispatch(this.store.dispatch); } /** * Dispatch an action * * @param action * - single action * - array of actions or promises (nesting supported) * - promise resolved with any of the above */ dispatch: ReturnType; /** * Same as dispatch() but also logs the action to server */ dispatchAndLog: ReturnType; /** * Same as dispatchAndLog() but dispatching is deferred until after logging the action to server */ logAndDispatch: ReturnType; /** * Returns store's state * * @param branch e.g. "notebook.folders" */ getState(branch?): S { const state = this.store.getState(); if (branch) { return get(state, branch); } return state; } /** * Subscribe to changes in a particular branch in the store * The handler will be executed immediately and every time the branch state reference changes * * @param branch e.g. "notebook.folders" * @param fn handler */ subscribe(branch: string, fn: (state, store?) => void, scope): Function { const applyScope = scope || inject('$rootScope'); let state = this.getState(branch); scopeUtils.safeDigest(applyScope, () => fn(state, this.store)); const unsubscribe = this.store.subscribe(() => { const newState = this.getState(branch); if (newState !== state) { scopeUtils.safeDigest(applyScope, () => fn(newState, this)); state = newState; } }); scope.$on('$destroy', unsubscribe); return unsubscribe; } getReduxStore() { return this.store; } } /** * Create a new store * * @param branches branches to init in the new store */ export default function create( branches: IBranches, options?: StoreOptions ): Store { return new Store(branches, options); } ================================================ FILE: quix-frontend/client/src/lib/ui/app.scss ================================================ @import './assets/css/badge'; @import './assets/css/fonts'; @import './assets/css/animations'; @import './assets/css/colors'; @import './assets/css/flex'; @import './assets/css/space'; @import './assets/css/panel'; @import './assets/css/section'; @import './assets/css/action'; @import './assets/css/button'; @import './assets/css/dropdown'; @import './assets/css/input'; @import './assets/css/icon'; @import './assets/css/toggle'; @import './assets/css/align'; @import './assets/css/border'; @import './assets/css/table'; @import './assets/css/label'; @import './assets/css/app/app-header'; @import './assets/css/app/app-menu'; @import './assets/css/dialog'; @import './assets/css/nav-tabs'; @import './assets/css/caret'; @import './assets/css/link'; @import './assets/css/spinner'; @import './assets/css/text'; @import './assets/css/scroll'; @import './assets/css/hint'; @import './assets/css/form'; @import './assets/css/media'; @import './assets/css/mouse'; @import './assets/css/tag'; @import './assets/css/home-action'; @import './assets/css/alert'; @import './assets/css/empty-state'; @import './assets/css/hover'; @import './assets/css/theme'; @import './assets/css/state'; @import './assets/css/heading'; @import './assets/css/no-select'; ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/action.scss ================================================ @import './def/colors.def'; @import './def/action.def'; @import './def/button.def'; .bi-theme--lighter { .bi-action { @include action('lighter'); } .bi-theme--dark { .bi-action { @include action('dark'); } } .bi-theme--darker { .bi-action { @include action('darker'); } } } .bi-theme--light { .bi-action { @include action('light'); } .bi-theme--lighter { .bi-action { @include action('lighter'); } } .bi-theme--dark { .bi-action { @include action('dark'); } } .bi-theme--darker { .bi-action { @include action('darker'); } } } .bi-theme--dark { .bi-action { @include action('dark'); } } .bi-theme--darker { .bi-action { @include action('darker'); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/alert.scss ================================================ @import './def/alert.def'; @import './def/colors.def'; .bi-alert { @include alert(); } .bi-alert--error { @include alert('error_outline', $danger, lighten($danger, 36)); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/align.scss ================================================ @import './def/flex.def'; @import './def/align.def'; .bi-spread { @extend %spread; } .bi-center { @include flex(row, null, center); } .bi-justify-right { @include flex(row, null, flex-end); } .bi-align { @include flex(row, center); } .bi-align--bottom { @include flex(row, flex-end !important); } .bi-align--top { @include flex(row, flex-start !important); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/animations.scss ================================================ @import './def/animations.def'; .bi-fade-in { @extend %animation-fade-in; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/app/app-header.scss ================================================ @import '../def/app/app-header.def'; .bi-app-header { @extend %app-header; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/app/app-menu.scss ================================================ @import '../def/app/app-menu.def'; .bi-app-menu { @extend %app-menu; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/badge.scss ================================================ @import './def/badge.def'; @import './def/colors.def'; .bi-badge { @include badge(); color: $grey--900; } .bi-badge--primary { @include badge($primary); } .bi-badge--success { @include badge($success); } .bi-badge--warning { @include badge($warning); } .bi-badge--danger { @include badge($danger); } .bi-badge--sm { @include badge(); @include badge-size(14px, 9px); border-radius: 7px; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/border.scss ================================================ @import './def/border.def'; .bi-border { @include border(); } .bi-border--top { @include border(top); } .bi-border--right { @include border(right); } .bi-border--bottom { @include border(bottom); } .bi-border--left { @include border(left); } .bi-no-border { border: 0 !important; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/button.scss ================================================ @import './def/colors.def'; @import './def/button.def'; @import './def/flex.def'; .bi-button--primary { @include button($primary); } .bi-button--secondary { @include button($secondary); } .bi-button--success { @include button($success); } .bi-button--warning { @include button($warning); } .bi-button--danger { @include button($danger); } .bi-button { @include button-size(); } .bi-button--sm { @include button-size(22px, 8px, 10px); } .bi-button-group { @include flex(); border-radius: 3px; overflow: hidden; button { border-radius: 0 !important; } a { border-radius: 0 !important; } } .bi-theme--lighter { .bi-button { @include button-theme('lighter'); } } .bi-theme--light { .bi-button { @include button-theme('light'); } .bi-theme--lighter { .bi-button { @include button-theme('lighter'); } } } .bi-theme--dark { .bi-button { @include button-theme('dark'); } } .bi-theme--darker { .bi-button { @include button-theme('darker'); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/caret.scss ================================================ @import './def/caret.def'; .bi-caret { @extend %caret; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/colors.scss ================================================ @import './def/colors.def'; @import './def/state.def'; .bi-theme--light { .bi-disabled { @include disabled('light'); } .bi-muted { @include muted('light'); } .bi-theme--lighter { .bi-disabled { @include disabled('lighter'); } .bi-muted { @include muted('lighter'); } } } .bi-theme--lighter { .bi-disabled { @include disabled('lighter'); } .bi-muted { @include muted('lighter'); } } .bi-theme--dark { .bi-disabled { @include disabled('dark'); } .bi-muted { @include muted('dark'); } } .bi-theme--darker { .bi-disabled { @include disabled('darker'); } .bi-muted { @include muted('darker'); } } .bi-primary { color: $primary !important; } .bi-secondary { color: $secondary !important; } .bi-success { color: $success !important; } .bi-warning { color: $warning !important; } .bi-danger { color: $danger !important; } .bi-white { color: $white !important; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/action.def.scss ================================================ @import 'colors.def'; @import 'morph.def'; @import 'state.def'; %action { position: relative; padding: 3px; border-radius: 3px; font-style: normal; white-space: nowrap; cursor: pointer; user-select: none; &:active:not([disabled='disabled']) { top: 1px; left: 1px; } } @mixin action($theme) { @extend %action; @include disabled($theme); @include muted($theme); @include hover($theme); @include active($theme); &.bi-action-loader { @extend %morph-to-loader; > span { width: 30px !important; height: 30px !important; line-height: 30px !important; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/alert.def.scss ================================================ @import './colors.def'; @import './icon.def'; @import './flex.def'; @import './space.def'; @import './border.def'; %alert { @include space-v__inner(); padding: 11px 12px; font-size: 11px; border-radius: 3px; .bi-alert-header { @include flex(row, center); font-size: 12px; font-weight: 600; &:before { @extend %icon; @include space-h(); } } .bi-alert-content { @include border(top); padding-top: 10px; } } @mixin alert($icon: 'wb_incandescent', $iconColor: $warning, $bgColor: $grey--50) { @extend %alert; color: darken($bgColor, 50) !important; background-color: $bgColor; border: 1px solid darken($bgColor, 6); .bi-alert-header { &:before { content: $icon; color: $iconColor; } } .bi-alert-content { border-color: darken($bgColor, 6); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/align.def.scss ================================================ @import './flex.def'; %spread { @include flex(row, center, space-between); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/animations.def.scss ================================================ @mixin animation-scale ($duration: .11s) { @keyframes scale { from { transform: scale(.5); opacity: 0; } to { transform: scale(1); opacity: 1; } } transform-origin: top; animation: scale $duration; } %animation-fade-in { @keyframes fade-in { from {opacity: .5;} to {opacity: 1;} } animation: fade-in .3s; } %animation-rotate { @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } } animation: rotate .5s linear infinite; } %animation-fade-in2 { @keyframes fade-in2 { from { opacity: 0; } to { opacity: 1; } } animation: fade-in2 .2s linear forwards; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/app/app-header.def.scss ================================================ @import '../colors.def'; @import '../header.def'; @import '../border.def'; %app-header { @include header(54px, 12px); .bi-app-user-logo { width: 36px; height: 36px; border-radius: 100px; } .bi-app-title { @include header-title(20px, 200); font-family: bi-ui; .bi-app-logo { width: 24px; margin-right: 8px; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/app/app-menu.def.scss ================================================ @import '../colors.def'; @import '../defaults.def'; @import '../flex.def'; @import '../border.def'; @import '../action.def'; @import '../state.def'; %app-menu { width: 48px; ul { li { @include flex(row, center, center); width: 100%; padding: 9px; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/badge.def.scss ================================================ @import './colors.def'; @mixin badge-size($height: 18px, $font-size: 11px) { height: $height; width: $height; line-height: $height; font-size: $font-size; } %badge { display: inline-block; text-align: center; color: $white; border-radius: 10px; @include badge-size(); } @mixin badge($color: $grey--400) { @extend %badge; background-color: $color; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/border.def.scss ================================================ @import 'defaults.def'; @mixin border($position: null, $color: $default-border-color) { @if $position { border-#{$position}-width: $default-border-width; border-#{$position}-style: solid; border-#{$position}-color: $color; } @else { border: 1px solid $color; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/button.def.scss ================================================ @import 'colors.def'; @import 'defaults.def'; @import 'flex.def'; @import 'border.def'; @import 'icon.def'; @import 'space.def'; @import 'morph.def'; @import 'state.def'; %button { @include flex(row, center); @include space-h__inner(5px); transition: opacity .3, background-color .3s; display: inline-flex; font-family: 'Open Sans'; text-transform: uppercase; outline: 0; border: none; border-radius: 3px; white-space: nowrap; // box-shadow: 0 1px 2px rgba(0, 0, 0, .10); cursor: pointer; &[disabled='disabled'] { opacity: .8; cursor: default; } &.bi-button-loader { @extend %morph-to-loader; } } @mixin button-color($bgColor: $grey--200, $color: $white) { background-color: $bgColor; color: $color !important; &:hover:not([disabled='disabled']) { background-color: darken($bgColor, 4); } } @mixin button-size($height: 30px, $padding: 10px, $font-size: 12px) { height: $height; padding: 0 $padding; font-size: $font-size; } @mixin button($bgColor: $grey--200, $color: $white) { @extend %button; @include button-color($bgColor, $color); @include button-size(); &:active:not([disabled='disabled']) { box-shadow: inset 1px 3px 8px darken($bgColor, 15), 1px 1px 1px $white; } } @mixin button-theme($theme) { @extend %button; @include disabled($theme); @if ($theme == 'lighter') { background-color: darken($lighter-hover-bg, 2); color: $lighter-color; } @else if ($theme == 'light') { background-color: darken($light-hover-bg, 2); color: $light-color; } @else if ($theme == 'dark') { background-color: lighten($dark-hover-bg, 2); color: $dark-color; } @else { background-color: lighten($darker-hover-bg, 2); color: $darker-color; } &:hover:not([disabled='disabled']) { @if ($theme == 'lighter') { background-color: darken($lighter-hover-bg, 5); } @else if ($theme == 'light') { background-color: darken($light-hover-bg, 5); } @else if ($theme == 'dark') { background-color: lighten($dark-hover-bg, 5); } @else { background-color: lighten($darker-hover-bg, 5); } } &:active:not([disabled='disabled']) { @if ($theme == 'lighter') { box-shadow: inset 1px 3px 8px darken($lighter-hover-bg, 10), 1px 1px 1px $lighter-bg; } @else if ($theme == 'light') { box-shadow: inset 1px 3px 8px darken($light-hover-bg, 10), 1px 1px 1px $light-bg; } @else if ($theme == 'dark') { background-color: lighten($dark-hover-bg, 3); box-shadow: none; } @else { background-color: lighten($darker-hover-bg, 3); box-shadow: none; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/caret.def.scss ================================================ @import './flex.def'; @import './icon.def'; %caret { @include flex-inline(row, center); &:after { @extend %icon; content: 'arrow_drop_down'; font-size: 18px !important; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/colors.def.scss ================================================ $grey--50: #FAFAFA; $grey--100: #F5F5F5; $grey--200: #ebebec; $grey--300: #d7d8da; $grey--400: #b8babe; $grey--500: #9a9da2; $grey--600: #686b73; $grey--700: #494e57; $grey--800: #353a44; $grey--900: #1d242f; $blue--300: #64B5F6; $blue--500: #2196F3; $orange--500: #FF9800; $red--300: #E57373; $red--500: #f44336; $green--300: #81C784; $green--500: #4CAF50; $light-green--500: #8BC34A; $white: #FFFFFF; $black: #000000; $primary: #FC4A6A; $secondary: #00A9F4; $success: $light-green--500; $warning: $orange--500; $danger: $red--500; $muted: $grey--600; $lighter-bg: $white; $lighter-hover-bg: $grey--100; $lighter-active-bg: $grey--100; $lighter-color: $grey--800; $lighter-muted-color: $grey--600; $lighter-disabled-color: $grey--400; $lighter-border-color: $grey--200; $light-bg: $grey--100; $light-hover-bg: $grey--200; $light-active-bg: $grey--200; $light-color: $grey--800; $light-muted-color: $grey--600; $light-disabled-color: $grey--500; $light-border-color: $grey--300; $dark-bg: $grey--800; $dark-hover-bg: lighten($dark-bg, 2); $dark-active-bg: lighten($dark-bg, 2); $dark-color: $grey--200; $dark-muted-color: $grey--500; $dark-disabled-color: $grey--500; $dark-border-color: $grey--700; $darker-bg: $grey--900; $darker-hover-bg: $grey--800; $darker-active-bg: $grey--800; $darker-color: $grey--200; $darker-muted-color: $grey--500; $darker-disabled-color: $grey--500; $darker-border-color: $grey--600; ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/content.def.scss ================================================ @import 'defaults.def'; @mixin content($padding: $default-space * 1.5) { padding: $padding; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/defaults.def.scss ================================================ @import './colors.def'; $default-font-family: 'Open Sans'; $default-font-size: 12px; $default-space: 10px; $default-text-color: $black; $default-border-color: $grey--200; $default-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); $default-border-width: 1px; $default-input-height: 36px; ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/dropdown.def.scss ================================================ @import 'colors.def'; @import 'defaults.def'; @import 'border.def'; @import 'flex.def'; @import 'icon.def'; @import 'state.def'; %dropdown-content { display: block; padding: 5px 10px; border: 1px solid $grey--200; border-radius: 3px; box-shadow: $default-box-shadow; overflow-y: auto; } %dropdown-menu { @extend %dropdown-content; padding: 5px 0; max-height: 300px; user-select: none; > li { @include flex(row, center); @include hover('lighter'); @include disabled('lighter'); position: relative; padding: 7px 20px; white-space: nowrap; cursor: pointer; &.bi-active:not([disabled]), &:hover:not([disabled]) { background-color: $grey--50; } &:not([disabled='disabled']) { &.selected { &:before { @extend %icon; position: absolute; content: 'check'; left: 5px; color: $primary; font-size: 14px !important; } } .bi-icon { @include muted('lighter'); } } .bi-icon { font-size: 18px; } } .bi-dropdown-separator { @include border(bottom); margin: 5px; padding: 0; &:first-child, &:last-child { height: 0; margin: 0; border: 0; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/empty-state.def.scss ================================================ @import './colors.def'; %empty-state { display: flex; flex-direction: column; font-family: 'bi-ui'; align-items: center; > * { display: flex; justify-content: center; } .bi-empty-state-icon { .bi-icon { font-size: 80px; } } .bi-empty-state-image { width: 150px; margin-bottom: 10px; } .bi-empty-state-header { margin-top: 20px; margin-bottom: 0; font-size: 18px; font-weight: 300; } .bi-empty-state-header + .bi-empty-state-content { margin-top: 3px; } .bi-empty-state-content { margin-top: 15px; margin-bottom: 0; font-size: 13px; font-weight: 400; } } %empty-state-with-image { @extend %empty-state; &:before { content: ''; display: block; height: 100px; margin-bottom: 0; background-size: contain; background-repeat: no-repeat; background-position: center; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/flex.def.scss ================================================ @mixin _flex($direction: row, $align: null, $justify: null) { flex-direction: $direction; @if $align { align-items: $align; } @if $justify { justify-content: $justify; } } @mixin flex($direction: row, $align: null, $justify: null) { @include _flex($direction, $align, $justify); display: flex; } @mixin flex-inline($direction: row, $align: null, $justify: null) { @include _flex($direction, $align, $justify); display: inline-flex; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/header.def.scss ================================================ @import 'defaults.def'; @import 'flex.def'; @import 'space.def'; @import 'align.def'; %header { @extend %spread; flex: 0 0 auto; box-sizing: border-box; > * { @include flex(row, center); } } @mixin header-title($font-size: 14px, $font-weight: initial) { font-size: $font-size; @if ($font-size <= 14) { font-weight: 600; } @else { font-weight: $font-weight; } } @mixin header-separator($color) { width: 1px; height: 24px; border-left: 1px solid darken($color, 5); border-right: 1px solid lighten($color, 5); align-self: center; } @mixin header($height, $space: $default-space * 1.5) { @extend %header; padding: 0 $space; > * { @include space-h__inner($space); } height: $height; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/heading.def.scss ================================================ @import 'colors.def'; @import 'morph.def'; @import 'state.def'; %heading { position: relative; &:after { content: ''; position: absolute; top: 50%; left: 0; right: 0; border-bottom: 1px solid transparent; z-index: 1; } .bi-heading-content { padding-left: 1em; padding-right: 1em; z-index: 2; } } @mixin heading($theme) { @extend %heading; @if ($theme == 'lighter') { .bi-heading-content { background-color: $lighter-bg; } &:after { border-color: $lighter-border-color; } } @else if ($theme == 'light') { .bi-heading-content { background-color: $light-bg; } &:after { border-color: $light-border-color; } } @else if ($theme == 'dark') { .bi-heading-content { background-color: $dark-bg; } &:after { border-color: $dark-border-color; } } @else { .bi-heading-content { background-color: $darker-bg; } &:after { border-color: $darker-border-color; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/hint.def.scss ================================================ @import './colors.def'; @import './flex.def'; @mixin hint($color: $warning) { @include flex(row, center); padding-left: 6px; font-size: 10px; border-left: 3px solid $color; color: $muted; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/icon.def.scss ================================================ @import 'colors.def'; @import 'state.def'; %icon { display: inline-block; font-family: 'Material Icons' !important; font-weight: normal; font-style: normal; font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none; white-space: nowrap; word-wrap: normal; direction: ltr; text-decoration: none; -webkit-font-smoothing: antialiased; } @mixin icon($theme) { @extend %icon; @include disabled($theme); @include muted($theme); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/input.def.scss ================================================ @import 'colors.def'; @import 'defaults.def'; @import 'border.def'; %input { @include border(); transition: border-color .2s; display: inline-flex; height: $default-input-height; min-width: 200px; padding: 6px $default-space; font-family: $default-font-family; font-size: $default-font-size; color: $black; outline: none; box-sizing: border-box; &[disabled] { background-color: lighten($grey--50, 1); cursor: not-allowed; } &:not([disabled]) { &:hover { border-color: lighten($blue--300, 20); } &:focus { border-color: $blue--300; } } &[required] { &.ng-dirty { &.ng-valid { border-color: $green--300; } &.ng-invalid { border-color: $red--300; } } } } @mixin input($theme) { @extend %input; @if ($theme == 'lighter') { color: $lighter-color; background-color: $white; &::placeholder { color: $lighter-muted-color; } } @else if ($theme == 'light') { color: $light-color; background-color: $white; &::placeholder { color: $light-muted-color; } } @else if ($theme == 'dark') { border: none; color: $dark-color; background-color: lighten($dark-hover-bg, 3); &::placeholder { color: $dark-muted-color; } } @else { border: none; color: $darker-color; background-color: lighten($darker-hover-bg, 3); &::placeholder { color: $darker-muted-color; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/label.def.scss ================================================ @import './colors.def'; %label { color: $grey--600; font-weight: 600; text-transform: uppercase; } %color-label { display: inline-flex; padding: 1px 6px; place-content: center; border-radius: 2px; font-size: 9px; color: $white !important; } @mixin label-dark() { @extend %label; color: $grey--600; } @mixin label-light() { color: $grey--400; } @mixin label-color__deep($bg-intensity) { .bi-label { @if $bg-intensity <= 400 { @include label-dark(); } @else { @include label-light(); } } } @mixin color-label($color) { @extend %color-label; background-color: $color; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/link.def.scss ================================================ @import './flex.def'; @import './icon.def'; @import './colors.def'; %link { @include flex-inline(row, center); color: $primary; text-decoration: none !important; cursor: pointer; &:hover { color: darken($primary, 8); } &[target="_blank"] { &:after { @extend %icon; content: 'open_in_new'; margin-left: .3em; font-size: 1em !important; text-decoration: none !important; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/media.def.scss ================================================ $small-screen-size: 768px; ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/morph.def.scss ================================================ @import 'colors.def'; @import 'animations.def'; @import 'spinner.def'; %morph-fade-out { @keyframes fade-out { 0% { max-width: 50px; } 20% { padding: 0; background-color: transparent; color: transparent; border: 0; } 100% { max-width: 30px; padding: 0; border-radius: 100px; background-color: transparent; color: transparent; border: 0; } } animation: fade-out .4s linear forwards; } %morph-to-loader { @extend %morph-fade-out; box-shadow: none; overflow: hidden; cursor: default; &:active { box-shadow: none; } > * { display: none; } > span { @extend %spinner; &:after { @extend %animation-fade-in2; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/nav-tabs.def.scss ================================================ @import './colors.def'; @import './flex.def'; @import './border.def'; @import './label.def'; @import './space.def'; %bi-nav-tabs { @include flex(row, center, center); @include border(bottom); @include label-dark(); @include space-h__inner(20px); } %bi-nav-tab { font-size: 15px; line-height: 30px; cursor: pointer; &.bi-active { color: $primary; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/panel.def.scss ================================================ @import 'colors.def'; @import 'defaults.def'; @import 'border.def'; @import 'header.def'; @import 'content.def'; @import 'space.def'; $panel-header-class: '.bi-panel-header'; $panel-content-class: '.bi-panel-content'; $panel-title-class: '.bi-panel-title'; %panel { border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, .05); overflow: hidden; } /// Simple panel (header + content) @mixin panel() { @extend %panel; > #{$panel-header-class} { @include header(44px); #{$panel-title-class} { @include header-title(); } & + #{$panel-content-class} { padding-top: 10px; } } > #{$panel-content-class} { @include content(); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/section.def.scss ================================================ @import 'colors.def'; @import 'defaults.def'; @import 'header.def'; @import 'content.def'; @import 'flex.def'; $section-header-class: '.bi-section-header'; $section-controls-class: '.bi-section-controls'; $section-content-class: '.bi-section-content'; $section-title-class: '.bi-section-title'; $section-separator-class: '.bi-section-header-spr'; %section { @include flex(column); > #{$section-header-class} { @include header(50px); #{$section-title-class} { @include header-title(16px); letter-spacing: 1px; } #{$section-separator-class} { @include header-separator($grey--200); } } > #{$section-controls-class} { @include header(30px); margin-bottom: $default-space * 1.5; } > #{$section-content-class}, > #{$section-content-class}--center, > #{$section-content-class}--list { flex: 1; overflow: auto; } > #{$section-content-class}--center { @include flex(column, center, center); } > #{$section-content-class}--list { padding-bottom: 400px !important; } &.bi-theme--dark { > #{$section-header-class} { color: $grey--200; } > #{$section-content-class}, > #{$section-content-class}--center, > #{$section-content-class}--list { background-color: $grey--800; } } } // Full-height, full-width section with scrollable content @mixin section($bg-color) { @extend %section; // background-color: $bg-color; > #{$section-content-class}, > #{$section-content-class}--center, > #{$section-content-class}--list { @include content(); } } // Full-height, fixed-width section with scrollable content @mixin section-static($content-bg-color, $width) { @include section($content-bg-color); width: $width; flex: 0 0 $width; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/space.def.scss ================================================ @import 'defaults.def'; @mixin space-h($space: $default-space) { margin-right: $space; } @mixin space-v($space: $default-space) { margin-top: $space; } @mixin space-h__inner($space: $default-space) { > *:not(:last-child) { @include space-h($space); } } @mixin space-v__inner($space: $default-space) { > *:not(:first-child) { @include space-v($space); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/spinner.def.scss ================================================ @import 'colors.def'; @import 'animations.def'; %spinner { @extend %animation-rotate; position: relative; display: inline-block; width: 30px; height: 30px; line-height: 30px; &:after { content: ''; position: absolute; display: block; top: 0; left: 0; width: 100%; height: 100%; border: 3px solid $blue--500; border-right-color: transparent; border-radius: 100px; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/state.def.scss ================================================ @import 'colors.def'; @import 'animations.def'; @import 'defaults.def'; @mixin disabled($theme) { &.bi-disabled, &[disabled='disabled'] { @if ($theme == 'lighter') { color: $lighter-disabled-color !important; } @else if ($theme == 'light') { color: $light-disabled-color !important; } @else if ($theme == 'dark') { color: $dark-disabled-color !important; } @else { color: $darker-disabled-color !important; } cursor: default; } } @mixin fade($theme) { @extend %animation-fade-in; transition: opacity .3s; &.bi-faded { opacity: .7; } } @mixin muted($theme) { @if ($theme == 'lighter') { color: $lighter-muted-color; } @else if ($theme == 'light') { color: $light-muted-color; } @else if ($theme == 'dark') { color: $dark-muted-color; } @else { color: $darker-muted-color; } } @mixin active($theme, $color: null) { &.bi-active { @if ($theme == 'lighter') { background-color: $lighter-active-bg; color: $color or $lighter-color; } @else if ($theme == 'light') { background-color: $light-active-bg; color: $color or $light-color; } @else if ($theme == 'dark') { background-color: $dark-active-bg; color: $color or $dark-color; } @else { background-color: $darker-active-bg; color: $color or $darker-color; } } } @mixin hover($theme, $color: null) { &:hover:not([disabled='disabled']) { @if ($theme == 'lighter') { background-color: $lighter-hover-bg; color: $color or $lighter-color; } @else if ($theme == 'light') { background-color: $light-hover-bg; color: $color or $light-color; } @else if ($theme == 'dark') { background-color: $dark-hover-bg; color: $color or $dark-color; } @else { background-color: $darker-hover-bg; color: $color or $darker-color; } } } @mixin elevate() { transition: box-shadow .3s; &:hover { box-shadow: 0 4px 8px lighten($grey--300, 3); } &:active { transition: box-shadow .2s; box-shadow: 0 2px 8px lighten($grey--300, 3); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/table.def.scss ================================================ @import './defaults.def'; %table { width: 100%; > thead > tr > th { padding: 8px; border-bottom: 2px solid $default-border-color; text-align: left; vertical-align: bottom; } > tbody > tr > td { padding: 8px; border-top: 1px solid $default-border-color; text-align: left; vertical-align: top; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/tag.def.scss ================================================ @import 'colors.def'; %tag { display: inline-block; padding: 0 8px; border: 1px solid currentColor; border-radius: 3px; font-size: 11px; line-height: 20px; color: $muted; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/theme.def.scss ================================================ @import 'colors.def'; @mixin theme($theme) { @if ($theme == 'lighter') { background-color: $lighter-bg; color: $lighter-color; } @else if ($theme == 'light') { background-color: $light-bg; color: $light-color; } @else if ($theme == 'dark') { background-color: $dark-bg; color: $dark-color; } @else { background-color: $darker-bg; color: $darker-color; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/toggle.def.scss ================================================ @import 'flex.def'; @import 'icon.def'; %toggle { &:after { @extend %icon; content: 'arrow_drop_down'; display: inline-block; width: 10px; height: 0; margin-left: -6px; font-size: 20px; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/def/trim.def.scss ================================================ %trim-hor { > *:last-child { margin-right: 0; } } %trim-ver { > *:last-child { margin-bottom: 0; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/dialog.scss ================================================ @import './def/colors.def'; .bi-dialog { $padding : 30px; // position: relative; min-width: 400px; min-height: 150px; padding: $padding; border: none; border-radius: 4px; box-shadow: 0 6px 12px rgba(0, 0, 0, .175); dialog-title, dialog-subtitle, dialog-content { display: flex; } dialog-title { margin-bottom: 30px; font-size: 22px; font-weight: 300; text-transform: uppercase; .bi-dialog-icon { font-size: 34px; } } dialog-subtitle { margin: -26px 0 40px 0; } dialog-footer { position: absolute; left: $padding; right: $padding; bottom: 20px; button { min-width: 80px; justify-content: center; } } .bi-dialog-close { position: absolute; top: 20px; right: 20px; z-index: 1000; } .bi-dialog-loader { position: absolute; bottom: 20px; left: 20px; z-index: 1000; } &.bi-confirm { padding: $padding $padding 90px $padding; dialog-content { margin-bottom: 20px; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/dropdown.scss ================================================ @import './def/dropdown.def'; @import './def/icon.def'; .bi-dropdown-menu { @extend %dropdown-menu; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/empty-state.scss ================================================ @import './def/empty-state.def'; @import './def/animations.def'; @import './def/state.def'; .bi-empty-state { @extend %empty-state; } .bi-empty-state--loading { @extend %empty-state; align-items: center; &:before { @extend %animation-rotate; content: ''; display: inline-block; width: 30px; height: 30px; border: 3px solid $blue--500; border-right-color: transparent; border-radius: 100px; } } .bi-theme--lighter { .bi-empty-state, .bi-empty-state--loading { @include muted('lighter'); } } .bi-theme--light { .bi-empty-state, .bi-empty-state--loading { @include muted('light'); } .bi-theme--lighter { .bi-empty-state, .bi-empty-state--loading { @include muted('lighter'); } } } .bi-theme--dark { .bi-empty-state, .bi-empty-state--loading { @include muted('dark'); } } .bi-theme--darker { .bi-empty-state, .bi-empty-state--loading { @include muted('darker'); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/flex.scss ================================================ @import './def/flex.def'; .bi-row, .bi-r { @include flex(row); min-width: 0; flex: 1; } .bi-r-h { @include flex(row); min-width: 0; flex: 1; overflow: hidden; } .bi-row-inline, .bi-r-i { @include flex-inline(row); } .bi-column, .bi-c { @include flex(column); min-width: 0; } .bi-sidebar-override { .bi-c { min-width: unset !important; } } .bi-c-h { @include flex(column); min-width: 0; overflow: hidden; } .bi-grow { flex-grow: 1; } .bi-dont-grow { flex-grow: 0; } .bi-dont-shrink { flex-shrink: 0; } .bi-wrap { flex-wrap: wrap; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/fonts.scss ================================================ @font-face { font-family: 'bi-ui'; font-style: normal; font-weight: 300; src: local('Fira Sans Light'), local('FiraSans-Light'), url(https://fonts.gstatic.com/s/firasans/v8/va9B4kDNxMZdWfMOD5VnPKreRhf6Xl7Glw.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'bi-ui'; font-style: normal; font-weight: 400; src: local('Fira Sans Regular'), local('FiraSans-Regular'), url(https://fonts.gstatic.com/s/firasans/v8/va9E4kDNxMZdWfMOD5Vvl4jLazX3dA.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: 'bi-ui'; font-style: normal; font-weight: 700; src: local('Fira Sans Bold'), local('FiraSans-Bold'), url(https://fonts.gstatic.com/s/firasans/v8/va9B4kDNxMZdWfMOD5VnLK3eRhf6Xl7Glw.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/form.scss ================================================ @import './def/colors.def'; @import './def/flex.def'; @import './def/space.def'; @import './def/defaults.def'; .bi-form, .bi-form--vertical { @include flex(column); @include space-v__inner(); .bi-form-row { .bi-form-label, .bi-form-label--required { flex-basis: 90px; flex-shrink: 0; font-size: 12px; color: $muted; } .bi-form-label--required { &:after { content: ' *'; color: $primary; } } .bi-form-input { flex-grow: 1; } } &.bi-form { .bi-form-row { @include flex(row); @include space-h__inner(); } } &.bi-form--vertical { @include space-v__inner(15px); .bi-form-row { @include flex(column); @include space-v__inner(4px); } .bi-form-label, .bi-form-label--required { flex-basis: unset; } .bi-form-input { flex-grow: unset; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/heading.scss ================================================ @import './def/heading.def'; .bi-theme--lighter { .bi-heading { @include heading('lighter'); } } .bi-theme--light { .bi-heading { @include heading('light'); } } .bi-theme--dark { .bi-heading { @include heading('dark'); } } .bi-theme--darker { .bi-heading { @include heading('darker'); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/hint.scss ================================================ @import './def/colors.def'; @import './def/hint.def'; .bi-hint { @include hint(); } .bi-hint--info { @include hint($primary); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/home-action.scss ================================================ @import './def/defaults.def'; @import './def/colors.def'; @import './def/state.def'; .bi-home-action { display: flex; height: 200px; flex-direction: column; flex-basis: 300px; border-radius: 8px !important; align-items: center; justify-content: center; cursor: pointer; span { font-size: 20px; font-weight: 300; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/hover.scss ================================================ @import './def/animations.def'; .bi-hover-parent { .bi-hover-target { transition: opacity .2s; opacity: 0; } &:hover { .bi-hover-target { opacity: 1; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/icon.scss ================================================ @import './def/icon.def'; .bi-icon { @extend %icon; } .bi-icon--sm { @extend %icon; font-size: 17px !important; } .bi-icon--xs { @extend %icon; font-size: 14px !important; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/input.scss ================================================ @import './def/defaults.def'; @import './def/flex.def'; @import './def/input.def'; .bi-theme--lighter { .bi-input { @include input('lighter'); } } .bi-theme--dark { .bi-input { @include input('dark'); } } textarea.bi-input { min-height: 50px; } .bi-input + .bi-input-action { margin-left: -1px; } .bi-input-action { @include flex(row, center, center); width: $default-input-height; height: $default-input-height; border: 1px solid $grey--300; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/label.scss ================================================ @import './def/label.def'; .bi-label { @extend %label; } .bi-label--sm { @extend %label; font-size: 12px !important; font-weight: normal !important; color: $grey--700 !important; letter-spacing: .5px; } .bi-label--large { @extend %label; font-size: 18px !important; font-weight: 300 !important; } .bi-label--primary { @include color-label($primary); } .bi-label--secondary { @include color-label($secondary); } .bi-label--success { @include color-label($success); } .bi-label--warning { @include color-label($warning); } .bi-label--danger { @include color-label($danger); } .bi-label--muted { @include color-label($grey--400); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/link.scss ================================================ @import './def/link.def'; .bi-link { @extend %link; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/media.scss ================================================ @import './def/media.def.scss'; @media screen and (max-height: $small-screen-size) { .bi-media--normal { display: none; } } @media screen and (min-height: $small-screen-size) { .bi-media--small { display: none; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/mouse.scss ================================================ .bi-pointer { cursor: pointer; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/nav-tabs.scss ================================================ @import './def/nav-tabs.def'; .bi-nav-tabs { @extend %bi-nav-tabs; .bi-nav-tab { @extend %bi-nav-tab; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/no-select.scss ================================================ .bi-no-select { user-select: none; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/panel.scss ================================================ @import './def/colors.def'; @import './def/defaults.def'; @import './def/panel.def'; @import './def/action.def'; .bi-panel { @include panel(); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/reset.scss ================================================ /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } // default BI rules html, body { height: 100%; overflow: hidden; } body { font-family: 'Open Sans'; font-size: 13px; line-height: 1.42857143; } *, :after, :before { box-sizing: border-box; } iframe { border: 0; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/scroll.scss ================================================ .bi-scroll { overflow: auto; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/section.scss ================================================ @import './def/colors.def'; @import './def/border.def'; @import './def/section.def'; .bi-section { @include section($grey--100); } .bi-section--300 { @include section-static($grey--100, 300px); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/space.scss ================================================ @import './def/defaults.def'; @import './def/space.def'; .bi-space-h__self { @include space-h(); } .bi-space-v__self { @include space-v(); } .bi-space-h, .bi-s-h { @include space-h__inner(); } .bi-space-v, .bi-s-v { @include space-v__inner(); } .bi-space-h--x15, .bi-s-h--x15 { @include space-h__inner($default-space * 1.5); } .bi-space-h--x2, .bi-s-h--x2 { @include space-h__inner($default-space * 2); } .bi-space-h--x3, .bi-s-h--x3 { @include space-h__inner($default-space * 3); } .bi-space-h--x05, .bi-s-h--x05 { @include space-h__inner($default-space / 2); } .bi-space-v--x15, .bi-s-v--x15 { @include space-v__inner($default-space * 1.5); } .bi-space-v--x2, .bi-s-v--x2 { @include space-v__inner($default-space * 2); } .bi-space-v--x3, .bi-s-v--x3 { @include space-v__inner($default-space * 3); } .bi-space-v--x05, .bi-s-v--x05 { @include space-v__inner($default-space / 2); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/spinner.scss ================================================ @import './def/spinner.def'; .bi-spinner { @extend %spinner; } .bi-spinner--sm { @extend %spinner; width: 20px !important; height: 20px !important; line-height: 20px !important; &:after { border-width: 2px !important; } } .bi-spinner--xs { @extend %spinner; width: 14px !important; height: 14px !important; line-height: 14px !important; &:after { border-width: 2px !important; } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/state.scss ================================================ @import 'def/state.def'; // default .bi-muted { @include muted('lighter'); } .bi-active { @include active('lighter'); } .bi-hover { @include hover('lighter'); } .bi-fade { @include fade('lighter'); } .bi-elevate { @include elevate(); } // dark .bi-theme--dark { .bi-muted { @include muted('dark'); } .bi-active { @include active('dark'); } .bi-hover { @include hover('dark'); } } // darker .bi-theme--darker { .bi-muted { @include muted('darker'); } .bi-active { @include active('darker'); } .bi-hover { @include hover('darker'); } } // lighter .bi-theme--lighter { .bi-muted { @include muted('lighter'); } .bi-active { @include active('lighter'); } .bi-hover { @include hover('lighter'); } } // light .bi-theme--light { .bi-muted { @include muted('light'); } .bi-active { @include active('light'); } .bi-hover { @include hover('light'); } .bi-theme--lighter { .bi-muted { @include muted('lighter'); } .bi-active { @include active('lighter'); } .bi-hover { @include hover('lighter'); } } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/table.scss ================================================ @import './def/table.def'; .bi-table { @extend %table; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/tag.scss ================================================ @import './def/tag.def'; .bi-tag { @extend %tag; } .bi-tag--sm { @extend %tag; line-height: 18px; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/text.scss ================================================ .bi-text { font-size: 13px; } .bi-text--ui { font-family: 'bi-ui'; } .bi-text--ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .bi-text--sm { font-size: 10px; } .bi-text--md { font-size: 14px; } .bi-text--lg, .bi-text--large { font-size: 20px; } .bi-text--200 { font-weight: 200; } .bi-text--300 { font-weight: 300; } .bi-text--400 { font-weight: 400; } .bi-text--600 { font-weight: 600; } .bi-text--700 { font-weight: 700; } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/theme.scss ================================================ @import './def/colors.def'; @import './def/theme.def'; .bi-theme--lighter { @include theme('lighter'); } .bi-theme--light { @include theme('light'); } .bi-theme--dark { @include theme('dark'); } .bi-theme--darker { @include theme('darker'); } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/toggle.scss ================================================ @import './def/toggle.def'; .bi-toggle { @extend %toggle; } .bi-toggle-right { @extend %toggle; &:after { transform: rotate(-90deg); } } ================================================ FILE: quix-frontend/client/src/lib/ui/assets/css/wrap.scss ================================================ ================================================ FILE: quix-frontend/client/src/lib/ui/bootstrap.ts ================================================ import './assets/css/reset.scss'; import 'jquery-ui/themes/base/resizable.css'; import 'jquery-ui/ui/widgets/resizable'; import './components/date-picker/DatePicker'; import './components/panel/Panel'; ================================================ FILE: quix-frontend/client/src/lib/ui/components/Highlighter.tsx ================================================ import React from 'react'; import ReactHighlighter from 'react-highlight-words'; export interface HighlighterProps { term: string; filter: string; } export const Highlighter = ({ term, filter, }: HighlighterProps) => { return ( ) } ================================================ FILE: quix-frontend/client/src/lib/ui/components/autocomplete/Autocomplete.tsx ================================================ import React from 'react'; import { AutocompleteProps, useAutocomplete } from './autocomplete.hook'; import { Input } from '../input/Input'; import { Dropdown } from '../dropdown/Dropdown'; import { Highlighter } from '../Highlighter'; export const Autocomplete = (props: AutocompleteProps) => { const [ { title, inputValue, placeholder, inputValid }, viewState, { onScroll, onValueChange, onValueSelect, getItems, onInputFocus, onInputBlur, }, ] = useAutocomplete(props); const inputClassName = `bi-pointer ${inputValid ? '' : ' bi-border-invalid'}${ props.classes?.input ? ` ${props.classes?.input}` : '' }`; const renderInput = (p: any) => ( { onValueChange(e.target.value); p.onChange && p.onChange(); }} onFocus={(e, ref) => onInputFocus(e, p, ref)} onBlur={(e) => onInputBlur(e, p)} endAdornment={keyboard_arrow_down} value={inputValue} /> ); const optionHtml = (option: any) => { if (props.primaryOption && option[title] === props.primaryOption[title]) { return (
  • e.preventDefault()} onClick={() => onValueSelect(option)} > {option[title]}
  • ); } switch (viewState.get()) { case 'Error': return (
  • Error occured
  • ); case 'Loading': return (
  • ); case 'Content': return (
  • onValueSelect(option)} className={props.classes?.listItem || ''} data-hook={props.liDataHook} > {option.render ? ( option.render(inputValue) ) : ( )}
  • ); case 'Empty': return (
  • No suggestions
  • ); default: return <> ; } }; return ( {(options) => (
      {options.map(optionHtml)}
    )}
    ); }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/autocomplete/autocomplete.hook.ts ================================================ /* eslint-disable react-hooks/exhaustive-deps */ import { useEffect } from 'react'; import { isEqual } from 'lodash'; import { useViewState, ViewStateActions, } from '../../../../services/hooks'; export interface AutocompleteProps { title: string; options: any[]; optionKey?(option: any): string; state?: string; getMore?(): void; defaultValue?: string; onChange?(value: string): void; onInputFocus?(): void; onSelect(option: any): void; setTitleOnValueChange?(value: string): string; setTitleOnValueSelect?(option: any): string; placeholder?: string; inputDataHook?: string; liDataHook?: string; primaryOption?: any; classes?: { input?: string; list?: string; listItem?: string; wrapper?: string; }; disableFreeWrite?: boolean; readonly?: boolean; } interface StateData { title: string; currentOptions: any[]; inputValue: string; inputValid: boolean; inputValueChanged: boolean; filteredOptions: any[]; placeholder?: string; selectedOption: any; } interface Actions { onScroll(UIElement: any): void; onValueChange(v: string): void; onValueSelect(primaryOption: any): void; getItems(): any[]; onInputFocus( e: any, p: any, ref?: React.MutableRefObject, ): void; onInputBlur( e: any, p: any, ref?: React.MutableRefObject, ): void; } const formatInput = (props: AutocompleteProps): StateData => { return { title: props.title, inputValue: props.defaultValue || '', inputValueChanged: false, inputValid: true, filteredOptions: props.options, currentOptions: props.getMore ? props.options : props.options.slice(0, 50), selectedOption: {}, placeholder: props.primaryOption ? props.primaryOption[props.title] : props.placeholder || 'Please select value', }; }; const States = ['Empty', 'Content', 'Loading', 'Error']; export const useAutocomplete = ( props: AutocompleteProps, ): [StateData, ViewStateActions, Actions] => { const [stateData, viewState] = useViewState( States, formatInput(props), ); useEffect(() => { const state = props.state || 'Content'; const options = props.options; const currentOptions = props.getMore ? options : options.slice(0, 50); const inputValue = stateData.inputValueChanged ? stateData.inputValue : props.defaultValue; viewState.set(state, { filteredOptions: options, currentOptions, inputValue, }); }, [props.state, props.options, props.defaultValue]); const onScroll = (UIElement: any) => { const element = UIElement.target; if ( element.scrollHeight - element.scrollTop <= element.clientHeight + 100 ) { if (!props.getMore) { if ( stateData.currentOptions.length !== stateData.filteredOptions.length ) { viewState.update({ currentOptions: stateData.filteredOptions.slice( 0, stateData.currentOptions.length + 50, ), }); } } else { props.getMore(); } } }; const onValueChange = (v: string) => { if (props.onChange) { props.onChange(v); } const inputValue = props.setTitleOnValueChange ? props.setTitleOnValueChange(v) : v; if (!props.getMore) { const _filteredOptions = props.options.filter((option) => option[stateData.title].includes(v), ); if (!_filteredOptions.length) { viewState.set('Empty', { filteredOptions: [], currentOptions: [], inputValue, inputValueChanged: true, }); } else { viewState.set('Content', { filteredOptions: _filteredOptions, currentOptions: _filteredOptions.slice(0, 50), inputValue, inputValueChanged: true, }); } } else { viewState.update({ inputValue, inputValueChanged: true, }); } }; const onValueSelect = (option: any) => { const isPrimaryOption = props.primaryOption && option[stateData.title] === props.primaryOption[stateData.title]; viewState.update({ selectedOption: option, inputValue: isPrimaryOption ? '' : props.setTitleOnValueSelect ? props.setTitleOnValueSelect(option) : option[stateData.title], inputValueChanged: true, inputValid: true, }); props.onSelect(option); }; const getItems = () => { if (viewState.is('Empty') && props.primaryOption) { return [props.primaryOption]; } if (!viewState.is('Content')) { return [{ [stateData.title]: '' }]; } return props.readonly ? [] : props.primaryOption && !isEqual(props.primaryOption, stateData.selectedOption) ? [props.primaryOption, ...stateData.currentOptions] : stateData.currentOptions; }; const onInputFocus = ( e: any, p: any, ref?: React.MutableRefObject, ) => { !props.readonly && ref && ref.current.select(); props.onInputFocus && props.onInputFocus(); p.onFocus && p.onFocus(); }; const onInputBlur = (e: any, p: any) => { let inputValue = props.defaultValue || ''; if (stateData.selectedOption && stateData.selectedOption[stateData.title]) { inputValue = props.setTitleOnValueSelect ? props.setTitleOnValueSelect(stateData.selectedOption) : stateData.selectedOption[stateData.title]; } viewState.update({ inputValid: props.primaryOption?.[stateData.title] === inputValue || inputValue === stateData.inputValue, }); p.onInputBlur && p.onInputBlur(); }; return [ stateData, viewState, { onScroll, onValueChange, onValueSelect, getItems, onInputFocus, onInputBlur, }, ]; }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/date-picker/DatePicker.tsx ================================================ import React from 'react'; import 'bootstrap-daterangepicker/daterangepicker.css'; import ReactDateRangePicker from 'react-bootstrap-daterangepicker'; import { DatePickerProps, useDatePicker } from './date-picker.hook'; export const DatePicker = (props: DatePickerProps) => { const [ { customDates }, { handleCallback, getLabel, getInitialDates }, viewState, ] = useDatePicker(props); switch (viewState.get()) { case 'Range': return (
    {props.title ? ( {props.title} ) : null} handleCallback([start, end] as any, label) } >
    {getLabel()}
    ); case 'RangeReadOnly': return (
    {props.title ? ( {props.title} ) : null}
    {getLabel()}
    ); default: return
    Type {props.type} not implemented yet.
    ; } }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/date-picker/date-picker-utils.ts ================================================ /* tslint:disable:no-non-null-assertion */ export const getKeyByValue = (object: Record, value: string) => { return Object.keys(object).find((key) => object[key] === value); }; const numbersRegex = /\d+/; export const getAmountAndUnitFromString = (str: string) => { const amount = str.match(numbersRegex); const unit = str.split(amount![0]).pop(); return [amount as any, unit]; }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/date-picker/date-picker.hook.ts ================================================ /* eslint-disable react-hooks/exhaustive-deps */ /* tslint:disable:no-non-null-assertion */ import { useEffect } from 'react'; import moment, { Moment } from 'moment'; import _ from 'lodash'; import { useViewState, ViewStateActions, } from '../../../../services/hooks'; import { getAmountAndUnitFromString, getKeyByValue } from './date-picker-utils'; export interface Range { start: null | number; end?: null | number; period?: null | string; } type DateRanges = Record; type DatePickerTypes = 'Range'; export interface OnChangeDatePickerProps { selectedDates: Moment[]; label?: string; isEqualToCustomRange: boolean; } export interface DatePickerProps { title?: string; dateFormat?: string; initialDates?: Range; customDates?: DateRanges; timePicker?: boolean; readonly?: boolean; onChange(props: Range): void; type: DatePickerTypes; classes?: { input?: string; inputDisabled?: string; formRow?: string; }; } interface StateData { selectedDates: Moment[]; isEqualToCustomRange: boolean; customRangeLabel: string; customDates?: DateRanges; } interface DatePickerActions { handleCallback(initialDates: Moment[], label?: string): void; getLabel(): string; getInitialDates(): Moment[]; } const States = ['Range', 'RangeReadOnly']; const formatDate = ( dates: Moment[] = [moment(), moment()], format: string = 'DD/MM/YYYY HH:mm', ) => dates.length > 1 ? dates[0].format(format) + ' - ' + dates[1].format(format) : dates[0].format(format); const formatInput = (props: DatePickerProps): StateData => { let formattedCustomDates: Record | undefined; if (props.customDates) { Object.keys(props.customDates).forEach((key) => { if (!formattedCustomDates) { formattedCustomDates = {}; } const [amount, unit] = getAmountAndUnitFromString( props.customDates![key], ); formattedCustomDates[key] = [ moment().subtract(amount, unit.toLowerCase()), moment(), ]; }); } if (props.initialDates) { const { start, end, period } = props.initialDates; const selectedDates: Moment[] = []; start && selectedDates.push(moment.unix(start)); end && selectedDates.push(moment.unix(end)); return { customRangeLabel: period ? getKeyByValue(props.customDates!, period)! : '', selectedDates, isEqualToCustomRange: !!period, customDates: formattedCustomDates, }; } return { customRangeLabel: '', selectedDates: [], isEqualToCustomRange: false, customDates: formattedCustomDates, }; }; const formatOutput = ( selectedDates: Moment[], isEqualToCustomRange: boolean, customDates?: DateRanges, label?: string, ): Range => { const _selectedDates = selectedDates.map((date) => date.utc()); const range: Range = { start: !isEqualToCustomRange ? _selectedDates[0].unix() : null, end: !isEqualToCustomRange && _selectedDates[1] ? _selectedDates[1].unix() : null, period: isEqualToCustomRange ? customDates![label!] : '', }; return range; }; export const useDatePicker = ( props: DatePickerProps, ): [StateData, DatePickerActions, ViewStateActions] => { const [stateData, viewState] = useViewState( States, formatInput(props), ); useEffect(() => { const newState = props.readonly ? 'RangeReadOnly' : props.type; viewState.set(newState, formatInput(props)); }, [props]); const handleCallback = (selectedDates: Moment[], label?: string) => { const isEqualToCustomRange = !!props.customDates?.[label || '']; viewState.update({ selectedDates, customRangeLabel: label, isEqualToCustomRange, }); props.onChange( formatOutput( selectedDates, isEqualToCustomRange, props.customDates, label, ), ); }; const getLabel = () => { if (stateData.isEqualToCustomRange) { return stateData.customRangeLabel; } if (stateData.selectedDates.length === 0) { switch (viewState.get()) { case 'Range': const initialDates = getInitialDates(); return formatDate(initialDates); default: return ''; } } return formatDate(stateData.selectedDates, props.dateFormat); }; const getInitialDates = () => { const { customDates, initialDates } = props; if (stateData.customDates && initialDates?.period && customDates) { const key = getKeyByValue(customDates, initialDates.period); return stateData.customDates[key!]; } return [moment(), moment()]; }; return [stateData, { handleCallback, getLabel, getInitialDates }, viewState]; }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/dropdown/Dropdown.tsx ================================================ import React, { useRef, useState } from 'react'; import ReactDOM from 'react-dom'; import { usePopper } from 'react-popper'; import { Placement } from '@popperjs/core'; import { isNil } from 'lodash'; import { withOutsideClick } from '../../../../services/hooks'; import './dropdown.scss'; interface DropdownProps { toggle(props: any): JSX.Element; options: any[]; isOpen?: boolean; placement?: Placement; children?(options: any[]): JSX.Element; states?: { toggle?: { onClick?: boolean; onKeyDown?: boolean; onFocus?: boolean; }; }; dynamicWidth?: boolean; readonly?: boolean; } const sameWidth = { name: 'sameWidth', enabled: true, phase: 'beforeWrite' as any, requires: ['computeStyles'], fn: ({ state }: any) => { state.styles.popper.width = `${state.rects.reference.width}px`; }, effect: ({ state }: any) => { state.elements.popper.style.width = `${state.elements.reference.offsetWidth}px`; }, }; export const Dropdown = ({ toggle, options, isOpen, placement, children, states, dynamicWidth = true, readonly, }: DropdownProps) => { const isOpenDefined = !isNil(isOpen); const [_isOpen, setIsOpen] = useState(false); const referenceToggle = useRef(null); const referenceOptions = useRef(null); const { styles, attributes, forceUpdate } = usePopper( referenceToggle.current, referenceOptions.current, { placement: placement || 'bottom-start', strategy: 'fixed', modifiers: dynamicWidth ? [sameWidth] : [], }, ); withOutsideClick([referenceToggle], () => { forceUpdate && forceUpdate(); setTimeout(() => setIsOpen(false), 0); }); return ( <> {toggle({ ref: referenceToggle, onClick: () => setIsOpen( isNil(states?.toggle?.onClick) ? !_isOpen : states?.toggle?.onClick, ), onKeyDown: () => setIsOpen( isNil(states?.toggle?.onKeyDown) ? true : states?.toggle?.onKeyDown, ), onFocus: () => setIsOpen( isNil(states?.toggle?.onFocus) ? true : states?.toggle?.onFocus, ), })} {readonly ? null : ReactDOM.createPortal(
    {(isOpenDefined ? isOpen : _isOpen) ? (
    {children(options)}
    ) : null}
    , document.querySelector('body') as any, )} ); }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/dropdown/dropdown.scss ================================================ .bi-dropdown-content { border-radius: 3px; } ================================================ FILE: quix-frontend/client/src/lib/ui/components/hoc/makePagination.tsx ================================================ import React, { useEffect, useState } from 'react'; import { Subtract } from 'utility-types'; import _ from 'lodash'; interface InjectedPaginationProps { data: any[]; columns: any[]; getChunk?(): void; isChunking?: boolean; } interface MakePaginationProps { initialData: any; columns: any[]; loadMore(offset: number, limit: number): any; paginationSize: number; tableSize?(size: number): void; getChunk?(): void; } const makePagination =

    ( Component: React.ComponentType

    , ) => { const MakePagination = (props: Subtract & MakePaginationProps) => { const { initialData, columns, loadMore, paginationSize, tableSize, ...restComponentProps } = props; const [isChunking, setIsChunking] = useState(false); const [resultsLeft, setResultsLeft] = useState(initialData && initialData.length === paginationSize + 1); const [data, setData] = useState(resultsLeft ? initialData.slice(0, paginationSize) : (initialData || [])); useEffect(() => { if (tableSize) { tableSize(data.length); } }, [data.length]); const getChunk = () => { if (!isChunking && resultsLeft) { setIsChunking(true); loadMore(data.length, paginationSize + 1)(response => { if (response.length === paginationSize + 1) { setData([...data, ...response.slice(0, paginationSize)]); } else { setResultsLeft(false); setData([...data, ...response]); } setIsChunking(false); }); } } const componentProps = { columns, data, isChunking, getChunk, ...restComponentProps, }; return } return MakePagination; } export default makePagination; ================================================ FILE: quix-frontend/client/src/lib/ui/components/input/Input.tsx ================================================ import React, { useRef } from 'react'; import './input.scss'; interface InputProps extends Partial< React.DetailedHTMLProps< React.InputHTMLAttributes, HTMLInputElement > > { startAdornment?: JSX.Element; endAdornment?: JSX.Element; disableFreeWrite?: boolean; readonly?: boolean; onFocus?( e: React.FocusEvent, ref?: React.MutableRefObject, ): void; onBlur?( e: React.FocusEvent, ref?: React.MutableRefObject, ): void; } export const Input = React.forwardRef( ( { className, startAdornment, endAdornment, disableFreeWrite, readonly, onFocus, onBlur, ...p }: InputProps, ref, ) => { const inputRef = useRef(null as any); const _readonly = disableFreeWrite || readonly; const additionalClasses = `${readonly ? ' bi-disabled' : ''}${ className ? ` ${className}` : '' }`; if (startAdornment || endAdornment) { const _wrapperClassName = 'bi-input bi-input-wrapper bi-align' + additionalClasses; return (

    {startAdornment} onFocus && onFocus(e, inputRef)} onBlur={(e) => onBlur && onBlur(e, inputRef)} {...p} /> {endAdornment}
    ); } const _className = 'bi-input' + additionalClasses; return ( onFocus && onFocus(e, (ref as any) || inputRef)} onBlur={(e) => onBlur && onBlur(e, (ref as any) || inputRef)} {...p} /> ); }, ); ================================================ FILE: quix-frontend/client/src/lib/ui/components/input/input.scss ================================================ @import '../../../../lib/ui/assets/css/def/colors.def.scss'; .bi-input-wrapper { padding: 0px 10px !important; .bi-input-no-border { border: 0; outline: none; cursor: inherit; font: inherit; color: inherit; width: 100%; height: 100%; } } .bi-border-valid { border-color: $green--300 !important; } .bi-border-invalid { border-color: $red--300 !important; } ================================================ FILE: quix-frontend/client/src/lib/ui/components/panel/Panel.tsx ================================================ import React from 'react'; interface PanelProps { header?: JSX.Element; children: any; className?: { main?: string; header?: string; content?: string; }; } export const Panel = ({ header, children, className }: PanelProps) => { const _main = className?.main ? `bi-s-v--x15 bi-panel bi-grow ${className?.main}` : 'bi-s-v--x15 bi-panel bi-grow'; const _header = className?.header ? `bi-panel-header ${className?.header}` : 'bi-panel-header'; const _content = className?.content ? `bi-panel-content ${className?.content}` : 'bi-panel-content'; return (
    {header ?
    {header}
    : null}
    {children}
    ); }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/states/EmptyState.tsx ================================================ import React from 'react'; import noResultsImg from '../../../../assets/no_data.svg'; export const EmptyState = () => (
    No results
    ); ================================================ FILE: quix-frontend/client/src/lib/ui/components/states/ErrorState.tsx ================================================ import React from 'react'; export const ErrorState = ({ errorMessage, }) => (
    error_outline
    {errorMessage}
    ); ================================================ FILE: quix-frontend/client/src/lib/ui/components/states/FilterInitialState.tsx ================================================ import React from 'react'; export const FilterInitialState = ({ entityName, }) => (
    Searching {entityName}...
    ); ================================================ FILE: quix-frontend/client/src/lib/ui/components/states/InitialState.tsx ================================================ import React from 'react'; export const InitialState = ({ entityName, }) => (
    Loading {entityName}...
    ); ================================================ FILE: quix-frontend/client/src/lib/ui/components/states/index.ts ================================================ export {InitialState} from './InitialState'; export {FilterInitialState} from './FilterInitialState'; export {EmptyState} from './EmptyState'; export {ErrorState} from './ErrorState'; ================================================ FILE: quix-frontend/client/src/lib/ui/components/table/Table.scss ================================================ .bi-table-cells { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } ================================================ FILE: quix-frontend/client/src/lib/ui/components/table/Table.tsx ================================================ import React from 'react'; import { TableRow } from './TableRow'; import '../../directives/search/search.scss'; import './Table.scss'; export interface TableProps { hookName?: string; columns: { header: string; render(cell: any): React.ReactNode; accessor: string; className: string; }[]; data: any[]; onRowClicked?(row: any): void; getChunk?(): void; isChunking?: boolean; } export const Table = ({ hookName, columns, data, onRowClicked, getChunk, isChunking = false, }: TableProps) => { const scroll = (UIElement) => { const element = UIElement.target; if (element.scrollHeight - element.scrollTop <= element.clientHeight + 1000) { getChunk && getChunk(); } } return (
    {columns.map((column, index) => ( ))} { data.map((fullRow, index) => ( ) ) }
    {column.header}
    {isChunking ?
    Loading...
    : null }
    ); }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/table/TableRow.tsx ================================================ import React from 'react'; export interface RowConfig { name: keyof T; title?: string; className?: string; filter?(value, item: T, index?): React.ReactNode; } export interface HighlightedRowConfig extends RowConfig { filter?( value, item: T, index, highlight?: (term: string) => React.ReactNode ): React.ReactNode; } export interface TableRowProps { columns: { header: string; render(cell: any): React.ReactNode; accessor: string; className: string; }[]; onRowClicked(row: any): void; row: any; } export const TableRow = ({ row, onRowClicked, columns }: TableRowProps) => { return ( { if (typeof onRowClicked === 'function') { return onRowClicked(row); } }} data-hook='table-row' > {columns.map((column, index) => { return ( {column.render(row)} ); })} ); }; ================================================ FILE: quix-frontend/client/src/lib/ui/components/table/table-testkit.ts ================================================ import {Testkit} from '../../../../../test/e2e/driver'; const enum Hooks { Initial = 'table-initial', Error = 'table-error', EmptyResult = 'table-empty-result', FilterInitial = 'table-filter-initial', TableRow = 'table-row', } export class TableTestkit extends Testkit { tableStates = { hasError: async () => { return (await this.query.hook(Hooks.Error)) !== null; }, hasLoading: async () => { return (await this.query.hook(Hooks.Initial)) !== null; }, hasFilterLoading: async () => { return (await this.query.hook(Hooks.FilterInitial)) !== null; }, hasEmptyResult: async () => { return (await this.query.hook(Hooks.EmptyResult)) !== null; }, } tableTotalRows = async () => { return (await this.query.hooks(Hooks.TableRow)).length; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.html ================================================
    keyboard_arrow_right
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.scss ================================================ @import '../../assets/css/def/colors.def'; @import '../../assets/css/def/defaults.def'; bi-breadcrumbs { .bi-link { color: unset; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.story.ts ================================================ export default app => app .story('UI', 'Breadcrumbs') .section('Breadcrumbs', ` Selected: {{selected}} `, scope => { scope.items = [{name: 'Foo'}, {name: 'Goo'}]; scope.onItemClick = item => scope.selected = item; }) .section('Custom breadcrumbs', ` face {{::item.name}} Selected: {{selected}} `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.ts ================================================ import template from './breadcrumbs.html'; import './breadcrumbs.scss'; import {initNgScope} from '../../../core'; export default function directive() { return { template, require: 'biOptions', restrict: 'E', transclude: true, scope: { onItemClick: '&' }, link: { pre(scope, element, attrs, biOptions, transclude) { initNgScope(scope) .withEvents({ onItemClick(item) { scope.onItemClick({item: biOptions.format(item)}); } }); scope.renderItem = (item, index) => { let html = transclude((_, _scope) => { _scope.item = item; _scope.$index = index; }); html = html.text().trim().length ? html : biOptions.render(item); return {html}; }; biOptions.watch(collection => { scope.collection = collection; }); } } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/common/dropdown-list.ts ================================================ import {IScope} from 'angular'; import {assign, includes, without, uniq} from 'lodash'; import * as JsSearch from 'js-search'; import {initNgScope, createNgModel, inject, utils} from '../../../core'; const isNull = value => { return !value && typeof value !== 'boolean' && typeof value !== 'number'; } const toString = value => { return isNull(value) ? '' : `${value}`; } export class DropdownList { private searcher: any = null; private deferredId = 0; private readonly $timeout: ng.ITimeoutService = inject('$timeout'); constructor( private readonly scope: IScope, private readonly element: any, private readonly attrs: any, private readonly controllers: Record, private readonly transclude: ng.ITranscludeFunction, private readonly config: { optionsAlias: string; isArray?: boolean; options?: Record; }, ) { const {ngModel, biOptions} = controllers; createNgModel(scope as any, ngModel) .formatWith(model => this.format(model)) .parseWith(model => this.parse(model)) .validateWith(() => this.validate()) .renderWith(model => this.render(model)) .watchDeep(!!config.isArray) .feedBack(false); initNgScope(scope) .withOptions(config.optionsAlias, { freetext: false, typeahead: false, dropdownWidth: null, dropdownMinWidth: 'toggle', alignDropdown: 'left', debounce: 0, type: 'text', filterBy: [], ...config.options }) .withVM({ isCustomToggle: false, renderedModel: null, keyNavOption: null, search: { text: null, parsed: null, }, options: { collection: null, filtered: null, searched: null, falsy: null, deferred: { loading: false }, items() { return this.searched || this.filtered; } } }) .withEvents({ onSearchChange: () => { const {vm, options} = this.scope; vm.search.toggle(true); if (!this.config.isArray || options.typeahead) { vm.options.toggle(true); this.search(); scope.onTypeahead({text: vm.search.text}); } }, onSearchKeypress: ({key}) => { const {options, vm} = scope; if (key === 'Enter' && options.freetext && !vm.keyNavOption) { this.applySearchText(vm.search.text); } }, onSearchBlur: () => { const {options, vm} = scope; if (options.freetext) { this.applySearchText(vm.search.text); } }, onSearchMousedown: () => { const {options, vm} = scope; if (options.typeahead) { scope.onTypeahead({text: null}); if (this.config.isArray) { vm.options.toggle(); } } }, onDropdownShow: () => { const {options} = this.scope; if (!this.config.isArray && options.typeahead && scope.model) { this.element.find('input').select(); } }, onDropdownHide: () => { this.reset(); }, onOptionSelect: (...options) => { const {vm} = this.scope; vm.options.toggle(false); if (this.config.isArray) { scope.model = uniq([...scope.model, ...options]); vm.search.text = null; this.element.find('input').focus(); } else { scope.model = options[0]; } if (scope.onSelect) { this.$timeout(() => scope.onSelect({model: scope.model})); } }, onOptionDelete: option => { if (this.config.isArray) { scope.model = without(scope.model, option); } } }); biOptions.watch(async (collection: any) => { const {vm} = this.scope; const deferredId = ++this.deferredId; if (collection && collection.then) { this.setOptions(null); vm.options.deferred.toggle(true); vm.options.deferred.loading = true; collection = await collection; } if (deferredId === this.deferredId) { utils.scope.safeApply(scope, () => { this.setOptions(collection); vm.options.deferred.loading = false; }); } }); scope.renderToggle = () => this.renderToggle(); scope.renderOption = option => this.renderOption(option); scope.placeholder = scope.placeholder || 'Select a value'; } private reset() { const {vm} = this.scope; vm.search.toggle(false); vm.options.searched = null; this.render(); } private format(model: any) { const {biOptions} = this.controllers; if (this.config.isArray) { return model ? model.map(item => biOptions.format(item)) : []; } return biOptions.format(model); } private parse(model: any[]) { const {biOptions} = this.controllers; let parsed; if (this.config.isArray) { parsed = model.map(item => biOptions.parse(item)); } else { parsed = biOptions.parse(model); } inject('$timeout')(() => { this.reset(); this.initOptions(); }); return parsed; } private validate() { return { required: model => { if (!this.attrs.required) { return true; } return this.config.isArray ? !!(model && model.length) : !isNull(model); } }; } private render(model: any[] = this.scope.model) { const {biOptions} = this.controllers; const {vm} = this.scope; if (this.config.isArray) { vm.renderedModel = model.map(item => biOptions.render(item)); vm.search.text = ''; } else { vm.search.text = biOptions.render(model); vm.search.parsed = biOptions.parse(model); } } private applySearchText(text) { const {vm, events} = this.scope; if (vm.search.enabled && !isNull(text)) { if (this.config.isArray) { const values: string[] | number[] = typeof text === 'string' ? text.split(',') : [text]; events.onOptionSelect(...values); } else { events.onOptionSelect(text); } } } private setOptions(collection: any[] = this.scope.vm.options.collection) { const {vm} = this.scope; vm.options.collection = collection; this.initOptions(); this.search(); } private initOptions(collection: any[] = this.scope.vm.options.collection) { const {vm, options} = this.scope; if (!collection) { vm.options.filtered = null; return; } const {biOptions} = this.controllers; vm.options.falsy = null; vm.options.filtered = collection.filter((option) => { if (!vm.options.falsy && isNull(biOptions.parse(option))) { vm.options.falsy = {option}; return false; } if (this.config.isArray && includes(vm.renderedModel, biOptions.render(option))) { return false; } return true; }); if (vm.options.filtered && options.filterBy.length && !this.scope.readonly) { this.searcher = new JsSearch.Search(options.filterBy[0]); this.searcher.indexStrategy = new JsSearch.AllSubstringsIndexStrategy(); this.searcher.tokenizer = { tokenize: text => text .split(/[^a-z0-9\-'\.]+/i) .filter(t => !!t) }; options.filterBy.forEach(prop => this.searcher.addIndex(prop)); this.searcher.addDocuments(vm.options.filtered); } else { this.searcher = null; } } private search(collection: any[] = this.scope.vm.options.filtered) { const {vm} = this.scope; if (!collection || !vm.search.enabled || !vm.search.text) { vm.options.searched = null; return; } let text = vm.search.text; if (this.searcher) { vm.options.searched = this.searcher.search(text); return; } const {biOptions} = this.controllers; text = toString(text).toLowerCase(); vm.options.searched = collection.filter(option => includes(toString(biOptions.render(option)).toLowerCase(), text)); } public renderToggle() { const {scope} = this; const {biOptions} = this.controllers; const {vm, placeholder, options} = scope; const {type} = options; let html; if (this.transclude.isSlotFilled('toggle')) { html = this.transclude((_, tscope) => { tscope.placeholder = placeholder; Object.defineProperty(tscope, biOptions.getItemName(), { get() { return scope.model; } }); Object.defineProperty(tscope, 'text', { get() { return vm.search.text; } }); }, null, 'toggle'); vm.isCustomToggle = true; } else { html = inject('$compile')(` expand_more `)(this.scope); } return {html}; } public renderOption(option: any) { const {biOptions} = this.controllers; const {vm} = this.scope; let html; if (this.transclude.isSlotFilled('opt')) { html = this.transclude((_, tscope) => { tscope[biOptions.getItemName()] = option; Object.defineProperty(tscope, 'text', { get() { return vm.search.enabled ? vm.search.text : ''; } }); }, null, 'opt'); } else { const scope = assign(this.scope.$new(), { option: biOptions.render(option) }); html = inject('$compile')(`
    {{::option}}
    `)(scope); } return {html}; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/content-editable/content-editable.scss ================================================ @import '../../assets/css/def/colors.def'; @import '../../assets/css/def/defaults.def'; @import '../../assets/css/def/icon.def'; [contenteditable] { transition-duration: .15s; transition-property: color, padding, border-color; position: relative; display: inline-block; padding: 6px 0 4px; border-bottom: 2px solid transparent; white-space: nowrap; &[contenteditable=true], &.ce-toggler-hover { margin-right: 1.5em; } &[contenteditable=true] { cursor: pointer; &:focus { padding: 6px 10px 4px; border-color: $primary; background-color: $white; color: $default-text-color; outline: none; cursor: text; } &.ce-toggler-hover:after { display: none; } &:after { @extend %icon; transition: all .2s; content: 'mode_edit'; position: absolute; right: -1.2em; top: 50%; margin-top: -.4em; padding-left: 8px; font-size: 100%; cursor: pointer; opacity: .2; } &:hover:after { display: inline; color: $primary; opacity: 1; } &:focus:after { display: inline; color: $primary; opacity: 1; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/content-editable/content-editable.ts ================================================ import {initNgScope, inject} from '../../../core'; import './content-editable.scss'; function selectText(element) { const range = window.document.createRange(); range.selectNodeContents(element.get(0)); const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } export default () => { function updateNgModel(scope, value, ngModel) { if (value) { ngModel.$setViewValue(value); } else { ngModel.$rollbackViewValue(); } inject('$timeout')(() => { if (!ngModel.$valid) { ngModel.$setViewValue(scope.lastValidValue); ngModel.$setValidity('pattern', false); } else { if (scope.lastValidValue !== ngModel.$viewValue) { scope.onChange({prevValue: scope.lastValidValue}); } scope.lastValidValue = ngModel.$viewValue; ngModel.$setValidity('pattern', true); } }); } return { restrict: 'A', require: ['ngModel'], scope: { ceOptions: '=', onChange: '&', onBlur: '&' }, link: { pre(scope, element, attrs, [ngModel]) { ngModel.$render = () => { scope.lastValidValue = ngModel.$modelValue; element.text(ngModel.$modelValue); }; initNgScope(scope, {ngModel}) .withOptions('ceOptions', { autoEdit: false, toggler: 'always' // always | hover }); if (scope.options.toggler === 'hover') { element.addClass('ce-toggler-hover'); } element .attr('spellcheck', false) .on('focusout', () => { updateNgModel(scope, element.text(), ngModel); scope.onBlur(); }) .on('focus', () => selectText(element)) .on('keypress', e => { // enter if (e.keyCode === 13) { element.blur(); e.preventDefault(); e.stopPropagation(); return false; } }) .on('keyup', e => { // escape if (e.keyCode === 27) { ngModel.$rollbackViewValue(); element.blur(); } }); if (scope.options.autoEdit) { attrs.$observe('contenteditable', enabled => { if (enabled === 'true') { element.focus(); setTimeout(() => { selectText(element); }); } }); } } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.html ================================================ content_copy
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.scss ================================================ bi-copy-to-clipboard { .bctc-input { position: fixed; left: -1000000px; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.story.ts ================================================ export default app => app .story('UI', 'Clipboard') .section('Copy to clipboard', ` `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.ts ================================================ import {initNgScope, inject} from '../../../core'; import {showToast} from '../../services/toast'; import template from './copy-to-clipboard.html'; import './copy-to-clipboard.scss'; export default function directive() { return { template, restrict: 'E', transclude: true, scope: { text: '<', lazyText:'&' }, link: { pre(scope, element) { initNgScope(scope).withEvents({ onCopy() { scope.textValue = scope.text || scope.lazyText(); inject('$timeout')(() => { const input = element.find('textarea'); input.get(0).focus(); (input.get(0) as any).select(); // tslint:disable-next-line:deprecation document.execCommand('Copy'); showToast({ text: 'Copied to clipboard', hideDelay: 3000, type: 'success', }); }); }, }); }, }, }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/date-picker/date-picker.scss ================================================ bi-date-picker { position: relative; .xdsoft_datetimepicker { left: 0 !important; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/date-picker/date-picker.story.ts ================================================ export default app => app .story('UI', 'Datepicker') .section('Datepicker', ` {{model}} `, scope => scope.model = '2019-02-01 00:00') .section('Datepicker raw', ` {{model2}} `, scope => scope.model2 = 1548979200000); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/date-picker/date-picker.ts ================================================ import './date-picker.scss'; import 'jquery-datetimepicker/build/jquery.datetimepicker.full.js'; import 'jquery-datetimepicker/jquery.datetimepicker.css'; import {assign} from 'lodash'; import {initNgScope, createNgModel} from '../../../core'; import BiDate from '../../services/date'; function getRange(options) { let minDate: Date, maxDate: Date; if (options.maxRange) { const range = BiDate.getRange(options.maxRange, {maxDate: options.maxDate}); maxDate = new Date(range.end); minDate = new Date(range.start); } else { minDate = (options.minDate && new Date(options.minDate)) || undefined; maxDate = (options.maxDate && new Date(options.maxDate)) || undefined; } return {minDate, maxDate}; } function formatter(model, dateFormat) { const date = model && new BiDate(model); return date && (dateFormat ? date.asMoment().format(dateFormat) : date.fromUTC().format(BiDate.DATE_FORMAT)); } function parser(model, dateFormat) { const date = new BiDate(model).toUTC(); return dateFormat ? date.format(dateFormat) : date.valueOf(); } function init(scope, element) { let params = { parentID: scope.options.parent === 'self' ? element : 'body', lazyInit: true, value: scope.model, defaultTime: '00:00', minDate: null, maxDate: null, timepicker: scope.options.timepicker, format: scope.options.widgetDateFormat, scrollInput: scope.options.enableScroll, className: scope.options.className, onShow() { if (scope.options.parent === 'self') { setTimeout(() => element.find('.xdsoft_datetimepicker').css({ left: 0, top: 34 }, 0)); } }, onChangeDateTime: date => { scope.$apply(() => { scope.model = date && date.valueOf(); scope.onChange({date: scope.model}); }); } }; params = assign(params, getRange(scope.options)); element.find('input').datetimepicker(params); } function renderer(element, model) { element.find('input').val(model); } export default () => { return { restrict: 'E', template: ` `, require: ['ngModel', '?errors'], scope: { onChange: '&', bdpOptions: '=', readonly: '=' }, link: { pre(scope, element, attrs, [ngModel, errors]) { createNgModel(scope, ngModel) .formatWith(model => formatter(model, scope.options.dateFormat)) .parseWith(model => parser(model, scope.options.dateFormat)) .renderWith(model => renderer(element, model)); initNgScope(scope, {errors}) .readonly(scope.readonly) .withOptions('bdpOptions', { size: 'normal', minDate: null, maxDate: null, maxRange: null, dateFormat: BiDate.DATE_FORMAT, timepicker: true, widgetDateFormat: 'Y/m/d H:i', enableScroll: true, className: '', parent: null // null|self }) .withErrors([{ name: 'required', text: 'Date is required' }]) .thenIfNotReadonly(() => init(scope, element)); scope.placeholder = attrs.placeholder; scope.$on('$destroy', () => element.find('input').datetimepicker('destroy')); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/draggable/draggable.story.ts ================================================ export default app => app .story('UI', 'Draggable') .section('Draggable', `
    Drag me
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/draggable/draggable.ts ================================================ import {forEach} from 'lodash'; export default () => { return { restrict: 'A', scope: { biDraggable: '&', }, link(scope, element) { let image; element.attr('draggable', true).get(0).addEventListener('dragstart', function(e) { const data = scope.biDraggable(); image = this.cloneNode(true); image.style.position = 'fixed'; image.style.top = '-1000000px'; document.body.appendChild(image); e.dataTransfer.setDragImage(image, 8, 10); if (typeof data === 'object') { forEach(data, (value, key) => e.dataTransfer.setData(key, value)); } else if (data) { e.dataTransfer.setData('Text', data); } else { return false; } }); element.get(0).addEventListener('dragend', () => image && image.remove()); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.scss ================================================ @import '../../assets/css/def/icon.def'; @import '../../assets/css/def/animations.def'; @import '../../assets/css/def/defaults.def'; bi-dropdown { position: relative; display: inline-flex; [ng-transclude="toggle"] { display: inline-flex; user-select: none; cursor: pointer; &.bt-caret { &:after { @extend %icon; content: 'arrow_drop_down'; font-size: 18px; vertical-align: text-top; } } &.bt-readonly { cursor: default; } bi-toggle { display: inline-flex; } } .bd-content { position: fixed; border-radius: 3px; z-index: 200; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.story.ts ================================================ export default app => app .story('UI', 'Dropdown') .section('Dropdown', ` menu Default
    • Option 1
    • Option 2
    • Option 3
    menu Align right
    • Option 1
    • Option 2
    • Option 3
    menu Center
    • Option 1
    • Option 2
    • Option 3
    menu Position right
    • Option 1
    • Option 2
    • Option 3
    menu Don't hide on menu click
    • Option 1
    • Option 2
    • Option 3
    menu Show on hover hide on click
    • Option 1
    • Option 2
    • Option 3
    menu With delay
    • Option 1
    • Option 2
    • Option 3
    `) .section('Dropdown menu', `
    • Selected option
    • Disabled option
    • Another option
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.ts ================================================ import {initNgScope, inject, utils} from '../../../core'; import Popper from 'popper.js'; import './dropdown.scss'; import template from './dropdown.html'; const {onKey, onBlur} = utils.dom; let instances = []; function setClasses(element, popperActualPlacement) { const [position_, align_] = popperActualPlacement.split('-'); let parsedAlign = ''; if (!align_) { parsedAlign = 'center'; } else if (align_ === 'start') { parsedAlign = 'left'; } else { parsedAlign = 'right' } element.removeClass(['top', 'bottom', 'left', 'right'].map(pos => `bd-position--${pos}`).join(' ')); element.addClass(`bd-position--${position_}`); element.addClass(`bd-align--${parsedAlign}`); } function show(scope, element) { if (scope.options.hideOthers) { instances = instances.filter(instance => { instance.hide(); return false; }); } instances.push({hide: () => scope.actions.hide(true)}); scope.vm.toggleEnabled(true); const timeout = inject('$timeout') return timeout(() => timeout(() => { const content = element.find('.bd-content'); const {position, align} = scope.options; let width = 'auto'; let minWidth = 'auto'; let popperPlacement = position; switch (align) { case 'left': popperPlacement += '-start' break; case 'center': break; case 'right': popperPlacement += '-end'; break; default: } if (!scope.popper) { scope.popper = new Popper(element.get(0), content.get(0), { placement: popperPlacement, positionFixed: true, modifiers: { preventOverflow: { boundariesElement: 'viewport', priority: ['bottom', 'top'] } }, onCreate(data) { setClasses(element, data.placement) }, onUpdate(data) { setClasses(element, data.placement) } }); } switch (scope.options.minWidth) { case 'toggle': minWidth = element.width(); break; default: } if (!scope.options.minWidth) { switch (scope.options.width) { case 'toggle': width = element.width(); break; default: } } content.css({ width, minWidth }); scope.vm.toggle(true); scope.onShow(); })) } function hide(scope, mute = false) { scope.vm.toggle(false); if (scope.popper) { scope.popper.destroy(); scope.popper = null; } if (!mute) { scope.onHide(); } } export default () => { return { restrict: 'E', template, transclude: { toggle: 'biToggle' }, scope: { bdIsOpen: '=?', bdOptions: '<', onShow: '&', onHide: '&', readonly: '=' }, link: { pre(scope, element, attrs) { let cleaners = []; let timeoutPromise; const timeout = inject('$timeout'); initNgScope(scope) .readonly(scope.readonly) .withOptions('bdOptions', { align: 'left', /* left|right|center */ position: 'bottom', /* bottom|top|right|left */ width: 'content', /* content|toggle */ minWidth: null, /* content|toggle */ toggleOn: 'click', /* click|hover|manual */ hideOn: 'hover', /* click|hover */ hideOnClick: true, hideOthers: true, delay: { show: 0 }, caret: false }) .withVM({ $init() { const toggle = this.toggle.bind(this); this.toggle = enabled => { toggle(enabled); inject('$timeout')(() => scope.bdIsOpen = this.enabled); return this.enabled; }; } }) .withEditableActions({ toggle(enabled) { if (typeof enabled === 'undefined') { enabled = scope.vm.enabled; } else { enabled = !enabled; } if (enabled) { scope.actions.hide(); } else { scope.actions.show(); } }, show() { timeoutPromise = inject('$timeout')(() => show(scope, element).then(() => { cleaners = [ onKey('escape', (off) => { scope.actions.hide(); off(); }, scope), onBlur(element, (off, child) => { if ( child && ( scope.options.hideOnClick === false || child.closest('bi-toggle').length || child.closest('[disabled]').length ) ) { return false; } scope.actions.hide(); off(); }, scope) ]; }), scope.options.delay.show); }, hide(mute = false) { timeout.cancel(timeoutPromise); cleaners.forEach(cleaner => cleaner()); hide(scope, mute); } }); scope.$watch('bdIsOpen', (isOpen, prev) => { if (isOpen !== prev && isOpen !== scope.vm.enabled) { scope.actions.toggle(isOpen); } }); scope.$on('$destroy', () => { if (scope.popper) { scope.popper.destroy(); scope.popper = null; } }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/droppable/droppable.story.ts ================================================ export default app => app .story('UI', 'Droppable') .section('Droppable', `
    Drag me
    Drop here
    {{foo}} `, scope => { scope.onDrag = () => { return {foo: 1}; }; scope.onDrop = foo => { scope.foo = foo; }; }); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/droppable/droppable.ts ================================================ import {utils} from '../../../core'; export default () => { return { restrict: 'A', scope: { biDroppable: '&', }, link(scope, element) { element.get(0).addEventListener('dragover', e => { e.preventDefault(); e.stopPropagation(); }); element.get(0).addEventListener('drop', e => { e.preventDefault(); e.stopPropagation(); const data = e.dataTransfer.types.reduce((res, type) => { res[type] = e.dataTransfer.getData(type); return res; }, {}); utils.scope.safeApply(scope, () => scope.biDroppable(data)); }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dual-action/dual-action.html ================================================ {{bdaIsOn ? bdaOnText : bdaOffText}} ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dual-action/dual-action.scss ================================================ @import '../../assets/css/def/colors.def.scss'; bi-dual-action { } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/dual-action/dual-action.ts ================================================ import {initNgScope, inject} from '../../../core'; import template from './dual-action.html'; import './dual-action.scss'; export default () => { return { restrict: 'EA', template, scope: { bdaIsOn: '=', bdaOnText: '@', bdaOffText: '@', bdaOnChange: '&' }, link: { pre(scope) { initNgScope(scope).withEvents({ toggle() { inject('$q').when(scope.bdaOnChange({isOn: !scope.bdaIsOn})).then(() => scope.bdaIsOn = !scope.bdaIsOn); } }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/editable/editable.html ================================================
    {{::vm.error.value}}
    edit ================================================ FILE: quix-frontend/client/src/lib/ui/directives/editable/editable.scss ================================================ @import '../../assets/css/def/colors.def.scss'; bi-editable { position: relative; display: block; &.be--editing { > [be-controls] { .bi-icon { font-size: 18px; } } } [be-controls] { .bi-action { font-size: 16px; color: $green--300; &:hover { color: darken($green--300, 10); } } } > [be-controls] { position: absolute; top: 0; right: 0; } .be-footer { flex-basis: 30px; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/editable/editable.story.ts ================================================ export default app => app .story('UI', 'Editable') .section('Editable', `
    {{model}} `, scope => scope.model = 'edit me') .section('options.mode=edit', `
    `) .section('Custom controls', `
    add
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/editable/editable.ts ================================================ import {cloneDeep} from 'lodash'; import angular from 'angular'; import {initNgScope, inject} from '../../../core'; import template from './editable.html'; import './editable.scss'; function finish(vm) { vm.edit.toggle(false); vm.error.toggle(false); vm.error.value = ''; } export default () => { return { restrict: 'EA', template, require: 'ngModel', transclude: true, scope: { beOptions: '=', onToggle: '&', onChange: '&', readonly: '=' }, link(scope, element, attr, ngModel, transclude) { let childScope = null; // we're not deep-cloning ngModel.$viewValue as an optimization // it'll be cloned when toggling edit mode ngModel.$render = () => childScope.be.value = ngModel.$viewValue; function submit(mute = false) { // check if the model was changed if (angular.equals(ngModel.$viewValue, childScope.be.value)) { if (!mute) { finish(scope.vm); } return; } // save reference to original value const originalValue = ngModel.$viewValue; // commit new value (can be invalid) ngModel.$setViewValue(cloneDeep(childScope.be.value)); if (!mute) { // wait for change to take effect inject('$timeout')(() => { // notify that a change has been made const promise = scope.onChange(); if (!promise) { finish(scope.vm); return; } if (promise) { scope.vm.loading.toggle(true); promise.then(() => finish(scope.vm), error => { // commit original value if promise was rejected ngModel.$setViewValue(originalValue); // show error scope.vm.error.toggle(true); scope.vm.error.value = error && error.data && error.data.errorDescription || 'Unknown error'; }) .finally(() => scope.vm.loading.toggle(false)); } }); } } initNgScope(scope) .readonly(scope.readonly) .withOptions('beOptions', { saveText: 'save', mode: 'toggle' // toggle(shows toggle button)|edit(in edit state by default) }) .withVM({ save: { isEnabled() { return scope.beForm.$valid && scope.beForm.$dirty; } }, loading: {}, error: { value: '' }, edit: { $init() { this._toggle = this.toggle.bind(this); this.toggle = function(value) { this._toggle(value); element.toggleClass('be--editing', this.enabled); scope.beForm.$setPristine(!this.enabled); }; } } }) .withEditableEvents({ onToggle(focus = false) { scope.vm.edit.toggle(); if (scope.vm.edit.enabled) { // make a deep copy of the model (so we can check for changes when submitting) childScope.be.value = cloneDeep(ngModel.$viewValue); if (focus) { inject('$timeout')(() => { element.find('.bi-input').first().focus(); }); } scope.onToggle(); } }, onSubmit(mute = false) { submit(mute); }, onCancel() { // rollback changes (will call renderer) ngModel.$rollbackViewValue(); finish(scope.vm); } }); transclude((clone, transcludedScope) => { childScope = transcludedScope; const elementControls = element.find('[be-controls]'); let cloneControls = clone.find('[be-controls]'); cloneControls = cloneControls.length ? cloneControls : clone.filter('[be-controls]'); if (cloneControls.length) { const cloneControlsChildren = cloneControls.children(); cloneControls.replaceWith(elementControls); if (cloneControlsChildren.length) { elementControls.html(cloneControlsChildren); } } element.find('.be-content').html(clone); childScope.be = { get edit() { return scope.vm.edit.enabled; }, value: null, save() { submit(); } }; }); if (scope.options.mode === 'edit' && scope.events.onToggle) { scope.events.onToggle(); childScope.$watch('be.value', () => scope.events.onSubmit(true), true); } scope.$on('$destory', () => childScope.$destroy()); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/filter/filter-items.ts ================================================ import {set} from 'lodash'; import {inject} from '../../../core'; export default () => { return { restrict: 'A', require: ['ngModel', '^biFilter'], scope: false, link(scope, element, attrs, [ngModel, biFilter]) { let mute = false; const hook = items => { if (!mute) { biFilter.setItems(items); } return items; }; ngModel.$formatters.push(hook); biFilter.on('filtered', (items) => { mute = true; set(scope, attrs.ngModel, items); inject('$timeout')(() => mute = false); }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/filter/filter-term.ts ================================================ import {inject} from '../../../core'; export default () => { return { restrict: 'A', require: ['ngModel', '^biFilter'], scope: false, link(scope, element, attrs, [ngModel, biFilter]) { const hook = items => { inject('$timeout')(() => biFilter.filter()); return items; }; ngModel.$parsers.push(hook); biFilter.addTerm(() => ngModel.$modelValue); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/filter/filter.story.ts ================================================ export default app => app .story('UI', 'Filter') .section('Filter', ` Allows to filter items of any directive which uses an array as input.
    `, scope => { scope.text = 'on'; scope.tags = ['one', 'two', 'three']; scope.filter = (item, [term]) => { return item.indexOf(term) !== -1; }; }); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/filter/filter.ts ================================================ import {srv} from '../../../core'; export class Controller extends srv.eventEmitter.EventEmitter { private readonly terms: Function[] = []; private items: any[]; private filtered: any[]; constructor(private readonly $scope) { super(); } private getTerms() { return this.terms.map(term => term()); } private reset() { this.filtered = this.items; } public setItems(items) { this.items = items; this.filter(); } public addTerm(term: Function) { this.terms.push(term); } public filter() { const terms = this.getTerms(); this.$scope.onChange(); if (terms.every(term => !term)) { this.reset(); this.$scope.onReset(); } else { this.filtered = this.items && this.items.filter(item => this.$scope.onFilter({item, terms})); } this.fire('filtered', this.filtered); } } export default () => { return { restrict: 'E', transclude: true, template: '
    ', scope: { onFilter: '&', onReset: '&', onChange: '&' }, controller: ['$scope', Controller] }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/filter/index.ts ================================================ export {default as filter} from './filter'; export {default as filterTerm} from './filter-term'; export {default as filterItems} from './filter-items'; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/focus/focus-if.ts ================================================ import {inject} from '../../../core'; export default () => { return { restrict: 'A', scope: { biFocusIf: '<' }, link(scope, element, attr) { scope.$watch('biFocusIf', value => value && inject('$timeout')(() => { element = element.is('.bi-input') ? element : element.find('.bi-input'); inject('$timeout')(() => element.get(0).focus()); })); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/focus/focus.story.ts ================================================ import {inject} from '../../../core'; export default app => app .story('UI', 'Focus') .section('Focus', ` `) .section('Focus If', ` `) ; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/focus/focus.ts ================================================ import {inject} from '../../../core'; export default () => { return { restrict: 'A', link(scope, element) { inject('$timeout')(() => { element = element.is('.bi-input') ? element : element.find('.bi-input'); inject('$timeout')(() => element.get(0).focus()); }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/focus/index.ts ================================================ export {default as focus} from './focus'; export {default as focusIf} from './focus-if'; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/foldable/foldable.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/foldable/foldable.scss ================================================ bi-foldable { display: block } bi-foldable, [bi-foldable] { [bf-toggle] { cursor: pointer; } [bf-controls] { display: inline-flex; &.bf-style--folder { font-size: 0; > i { font-size: 19px; &:before { content: 'arrow_drop_down'; } } } } .bf-btn { transition: .3s; } .bf-folded { transform: rotate(-90deg); &:before { content: 'expand_more'; } } .bf-unfolded { &:before { content: 'expand_more'; } } .bf-no-transition { transition: none !important; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/foldable/foldable.story.ts ================================================ export default app => app .story('UI', 'Foldable') .section('Simple fold', `
    bi-foldable
    Binding from outside can go here: {{outsideBinding}}
    fold status: {{bf.fold}}
    `, scope => { scope.outsideBinding = `I'm a bidning set from outside scope`; }) .section('Fold with saved state', `
    bi-foldable
    fold status: {{bf.fold}}
    `) .section('options.style = folder', `
    folder
    folder content
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/foldable/foldable.ts ================================================ import {initNgScope, inject} from '../../../core'; import template from './foldable.html'; import './foldable.scss'; export default () => { return { restrict: 'EA', template, transclude: true, scope: { isFolded: '=', stateName: ' { if (typeof scope.isFolded !== 'undefined') { scope.isFolded = scope.vm.fold.enabled; } scope.onToggle({fold: scope.vm.fold.enabled}); }); } }); if (scope.stateName) { scopeHelper.withState(scope.stateName, 'fold', {}); } transclude((clone, transcludedScope) => { let toggleElement = clone.find('[bf-toggle]'); toggleElement = toggleElement.length ? toggleElement : clone.filter('[bf-toggle]'); const controlsElement = element.find('[bf-controls]').remove(); let targetControlsElement = clone.find('[bf-controls]'); targetControlsElement = targetControlsElement.length ? targetControlsElement : clone.filter('[bf-controls]'); if (toggleElement.length) { toggleElement.on('click', event => { scope.events.onToggle(event); scope.$digest(); }); scope.$on('$destory', () => $(toggleElement).off('click')); } if (targetControlsElement.length) { targetControlsElement.replaceWith(controlsElement); } element.find('.bf-content').replaceWith(clone); transcludedScope.bf = { get fold() { return scope.vm.fold.enabled; } }; $timeout(() => clone.find('.bf-no-transition').removeClass('bf-no-transition')); scope.$watch('isFolded', (isFolded: boolean) => typeof isFolded === 'boolean' && scope.vm.fold.toggle(isFolded)); }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/html/html.ts ================================================ import { inject } from '../../../core'; export default () => { let timeout; return { restrict: 'A', scope: { biHtml: '&', biHtmlDelay: '@' }, async link(scope, element) { const delay = parseInt(scope.biHtmlDelay, 10); const html = scope.biHtml({scope: scope.$parent}); if (!html) { return; } const render = () => element.html(html.html); if (!isNaN(scope.biHtmlDelay)) { (timeout = timeout || inject('$timeout'))(render, delay); } else { render(); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/icon-badge/icon-badge.html ================================================
    {{countValue()}}
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/icon-badge/icon-badge.scss ================================================ @import '../../assets/css/def/defaults.def'; @import '../../assets/css/def/colors.def'; .bi-icon-with-badge { position: relative; .bi-icon-badge-wide { font-size: 0.45rem; right: -3px; } .bi-badge { position: absolute; z-index: 1; right: 0; padding: 0 3px; } ng-transclude { display: block; line-height: 0; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/icon-badge/icon-badge.ts ================================================ import './icon-badge.scss'; import template from './icon-badge.html'; export default () => { return { restrict: 'E', template, transclude: true, scope: { count: '<', hide: '<' }, link(scope) { scope.countValue = () => (scope.count < 100 ? scope.count : '99+'); }, }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/index.ts ================================================ export { default as stateLoader } from './state-loader/state-loader'; export { default as dropdown } from './dropdown/dropdown'; export { default as tbl } from './table/table'; export { default as tblHeader } from './table/header/table-header'; export { default as tblRow } from './table/row/table-row'; export { default as contenteditable } from './content-editable/content-editable'; export { default as editable } from './editable/editable'; export { default as foldable } from './foldable/foldable'; export { default as datePicker } from './date-picker/date-picker'; export { focus, focusIf } from './focus'; export { default as progressLine } from './progress-line/progress-line'; export { default as simpleSelect } from './simple-select/simple-select'; export { default as info } from './info/info'; export { default as iconWithBadge } from './icon-badge/icon-badge'; export { default as tooltip } from './tooltip/tooltip'; export { default as tags } from './tags/tags'; export { default as tabs } from './tabs/tabs'; export { default as tabsRouter } from './tabs/tabs-router'; export { default as onImageLoad } from './on-image-load/on-image-load'; export { default as dualAction } from './dual-action/dual-action'; export { default as search } from './search/search'; export { default as maximizable } from './maximizable/maximizable'; export { default as copyToClipboard } from './copy-to-clipboard/copy-to-clipboard'; export { default as progressGauge } from './progress-gauge/progress-gauge'; export { default as draggable } from './draggable/draggable'; export { default as droppable } from './droppable/droppable'; export { filter, filterTerm, filterItems } from './filter'; export { default as html } from './html/html'; export { default as breadcrumbs } from './breadcrumbs/breadcrumbs'; export { scrollTo } from './scroll'; export { default as resizable } from './resizable/resizable'; export { default as infiniteScroll } from './infinite-scroll/infinite-scroll'; export { default as keyNav } from './key-nav/key-nav'; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/infinite-scroll/infinite-scroll.ts ================================================ import {throttle} from 'lodash'; import {initNgScope, inject} from '../../../core'; import {BufferedCollection} from '../../../core/srv/collections'; const shouldFetchMore = element => { const viewportHeight = element.height(); const contentHeight = element.get(0).scrollHeight; const topOffset = element.scrollTop(); return contentHeight - topOffset - viewportHeight < 40; } const sync = (scope, collection: BufferedCollection) => { inject('$timeout')(() => scope.bisBuffer = collection.models.map(({data}) => data)); } const getScrollhandler = (scope, element) => throttle(() => { const {collection} = scope.vm; if (collection && collection.hasMore() && shouldFetchMore(element)) { collection.more(); sync(scope, collection); } return true; }, 500); export default () => { return { restrict: 'A', scope: { biInfiniteScroll: '<', bisOptions: '<', bisBuffer: '=', }, link(scope, element) { initNgScope(scope) .withOptions('bisOptions', { chunkSize: 20 }) .withVM({ collection: null }); element.on('scroll', getScrollhandler(scope, element)); scope.$watch('biInfiniteScroll', items => { if (!items || typeof items.length === 'undefined') { return; } const collection = new BufferedCollection().setChunkSize(scope.options.chunkSize); collection.fetch(); collection.feed(items); if (items.length < scope.options.chunkSize) { collection.seal(); } scope.vm.collection = collection; sync(scope, collection); }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/info/info.html ================================================ info_outline
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/info/info.scss ================================================ @import '../../assets/css/def/defaults.def'; @import '../../assets/css/def/colors.def'; bi-info { width: 17px; height: 18px; bi-dropdown { bi-toggle { display: inline-block; height: 18px; font-size: 18px !important; color: $primary; } } .bi-info-content { position: relative; margin-top: 4px; padding: 8px 10px; color: $white; font-size: 12px; white-space: nowrap; box-shadow: $default-box-shadow; &:before { position: absolute; content: ''; top: -6px; left: 50%; width: 0; height: 0; margin-left: -6px; border-style: solid; border-width: 0 6px 6px 6px; border-color: transparent transparent #000000 transparent; opacity: .75; } > .bi-info-backdrop { position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: 3px; background-color: $black; opacity: .75; } > [ng-transclude] { position: relative; z-index: 1; > * { text-transform: initial; font-weight: normal; white-space: nowrap; } } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/info/info.ts ================================================ import './info.scss'; import template from './info.html'; export default () => { return { restrict: 'E', template, transclude: true, scope: false }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/key-nav/key-nav.ts ================================================ import {values, isUndefined } from 'lodash'; import angular from 'angular'; import {initNgScope, inject, utils} from '../../../core'; const NAVIGATION_KEYS = { UP: 38, DOWN: 40, SELECT: 13, PAGEDOWN: 34, PAGEUP: 33, END: 35, HOME: 36 }; function canScroll(element) { return element.css('overflow-y') === 'scroll' || element.css('overflow-y') === 'auto'; } function adjustScroll(scope, element) { const {scrollableElement} = scope.vm; const item = angular.element(getElements(scope, element)[scope.vm.currentItemIndex]); if (item.length) { const topPeekHeight = 50; const {top} = item.position(); if (top <= 0 || top + item.outerHeight() >= scrollableElement.innerHeight()) { scrollableElement.stop().animate({scrollTop: scrollableElement.scrollTop() + top - topPeekHeight}, 100); } } } function setCurrentItemByIndex(scope, element, index) { scope.vm.currentItemIndex = index; if (index >= 0) { // TODO: review; timeout to give ng-repeat time to do it's magic inject('$timeout')(() => { const elements = getElements(scope, element); if (elements.length !== scope.vm.collection.length) { throw new Error('KeyNav: number of elements doesn\'t match collection!'); } scope.keyNavCurrentItem = scope.vm.collection[index]; }); } else { scope.keyNavCurrentItem = null; } } function dispatchNavigationEvent(scope: any, key: any) { switch (key) { case NAVIGATION_KEYS.SELECT: scope.actions.selectCurrentItem(); break; default: scope.actions.navigate(key); } } function isItemDisabled(scope, element,index) { const elements = getElements(scope, element); return !isUndefined(elements.eq(index).attr('disabled')); } function setupCollection(scope, element, collection) { scope.vm.elements = null; scope.vm.collection = collection; if (scope.vm.collection.length && scope.options.markFirst) { setCurrentItemByIndex(scope, element, 0); } else { setCurrentItemByIndex(scope, element, -1); } } function getElements(scope, element) { let elements; if (scope.vm.elements) { elements = scope.vm.elements; } else { scope.vm.elements = elements = element.find('[key-nav-item]'); } return elements; } export default function () { return { restrict: 'EA', scope: { biKeyNav: '=', keyNavCurrentItem: '=?', keyNavOnSelect: '&', keyNavOptions: '=' }, link: { post(scope: ng.IScope, element) { initNgScope(scope) .withOptions(scope.keyNavOptions, { markFirst: false }, false) .withVM({ currentItemIndex: null, collection: null, elements: null, $init() { this.scrollableElement = canScroll(element) ? element : element.scrollParent(); } }) .withActions({ selectItem(index) { const item = scope.vm.collection[index]; if (isUndefined(item) || isItemDisabled(scope, element, index)) { return; } setCurrentItemByIndex(scope, element, index); inject('$timeout')(() => scope.keyNavOnSelect({item})); }, selectCurrentItem() { scope.actions.selectItem(scope.vm.currentItemIndex); }, navigate(key: any) { let index = scope.vm.currentItemIndex; switch (key) { case NAVIGATION_KEYS.DOWN: // tslint:disable-next-line: restrict-plus-operands index = Math.min(scope.vm.collection.length - 1, index + 1); break; case NAVIGATION_KEYS.UP: index = Math.max(0, index - 1); break; case NAVIGATION_KEYS.PAGEDOWN: // tslint:disable-next-line: restrict-plus-operands index = Math.min(scope.vm.collection.length - 1, index + 7); break; case NAVIGATION_KEYS.PAGEUP: index = Math.max(0, index - 7); break; case NAVIGATION_KEYS.HOME: index = 0; break; case NAVIGATION_KEYS.END: index = scope.vm.collection.length - 1; break; default: return; } setCurrentItemByIndex(scope, element, index); adjustScroll(scope, element); } }); utils.dom.onKey(values(NAVIGATION_KEYS), (_, key) => { dispatchNavigationEvent(scope, key); }, scope); scope.$watch('biKeyNav', collection => collection && setupCollection(scope, element, collection)); } } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/maximizable/maximizable.scss ================================================ @import '../../assets/css/def/colors.def'; [bi-maximizable] { position: relative; .bm-toggle { position: absolute; top: 0; right: 0; &.bm-toggle-custom { position: unset; } } &.bm--maximized { position: fixed; right: 5%; left: 5%; top: 5%; bottom: 5%; margin: 0 !important; padding: 15px; background: $white; border-radius: 3px; z-index: 201; + .bm-backdrop { display: block; } .bm-toggle { position: absolute; top: 15px; right: 15px; z-index: 1000; &.bm-toggle-custom { position: unset; } } } & + .bm-backdrop { content: ''; position: fixed; display: none; right: 0; left: 0; top: 0; bottom: 0; background-color: $black; opacity: .5; z-index: 200; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/maximizable/maximizable.story.ts ================================================ export default app => app .story('UI', 'Maximizable') .section('Maximizable', `
    Maximize me
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/maximizable/maximizable.ts ================================================ import {initNgScope, inject, utils} from '../../../core'; import './maximizable.scss'; const renderToggle = (scope, element) => { let parent = element.find('[bm-toggle]'); let isCustom = false; if (parent.length) { isCustom = true; } else { parent = element; } parent.append(inject('$compile')(` {{::options.onIcon}} {{::options.offIcon}} `)(scope)); } export default () => { return { restrict: 'A', scope: { biMaximizable: '=', isMaximized: '=', bmOptions: '=', onLoad: '&', onToggle: '&', }, link(scope, element) { let cleaner: Function = () => {}; initNgScope(scope) .withVM({}) .withOptions('bmOptions', { onIcon: 'fullscreen', offIcon: 'fullscreen_exit' }) .withActions({ toggle() { scope.vm.toggle(); element.toggleClass('bm--maximized', scope.vm.enabled); if (scope.vm.enabled) { element.after('
    '); cleaner = utils.dom.onKey('escape', () => scope.actions.toggle(), scope); } else { element.parent().find('.bm-backdrop').remove(); cleaner(); } inject('$timeout')(() => { if (typeof scope.isMaximized !== 'undefined') { scope.isMaximized = scope.vm.enabled; } scope.onToggle({maximized: scope.vm.enabled}); }); } }); renderToggle(scope, element); scope.onLoad({ instance: { toggle() { scope.actions.toggle(); } } }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/on-image-load/on-image-load.ts ================================================ import {utils} from '../../../core'; export default function() { return { restrict: 'A', scope: { biOnImageLoad: '<' }, link(scope, element) { element. on('load', () => { utils.scope.safeApply(scope, () => scope.biOnImageLoad.onLoad && scope.biOnImageLoad.onLoad()); }). on('error', () => { utils.scope.safeApply(scope, () => scope.biOnImageLoad.onError && scope.biOnImageLoad.onError()); }); } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.html ================================================ {{value}}% ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.scss ================================================ @import '../../assets/css/def/colors.def'; bi-progress-gauge { position: relative; font-size: 0; > span { position: absolute; display: flex; top: 0; bottom: 0; left: 0; right: 0; align-items: center; font-size: 9px; font-weight: 200; color: $muted; text-align: center; > * { margin: auto; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.story.ts ================================================ export default app => app .story('UI', 'Progress') .section('Progress gauge', ` `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.ts ================================================ import {initNgScope} from '../../../core'; import template from './progress-gauge.html'; import './progress-gauge.scss'; export default function () { return { template, restrict: 'E', scope: { value: '=', bpgOptions: '=' }, link (scope, element) { initNgScope(scope).withOptions(scope.bpgOptions, { radius: 15, stroke: 3 }); } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-line/progress-line.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-line/progress-line.scss ================================================ bi-progress-line { position: relative; display: block; height: 0; $progress-line-fg: #4c9ef0; div { height: 3px; margin: 0; &.bpl-main { transition: width .5s; background-color: $progress-line-fg; } &.bpl-container { position: absolute; left: 0; right: 0; top: 0; bottom: 0; } &.bpl-container-off { transition: opacity 3.5s; position: absolute; left: 0; right: 0; top: 0; bottom: 0; background-color: $progress-line-fg; opacity: 1; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/progress-line/progress-line.ts ================================================ import {inject} from '../../../core'; import template from './progress-line.html'; import './progress-line.scss'; export default function () { return { template, restrict: 'E', scope: { value: '=', running: '=' }, link (scope, element) { scope.off = false; scope.progressBarStyle = function() { if (scope.running) { return { // tslint:disable-next-line: restrict-plus-operands width: scope.running ? scope.value + '%' : '100%' }; } return { width: '0' }; }; scope.$watch('running', running => { if (running === false) { scope.off = true; inject('$timeout')(() => { element.find('.bpl-container-off').css('opacity', 0); }); } }); } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/resizable/resizable.ts ================================================ import {initNgScope, inject} from '../../../core'; export default () => { return { restrict: 'A', scope: { onResize: '&', brOptions: '=', }, link(scope, element) { const conf = initNgScope(scope) .withVM({ $export() { return {width: element.width()}; }, $import({width}) { element.width(width); } }) .withOptions('brOptions', { minWidth: null, handles: null }) .withEvents({ onResize() { inject('$timeout')(() => scope.onToggle({maximized: scope.vm.enabled})); } }); if (scope.options.stateName) { conf.withState(scope.options.stateName, 'resizable', {}); } inject('$timeout')(() => element.resizable({ minWidth: scope.options.minWidth, handles: scope.options.handles, resize(event, ui) { ui.size.height = ui.originalSize.height; scope.state.save(); } })); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/scroll/index.ts ================================================ export {default as scrollTo} from './scroll-to'; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/scroll/scroll-to.ts ================================================ import {inject, utils} from '../../../core'; const OFFSET = -10; export default () => { return { restrict: 'A', scope: false, link(scope, element, attr) { attr.$observe('biScrollTo', scroll => { if (scroll === 'true') { inject('$timeout')(() => { utils.dom.scrollIntoView(element, true, OFFSET); }); } }); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/search/search.html ================================================ {{::options.contextIcon}} {{::options.searchIcon}} close ================================================ FILE: quix-frontend/client/src/lib/ui/directives/search/search.scss ================================================ @import '../../assets/css/def/colors.def'; @import '../../assets/css/def/defaults.def'; bi-search { display: inline-flex; position: relative; .bi-input { padding-right: 32px; &.bs-has-context-icon { padding-left: 34px; } } .bi-icon { font-size: 22px; } .bs-search, .bs-close, .bs-context { transition: color .3s; position: absolute; top: 50%; margin-top: -11px; } .bs-search { right: 6px; } .bs-close { right: 5px; margin-top: -14px; .bi-icon { color: $primary !important; } } .bs-context { left: 6px; } &.bs-focused, &.bs-hovered &.bs-has-text { .bs-search { color: $primary !important; } } &.bs-has-text { .bi-input { border-color: $blue--300 !important; } } &.bi-search--rnd, &.bi-search--borderless { .bi-input { height: 42px !important; font-weight: 600; &.bs-has-context-icon { padding-left: 40px; } } .bs-context { left: 12px; } .bs-search { right: 14px; } .bs-close { right: 12px; } } &.bi-search--rnd { border-radius: 100px; .bi-input { padding: 0 40px 0 20px; border-radius: 100px; } } &.bi-search--borderless { .bi-input { padding-left: 0; border: 0; &.bs-has-context-icon { padding-left: 29px; } } .bs-context { left: 0; } .bs-search, .bs-close { right: 0; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/search/search.story.ts ================================================ export default app => app .story('UI', 'Input') .section('Search input', ` searchText: {{searchText}} `) .section('Round search input', ` searchText: {{searchText}} `) .section('Borderless search input', ` searchText: {{searchText}} `) .section('Custom icons', ` searchText: {{searchText}} `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/search/search.ts ================================================ import {initNgScope, createNgModel} from '../../../core'; import template from './search.html'; import './search.scss'; export default function directive() { return { template, require: 'ngModel', restrict: 'E', transclude: true, scope: { minLength: '<', bsOptions: '<', onEnter: '&', placeholder: '@' }, link: { pre(scope, element, attrs, ngModel) { createNgModel(scope, ngModel) .formatWith(text => ({text})) .parseWith(({text}) => text) .feedBack(false) .watchWith(({text}) => element.toggleClass('bs-has-text', !!text)) .watchDeep(true); initNgScope(scope) .withOptions('bsOptions', { searchIcon: 'search', contextIcon: null }) .withEvents({ onClear() { scope.model.text = ''; element.find('.bi-input').focus(); }, onKeypress(e) { if (e.keyCode === 13) { scope.onEnter(); } } }); element.on('mouseenter', '.bi-input', () => element.addClass('bs-hovered')); element.on('mouseleave', '.bi-input', () => element.removeClass('bs-hovered')); element.on('focus', '.bi-input', () => element.addClass('bs-focused')); element.on('blur', '.bi-input', () => element.removeClass('bs-focused')); } } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.html ================================================
    • {{vm.search.text}} No matches Start typing to see matches
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.scss ================================================ @import '../../assets/css/def/colors.def'; bi-select, bi-simple-select { display: inline-flex; input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } bi-dropdown { &.bs-custom-toggle { bi-toggle { i { position: unset; } } } bi-toggle { position: relative; i { position: absolute; right: 5px; top: 6px; cursor: pointer; } .bi-input { padding-right: 30px; cursor: pointer; } } .bd-content { [ng-transclude=''] { .bi-dropdown-menu { width: 100%; line-height: initial !important; font-size: 13px !important; border-top: 0; } } } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.story.ts ================================================ import {inject} from '../../../core'; export default app => app .story('UI', 'Select') .section('Select', ` selected1: {{selected1 || 'Nothing selected'}} selected2: {{selected2 || 'Nothing selected'}} selected3: {{selected3 || 'Nothing selected'}} `) .section('Typeahead', ` `, scope => { scope.onSearchChange = () => scope.promise = inject('$timeout')(() => { return [{title: 'Empty', value: ''}, {title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]; }, 2000); }) .section('Null item', ` `) .section('Custom toggle', ` {{item.formatted}} selected: {{selected4 || 'Nothing selected'}} `) .section('Custom items', `
    {{::item.value}}. {{::item.title}}
    selected: {{selected4 || 'Nothing selected'}} `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.ts ================================================ import template from './simple-select.html'; import './simple-select.scss'; import {DropdownList} from '../common/dropdown-list'; export interface IScope extends ng.IScope { model: any[]; } export default function directive() { return { template, require: ['ngModel', 'biOptions'], restrict: 'E', transclude: { toggle: '?toggle', opt: '?opt' }, scope: { bsOptions: '=', onTypeahead: '&', readonly: '=', placeholder: '@' }, link: { pre(scope: IScope, element, attrs, [ngModel, biOptions], transclude) { return new DropdownList(scope, element, attrs, {ngModel, biOptions}, transclude, { optionsAlias: 'bsOptions', }); } } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/state-loader/state-loader.scss ================================================ @import '../../assets/css/def/animations.def'; [bi-state-loader] { @extend %animation-fade-in; transition: opacity .3s !important; &.loading-state { opacity: .5; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/state-loader/state-loader.ts ================================================ import './state-loader.scss'; let prefix = ''; function getTargetDepth(state1: string, state2: string) { let res = 0; const prefixLength = prefix ? prefix.split('.').length - 1 : 0; if (state1 === state2) { return prefixLength || res; } const s1 = state1.split('.'); const s2 = state2.split('.'); const len = Math.min(s1.length, s2.length); for (let i = 0; i < len; i++) { if (s1[i] === s2[i]) { res++; } else { break; } } return res; } export function setPrefix(p: string) { prefix = p; } export default function() { return { restrict: 'A', scope: {}, link(scope, element, attrs) { scope.$on('$stateChangeStart', function (_, to, __, from) { const myDepth = element.parents('[ui-view]').length; const targetDepth = getTargetDepth(to.name, from.name); if (myDepth === targetDepth) { element.addClass('loading-state spinner'); } }); scope.$on('$stateChangeSuccess', function () { element.removeClass('loading-state spinner'); }); } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/header/table-header.html ================================================
    unfold_more {{::formatField(field)}} {{::formatField(field)}}
    {{order.field !== field ? 'unfold_more' : order.field === field && !order.reverse ? 'arrow_drop_up' : 'arrow_drop_down'}} {{::formatField(field)}} {{::formatField(field)}}
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/header/table-header.scss ================================================ @import '../../../assets/css/def/defaults.def'; // sortable-table-header .bi-tbl-header { .bi-table-th-content span { white-space: nowrap; } .bi-tbl-sort-icon { margin-left: -8px; } a { color: $default-text-color !important; text-decoration: none !important; white-space: nowrap; .fa { position: relative; margin-right: 3px; color: $default-text-color; &.fa-sort-desc { top: -2px; } &.fa-sort-asc { top: 3px; } } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/header/table-header.ts ================================================ import {inject} from '../../../../core'; import template from './table-header.html'; import './table-header.scss'; export default () => { return { template, restrict: 'A', replace: true, scope: { fields: '=', order: '=', biTableHeaderOptions: '=', onOrderChange: '&' }, link: { pre(scope) { const options = scope.biTableHeaderOptions || {}; const toHumanCase = inject('$filter')('biToHumanCase'); scope.setOrder = function (field) { if (field === scope.order.field) { scope.order.reverse = !scope.order.reverse; } else { scope.order.field = field; scope.order.reverse = false; } scope.onOrderChange({order: scope.order}); }; scope.formatField = function (field) { field = field.title || field.name || field; return options.dontTransformColumnNames ? field : toHumanCase(field); }; } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/row/table-row.ts ================================================ import {assign} from 'lodash'; import angular from 'angular'; import {inject} from '../../../../core'; export default () => { const entityMap = { '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''', '/': '/' }; const htmlEscape = function (string) { if (typeof string === 'undefined') { return ''; } // tslint:disable-next-line: restrict-plus-operands return ('' + string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; }); }; const getColumnsHtml = function (row, fields, index, formatter) { const res = []; fields.forEach(function (field) { const data = typeof row.data === 'object' ? row.data : row; const name = field.name || field; let content; const contentElement = angular.element('
    '); const $compile: angular.ICompileService = inject('$compile'); if (field.filter) { content = field.filter(data[name], row, index, (html, locals, scope) => $compile(html)(assign(scope.$new(), locals)) .on('$destroy', e => { const elementScope = angular.element(e.target).scope(); if (elementScope) { elementScope.$destroy(); } })); } else if (formatter) { content = formatter(name, data[name], row, index, (html, locals, scope) => $compile(html)(assign(scope.$new(), locals))); } else { content = htmlEscape(data[name]); } if (typeof content === 'object') { contentElement.html(content); } else { contentElement.html(content === '' ? ' ' : content); } res.push(contentElement); }); return res; }; return { restrict: 'A', scope: { fields: '=', row: '=', index: '<', formatter: '&', biTableRowOptions: '=' }, link: { pre(scope, element) { if (scope.biTableRowOptions.dynamicFields) { scope.$watch('fields', fields => { element.html(getColumnsHtml(scope.row, scope.fields, scope.index, scope.formatter())); }); } else { element.html(getColumnsHtml(scope.row, scope.fields, scope.index, scope.formatter())); } } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/table.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/table.scss ================================================ @import '../../assets/css/def/defaults.def'; @import '../../assets/css/def/colors.def'; .bi-table-container, bi-tbl { display: block; table > tbody { transition: opacity 0.3s; &.bi-tbl-fade-out { opacity: 0.2; } } .bi-table-th-placeholder { height: 0; overflow: hidden; } &.bi-table-sticky-header { position: relative; display: flex; flex-direction: column; padding-top: 36px; > div { border-top: 2px solid $default-border-color; overflow: auto; } table { th { padding: 0 8px !important; border-bottom: 0 !important; .bi-table-th-content { position: absolute; top: 10px; } } tr:first-child td { border-top: 1px solid transparent; } } } .bi-tbl-spinner-container { height: 30px; overflow: hidden; } &.bi-table--nav { tbody { tr { cursor: pointer; &.bi-active { background-color: $grey--100 !important; } &:hover { background-color: $grey--50; } td { a, .bi-hint { line-height: normal; } } } } } &.bi-table--data { $header-height: 32px; padding-top: $header-height !important; background-color: $grey--200; border: 1px solid $grey--300; overflow: hidden; > div { display: flex; flex-direction: column; flex-grow: 1; border-top: 2px solid $grey--300; background-color: $white; } table > thead, table > tbody { td, th { max-width: 300px; white-space: nowrap; word-break: break-all; overflow: hidden; } } table > thead { th { &:not(:first-child) > .bi-table-th-content > span { margin-left: -8px; padding-left: 8px; border-left: 1px solid $grey--300 !important; } border-bottom: none; } .bi-table-th-content { top: 0 !important; span { display: flex; height: $header-height; font-weight: bold; align-items: center; } } } table > tbody { > tr { &:nth-child(even) { background-color: $grey--100; } &:nth-child(odd) { background-color: $white; } &:last-child { border-bottom: 1px solid $grey--300; } > td { padding: 5px 8px !important; border-top: 1px solid $grey--300; font-size: 12px; &:not(:first-child) { border-left: 1px solid $grey--300; } a:visited { color: $muted !important; } } } } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/table.story.ts ================================================ import { BufferedCollection } from "../../../core/dist/src/srv/collections"; export default app => app .story('UI', 'Table') .section('Simple table', ` `, scope => { scope.fields = ['colA', 'colB', 'colC']; scope.rows = [{ colA: 1, colB: 2, colC: 3 }, { colA: 4, colB: 5, colC: 6 }]; scope.filter = (row) => { return true; }; scope.emptyFilter = (row) => { return false; }; }) .section('Nav table', ` `) .section('Data table', ` `) .section('Data table with infinite scroll', ` `, scope => { scope.items = '123456'.split('').map((num, index) => ({colA: num + index, colB: num + index + 1, colC: num + index + 2})); }) .section('Empty table', ` `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/table/table.ts ================================================ import {throttle, debounce, without, find} from 'lodash'; import {inject, initNgScope} from '../../../core'; import template from './table.html'; import './table.scss'; import { BufferedCollection, PartitionedCollection } from '../../../core/srv/collections'; const isCollection = (collection: BufferedCollection | PartitionedCollection) => { return collection && collection.models instanceof Array; } export default () => { const ACTIONS = { getSortValue(scope, row) { const fieldName = scope.order.field.name || scope.order.field; return scope.order.field.sort ? scope.order.field.sort(row[fieldName], row) : row[fieldName]; } }; function shouldFetchMore(container) { const viewportHeight = container.height(); const contentHeight = container.get(0).scrollHeight; const topOffset = container.scrollTop(); return contentHeight - topOffset - viewportHeight < 40; } function adjustHeaderPosition(container, columns) { // tslint:disable-next-line: restrict-plus-operands columns.css('margin-left', (-1 * container.get(0).scrollLeft) + 'px'); } function initInfiniteScroll(scope, element, container, options) { if (options.infiniteScroll) { let columns = element.find('table thead .bi-table-th-content'); scope.infiniteScrollEnabled = true; const redrawColumnsFunc = debounce(() => { if (!columns.length) { columns = element.find('table thead .bi-table-th-content'); } columns.hide().show(0); adjustHeaderPosition(container, columns); }, 200); const applyFunc = () => scope.vm.getItems().more(); const thenFunc = options.stickyHeader ? () => redrawColumnsFunc() : () => null; return throttle(axis => { if (axis === 'y' && scope.vm.getItems().hasMore() && shouldFetchMore(container)) { scope.$apply(applyFunc).then(thenFunc); } return true; }, 500); } } function initStickyHeader(element, container, options) { if (options.stickyHeader) { let columns = element.find('table thead .bi-table-th-content'); element.addClass('bi-table-sticky-header'); // scroll the sticky header horizontally return axis => { if (axis === 'x') { if (!columns.length) { columns = element.find('table thead .bi-table-th-content'); } adjustHeaderPosition(container, columns); } return true; }; } } function initEvents(scope, element, container, options) { const scrollHandlers = without([ initInfiniteScroll(scope, element, container, options), initStickyHeader(element, container, options) ], undefined); if (scrollHandlers.length) { const domContainer = container.get(0); let lastXScroll = 0; const scrollHandler = () => { const axis = lastXScroll - domContainer.scrollLeft !== 0 ? 'x' : 'y'; scrollHandlers.every(handler => handler(axis)); lastXScroll = domContainer.scrollLeft; }; container.on('scroll', scrollHandler); } } function initOrderBy(scope) { if (scope.orderBy) { const orderByField = find(scope.fields, field => field === scope.orderBy || (field as any).name === scope.orderBy); scope.order = { field: orderByField, reverse: !!scope.reverse }; if (!(scope.vm.getItems() instanceof BufferedCollection)) { scope.getSortValue = row => ACTIONS.getSortValue(scope, row); } } } function orderCollection(scope, element) { if (isCollection(scope.vm.getItems())) { scope.vm.loading = true; inject('$timeout')(() => { const copy = Object.assign( Object.create( Object.getPrototypeOf(scope.vm.getItems())), scope.vm.getItems()); const buffer = copy._buffer; copy.fetch(); copy.feed(inject('$filter')('orderBy')(buffer, row => ACTIONS.getSortValue(scope, row), scope.order.reverse)); if (buffer.length < scope.options.chunkSize) { copy.seal(); } renderItems(scope, element, copy); }); } } const initRows = (scope, element, rows: any[]) => { let items: any = rows; if (scope.options.infiniteScroll) { const collection = new BufferedCollection().setChunkSize(scope.options.chunkSize); collection.fetch(); collection.feed(scope.rows); if (scope.rows.length < scope.options.chunkSize) { collection.seal(); } items = collection; } renderItems(scope, element, items); } const initCollection = (scope, element, collection) => { renderItems(scope, element, collection); } const renderItems = (scope, element, items = scope.vm.getItems()) => { scope.vm.loading = true; scope.vm.toggleEnabled(true); inject('$timeout')(() => { scope.vm.setItems(items); const itemsRef = isCollection(scope.vm.getItems()) ? `items.models` : `items`; const itemRef = isCollection(scope.vm.getItems()) ? `model.data` : `model`; const html = inject('$compile')(` {{::emptyStateMsg}} `)(scope.vm.getScope()); element.find('tbody').html(html); inject('$timeout')(() => { scope.vm.destroyOldScope(); scope.vm.toggleVisible(true); scope.vm.loading = false; scope.onRendered(); }); }); } return { template, restrict: 'E', scope: { fields: '=', rows: '=', collection: '=', selected: '=', orderBy: '@', reverse: '@', filter: '&', formatter: '&', btOptions: '=', onRowClick: '&', onRowSelect: '&', onRowDeselect: '&', onRendered: '&', onDestroyed: '&', emptyStateMsg: '@' }, link: { pre(scope, element, attrs) { const container = element.find('> div'); initNgScope(scope) .withOptions('btOptions', { dynamicFields: false, infiniteScroll: false, stickyHeader: false, dontTransformColumnNames: false, trackBy: null, chunkSize: 50 }) .withVM({ enabled: false, id: '', scope: null, oldScope: null, $init() { this.selected = scope.selected; }, setItems(items) { this.oldScope = this.scope; this.scope = scope.$new(); this.scope.items = items; scope.items = items; }, getItems() { return this.scope && this.scope.items; }, getScope() { return this.scope; }, destroyOldScope() { if (this.oldScope) { this.oldScope.$destroy(); scope.onDestroyed(); } } }) .withEvents({ onOrderChange() { orderCollection(scope, element); }, onRowClick(row) { if (scope.vm.selected === row) { scope.vm.selected = null; scope.onRowDeselect({row}); } else { scope.vm.selected = row; scope.onRowSelect({row}); } scope.onRowClick({row}); } }); initEvents(scope, element, container, scope.options); initOrderBy(scope); scope.filter = scope.filter(); scope.emptyStateMsg = scope.emptyStateMsg || `Can't find any items`; scope.$watch('selected', selected => scope.vm.selected = selected); scope.$watch('rows', (rows, prev) => { if (rows && (rows !== prev || !scope.vm.getItems())) { initRows(scope, element, rows); } }); scope.$watch('collection', (collection, prev) => { if (collection && (collection !== prev || !scope.vm.getItems())) { initCollection(scope, element, collection); } }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tabs/tabs-router.html ================================================
    {{::tab.icon}} {{::tab.title || tab.name}}
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tabs/tabs-router.ts ================================================ import {initNgScope, inject} from '../../../core'; import {last} from 'lodash'; import {IScope} from 'angular'; import template from './tabs-router.html'; import './tabs.scss'; export interface IBiTab { name: string; title: string; icon: string; id: string; } export interface TabsRouterScope extends IScope { tabs: IBiTab[]; } export default () => { const $state = inject('$state'); return { restrict: 'E', template, transclude: true, scope: { tabs: '<', btOptions: '=' }, link(scope: TabsRouterScope, element: JQuery, attr: ng.IAttributes, ctrls) { initNgScope(scope) .withOptions('btOptions', { mode: 'default', // default | flat }) .withVM({ tabs: { $init() { this.current = last($state.current.name.split('.')); this.all = scope.tabs; }, } }) .withEvents({ onTabClick(tabName: string) { scope.vm.tabs.current = tabName; $state.go(`^.${tabName}`); } }); element.addClass(`bi-tabs--${scope.options.mode}`); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tabs/tabs.html ================================================
    {{::tab.icon}} {{::tab.title}} {{::tab.name | biToHumanCase}}
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tabs/tabs.scss ================================================ @import '../../assets/css/def/colors.def'; @import '../../assets/css/def/defaults.def'; bi-tabs, bi-tabs-router { .bi-tabs-header { position: relative; flex-basis: 42px; border-bottom: 1px solid $default-border-color; .bi-tab { min-width: 80px; margin-bottom: -1px; padding: 0 15px; cursor: pointer; &.bi-active { > * { color: $grey--800 !important; } } } } &.bi-tabs--default { .bi-tab { height: 36px; border: 1px solid transparent; &.bi-active { border-color: $grey--300; border-top: 2px solid $warning; border-bottom-color: $grey--50; border-radius: 3px 3px 0 0; background-color: $grey--50; > * { margin-top: -1px; color: $grey--800 !important; } } } .bi-tabs-content { margin-top: -1px; } } &.bi-tabs--flat { .bi-tabs-header { border-bottom: 1px solid $default-border-color; } .bi-tab { transition: border-color .3s; height: 42px; border-bottom: 2px solid transparent; &:hover, &.bi-active { border-bottom: 2px solid $warning; } } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tabs/tabs.story.ts ================================================ export default app => app .story('UI', 'Tabs') .section('Tabs', `
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    current: {{current}} `, $scope => $scope.current = 'two') .section('Flat tabs', `
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    Content of {{::tabs.current}}
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tabs/tabs.ts ================================================ import {initNgScope, inject} from '../../../core'; import {IScope as ngScope} from 'angular'; import template from './tabs.html'; import './tabs.scss'; export interface IBiTab { name: string; title: string; icon: string; } export interface IScope extends ngScope { tabs: IBiTab[]; } export default () => { const $timeout: ng.ITimeoutService = inject('$timeout'); return { restrict: 'E', template, transclude: true, scope: { tabs: '<', btCurrent: '=', btOptions: '=', onChange: '&' }, link(scope: IScope, element: JQuery, attr: ng.IAttributes, ctrls, transclude: ng.ITranscludeFunction) { initNgScope(scope) .withOptions('btOptions', { mode: 'default', // default | flat headerClass: [], contentClass: [] }) .withVM({ tabs: { $init() { this.current = scope.btCurrent || scope.tabs[0].name; this.all = scope.tabs; }, } }) .withEvents({ onTabClick(tabName: string) { scope.vm.tabs.current = tabName; $timeout(() => scope.onChange({tab: tabName})); } }); transclude((clone, transcludedScope) => { element.find('.bi-tabs-content').append(clone); transcludedScope.tabs = { get current() { return scope.vm.tabs.current; } }; }); element.addClass(`bi-tabs--${scope.options.mode}`); scope.$watch('btCurrent', current => current && (scope.vm.tabs.current = current)); } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tags/tags.html ================================================
    close
    • {{vm.search.text}} No matches Start typing to see matches
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tags/tags.scss ================================================ @import '../../assets/css/def/defaults.def.scss'; @import '../../assets/css/def/colors.def.scss'; @import '../../assets/css/def/flex.def.scss'; $tags-input-height: $default-input-height - 2*$default-border-width; bi-tags { @include flex(column); .bi-tags-container { display: flex !important; min-height: 36px !important; padding: 5px 5px 0 5px !important; background: $white !important; height: auto !important; } .bi-tags-input { min-width: 50px !important; height: 25px !important; margin: 0 5px 5px 0 !important; padding: 0 10px !important; border: 0 !important; background-color: transparent !important; } .bi-tags-tag { max-width: 100%; margin: 0 5px 5px 0; padding: 0 10px; background-color: $grey--200; border-radius: 3px; height: $default-input-height - 2 * 6px; line-height: 24px; &:last-of-type { margin-right: 0; } .bi-tags-content { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .bi-tags-remove { margin-right: -4px; font-size: 10px; font-weight: bold; &:hover { background-color: darken($grey--200, 5) !important; } } } bi-dropdown { .bi-dropdown-menu { display: block; margin-top: -1px; } } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tags/tags.story.ts ================================================ import {inject} from '../../../core'; export default app => app .story('UI', 'Tags') .section('Tags', ` tags: {{tags}} tagsfreetext: {{tagsfreetext}} tagsfreetext: {{tagsfreetextnoac}} tagsrequired: {{tagsrequired}} `).section('Tags deferred', ` `, scope => { scope.onInputChange = () => scope.promise = inject('$timeout')(() => { return [{title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]; }, 2000); }); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tags/tags.ts ================================================ import template from './tags.html'; import './tags.scss'; import {DropdownList} from '../common/dropdown-list'; export interface IScope extends ng.IScope { model: any[]; } function renderTag(transclude, biOptions, tag) { let html; if (transclude.isSlotFilled('tag')) { html = transclude((_, tscope) => { tscope.tag = tag; }, null, 'tag'); } else { html = biOptions.render(tag); } return {html}; } export default function directive(): ng.IDirective { return { template, require: ['ngModel', 'biOptions'], restrict: 'E', transclude: { tag: '?tag', opt: '?opt', }, scope: { btOptions: '=', onTypeahead: '&', readonly: '=', placeholder: '@' }, link: { pre(scope: IScope, element, attrs, [ngModel, biOptions]: [ng.INgModelController, any], transclude) { scope.renderTag = tag => renderTag(transclude, biOptions, tag); return new DropdownList(scope, element, attrs, {ngModel, biOptions}, transclude, { optionsAlias: 'btOptions', isArray: true, options: { freetext: false, typeahead: true, } }); } } }; } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.html ================================================
    {{::btText}}
    ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.scss ================================================ @import '../../assets/css/def/defaults.def'; @import '../../assets/css/def/colors.def'; bi-tooltip { display: inline-flex; .bd-content { background-color: transparent !important; } .bd-position--top { .bi-tooltip-content { margin-top: 0; margin-bottom: 8px; &:before { top: initial; bottom: -6px; border-width: 6px 6px 0 6px; border-color: #000000 transparent transparent transparent; } } } .bi-tooltip-content { position: relative; margin-top: 16px; padding: 8px 14px; color: $white; font-size: 11px; white-space: nowrap; box-shadow: $default-box-shadow; &:before { position: absolute; content: ''; top: -6px; left: 50%; width: 0; height: 0; margin-left: -5px; border-style: solid; border-width: 0 6px 6px 6px; border-color: transparent transparent #000000 transparent; opacity: .8; } > .bi-tooltip-backdrop { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: $black; border-radius: 3px; opacity: .8; } > * { position: relative; z-index: 1; > * { text-transform: initial; font-weight: normal; white-space: nowrap; } } } [ng-transclude="toggle"] { cursor: default !important; } } ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.story.ts ================================================ export default app => app .story('UI', 'Tooltip') .section('Tooltip', `
    I'm big!
    Linebreak!
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.ts ================================================ import {initNgScope} from '../../../core'; import './tooltip.scss'; import template from './tooltip.html'; export default () => { return { restrict: 'E', template, transclude: { toggle: 'biToggle' }, scope: { btText: '@', btOptions: '<' }, link: { pre(scope) { initNgScope(scope).withOptions('btOptions', { position: 'bottom' }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/ui/filters/absolute-date.ts ================================================ import DateService from '../services/date'; export default function() { return function (date: string) { return DateService.moment(date).format(DateService.DATE_FORMAT); }; } ================================================ FILE: quix-frontend/client/src/lib/ui/filters/date-utc.ts ================================================ import {inject} from '../../core'; import DateService from '../services/date'; export default function() { return function (date: string | number, resolutionOrFormat: 'seconds' | 'milliseconds') { date = DateService.fromUTC(date).valueOf(); let format = 'yyyy-MM-dd HH:mm'; if (resolutionOrFormat === 'seconds') { format += ':ss'; } else if (resolutionOrFormat === 'milliseconds') { format += ':ss.sss'; } else { format = resolutionOrFormat; } return inject('$filter')('date')(date, format); }; } ================================================ FILE: quix-frontend/client/src/lib/ui/filters/date.ts ================================================ import {inject} from '../../core'; export default function() { return function (date: string, resolutionOrFormat?: 'seconds' | 'milliseconds') { let format = 'yyyy-MM-dd HH:mm'; if (resolutionOrFormat === 'seconds') { format += ':ss'; } else if (resolutionOrFormat === 'milliseconds') { format += ':ss.sss'; } else { format = resolutionOrFormat; } return inject('$filter')('date')(date, format); }; } ================================================ FILE: quix-frontend/client/src/lib/ui/filters/highlight.story.ts ================================================ export default app => app .story('UI', 'Highlight') .section('Highlight', `
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/filters/highlight.ts ================================================ export default [ '$sce', ($sce) => { return (haystack, needle: string | string[]) => { if (!haystack || !needle) { return haystack; } const needles: string[] = typeof needle === 'string' ? [needle] : needle; // tslint:disable-next-line: restrict-plus-operands return $sce.trustAsHtml(('' + haystack).replace(new RegExp(needles.map(n => `(${n})`).join('|'), 'gi'), match => `${match}`)); }; }, ]; ================================================ FILE: quix-frontend/client/src/lib/ui/filters/index.ts ================================================ export {default as biToHumanCase} from './to-human-case'; export {default as biDate} from './date'; export {default as biDateUTC} from './date-utc'; export {default as biRelativeDate} from './relative-date'; export {default as biHighlight} from './highlight'; ================================================ FILE: quix-frontend/client/src/lib/ui/filters/relative-date.ts ================================================ import DateService from '../services/date'; export default function() { return function (date: string) { return DateService.moment(date).fromNow(); }; } ================================================ FILE: quix-frontend/client/src/lib/ui/filters/to-human-case.ts ================================================ import {last} from 'lodash'; export default function() { const regexp = /(^.)|(_.)|(.[A-Z])/g; function capitalize(input: string) { return input.replace(regexp, function (match) { const res = last(match).toUpperCase(); if (match.length === 1) { return res; } if (match.charAt(0) === '_') { return ' ' + res; } return match.charAt(0) + ' ' + res; }); } return function (input: string) { return capitalize(input || ''); }; } ================================================ FILE: quix-frontend/client/src/lib/ui/index.ts ================================================ import angular from 'angular'; import 'angular-sanitize'; import 'angular-svg-round-progressbar'; import init from './init'; import './app.scss'; init(angular.module('bi.ui', [ 'ngSanitize', 'bi.core', 'angular-svg-round-progressbar' ])); export * from './services'; ================================================ FILE: quix-frontend/client/src/lib/ui/init.ts ================================================ import {forEach} from 'lodash'; import * as directives from './directives'; import * as filters from './filters'; const excluded = ['contenteditable']; function toDirectiveName(name: string) { if (excluded.indexOf(name) !== -1) { return name; } return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`; } export default function init(ngApp: angular.IModule) { forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any)); forEach(filters, (fn, name) => ngApp.filter(name, fn as any)); } ================================================ FILE: quix-frontend/client/src/lib/ui/services/confirm.story.ts ================================================ import {inject} from '../../../core'; import {default as confirm} from './confirm'; export default app => app .story('UI', 'Dialog') .section('Confirm dialog', ` import {confirm} from '@wix/bi-ui'; {{output}} my custom confirm dialog Are you sure you want to continue? `, (scope, element) => { scope.showConfirm = () => confirm(element.find('dialog.confirm'), scope) .then(() => scope.output = 'resolved', () => scope.output = 'rejected'); }) .section('Deferred confirm', ` deferred confirm Are you sure you want to continue? deferred confirm Are you sure you want to continue? `, (scope, element) => { scope.showDeferred = () => confirm(element.find('dialog.deferred-confirm'), scope); scope.showDeferredWithError = () => confirm(element.find('dialog.deferred-confirm-error'), scope); scope.onConfirm = () => inject('$timeout')(() => true, 3000); scope.onConfirmWithError = () => inject('$timeout')(() => { return inject('$q').reject({errorDescription: 'Deferred error!'}); }, 3000); }); ================================================ FILE: quix-frontend/client/src/lib/ui/services/confirm.ts ================================================ import { defaults, assign } from 'lodash'; import { inject } from '../../core'; import { default as dialog, IDialogOptions } from './dialog'; export interface IConfirmOptions extends IDialogOptions { actionType: 'create' | 'destroy' | 'trash' | 'neutral'; icon?: string; yes?: string; no?: string; resolveOnEnter?: boolean; } function init(htmlOrOptions: string | IConfirmOptions, promise: any) { let { scope, element } = promise; let options: Partial; scope = scope(); element = element(); if (typeof htmlOrOptions === 'string') { options = { actionType: 'neutral', yes: element.attr('yes'), no: element.attr('no'), }; } else { options = htmlOrOptions; } options = defaults({}, options, { actionType: 'neutral', yes: 'yes', no: 'cancel', }); scope.dialogOptions.showCloseAction = false; scope.dialogOptions.iconClass = options.actionType === 'destroy' || options.actionType === 'trash' ? 'bi-danger' : 'bi-primary'; if (options.resolveOnEnter) { element = element.bind('keyup', (event) => { if (event.which === 13) { scope.dialogEvents.resolve(); } }); } element.addClass('bi-confirm').append( inject('$compile')(` `)(assign(scope, { confirmOptions: options })) ); return promise; } export default function( htmlOrOptions: string | IConfirmOptions, scope?, locals? ) { return init(htmlOrOptions, dialog(htmlOrOptions, scope, locals)); } ================================================ FILE: quix-frontend/client/src/lib/ui/services/date.ts ================================================ import moment from 'moment'; if (moment) { moment.locale('en', { relativeTime : { future: 'in %s', past: '%s ago', s: '%d second', ss: '%d seconds', m: '%d minute', mm: '%d minutes', h: '%d hour', hh: '%d hours', d: '%d day', dd: '%d days', M: '%d month', MM: '%d months', y: '%d year', yy: '%d years' } }); } function getTimezoneOffset(date) { return new Date(date).getTimezoneOffset(); } export default class DateService { public static DATE_FORMAT = 'YYYY-MM-DD HH:mm'; private readonly date: number | string; constructor(date?: number | string) { this.date = date || Date.now(); } static moment = moment; static getRange(duration, {maxDate = null, format = false} = {}) { let start, end; const now = moment(maxDate || undefined).utc().startOf('day'); start = now.clone().subtract(moment.duration(duration)); end = now; if (format) { start = start.format(); end = end.format(); } else { start = start.valueOf(); end = end.valueOf(); } return {start, end}; } static fromUTC(date) { return moment(date).add(getTimezoneOffset(date), 'minutes'); } fromUTC() { return moment(this.date).add(getTimezoneOffset(this.date), 'minutes'); } toUTC() { return moment.utc(this.date).subtract(getTimezoneOffset(this.date), 'minutes'); } asMoment() { return moment(this.date); } asDate() { return new Date(this.date as string); } } ================================================ FILE: quix-frontend/client/src/lib/ui/services/dialog-testkit.ts ================================================ import { Testkit } from '../../../../test/e2e/driver'; export class DialogTestkit extends Testkit { async isShown() { return (await this.query.$('dialog')) !== null; } } ================================================ FILE: quix-frontend/client/src/lib/ui/services/dialog.story.ts ================================================ import {default as dialog} from './dialog'; export default app => app .story('UI', 'Dialog') .section('Dialog', ` import {dialog} from '@wix/bi-ui'; {{output}} my custom dialog Dialog content `, (scope, element) => { scope.showDialog = () => { dialog(element.find('dialog.dialog'), scope).then(() => scope.output = 'resolved', () => scope.output = 'rejected'); }; }); ================================================ FILE: quix-frontend/client/src/lib/ui/services/dialog.ts ================================================ import {assign, defaults} from 'lodash'; import angular from 'angular'; import {registerDialog} from 'dialog-polyfill'; import {inject} from '../../core'; let instance = {scope: null, dialog: null}; export interface IDialog extends ng.IPromise { element(): Object; scope(): Object; } export interface IDialogOptions { html: string; title?: string; subTitle?: string; icon?: string; showCloseAction?: boolean; onConfirm?(scope): any; } function createScope(deferred, scope?, locals?) { scope = scope ? scope.$new() : inject('$rootScope').$new(true); if (locals) { assign(scope, locals); } scope.dialogEvents = { reject() { deferred.reject(); }, resolve() { const res = this.onConfirm(scope); if (res && res.then) { scope.dialogError = null; scope.dialogResolving = true; res .then(r => deferred.resolve(r, scope), e => scope.dialogError = e) .finally(() => scope.dialogResolving = false); } else { deferred.resolve(scope); } } }; return scope; } function showDialog(scope, htmlOrOptions: string | IDialogOptions) { let options: IDialogOptions; if (typeof htmlOrOptions === 'string') { options = { html: htmlOrOptions } } else { options = { ...htmlOrOptions, html: ` ${htmlOrOptions.icon ? ` ${htmlOrOptions.icon} ` : ''} ${htmlOrOptions.title} ${htmlOrOptions.subTitle ? `${htmlOrOptions.subTitle}` : ''} ${htmlOrOptions.html} ` }; } options = defaults({}, options, { showCloseAction: true }); const element = angular.element(options.html) .removeAttr('ng-non-bindable') .addClass('bi-dialog') .prepend(` close `) .append(` {{dialogError.data && dialogError.data.errorDescription || 'Unknown error'}} `); scope.dialogEvents.onConfirm = options.onConfirm || (() => inject('$parse')(element.attr('on-confirm'))(scope)); const dialog = inject('$compile')(element)(assign(scope, {dialogOptions: options})) .on('close', () => scope.dialogEvents.reject()) .appendTo(window.document.body) .get(0); registerDialog(dialog); inject('$timeout')(() => dialog.showModal()); return (instance = {scope, dialog}); } function destroy({scope, dialog}) { if (scope) { scope.$destroy(); } if (dialog) { if (dialog.getAttribute('open') !== null) { dialog.close(); } dialog.remove(); } instance = {scope: null, dialog: null}; } export default function(htmlOrOptions: string | IDialogOptions, parentScope?, locals?): IDialog { destroy(instance); const deferred = ((inject('$q') as ng.IQService)).defer(); const {scope, dialog} = showDialog(createScope(deferred, parentScope, locals), htmlOrOptions); const promise = deferred.promise.finally(() => destroy({scope, dialog})) as IDialog; promise.element = () => angular.element(dialog); promise.scope = () => scope; return promise; } ================================================ FILE: quix-frontend/client/src/lib/ui/services/index.ts ================================================ export {default as dialog} from './dialog'; export {default as confirm} from './confirm'; export {default as BiDate} from './date'; import * as toastExport from './toast'; export const toast = toastExport; ================================================ FILE: quix-frontend/client/src/lib/ui/services/toast.scss ================================================ @import '../assets/css/def/colors.def'; @import '../assets/css/def/defaults.def'; @import '../assets/css/def/action.def'; .bi-toast { position: fixed; left: 15px; bottom: 15px; padding: 0 20px; line-height: 48px; color: $white; background-color: darken($grey--800, 7); border-radius: 3px; box-shadow: $default-box-shadow; } ================================================ FILE: quix-frontend/client/src/lib/ui/services/toast.story.ts ================================================ import * as toast from './toast'; export default app => app .story('UI', 'Toast') .section('Toast', ` import {toast} from '@wix/bi-ui'; Status: {{status}} `, $scope => { $scope.status = 'hidden'; $scope.showToast = (({text, cancel, ok, hideDelay}) => { $scope.status = 'visible'; toast.showToast({text, cancel, ok, hideDelay}) .then(() => $scope.status = 'hidden and resolved') .catch(() => $scope.status = 'hidden and rejected'); }); $scope.hideToast = () => { $scope.status = 'hidden'; toast.hideToast(); }; }); ================================================ FILE: quix-frontend/client/src/lib/ui/services/toast.ts ================================================ import {last} from 'lodash'; import {inject, utils} from '../../core'; import './toast.scss'; enum Icons { success = 'check', error = 'error_outline', } enum IconClass { success = 'bi-success', error = 'bi-danger', } let instances = []; let hideTimeout = null; function createScope(deferred) { const scope = inject('$rootScope').$new(true); scope.ok = function() { deferred.resolve(); }; scope.cancel = function() { deferred.reject(); }; return scope; } function show(scope, text, type, okText, cancelText) { scope.text = text; scope.type = Icons[type]; scope.okText = okText; scope.cancelText = cancelText; scope.iconClass = IconClass[type]; const element = inject('$compile')(`
    {{::type}} {{text}} {{::okText}} {{::cancelText}}
    `)(scope); instances.push({scope, element}); inject('$timeout')(() => element.appendTo(window.document.body)); } function destroy() { while (instances.length) { const {scope, element} = instances.pop(); element.remove(); scope.$destroy(); } inject('$timeout').cancel(hideTimeout); hideTimeout = null; instances = []; } export function showToast({ text, type = null, ok = '', cancel = '', hideDelay = 0 }: { text: string; type?: 'success' | 'error' | null; ok?: string; cancel?: string; hideDelay?: number; }, hideDelayArg = hideDelay) { const deferred = ((inject('$q') as ng.IQService)).defer(); const scope = createScope(deferred); destroy(); show(scope, text, type, ok, cancel); if (hideDelayArg) { hideTimeout = inject('$timeout')(destroy, hideDelayArg); } return deferred.promise.finally(destroy); } export function hideToast() { destroy(); } export function updateText(text: string) { if (!instances.length) { return; } const {scope} = last(instances); utils.scope.safeApply(scope, () => scope.text = text); } ================================================ FILE: quix-frontend/client/src/lib/ui/stories/action.story.ts ================================================ export default app => { app.story('UI', 'Action') .section('Icon actions', /*html*/`
    save cached delete save cached delete save cached delete
    save cached delete save cached delete save cached delete
    See all available icons here
    `) .section('Buttons actions', /*html*/`
    default primary success warning danger
    default primary success warning danger
    `) .section('Round actions', /*html*/`
    edit edit edit
    edit edit edit
    `); app.story('UI', 'Loader') .section('Action loader', /*html*/` cached `); }; ================================================ FILE: quix-frontend/client/src/lib/ui/stories/alert.story.ts ================================================ export default app => app .story('UI', 'Alert') .section('Alert', /*html*/`
    My alert
    My alert content
    My error
    01010110100100010101
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/align.story.ts ================================================ export default app => app .story('UI', 'Layout') .section('Align', `
    top
    middle
    bottom
    `) .section('Spread', `
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/badge.story.ts ================================================ export default app => app .story('UI', 'Badge') .section('Badge', ` 1 2 3 4 5 `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/border.story.ts ================================================ export default app => app .story('UI', 'Misc') .section('Border', `
    I have a border
    I have a top border
    I have a right border
    I have a bottom border
    I have a left border
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/button.story.ts ================================================ export default app => { app.story('UI', 'Button') .section('Main Buttons', `
    `); app.story('UI', 'Loader') .section('Button loader', ` `); }; ================================================ FILE: quix-frontend/client/src/lib/ui/stories/colors.story.ts ================================================ export default app => app .story('UI', 'Colors') .section('Main colors', ` color_lens color_lens color_lens color_lens color_lens color_lens @import '../lib/ui/assets/css/def/colors.def'; `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/empty-state.story.ts ================================================ export default app => app .story('UI', 'Empty state') .section('Empty state', `
    Default state
    State content
    Info state
    Empty state content
    Empty state without header
    Nothing state
    Empty state content
    Pending state
    Empty state content
    Error state
    Empty state content
    Empty state content
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/flex.story.ts ================================================ export default app => app .story('UI', 'Layout') .section('Column / Row', `
    column
    row
    `) .section('Grow', `
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/form.story.ts ================================================ export default app => app .story('UI', 'Form') .section('Horizontal labels (Default)', `
    label1
    label1
    `) .section('Vertical labels', `
    label1
    label1
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/hint.story.ts ================================================ export default app => app .story('UI', 'Hint') .section('Hint', `
    I'm a hint I'm an info
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/home-action.story.ts ================================================ export default app => { app.story('UI', 'Home action') .section('Home action', `
    assignment_ind View profile by user
    `); }; ================================================ FILE: quix-frontend/client/src/lib/ui/stories/input.story.ts ================================================ export default app => app .story('UI', 'Input') .section('Text input', ` `) .section('Textarea', ` `) .section('Input with action', `
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/label.story.ts ================================================ export default app => app .story('UI', 'Label') .section('Labels', ` big default small `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/media.story.ts ================================================ export default app => app .story('UI', 'Media') .section('Media', ` I should be visible on normal screens only I should be visible on small screens only `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/scroll.story.ts ================================================ export default app => app .story('UI', 'Scroll') .section('Scroll', `
    I'm scrollable
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/space.story.ts ================================================ export default app => app .story('UI', 'Layout') .section('Space', `
    horizontal
    vertical
    `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/spinner.story.ts ================================================ export default app => app .story('UI', 'Loader') .section('Spinner', ` `); ================================================ FILE: quix-frontend/client/src/lib/ui/stories/tag.story.ts ================================================ export default app => { app.story('UI', 'Tag') .section('Tags', ` Default Primary Success Warning Danger `); }; ================================================ FILE: quix-frontend/client/src/lib/ui/stories/text.story.ts ================================================ export default app => app .story('UI', 'Text') .section('Small text', ` I'm a small text `); ================================================ FILE: quix-frontend/client/src/lib/ui/typings/globals.d.ts ================================================ import {LoDashStatic} from "lodash"; declare global { module NodeJS { interface Global { window: Window; angular: ng.IAngularStatic; localStorage: any; inject: ng.IInjectStatic; _: LoDashStatic } } interface Window { beforeEach: any; afterEach: any; angular: ng.IAngularStatic; localStorage: any; inject: ng.IInjectStatic; _: LoDashStatic jQuery: JQueryStatic } } ================================================ FILE: quix-frontend/client/src/lib/ui/typings/turnerjs.d.ts ================================================ /// declare class __TurnerComponentDriver__ extends TurnerComponentDriver {} declare module 'turnerjs' { export class TurnerComponentDriver extends __TurnerComponentDriver__ {} } ================================================ FILE: quix-frontend/client/src/lib/ui/typings/types.d.ts ================================================ declare module '*.scss'; declare module '*.html'; ================================================ FILE: quix-frontend/client/src/lib/viz/bootstrap.ts ================================================ import angular from 'angular'; import '../../lib/core'; import '../ui'; import '../code-editor'; export default angular.module('bi.viz', ['bi.core', 'bi.ui', 'bi.codeEditor']); ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/chart-renderer.ts ================================================ import {IMeta, IFilterData} from '../../services/chart/chart-conf'; import {isDimension, isDate} from '../../services/chart/chart-utils'; declare const Plotly; function getXAxisType(filter: IFilterData, meta: IMeta) { if (isDate(filter.x, meta)) { return 'date'; } if (isDimension(filter.x, meta)) { return 'bar'; } } export class ChartRenderer { private chart = null; constructor(private readonly container) { } public error(e) { this.container.html(`
    ${e}
    `); } public draw(data: any[], filteredMeta: IMeta, meta: IMeta, filter: IFilterData) { const xAxisType = getXAxisType(filter, meta); data = data.map(serie => ({ ...serie, type: xAxisType, })); const layout = { barmode: 'group', margin: { l: 30, r: 30, b: 30, t: 30, pad: 4, }, legend: { 'orientation': 'v', }, yaxis: { automargin: true, }, xaxis: { automargin: true, autorange: true, type: xAxisType, } }; if (this.chart) { this.destroy(); } this.chart = Plotly.newPlot(this.container.get(0), data, layout, { displaylogo: false, }); } public destroy() { Plotly.purge(this.container.get(0)); } } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/chart.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/chart.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; bi-viz-chart { position: relative; display: flex; flex-direction: column; flex-grow: 1; [bi-maximizable] { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .bm--maximized { .bvc-container { max-height: 70%; } } .modebar-container { margin: 2px 30px 0 0 !important; } } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/chart.ts ================================================ import {initNgScope, inject} from '../../../core'; import {ChartRenderer} from './chart-renderer'; import {IInputItem} from '../../services/viz-conf'; import {ChartViz} from '../../services/chart/chart-viz-service'; import template from './chart.html'; import './chart.scss'; export interface IScope extends angular.IScope { vm: any; state: any; statePrefix: string; $state: any; data: IInputItem[]; fields: string[]; maximizable: any; viz: ChartViz; events: any; } function createRenderer(scope: IScope, element) { return new ChartRenderer(element.find('.bvc-container')); } function load(scope: IScope, element) { scope.viz = scope.viz || new ChartViz(scope.data, createRenderer(scope, element), { fields: scope.fields, xMeta: 'all', }); scope.viz.filter().draw(); } function loadAsync(scope, element) { inject('$timeout')(() => load(scope, element)); } export default () => { return { restrict: 'E', template, scope: { data: '<', fields: '<', bvOptions: '<', statePrefix: '@', $state: '<' }, link: { pre(scope: IScope, element) { const timeout = inject('$timeout'); initNgScope(scope) .withOptions('bvOptions', { filter: true }) .withVM({ maximize: { $export() { return {isMaximized: this.enabled}; }, $import({isMaximized}) { this.toggle(isMaximized === 'true'); } } }) .withEvents({ onMaximizableLoad(instance) { if (scope.vm.maximize.enabled) { timeout(() => instance.toggle(true), 100); scope.vm.maximize.toggle(false); } }, onMaximizeToggle() { loadAsync(scope, element); }, onFilterChange() { loadAsync(scope, element); } }) .withState(scope.$state || 'chart', `${scope.statePrefix}chart`, {}); if (!scope.vm.maximize.enabled) { loadAsync(scope, element); } scope.$on('$destroy', () => scope.viz.destroy()); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/filter/chart-filter.html ================================================
    X Axis
    Y Axis
    Group by
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/filter/chart-filter.scss ================================================ @import '../../../../ui/assets/css/def/colors.def'; bi-viz-chart-filter { display: block; flex-basis: 300px; } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/chart/filter/chart-filter.ts ================================================ import {initNgScope, createNgModel} from '../../../../core'; import {IFilterData, IFilterMeta} from '../../../services/chart/chart-conf'; import template from './chart-filter.html'; import './chart-filter.scss'; export interface IScope { model: IFilterData; meta: IFilterMeta; onChange: Function; onReset: Function; onDataFilterChange: Function; onViewFilterChange: Function; } export default () => { return { restrict: 'E', template, require: 'ngModel', scope: { meta: '=', onChange: '&', onViewFilterChange: '&', onDataFilterChange: '&', onReset: '&' }, link: { pre(scope: IScope, element, attr, ngModel) { createNgModel(scope as any, ngModel).watchDeep(true); initNgScope(scope).withEvents({ onReset() { scope.onChange(); scope.onReset(); }, onDataFilterSelect() { scope.onChange(); scope.onDataFilterChange(); } }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/index.ts ================================================ export {default as viz} from './viz'; export {default as vizChart} from './chart/chart'; export {default as vizChartFilter} from './chart/filter/chart-filter'; export {default as vizTable} from './table/table'; export {default as vizPicker} from './picker/picker'; export {default as vizPie} from './pie/pie'; export {default as vizPieFilter} from './pie/filter/pie-filter'; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/picker/picker.html ================================================
    {{::{ table: 'table_chart', pie: 'pie_chart', chart: 'show_chart', har: 'network_check', path: 'bubble_chart', sankey: 'sort', funnel: 'view_column', plan: 'info' }[type]}}
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/picker/picker.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; bi-viz-picker { display: block; } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/picker/picker.ts ================================================ import {difference, intersection} from 'lodash'; import {initNgScope, inject} from '../../../core'; import {IFieldCategories} from '../../services/chart/chart-conf'; import {categorizeFields} from '../../services/chart/chart-utils'; import template from './picker.html'; import './picker.scss'; function getVizTypes({dimensions, values, all}: IFieldCategories, types: string[] = []): string[] { const res = ['table']; if (values.length > 0 && all.length > 1) { res.push('chart'); } if (values.length > 0 && dimensions.length > 0) { res.push('pie'); } if (!difference(['pathString', 'count'], all).length) { res.push('sankey', 'funnel'); } return types.length ? intersection(types, res) : res; } export default () => { return { restrict: 'E', template, scope: { data: '<', selected: '=', types: '=', onSelect: '&' }, link: { pre(scope, element) { initNgScope(scope) .withVM({ init() { this.types = getVizTypes(categorizeFields(scope.data && scope.data[0]), scope.types); this.selected = this.types.indexOf(scope.selected) !== -1 ? scope.selected : this.types[0]; } }) .withEvents({ onSelect(type) { scope.vm.selected = type; inject('$timeout')(() => scope.onSelect({type})); } }); scope.types = scope.vm.types.length > 1 ? scope.vm.types : null; scope.onSelect({type: scope.vm.selected}); scope.$watch('data', (d, pd) => d !== pd && scope.vm.init()); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/filter/pie-filter.html ================================================
    Label
    Value
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/filter/pie-filter.scss ================================================ @import '../../../../ui/assets/css/def/colors.def'; bi-viz-pie-filter { display: block; flex-basis: 300px; } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/filter/pie-filter.ts ================================================ import {initNgScope, createNgModel} from '../../../../core'; import {IFilterData, IFilterMeta} from '../../../services/chart/chart-conf'; import template from './pie-filter.html'; import './pie-filter.scss'; export interface IScope { model: IFilterData; meta: IFilterMeta; onChange: Function; onReset: Function; onDataFilterChange: Function; onViewFilterChange: Function; } export default () => { return { restrict: 'E', template, require: 'ngModel', scope: { meta: '=', onChange: '&', onViewFilterChange: '&', onDataFilterChange: '&', onReset: '&' }, link: { pre(scope: IScope, element, attr, ngModel) { createNgModel(scope as any, ngModel) .watchDeep(true); initNgScope(scope).withEvents({ onReset() { scope.onChange(); scope.onReset(); }, onDataFilterSelect() { scope.onChange(); scope.onDataFilterChange(); } }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/pie-renderer.ts ================================================ import {IMeta, IFilterData} from '../../services/chart/chart-conf'; declare const Plotly; export class PieRenderer { private chart = null; constructor(private readonly container) { } public error(e) { this.container.html(`
    ${e}
    `); } public draw(data: any[], filteredMeta: IMeta, meta: IMeta, filter: IFilterData) { const xAxisType = 'pie'; data = data.map(serie => ({ ...serie, type: xAxisType, labels: serie.x, values: serie.y, })); const layout = { margin: { l: 30, r: 30, b: 30, t: 30, pad: 4, }, legend: { 'orientation': 'v', }, }; if (this.chart) { this.destroy(); } this.chart = Plotly.newPlot(this.container.get(0), data, layout, { displaylogo: false, }); } public destroy() { Plotly.purge(this.container.get(0)); } } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/pie.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/pie.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; bi-viz-pie { position: relative; display: flex; flex-direction: column; flex-grow: 1; .bvp-container { margin-left: -16px; width: 100% } [bi-maximizable] { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .bm--maximized { .bvp-container { max-height: 70%; } } .modebar-container { margin: 2px 30px 0 0 !important; } } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/pie/pie.ts ================================================ import { initNgScope, inject } from '../../../core'; import {PieRenderer} from './pie-renderer'; import {IInputItem} from '../../services/viz-conf'; import {ChartViz} from '../../services/chart/chart-viz-service'; import template from './pie.html'; import './pie.scss'; export interface IScope extends angular.IScope { vm: any; state: any; statePrefix: string; $state: any; data: IInputItem[]; fields: string[]; maximizable: any; viz: ChartViz; events: any; } function createRenderer(scope: IScope, element) { return new PieRenderer(element.find('.bvp-container')); } function load(scope: IScope, element) { scope.viz = scope.viz || new ChartViz(scope.data, createRenderer(scope, element), { fields: scope.fields, xMeta: 'dimensions', }); scope.viz.filter().draw(); } function loadAsync(scope, element) { inject('$timeout')(() => load(scope, element)); } export default () => { return { restrict: 'E', template, scope: { data: '<', fields: '<', bvOptions: '<', statePrefix: '@', $state: '<' }, link: { pre(scope: IScope, element) { const timeout = inject('$timeout'); initNgScope(scope) .withOptions('bvOptions', { filter: true }) .withVM({ maximize: { $export() { return {isMaximized: this.enabled}; }, $import({isMaximized}) { this.toggle(isMaximized === 'true'); } } }) .withEvents({ onMaximizableLoad(instance) { if (scope.vm.maximize.enabled) { timeout(() => instance.toggle(true), 100); scope.vm.maximize.toggle(false); } }, onMaximizeToggle() { loadAsync(scope, element); }, onFilterChange() { loadAsync(scope, element); } }) .withState(scope.$state || 'pie', `${scope.statePrefix}pie`, {}); if (!scope.vm.maximize.enabled) { loadAsync(scope, element); } scope.$on('$destroy', () => scope.viz.destroy()); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/table/table-renderer.ts ================================================ import {inject} from '../../../core'; import {BufferedCollection} from '../../../core/srv/collections'; export class TableRenderer { constructor(private readonly container) { } public draw(scope, data: BufferedCollection, fields: string[], formatter) { const childScope = scope.$new(); childScope.data = data; childScope.fields = fields; childScope.formatter = formatter; this.container.html(inject('$compile')(`
    No results
    `)(childScope)); } } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/table/table.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/table/table.scss ================================================ @import '../../../ui/assets/css/def/colors.def'; bi-viz-table { position: relative; display: flex; flex-direction: column; flex-grow: 1; overflow: hidden; } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/table/table.ts ================================================ import jquery from 'jquery'; import {initNgScope, inject} from '../../../core'; import {BufferedCollection} from '../../../core/srv/collections'; import {TableRenderer} from './table-renderer'; import template from './table.html'; import './table.scss'; export interface IScope extends angular.IScope { vm: any; state: any; statePrefix: string; $state: any; data: BufferedCollection; fields: string[]; maximizable: any; events: any; } function load(scope: IScope, element) { new TableRenderer(element.find('.bvt-container')).draw(scope, scope.data, scope.fields, scope.formatter); } function loadAsync(scope, element) { inject('$timeout')(() => load(scope, element)); } export default () => { return { restrict: 'E', template, scope: { data: '<', fields: '<', isPartial: '<', formatter: '&', statePrefix: '@', $state: '<' }, link: { pre(scope: IScope, element) { const timeout = inject('$timeout'); initNgScope(scope) .withVM({ maximize: { $export() { return {isMaximized: this.enabled}; }, $import({isMaximized}) { this.toggle(isMaximized === 'true'); } } }) .withEvents({ onMaximizableLoad(instance) { if (scope.vm.maximize.enabled) { timeout(() => instance.toggle(true), 100); scope.vm.maximize.toggle(false); } }, onMaximizeToggle() { loadAsync(scope, element); }, onFilterChange() { loadAsync(scope, element); } }) .withState(scope.$state || 'table', `${scope.statePrefix}table`, {}); if (!scope.vm.maximize.enabled) { loadAsync(scope, element); } element.on('dblclick', 'bi-tbl td', e => { jquery(e.currentTarget).css('white-space', 'normal'); }); } } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/directives/viz.html ================================================
    ================================================ FILE: quix-frontend/client/src/lib/viz/directives/viz.scss ================================================ bi-viz { display: flex; flex-direction: column; flex-grow: 1; bi-viz-picker { margin-right: 20px; } } ================================================ FILE: quix-frontend/client/src/lib/viz/directives/viz.ts ================================================ import {initNgScope} from '../../core'; import template from './viz.html'; import './viz.scss'; export default () => { return { restrict: 'E', template, scope: { type: '@', data: '<', fields: '<', tableData: '<', tableFields: '<', isPartial: '<', bvOptions: '<', tableFormatter: '&', statePrefix: '@', $state: '<' }, link: scope => { initNgScope(scope) .withOptions('bvOptions', { picker: false, filter: true, types: [] }) .withVM({ selected: {}, $init() { this.toggle(true); if (!scope.options.picker) { this.select(scope.type || 'table'); } }, isVisible(type) { return this.selected[type]; }, select(type) { this.type = type; this.selected[type] = true; scope.type = type; } }) .withEvents({ onSelect(type) { scope.vm.select(type); } }) .withState(scope.$state || 'viz', 'viz', {}); scope.$watch('type', type => type && scope.events.onSelect(type)); scope.$watch('data', (d, pd) => d !== pd && scope.vm.init()); } }; }; ================================================ FILE: quix-frontend/client/src/lib/viz/index.ts ================================================ import ngApp from './bootstrap'; import init from './init'; init(ngApp); ================================================ FILE: quix-frontend/client/src/lib/viz/init.ts ================================================ import {forEach} from 'lodash'; import * as directives from './directives'; function toDirectiveName(name: string) { return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`; } export default function init(ngApp: angular.IModule) { forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any)); } ================================================ FILE: quix-frontend/client/src/lib/viz/services/chart/chart-conf.ts ================================================ import {IInputItem} from '../viz-conf'; export type IData = IInputItem[]; export interface IMeta extends IFieldCategories {} export interface IFilterMeta extends IMeta { x: string[]; y: string[]; group: string[]; } export interface IFilterData { x: string; y: string[]; group: string[]; aggType: 'sum' | 'avg'; } export interface IFieldCategories { all: string[]; dimensions: string[]; values: string[]; dates: string[]; } export interface IRendererData { } ================================================ FILE: quix-frontend/client/src/lib/viz/services/chart/chart-data-service.ts ================================================ import {VizData} from '../viz-data-service'; import {IInputItem} from '../viz-conf'; import {IMeta, IData, IFilterData} from './chart-conf'; import {metaTransducer, inputFilterTransducer} from '../../transducers/chart'; /** * Class responsible for input transformation and filtering */ export class ChartData extends VizData { constructor(input: IInputItem[], customTransducers?) { super(input, { metaTransducer, inputFilterTransducer }, customTransducers); } filterData(filter: IFilterData) { const serieIndexes = {}; this.filteredData = this.data.reduce((res, item) => { filter.y.forEach((yField) => { const key = `${filter.group.map(field => item[field]).join(' + ')}${ filter.group.length ? (filter.y.length > 1 ? `[${yField}]` : '') : yField }`; serieIndexes[key] = typeof serieIndexes[key] === 'undefined' ? res.length : serieIndexes[key]; res[serieIndexes[key]] = res[serieIndexes[key]] || { name: key, x: [], y: [], }; const {x, y} = res[serieIndexes[key]]; x.push(item[filter.x]); y.push(item[yField]); }); return res; }, []); return this; } } ================================================ FILE: quix-frontend/client/src/lib/viz/services/chart/chart-filter-service.ts ================================================ import {defaults, assign} from 'lodash'; import {IMeta, IFilterData, IFilterMeta} from './chart-conf'; import {VizFilter} from '../viz-filter-service'; function getDefaults(filterMeta: IFilterMeta, fields: string[]): IFilterData { const {x, y} = filterMeta; const res: IFilterData = {x: null, y: [], group: [], aggType: 'sum'}; if (!fields) { return assign(res, {x: x[0], y: [y[1]]}); } return fields.reduce((result, field) => { if (result.x && result.y.length) { return result; } if (x.indexOf(field) !== -1 && !result.x) { result.x = field; } else if (y.indexOf(field) !== -1 && !result.y.length) { result.y.push(field); } return result; }, res); } export class ChartFilter extends VizFilter { constructor(private readonly fields: string[], private readonly xMeta: 'all' | 'dimensions') { super(); } protected createMeta(meta: IMeta, filteredMeta: IMeta): IFilterMeta { return { all: meta.all, dimensions: meta.dimensions, values: meta.values, dates: meta.dates, x: meta[this.xMeta], y: meta.values, group: [...meta.dimensions, ...meta.values] }; } protected createData(filterMeta: IFilterMeta): IFilterData { return defaults(this.data, getDefaults(filterMeta, this.fields)); } } ================================================ FILE: quix-frontend/client/src/lib/viz/services/chart/chart-utils.ts ================================================ import {IInputItem} from '../viz-conf'; import {IFieldCategories, IMeta} from './chart-conf'; const getValueType = (value: string): string => { if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) { return 'date'; } if (!isNaN(value as any) && (!!value || value as any === 0)) { return 'value'; } return 'dimension'; }; export const categorizeFields = (input: IInputItem = {}): IFieldCategories => { return Object.keys(input || {}).reduce((res, field) => { const type = getValueType(input[field]); if (type === 'dimension') { res.dimensions.push(field); } else if (type === 'value') { res.values.push(field); } else if (type === 'date') { res.dates.push(field); } res.all.push(field); return res; }, {all: [], dimensions: [], values: [], dates: []}); }; export const isDate = (field: string, meta: IMeta): boolean => { return meta.dates.indexOf(field) !== -1; }; export const isDimension = (field: string, meta: IMeta): boolean => { return meta.dimensions.indexOf(field) !== -1; }; ================================================ FILE: quix-frontend/client/src/lib/viz/services/chart/chart-viz-service.ts ================================================ import {Viz} from '../viz-service'; import {ChartData} from './chart-data-service'; import {IData, IMeta, IFilterData} from './chart-conf'; import {ChartFilter} from './chart-filter-service'; import {IInputItem, IRenderer} from '../viz-conf'; export class ChartViz extends Viz { constructor (data: IInputItem[], renderer: IRenderer, { fields, xMeta, }: { fields: string[]; xMeta: 'all' | 'dimensions'; }) { super(new ChartData(data), new ChartFilter(fields, xMeta), renderer); } } ================================================ FILE: quix-frontend/client/src/lib/viz/services/viz-conf.ts ================================================ export interface IInputItem { [key: string]: any; } export interface IRenderer { error(e): any; draw(data: Data, meta: Meta, filteredMeta: Meta, filter: FilterData): void; destroy(): void; } ================================================ FILE: quix-frontend/client/src/lib/viz/services/viz-data-service.ts ================================================ import {clone} from 'lodash'; import {seq, compose, map} from 'transducers.js'; export interface ITransducers { inputTransducer?(input: Input): Function; inputFilterTransducer?(filterData: FilterData, meta: Meta): Function; metaTransducer?(): Function; dataTransducer?(meta: Meta): Function; } export interface ICustomTransducers { meta?(): Function; data?(meta: Meta): Function; } function transduce( rawInput: Input, transducers: ITransducers, customTransducers: ICustomTransducers = {} ) { const {input, meta} = seq(rawInput, compose( transducers.inputTransducer(rawInput), transducers.metaTransducer(), customTransducers.meta() )); const data = seq(input, compose( transducers.dataTransducer(meta), customTransducers.data(meta) )); return {input, meta, data}; } /** * Class responsible for input transformation and filtering */ export class VizData { private readonly input: Input; private readonly meta: Meta; protected data: Data; private filteredMeta: Meta; protected filteredData: Data; constructor( rawInput: Input, private readonly transducers: ITransducers = {}, private readonly customTransducers: ICustomTransducers = {} ) { [ 'inputTransducer', 'inputFilterTransducer', 'metaTransducer', 'dataTransducer' ].forEach(transducer => transducers[transducer] = transducers[transducer] || (() => map(x => x))); [ 'meta', 'data' ].forEach(transducer => customTransducers[transducer] = customTransducers[transducer] || (() => map(x => x))); let input, meta, data; if (rawInput && typeof rawInput[Symbol.iterator] === 'function') { const res = transduce(rawInput, transducers, this.customTransducers); input = res.input; meta = res.meta; data = res.data; } else { input = rawInput; meta = null; data = rawInput; } this.input = input; this.meta = this.filteredMeta = meta; this.data = this.filteredData = data; } public getMeta(): Meta { return this.meta; } public getFilteredMeta(): Meta { return this.filteredMeta; } public getFilteredData(): Data { return this.filteredData; } public filterInput(filter: FilterData, customInputFilterTransducer: (filter: FilterData, meta: Meta) => any = () => map(x => x)): VizData { const input = seq(this.input, compose(customInputFilterTransducer(filter, this.meta), this.transducers.inputFilterTransducer(filter, this.meta))); const {meta, data} = transduce(input, this.transducers, this.customTransducers); this.filteredMeta = meta; this.data = this.filteredData = data; return this; } public filterData(filter: FilterData, dataFilter?: (data: Data, filter: FilterData, meta: Meta) => Data): VizData { if (dataFilter) { this.filteredData = dataFilter(clone(this.data), filter, this.filteredMeta); return this; } this.filteredData = clone(this.data); return this; } } ================================================ FILE: quix-frontend/client/src/lib/viz/services/viz-filter-service.ts ================================================ import {assign} from 'lodash'; export abstract class VizFilter { private meta: FilterMeta = {} as any; protected data: FilterData = {} as any; protected abstract createMeta(meta: Meta, filteredMeta: Meta): FilterMeta; protected abstract createData(filterMeta: FilterMeta): FilterData; init(meta: Meta, filteredMeta: Meta): VizFilter { this.meta = assign(this.meta, this.createMeta(meta, filteredMeta)); this.data = assign(this.data, this.createData(this.meta)); return this; } getMeta(): FilterMeta { return this.meta; } getData(): FilterData { return this.data; } } ================================================ FILE: quix-frontend/client/src/lib/viz/services/viz-service.ts ================================================ import {VizData} from './viz-data-service'; import {VizFilter} from './viz-filter-service'; import {IRenderer} from './viz-conf'; export class Viz { constructor ( private readonly data: VizData, private readonly fltr: VizFilter, private readonly renderer: IRenderer, ) {} private initFilter() { return this.fltr.init(this.data.getMeta(), this.data.getFilteredMeta()).getData(); } getFilter() { return this.fltr; } filterInput(filterTransducer?: (filter: FilterData, meta: Meta) => any): Viz { this.data.filterInput(this.initFilter(), filterTransducer); return this; } filterData(dataFilter?: (data: Data, filter: FilterData, meta: Meta) => Data): Viz { this.data.filterData(this.initFilter(), dataFilter); return this; } filter(): Viz { try { return this.filterInput().filterData(); } catch (e) { console.error(e); this.renderer.error(e); throw e; } } draw(): Viz { this.renderer.draw(this.data.getFilteredData(), this.data.getFilteredMeta(), this.data.getMeta(), this.getFilter().getData()); return this; } destroy() { this.renderer.destroy(); } } ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/chart/chart-input-filter-transducer.ts ================================================ import {pick} from 'lodash'; import {compose, map} from 'transducers.js'; import {IFilterData, IMeta} from '../../services/chart/chart-conf'; import {ungroup, parseFloats, sort} from '../'; import {IInputItem} from '../../services/viz-conf'; import {isDimension} from '../../services/chart/chart-utils'; import {parseDates} from '../parse-dates-transducer'; function sortByContext(filter: IFilterData, meta: IMeta) { return sort((a: IInputItem, b: IInputItem) => { if (isDimension(filter.x, meta)) { return b[filter.y[0]] - a[filter.y[0]]; } return a[filter.x] - b[filter.x]; }); } export const inputFilterTransducer = (filter: IFilterData, meta: IMeta) => { const fields = [filter.x, ...filter.group]; const values = filter.y; const all = [...fields, ...values]; return compose( map(input => pick(input, all)), parseDates(meta.dates), parseFloats(meta.values), ungroup({fields, values, aggType: filter.aggType}), sortByContext(filter, meta) ); }; ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/chart/chart-meta-transducer.ts ================================================ import {IInputItem} from '../../services/viz-conf'; import {IMeta} from '../../services/chart/chart-conf'; import {categorizeFields} from '../../services/chart/chart-utils'; export class Meta { private index = 0; private readonly input = []; private meta: IMeta = { all: [], dimensions: [], values: [], dates: [] }; constructor(private readonly xform) { } '@@transducer/result'() { return {input: this.input, meta: this.meta}; } '@@transducer/step'(res, input: IInputItem, index) { this.input.push(input); if (this.index === 0) { this.meta = categorizeFields(input); } this.xform['@@transducer/step'](res, [input, this.meta]); this.index++; return res; } } export const metaTransducer = () => xform => new Meta(xform); ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/chart/index.ts ================================================ export {metaTransducer} from './chart-meta-transducer'; export {inputFilterTransducer} from './chart-input-filter-transducer'; ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/index.ts ================================================ export {sort} from './sort-transducer'; export {ungroup} from './ungroup-transducer'; export {parseFloats} from './parse-floats-transducer'; export {parseDates} from './parse-dates-transducer'; ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/parse-dates-transducer.ts ================================================ import {IInputItem} from '../services/viz-conf'; import {BiDate} from '../../ui'; export class ParseDates { constructor(private readonly fields: string[], private readonly xform) { } '@@transducer/result'(v) { return this.xform['@@transducer/result'](v); } '@@transducer/step'(res, input: IInputItem) { this.fields.forEach(field => input[field] = BiDate.moment(input[field]).valueOf()); this.xform['@@transducer/step'](res, input); return res; } } export const parseDates = (fields: string[]) => xform => new ParseDates(fields, xform); ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/parse-floats-transducer.ts ================================================ import {IInputItem} from '../services/viz-conf'; export class ParseFloats { constructor(private readonly fields: string[], private readonly xform) { } '@@transducer/result'(v) { return this.xform['@@transducer/result'](v); } '@@transducer/step'(res, input: IInputItem) { this.fields.forEach(field => input[field] = parseFloat(input[field])); this.xform['@@transducer/step'](res, input); return res; } } export const parseFloats = (fields: string[]) => xform => new ParseFloats(fields, xform); ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/sort-transducer.ts ================================================ import {seq} from 'transducers.js'; import {IInputItem} from '../services/viz-conf'; export class Sort { constructor(private readonly fn, private readonly xform) { } '@@transducer/result'(v) { return seq(v.sort(this.fn), xform => this.xform); } '@@transducer/step'(res, input: IInputItem) { res.push(input); return res; } } export const sort = fn => xform => new Sort(fn, xform); ================================================ FILE: quix-frontend/client/src/lib/viz/transducers/ungroup-transducer.ts ================================================ import {clone} from 'lodash'; import {IInputItem} from '../services/viz-conf'; export interface IUngroupConf { fields: string[]; values: string[]; aggType: 'sum' | 'avg'; } export class Ungroup { private readonly inputCache = {}; private readonly indexCache = {}; constructor(private readonly conf: IUngroupConf, private readonly xform) { } '@@transducer/result'(v) { return this.xform['@@transducer/result'](v); } '@@transducer/step'(res, input: IInputItem) { const key = this.conf.fields.map(field => input[field]).join('|'); if (!this.inputCache[key]) { this.inputCache[key] = clone(input); this.indexCache[key] = 1; this.xform['@@transducer/step'](res, this.inputCache[key]); } else { this.conf.values.forEach(value => { if (this.conf.aggType === 'sum') { this.inputCache[key][value] += input[value]; } else if (this.conf.aggType === 'avg') { this.inputCache[key][value] = ((this.inputCache[key][value] * this.indexCache[key]) + input[value]) / (this.indexCache[key] + 1); } }); this.indexCache[key]++; } return res; } } export const ungroup = (conf: IUngroupConf) => xform => new Ungroup(conf, xform); ================================================ FILE: quix-frontend/client/src/lib/viz/utils/index.ts ================================================ export * from './utils'; ================================================ FILE: quix-frontend/client/src/lib/viz/utils/utils.ts ================================================ export function percentage(what: number, of: number): number { return Math.round((what / of * 100) * 100) / 100; } export function normalize(value, maxValue, min, max): number { return Math.max(Math.round(value / maxValue * max), min); } ================================================ FILE: quix-frontend/client/src/lib/web-worker-infra/types.ts ================================================ /* Constraints */ export interface RQRSConstraint { [key: string]: any; } export type RqtoRSConstraint = {[K in keyof RQ]: keyof RS}; /* Basic Types */ export type RequestMsgTypes = keyof RQ; //all possible request types export type ResponseMsgTypes = keyof RS; //all possible response types export type AllMsgTypes = keyof RQ | keyof RS; //guess export type RequestTypeToResponseTypeMap> = { [K in RequestMsgTypes]: RQtoRs[K]; }; export type WorkerFunctionsMap> = { [K in RequestMsgTypes]: (data: RQ[K]) => RS[RQtoRs[K]]; }; /** * Helper type for next types */ export interface WorkerMsgT | ResponseMsgTypes> { id: number; type: T; data: (RS & RQ)[T]; } /* * Bit of explanation for this ugliness: * We need both generic types, and union types. * We need union types because Map() an onMessage() must have a concrete type. */ //Union types export type WorkerResponse = { [T in ResponseMsgTypes]: WorkerMsgT; }[ResponseMsgTypes]; export type WorkerResponseData = RS[keyof RS]; export type WorkerRequest = { [T in RequestMsgTypes]: WorkerMsgT; }[RequestMsgTypes]; //Generic types export type WorkerResponseDataT< RQ, RS, T extends RequestMsgTypes, RQtoRs extends RqtoRSConstraint > = RS[RQtoRs[T]]; export type WorkerRequestT> = WorkerMsgT; export type WorkerResponseT> = WorkerMsgT; /* Worker types */ export interface WorkerClientMessageEvent extends MessageEvent { data: WorkerResponse; } export interface WorkerClient extends Worker { onmessage(e: WorkerClientMessageEvent): void; postMessage>(message: WorkerRequestT, transfer?: any[]): void; postMessage>(message: WorkerRequestT, options: {transfer: any[]}): void; } export interface WorkerMessageEvent extends MessageEvent { data: WorkerRequest; } export interface TypedWorker extends DedicatedWorkerGlobalScope { onmessage(e: WorkerMessageEvent): void; postMessage>(message: WorkerResponseT, transfer?: any[]): void; postMessage>(message: WorkerResponseT, options: {transfer: any[]}): void; } ================================================ FILE: quix-frontend/client/src/lib/web-worker-infra/web-worker/index.ts ================================================ import { TypedWorker, RQRSConstraint, RqtoRSConstraint, WorkerFunctionsMap, RequestMsgTypes, WorkerRequestT, RequestTypeToResponseTypeMap, } from '../types'; export {TypedWorker, RequestTypeToResponseTypeMap, WorkerFunctionsMap} from '../types'; export function TypedWorkerFactory< RQ extends RQRSConstraint, RS extends RQRSConstraint, RQtoRs extends RqtoRSConstraint >(msgTypeMapping: RequestTypeToResponseTypeMap, functionsMap: WorkerFunctionsMap) { return (self: TypedWorker) => { self.onmessage = e => { try { handleMsg(e.data); } catch (e) { console.error('something bad happened', e); } }; function handleMsg>(req: WorkerRequestT) { const {data} = req; const responseType = msgTypeMapping[req.type]; const responseData = functionsMap[req.type](data); const response = { id: req.id, type: responseType, data: responseData, } as any; self.postMessage(response); } }; } ================================================ FILE: quix-frontend/client/src/lib/web-worker-infra/web-worker-manager/index.ts ================================================ import { RequestMsgTypes, RQRSConstraint, RqtoRSConstraint, WorkerClient, WorkerRequestT, WorkerResponseData, WorkerResponseDataT, } from '../types'; export {RequestTypeToResponseTypeMap, WorkerFunctionsMap} from '../types'; function XHRWorker(url, maxAge?): Promise { return new Promise((resolve, reject) => { const oReq = new XMLHttpRequest(); oReq.addEventListener('load', () => { const worker = new Worker(URL.createObjectURL(new Blob([oReq.responseText]))); resolve(worker); }); oReq.addEventListener('error', e => { reject(new Error(oReq.responseText || 'Unknown error, failed fetching web worker')); }); oReq.open('get', url, true); if (maxAge) { oReq.setRequestHeader('Cache-Control', `max-age=${maxAge}`); } oReq.send(); }); } export type Omit = Pick>; export class TypedWorkerManager< RQ extends RQRSConstraint, RS extends RQRSConstraint, RQtoRS extends RqtoRSConstraint > { private requestId = 1; private readonly requestIdToPromise = new Map) => void>(); constructor(private readonly worker: WorkerClient) { this.worker.onmessage = e => { const response = e.data; const resolve = this.requestIdToPromise.get(response.id); this.requestIdToPromise.delete(response.id); if (!resolve) { throw new Error(`WorkerMngr:: Can't find promise, something horrible happend. id: ${response.id}`); } resolve(response.data); }; } protected sendMsg>( msg: Omit, 'id'>, ): Promise> { const sentMsg: WorkerRequestT = {...msg, id: this.requestId++}; return new Promise(resolve => { this.requestIdToPromise.set(sentMsg.id, resolve); this.worker.postMessage(sentMsg); }); } static async createFromUrl< RQ extends RQRSConstraint, RS extends RQRSConstraint, RQtoRS extends RqtoRSConstraint, T extends TypedWorkerManager >(this: new (w: WorkerClient) => T, url: string, maxAge = null) { const worker = await XHRWorker(url, maxAge); // tslint:disable-next-line: no-static-this return new this(worker); } } ================================================ FILE: quix-frontend/client/src/plugins/db/athena-db-plugin.ts ================================================ import { App } from '../../lib/app'; import {DbPlugin} from '../../services/plugins'; import {DB} from '../../config'; import {IFile, ModuleEngineType} from '@wix/quix-shared'; import {sanitizeTableToken} from '../../services'; export class AthenaDbPlugin extends DbPlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Athena, hooks); } getSampleQuery(table: IFile) { return `SELECT * FROM ${[...table.path, table].map(({name}) => sanitizeTableToken(name, '"')).join('.')} LIMIT ${DB.SampleLimit} ` } } ================================================ FILE: quix-frontend/client/src/plugins/db/bigquery-db-plugin.ts ================================================ import {DbPlugin} from '../../services/plugins'; import {IFile, ModuleEngineType} from '@wix/quix-shared'; import {DB} from '../../config'; import { App } from '../../lib/app'; export class BigQueryDbPlugin extends DbPlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.BigQuery, hooks); } getSampleQuery(table: IFile) { return `SELECT * FROM \`${[...table.path, table].map(({name}) => name).join('.')}\` LIMIT ${DB.SampleLimit} ` } } ================================================ FILE: quix-frontend/client/src/plugins/db/index.ts ================================================ export * from './athena-db-plugin'; export * from './presto-db-plugin'; export * from './jdbc-db-plugin'; export * from './bigquery-db-plugin'; ================================================ FILE: quix-frontend/client/src/plugins/db/jdbc-db-plugin.ts ================================================ import { App } from '../../lib/app'; import {DbPlugin} from '../../services/plugins'; import {IFile, ModuleEngineType} from '@wix/quix-shared'; import {DB} from '../../config'; import {sanitizeTableToken} from '../../services'; export class JdbcDbPlugin extends DbPlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Jdbc, hooks); } getSampleQuery(table: IFile) { return `SELECT * FROM ${[...table.path, table].map(({name}) => sanitizeTableToken(name, '"')).join('.')} LIMIT ${DB.SampleLimit} ` } } ================================================ FILE: quix-frontend/client/src/plugins/db/presto-db-plugin.ts ================================================ import { App } from '../../lib/app'; import {DbPlugin} from '../../services/plugins'; import {IFile, ModuleEngineType} from '@wix/quix-shared'; import {DB} from '../../config'; import {sanitizeTableToken} from '../../services'; export class PrestoDbPlugin extends DbPlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Presto, hooks); } getSampleQuery(table: IFile) { return `SELECT * FROM ${[...table.path, table].map(({name}) => sanitizeTableToken(name, '"')).join('.')} LIMIT ${DB.SampleLimit} ` } } ================================================ FILE: quix-frontend/client/src/plugins/index.ts ================================================ import {pluginFactory} from './plugin-factory'; import {PluginManager} from '../services/plugins'; import {hooks} from '../hooks'; export const pluginManager = new PluginManager(pluginFactory, hooks.note); ================================================ FILE: quix-frontend/client/src/plugins/note/athena-note-plugin.ts ================================================ import { ModuleEngineType } from '@wix/quix-shared'; import { App } from '../../lib/app'; import { NotePlugin } from '../../services/plugins'; export class AthenaNotePlugin extends NotePlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Athena, hooks, { syntaxValidation: true, canCreate: true, enableQueryFormatter: true, }); } } ================================================ FILE: quix-frontend/client/src/plugins/note/bigquery-note-plugin.ts ================================================ import bytes from 'bytes'; import { ModuleEngineType } from '@wix/quix-shared'; import { App } from '../../lib/app'; import { NotePlugin } from '../../services/plugins'; export class BigQueryNotePlugin extends NotePlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.BigQuery, hooks, { syntaxValidation: true, canCreate: true, dateFormat: 'YYYY/MM/DD HH:mm:ss', }); } formatStats(stats: {[key: string]: any}) { const bytesConfig = {thousandsSeparator: ',', unitSeparator: ' ', decimalPlaces: 0}; return [{ title: 'Cache', value: stats.cacheHit ? 'Hit' : 'Miss', }, { title: 'Bytes processed', value: bytes(stats.bytesProcessed, bytesConfig), }, { title: 'Bytes billed', value: bytes(stats.bytesBilled, bytesConfig), }]; } } ================================================ FILE: quix-frontend/client/src/plugins/note/default-note-plugin.ts ================================================ import {ModuleEngineType} from '@wix/quix-shared'; import {NotePlugin} from '../../services/plugins'; export class DefaultNotePlugin extends NotePlugin { constructor(app) { super( app, 'default', ModuleEngineType.Presto, {}, { syntaxValidation: false, canCreate: false, }, ); } } ================================================ FILE: quix-frontend/client/src/plugins/note/index.ts ================================================ export * from './default-note-plugin'; export * from './athena-note-plugin'; export * from './presto-note-plugin'; export * from './jdbc-note-plugin'; export * from './bigquery-note-plugin'; export * from './python-note-plugin'; ================================================ FILE: quix-frontend/client/src/plugins/note/jdbc-note-plugin.ts ================================================ import { ModuleEngineType } from '@wix/quix-shared'; import { App } from '../../lib/app'; import { NotePlugin } from '../../services/plugins'; export class JdbcNotePlugin extends NotePlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Jdbc, hooks, { syntaxValidation: false, canCreate: true, }); } } ================================================ FILE: quix-frontend/client/src/plugins/note/presto-note-plugin.ts ================================================ import { ModuleEngineType } from '@wix/quix-shared'; import { App } from '../../lib/app'; import { NotePlugin } from '../../services/plugins'; export class PrestoNotePlugin extends NotePlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Presto, hooks, { syntaxValidation: true, canCreate: true, enableQueryFormatter: true, }); } } ================================================ FILE: quix-frontend/client/src/plugins/note/python-note-plugin.ts ================================================ import { ModuleEngineType } from '@wix/quix-shared'; import { App } from '../../lib/app'; import { NotePlugin } from '../../services/plugins'; export class PythonNotePlugin extends NotePlugin { constructor(app: App, name: string, hooks: any) { super(app, name, ModuleEngineType.Python, hooks, { syntaxValidation: true, canCreate: true, }); } renderRunner() { return ` `; } } ================================================ FILE: quix-frontend/client/src/plugins/plugin-factory.ts ================================================ import {App} from '../lib/app'; import { Store } from '../lib/store'; import * as DbPlugins from './db'; import * as NotePlugins from './note'; export const pluginFactory = { db(app: App, store: Store, id: string, engine: string, noteHooks: any) { switch (engine) { case 'presto': return new DbPlugins.PrestoDbPlugin(app, id, noteHooks); case 'athena': return new DbPlugins.AthenaDbPlugin(app, id, noteHooks); case 'jdbc': return new DbPlugins.JdbcDbPlugin(app, id, noteHooks); case 'bigquery': return new DbPlugins.BigQueryDbPlugin(app, id, noteHooks); default: throw new Error(`No definition for "${engine}" engine db plugin`); } }, note(app: App, store: Store, id: string, engine: string, noteHooks: any) { switch (engine) { case 'presto': return new NotePlugins.PrestoNotePlugin(app, id, noteHooks); case 'athena': return new NotePlugins.AthenaNotePlugin(app, id, noteHooks); case 'jdbc': return new NotePlugins.JdbcNotePlugin(app, id, noteHooks); case 'bigquery': return new NotePlugins.BigQueryNotePlugin(app, id, noteHooks); case 'python': return new NotePlugins.PythonNotePlugin(app, id, noteHooks); default: return noteHooks.plugin.call(app, store, engine, id) || new NotePlugins.DefaultNotePlugin(app); } }, }; ================================================ FILE: quix-frontend/client/src/react-components/file-explorer/FileExplorerComponent.scss ================================================ @import '../../lib/ui/assets/css/def/state.def'; @import '../../lib/ui/assets/css/def/colors.def'; @import '../../lib/ui/assets/css/text.scss'; @import '../../lib/file-explorer/directives/file-explorer.scss'; quix-file-explorer { .bi-spinner--xs { &:after { border-color: $dark-muted-color; border-right-color: transparent; } margin-right: 3px; } @for $i from 0 through 3 { .fe-item-depth-#{$i} { padding-left: $i * 12px + 6px; padding-right: 3px; } } .fe-item { border-left: 2px solid transparent; transition: border-color .2s; &:hover { border-color: $primary; } } } ================================================ FILE: quix-frontend/client/src/react-components/file-explorer/FileExplorerComponent.tsx ================================================ import './FileExplorerComponent.scss'; import * as _ from 'lodash'; import React, { useEffect, useState } from 'react'; import { v4 as uuid } from 'uuid'; import {TreeItem, Node} from './TreeItem'; const EXPAND_ALL_NODES_LIMIT = 3000; interface MenuOptionProps { title: string; action(sub: Tree, path: string[]): void; } export interface FileExplorerProps { tree: Tree[] | Tree; onTransformNode(node: Tree, path: string[]): Tree; onFetchChildren?(node: Tree, path: string[]): Promise; menuOptions: { [key:string]: MenuOptionProps[]; }; expandedNodes: boolean; highlight: string; } export interface Tree { id: string; name: string; type: string; transformed: boolean; lazy?: boolean; icon?: string; textIcon?: string; children?: Tree[]; } const countAllSubChildren = (node: Tree, withLazy: boolean = false, count = 0) => { if (!node.children || (!withLazy && node.lazy)) { return count; } const sum = node.children.length; const sumChildren = node.children.map(child => countAllSubChildren(child, withLazy, count)).reduce((a, b) => a + b, 0); return sum + sumChildren; } export const FileExplorer = (props: FileExplorerProps) => { const [innerTree, setInnerTree] = useState([]); useEffect(() => { const transformedNode = transformChildNodes( { children: Array.isArray(props.tree) ? props.tree : [props.tree] } as Node, [], ); setInnerTree(transformedNode.children); }, [props.tree]); const updateNode = (subNode: Node, transformedNode: Node, iteratorNode: Tree, path: string[]) => { const fullPath = [...path, transformedNode.id || subNode.id]; for (let i = 1; i < fullPath.length; i++) { iteratorNode = iteratorNode?.children.find(nodeProps => nodeProps.id === fullPath[i]); } iteratorNode.children = transformedNode.children; return iteratorNode; } const transformLazy = async (index: number, subNode: Node, path: string[]) => { const iteratorNode = innerTree[index]; const transformedNode = await transformChildNodesLazy(iteratorNode, subNode, path); return updateNode(subNode, transformedNode, iteratorNode, path); } const transform = (index: number, subNode: Node, path: string[]) => { const iteratorNode = innerTree[index]; const transformedNode = transformChildNodes(subNode, path); return updateNode(subNode, transformedNode, iteratorNode, path); } const transformChildNodesLazy = async (mainNode: Node, node: Node, path: string[]): Promise => { let transformedNode = node; if (node.lazy) { if (!_.isEqual(node.children, [{}])) { return node; } const fetchedChildren = await props.onFetchChildren(mainNode, [...path, node.id]); transformedNode = {children: fetchedChildren} as Node; } return transformChildNodes(transformedNode, path); } const transformChildNodes = (node: Node, path: string[]): Node => { const currentNode = _.cloneDeep(node); for (const [index, child] of currentNode.children.entries()) { if (!child.transformed) { const shouldBeLazy = !!child.children && !child.children.length; const transformedChild = props.onTransformNode(child, path); transformedChild.children = transformedChild.lazy && shouldBeLazy ? [{} as any] : transformedChild.children; transformedChild.id = transformedChild.id || uuid(); currentNode.children[index] = transformedChild; } } return currentNode; } const onMenuClick = (subNode: Node, option: { title: string }, path: string[], node: Node) => { (option as MenuOptionProps).action(node, [...path, subNode.id]) }; return (
      { innerTree.length !== 0 ? innerTree.map((sub, index) => ( onMenuClick(subNode, option, path, sub)} onTransformChildNodesLazy={(subNode, path) => transformLazy(index, subNode, path)} onTransformChildNodes={(subNode, path) => transform(index, subNode, path)} expandAllNodes={ props.expandedNodes && countAllSubChildren({children: innerTree} as Node) < EXPAND_ALL_NODES_LIMIT } path={[]} highlight={props.highlight || null} /> )) : null }
    ) } ================================================ FILE: quix-frontend/client/src/react-components/file-explorer/TreeItem.tsx ================================================ import React, {useEffect, useState} from 'react'; import _ from 'lodash'; import {TreeItemMenu} from './TreeItemMenu'; import {Highlighter} from '../../lib/ui/components/Highlighter'; export interface Node { id: string; name: string; type: string; transformed: boolean; lazy?: boolean; icon?: string; textIcon?: string; children?: Node[]; more?: boolean; } interface TreeItemProps { node: Node; menuOptions: { [key:string]: { title: string; }[]; }; path: string[]; highlight: string; expandAllNodes: boolean; onMenuClick(node: Node, option: { title: string }, path: string[]): void; onTransformChildNodes(node: Node, path: string[]): Node; onTransformChildNodesLazy(node: Node, path: string[]): Promise; } const InnerTreeItem = ({ node: initialNode, menuOptions, path, highlight, expandAllNodes, onMenuClick, onTransformChildNodes, onTransformChildNodesLazy, }: TreeItemProps) => { const [node] = useState(initialNode); const [isLoading, setIsLoading] = useState(false); const [expanded, setExpanded] = useState(false); const [clickedFirstTime, setClickedFirstTime] = useState(false); useEffect(() => { if (!node.lazy && expandAllNodes) { toggleNode(); } }, []); const onClick = async () => { if (!expanded) { toggleNode(); } else { setExpanded(false); } if (!clickedFirstTime) { setClickedFirstTime(true); } } const toggleNode = async () => { setExpanded(true); if (!node.children || !node.children.find(child => !child.transformed)) { return; } if (node.lazy) { setIsLoading(true); const transformedNode = await onTransformChildNodesLazy(node, path); node.children = transformedNode.children; setIsLoading(false); } else { const transformedNode = onTransformChildNodes(node, path); node.children = transformedNode.children; } } const preIcon = (_onClick: () => void) => ( isLoading ? : Array.isArray(node.children) ? expanded ? arrow_drop_down : arrow_right : null ) const describeIcon = ( node.textIcon ?
    {node.textIcon}
    : {node.icon || 'hourglass_empty'} ) const menu = ( menuOptions[node.type] ? onMenuClick(node, option, path)} /> : null ) const getText = () => { if (highlight && node.children) { return ( ); } return node.name; } return (
  • {preIcon(onClick)} {describeIcon} {getText()} {menu}
      { expanded && !isLoading ? node.children?.map(childNode => childNode.id && ) : null }
  • ) } function TreeItemPropsAreEqual(prevProps, nextProps) { const prevNode: Node = prevProps.node; const nextNode: Node = nextProps.node; return prevNode.id === nextNode.id; } export const TreeItem = React.memo(InnerTreeItem, TreeItemPropsAreEqual); ================================================ FILE: quix-frontend/client/src/react-components/file-explorer/TreeItemMenu.tsx ================================================ import React from 'react'; import {Dropdown} from '../../lib/ui/components/dropdown/Dropdown'; interface TreeItemMenuProps { menuOptions: { title: string; }[]; onMenuClick(option: { title: string; }): void; } export const TreeItemMenu = ({ menuOptions, onMenuClick, }: TreeItemMenuProps) => { return ( more_vert } placement="bottom-end" options={menuOptions} dynamicWidth={false} > {(options) =>
      {options.map((option) =>
    • { onMenuClick(option); }} > {option.title}
    • )}
    }
    ) } ================================================ FILE: quix-frontend/client/src/react-components/file-explorer/file-explorer-testkit.ts ================================================ import { Testkit } from '../../../test/e2e/driver'; const enum Hooks { FileExplorerTab = 'app-menu-DB Explorer', TreeItemContent = 'tree-item-content', TreeItemLoadingIcon = 'tree-item-loading-icon', TreeItemOpenedIcon = 'tree-item-opened-icon', TreeItemClosedIcon = 'tree-item-closed-icon', FileExplorerSearch = 'file-explorer-search', } export class FileExplorerTestkit extends Testkit { async toggleFileExplorerTab() { await this.click.hook(Hooks.FileExplorerTab); } async numOfTreeItems() { return (await this.query.hooks(Hooks.TreeItemContent)).length; } async numOfLoadingTreeItems() { return (await this.query.hooks(Hooks.TreeItemLoadingIcon)).length; } async numOfOpenedTreeItems() { return (await this.query.hooks(Hooks.TreeItemOpenedIcon)).length; } async numOfClosedTreeItems() { return (await this.query.hooks(Hooks.TreeItemClosedIcon)).length; } async clickOnTreeItemByPosition(position: number) { return (await this.query.hooks(Hooks.TreeItemContent))[position].click(); } async getTreeItemIndexByName(name: string) { const position = await this.evaluate.hooks( Hooks.TreeItemContent, (elements, args) => elements.findIndex(element => element.innerHTML === args.name), {name}); return position; } async isTreeItemExistsByName(name: string) { const res = await this.getTreeItemIndexByName(name); return res !== -1; } async clickOnItemByName(name: string) { const position = await this.getTreeItemIndexByName(name); return this.clickOnTreeItemByPosition(position); } async search(query: string) { return this.keyboard.type(Hooks.FileExplorerSearch, query); } } ================================================ FILE: quix-frontend/client/src/react-components/file-explorer/file-explorer.ts ================================================ import { IReactComponentConfig } from '../../lib/app/services/plugin-builder'; import {FileExplorer} from './FileExplorerComponent'; export default (): IReactComponentConfig => ({ name: 'File Explorer', template: FileExplorer, scope: ['tree', 'onTransformNode', 'onFetchChildren', 'menuOptions', 'expandedNodes', 'highlight'], }); ================================================ FILE: quix-frontend/client/src/react-components/index.ts ================================================ export {default as quixFileExplorer} from './file-explorer/file-explorer'; ================================================ FILE: quix-frontend/client/src/services/db.ts ================================================ export const sanitizeTableToken = (token: string, quoteChar: string) => { if (token.includes('.') || token.includes('-')) { return `${quoteChar}${token}${quoteChar}`; } return token; } ================================================ FILE: quix-frontend/client/src/services/dialog.ts ================================================ import { isArray } from 'lodash'; import { confirm } from '../lib/ui'; import { utils } from '../lib/core'; function contextText(context: any, type: string) { return isArray(context) ? `the (${context.length}) selected ${utils.dom.escape(type)}s` : `the ${utils.dom.escape(type)} "${utils.dom.escape( context.name )}"`; } function confirmActionTitle(action: string, type: string): string { switch (action) { case 'delete': return `${action} ${type}`; case 'trash': return `Move ${type} to Trash Bin`; default: return `Operation failed`; } } function actionText(action: string) { switch (action) { case 'trash': return 'move'; case 'delete': return 'delete'; default: return ''; } } function confirmHtml( action: string, context: any, type: string, customText: string ): string { const custom = customText ? `(${utils.dom.escape(customText)})` : ''; const areYouSure = 'Are you sure you want to ' + `${actionText(action)} ${contextText(context, type)}`; switch (action) { case 'delete': return `
    ${areYouSure} ${custom} ?
    `; case 'trash': return `
    ${areYouSure} to Trash Bin ${custom} ?
    `; default: return `${customText}`; } } export const confirmAction = ( action: 'delete' | 'trash' | 'retry', type: 'notebook' | 'note' | 'folder' | 'item', context: any, customText = '', onConfirm: (scope: any) => any = () => {} ) => { return confirm({ title: confirmActionTitle(action, type), actionType: { delete: 'destroy' }[action] || 'neutral', icon: { delete: 'delete_forever', retry: 'report' }[action] || null, yes: action === 'trash' ? 'move to trash bin' : action, onConfirm, html: confirmHtml(action, context, type, customText), }); }; export const prompt = ( { title, subTitle, yes, content, onConfirm, }: { title: string; subTitle?: string; yes: string; content: string; onConfirm?(scope: any): any; }, scope?, locals? ) => { return confirm( { title, subTitle, actionType: 'neutral', yes, html: `
    ${content}
    `, onConfirm, }, scope, locals ); }; ================================================ FILE: quix-frontend/client/src/services/files.ts ================================================ import { isArray, last, takeWhile } from 'lodash'; import { Store } from '../lib/store'; import { App } from '../lib/app'; import { IFile, FileActions, createFolder, IFilePathItem, FileType, TrashBinActions, } from '@wix/quix-shared'; import { isOwner } from './permissions'; import { cache } from '../store'; export const addFolder = async ( store: Store, app: App, parentOrPath: IFile | IFilePathItem[], props: Partial = {} ): Promise => { let path = isArray(parentOrPath) ? parentOrPath : [ ...parentOrPath.path, { id: parentOrPath.id, name: parentOrPath.name, }, ]; path = path.length ? path : await fetchRootPath(); const folder = createFolder(path, { ...props, owner: app.getUser().getEmail(), }); return store .logAndDispatch(FileActions.createFile(folder.id, folder)) .then(() => folder); }; export const deleteFolder = (store: Store, app: App, folder: IFile) => { const { id } = folder; return store .logAndDispatch(TrashBinActions.moveFolderToTrashBin(id)) .then(() => { if (store.getState('folder.folder')) { goUp(app, folder); } }); }; export const isRoot = (file: Pick) => { return !file.path.length && file.type === FileType.folder; }; export const fetchRoot = (): Promise => { return cache.files.get().then((files) => files.find(isRoot)); }; export const fetchFile = (id: string): Promise => { return cache.files .get() .then((files) => files.find((file) => file.id === id)); }; export const fetchFileByName = ( name: string, parent?: IFile ): Promise => { return cache.files .get() .then((files) => files.find( (file) => file.name === name && (!parent || (file.path.length && last(file.path).id === parent.id)) ) ); }; export const createFileByNamePath = ( store: Store, app: App, namePath: string[], fileCreator: (name: string, parent: IFile) => Promise ): Promise => { return (namePath.reduce>(async (res, name, index) => { const parent = await res; let file = await fetchFileByName(name, parent); if (!file) { const isFolder = index < namePath.length - 1; if (isFolder) { file = file || (await addFolder(store, app, parent, { name })); } else { file = fileCreator(name, parent) as any; } } return file; }, fetchRoot()) as unknown) as Promise; }; export const fetchFileParent = (id: string): Promise => { return fetchFile(id).then((file) => fetchFile(last(file.path).id)); }; export const fetchRootPath = (): Promise => { return fetchRoot().then( (file) => (file && [{ id: file.id, name: file.name }]) || [] ); }; export const goToFile = ( app: App, file: Pick, params: { isNew?: boolean; note?: string; } = { isNew: false, note: null, }, options?: any ) => { const id = isRoot(file) && isOwner(app, file) ? null : file.id; return app.go( file && file.type === FileType.notebook ? 'notebook' : 'files', { id, isNew: params.isNew, note: params.note, }, options ); }; export const goToRoot = (app: App) => { app.go('files', { id: null, isNew: false, }); }; export const goUp = (app: App, file: Pick) => { const pathItem = last(file.path); const folder = { ...pathItem, type: FileType.folder, path: takeWhile(file.path, (item) => item.id !== pathItem.id), owner: file.owner, }; goToFile(app, folder); }; ================================================ FILE: quix-frontend/client/src/services/hooks/index.ts ================================================ export * from './with-outside-click'; export * from './use-view-state'; ================================================ FILE: quix-frontend/client/src/services/hooks/use-view-state.ts ================================================ import { useState } from 'react'; export interface ViewStateActions { get(): S; set(s: S, d?: Partial): void; update(d: Partial): void; is(s: S): boolean; min(s: S): boolean; after(s: S): boolean; } export const useViewState = ( states: S[], defaultData: D, ) => { const [{ state, data }, setState] = useState({ state: states[0], data: defaultData, }); return [ data, { get: () => state, set: (s: S, d?: Partial) => setState((prevState) => ({ state: s, data: { ...prevState.data, ...d } })), update: (d: Partial) => setState((prevState) => ({ state, data: { ...prevState.data, ...d } })), is: (s: S) => s === state, min: (s: S) => states.indexOf(s) <= states.indexOf(state), after: (s: S) => states.indexOf(s) < states.indexOf(state), }, ] as const; }; ================================================ FILE: quix-frontend/client/src/services/hooks/with-outside-click.ts ================================================ import { useEffect } from 'react'; export const withOutsideClick = ( refs: React.MutableRefObject[], onClickOutside: () => void, ) => { useEffect(() => { const handler = (event: any) => { const inside: boolean[] = []; refs .filter((ref) => ref?.current) .forEach((ref) => { const parent = $(ref.current.parentElement); const target = $(event.target); if (!target.closest(parent).length || target.closest(event).length) { inside.push(false); } else { inside.push(true); } }); if (inside.length && inside.every((i) => !i)) { onClickOutside(); } }; $('body').on('click', handler); return () => { $('body').off('click', handler); }; }, [refs]); }; ================================================ FILE: quix-frontend/client/src/services/index.ts ================================================ export {addNotebook, deleteNotebook, saveQueuedNotes, hasQueuedNotes, goToExamples, copyNotebook, copyNote} from './notebook'; export {addFolder, deleteFolder, isRoot, goToFile, goToRoot, goUp, fetchRoot, fetchFile, fetchFileParent, fetchRootPath} from './files'; export {confirmAction, prompt} from './dialog'; export {StateManager} from './state'; export {getRunners} from './runners'; export {closePopup, openTempQuery, openSearchResults} from './popup'; export {extractTextAroundMatch as extractLinesAroundMatch} from './search'; export {browserNotificationsManager} from './notifications'; export {sanitizeTableToken} from './db'; export {subscribeToStateChanges} from './subscription'; export { IPermissions, isOwner, getDefaultPermissions, getFolderPermissions, getNotebookPermissions } from './permissions'; ================================================ FILE: quix-frontend/client/src/services/notebook.ts ================================================ import { isArray } from 'lodash'; import { Store } from '../lib/store'; import { App } from '../lib/app'; import { FileType, IFile, INotebook, INote, NotebookActions, createNotebook, NoteActions, IFilePathItem, createNote, TrashBinActions, } from '@wix/quix-shared'; import { fetchRootPath, goUp, goToFile, confirmAction } from './'; import { createFileByNamePath as addFileByNamePath } from './files'; import { pluginManager } from '../plugins'; import { setSaving } from '../store/notebook/notebook-actions'; const resolvePath = async (parentOrPath: IFile | IFilePathItem[]) => { const path = isArray(parentOrPath) ? parentOrPath : [ ...parentOrPath.path, { id: parentOrPath.id, name: parentOrPath.name, }, ]; return path.length ? path : fetchRootPath(); }; export const addNotebook = async ( store: Store, app: App, parentOrPath: IFile | IFilePathItem[], options: { addNote: boolean }, props: Partial = {} ): Promise => { const path = await resolvePath(parentOrPath); const notebook = createNotebook(path, { ...props, owner: app.getUser().getEmail(), }); const actions: any[] = [ NotebookActions.createNotebook(notebook.id, notebook), ]; if (options.addNote) { const types = pluginManager .module('note') .plugins() .filter((plugin) => plugin.getConfig().canCreate) .map((plugin) => plugin.getId()); const note = createNote(notebook.id, { type: types[0] }); actions.push(NoteActions.addNote(note.id, note)); } return store.logAndDispatch(actions).then(() => notebook); }; export const addNote = async ( store: Store, notebookId: string, type: string, props: Partial = {}, onCreate?: (note: INote) => void ): Promise => { const note = createNote(notebookId, { ...props, type }); return store .logAndDispatch(NoteActions.addNote(note.id, note)) .then(() => { if (onCreate) { onCreate(note); } return note; }) .catch(() => confirmAction( 'retry', 'note', note, 'Failed to create a new note. Please try again in a few moments.', () => addNote(store, notebookId, type, props, onCreate) ) ); }; export const addNotebookByNamePath = async ( store: Store, app: App, namePath: string[] ): Promise => { return addFileByNamePath(store, app, namePath, (name, parent) => addNotebook(store, app, parent, { addNote: false }, { name }) ); }; export const copyNotebook = async ( store: Store, app: App, parentOrPath: IFile | IFilePathItem[], sourceNotebook: INotebook ) => { const { name, notes } = sourceNotebook; const path = await resolvePath(parentOrPath); const newNotebook = createNotebook(path, { name: `Copy of ${name}`, owner: app.getUser().getEmail(), }); return store .logAndDispatch([ NotebookActions.createNotebook(newNotebook.id, newNotebook), ...notes.map(({ name: noteName, type, content, richContent, owner }) => { const note = createNote(newNotebook.id, { name: noteName, type, content, richContent, owner, } as any); return NoteActions.addNote(note.id, note); }), ]) .then(() => goToFile( app, { ...newNotebook, type: FileType.notebook }, { isNew: false } ) ) .then(() => newNotebook); }; export const copyNote = async ( store: Store, app: App, targetNotebook: INotebook, sourceNote: INote ) => { const { name, content, richContent, type } = sourceNote; const newNote = createNote(targetNotebook.id, { name: `Copy of ${name}`, type, content, richContent, owner: app.getUser().getEmail(), }); return store .logAndDispatch([NoteActions.addNote(newNote.id, newNote)]) .then(() => goToFile( app, { ...targetNotebook, type: FileType.notebook }, { isNew: false, note: newNote.id } ) ) .then(() => newNote); }; export const deleteNotebook = async ( store: Store, app: App, notebook: INotebook ) => { const { id } = notebook; store .dispatchAndLog(TrashBinActions.moveNotebookToTrashBin(id)) .then(() => goUp(app, notebook)); }; export const saveQueuedNotes = (store: Store) => { const { notes } = store.getState('notebook.queue') as { notes: Record; }; store.dispatch(setSaving(true)); return (store.logAndDispatch( Object.keys(notes).map((id) => NoteActions.updateContent(id, notes[id].content, notes[id].richContent) ) ) as any).finally(() => store.dispatch(setSaving(false))); }; export const hasQueuedNotes = (store: Store) => { return store.getState('notebook.queue.size') > 0; }; export const goToNotebook = ( app: App, notebook: INotebook, params?: { isNew?: boolean; note?: string }, options?: any ) => { return goToFile( app, { ...notebook, type: FileType.notebook }, params, options ); }; export const goToExamples = (app: App) => { app.go('notebook', { id: 'examples', note: 'simple', isNew: false, }); }; ================================================ FILE: quix-frontend/client/src/services/notifications.ts ================================================ import {isFunction} from 'lodash'; interface INotificationTemplate { name: string; icon: string; title: string; body: ((...args: any[]) => string) | string; onlyWhenHidden: boolean; onClick?(window: Window): void; } class BrowserNotificationsManager { private staticsBaseUrl: string; private readonly Notification = typeof Notification === 'undefined' ? null : Notification; private readonly templates: Record = {}; constructor() { if (this.Notification && this.Notification.permission === 'default') { this.Notification.requestPermission(); } } private fixUrl(url: string) { return `${this.staticsBaseUrl}${url}`; } setStaticsBaseUrl(staticsBaseUrl: string) { this.staticsBaseUrl = staticsBaseUrl; } register(template: INotificationTemplate) { this.templates[template.name] = template; } notify(templateName: string, ...args: any[]) { const template = this.templates[templateName]; if (!this.Notification || !template) { return; } let body: string; if (!template.onlyWhenHidden || window.document.hidden) { if (isFunction(template.body)) { body = template.body(...args); } else { body = template.body; } const notification = new this.Notification(template.title, {body, icon: this.fixUrl(template.icon)}); if (template.onClick) { notification.onclick = template.onClick.bind(notification, window); } } } } export const browserNotificationsManager = new BrowserNotificationsManager(); ================================================ FILE: quix-frontend/client/src/services/permissions.ts ================================================ import {App} from '../lib/app'; import {IEntity, IFile} from '@wix/quix-shared'; import {isRoot} from './files'; export interface IPermissions { edit?: boolean; delete?: boolean; rename?: boolean; clone?: boolean; like?: boolean; share?: boolean; bulk?: IPermissions; } export interface IFolderPermissions extends IPermissions{ addFolder?: boolean; addNotebook?: boolean; } export interface INotebookPermissions extends IPermissions{ addNote?: boolean; note?: IPermissions & { reorder?: boolean; }; bulk?: INotebookPermissions & { reorder?: boolean; }; } export const isOwner = (app: App, entity: Pick) => { return entity.owner === app.getUser().getEmail(); } export const getDefaultPermissions = (): IPermissions => { return { edit: false, delete: false, rename: false, clone: false, like: false, bulk: null }; } export const getFolderPermissions = (app: App, folder: IFile): IFolderPermissions => { const isFolderOwner = isOwner(app, folder); const isRootFolder = isRoot(folder); return { edit: isFolderOwner, delete: isFolderOwner && !isRootFolder, rename: isFolderOwner && !isRootFolder, clone: false, like: false, share: true, addFolder: isFolderOwner && folder.path.length < 2, addNotebook: isFolderOwner, bulk: { delete: isFolderOwner, rename: false, clone: false, like: false, } }; } export const getNotebookPermissions = (app: App, folder: IFile): INotebookPermissions => { const isFolderOwner = isOwner(app, folder); return { edit: isFolderOwner, delete: isFolderOwner, rename: isFolderOwner, addNote: isFolderOwner, clone: true, like: true, share: true, note: { edit: isFolderOwner, delete: isFolderOwner, rename: isFolderOwner, reorder: isFolderOwner, clone: true, like: false, share: true, }, bulk: { delete: isFolderOwner, reorder: isFolderOwner, clone: false, like: false, }, }; } ================================================ FILE: quix-frontend/client/src/services/plugins/index.ts ================================================ export * from './plugin-manager'; export * from './plugin-types'; ================================================ FILE: quix-frontend/client/src/services/plugins/plugin-manager.ts ================================================ import {App} from '../../lib/app'; import {TModuleComponentType, ModuleEngineType} from '@wix/quix-shared'; import {Plugin, TPluginMap, resolvePluginType} from './plugin-types'; import { Store } from '../../lib/store'; export class PluginManager { private readonly pool: Plugin[] = []; constructor(private readonly pluginFactory: any, public readonly hooks: H) {} private getPluginById( id: string, type: T, ): TPluginMap[T] { const PluginClass = resolvePluginType(type); return this.pool.find( p => p.getId() === id && p instanceof PluginClass, ) as any; } private getPluginsByType( type: T, ): TPluginMap[T][] { const PluginClass = resolvePluginType(type); return this.pool.filter(p => p instanceof PluginClass) as any; } module(type: T) { return { plugin: (id: string, engine?: ModuleEngineType, app?: App, store?: Store) => { if (engine) { const plugin = this.pluginFactory[type](app, store, id, engine, this.hooks); if (plugin) { this.pool.push(plugin); } } return ( this.getPluginById(id, type) || this.getPluginById('default', type) ); }, plugins: () => { return this.getPluginsByType(type); }, }; } } ================================================ FILE: quix-frontend/client/src/services/plugins/plugin-types.ts ================================================ import {IFile, TModuleComponentType, ModuleEngineType, INote} from '@wix/quix-shared'; import { Time } from '../../config'; import {App} from '../../lib/app'; import formatter from '../../lib/sql-formatter/sqlFormatter'; interface CustomAction { icon: string; title: string; permissions: string; handler(note: INote): INote; } export const resolvePluginType = (type: TModuleComponentType) => { if (PluginMap[type]) { return PluginMap[type]; } throw new Error(`"${type}" doesn't mach any known plugin type`); }; export class Plugin { constructor( app: App, protected readonly id: string, protected readonly engine: ModuleEngineType, hooks: any, ) {} public getId() { return this.id; } public getEngine() { return this.engine; } } export class NotePlugin extends Plugin { constructor( app: App, id: string, engine: ModuleEngineType, hooks: any, private readonly config: { syntaxValidation: boolean; canCreate: boolean; dateFormat?: string; enableQueryFormatter?: boolean; }, ) { super(app, id, engine, hooks); this.config.dateFormat = this.config.dateFormat || Time.Format; } getConfig() { return this.config; } formatStats(stats: {[key: string]: any}) { return []; } renderRunner() { return ` `; } getCustomActions(): CustomAction[] { const res: CustomAction[] = []; if (this.config.enableQueryFormatter) { res.push({ icon: 'format_paint', title: 'Format query', permissions: 'edit', handler: (note: INote) => { note.content = formatter.format(note.content, {upperCase: true, language: 'quixsql'}); return note; } }) } return res; } } export class DbPlugin extends Plugin { constructor(app: App, id: string, engine: ModuleEngineType, hooks: any) { super(app, id, engine, hooks); } getSampleQuery(table: IFile): string { throw new Error(`No default implementation`); } } export const PluginMap = { note: NotePlugin, db: DbPlugin, }; export type TPluginMap = { [K in keyof typeof PluginMap]: InstanceType; }; ================================================ FILE: quix-frontend/client/src/services/popup.ts ================================================ import {assign} from 'lodash'; import {inject} from '../lib/core'; import {singletone} from '../utils'; const popup = singletone(); export const closePopup = () => popup((scope, element) => { element.remove(); scope.$destroy(); return null; }); const openPopup = (html: string, scope, locals: Record = {}) => { if (popup()) { return () => {}; } const popupScope: any = assign(scope.$new(true), locals, { events: { onLoad(instance) { inject('$timeout')(() => instance.toggle()); }, onToggle(maximized: boolean) { if (!maximized) { closePopup(); } } } }); const element = inject('$compile')(`
    ${html}
    `)(popupScope).appendTo(document.body); closePopup()(popupScope, element); return closePopup; } export const openSearchResults = (scope) => { const closeFn = openPopup(` `, scope); popup((_, element) => element.addClass('quix-search-popup')); return closeFn; } export const openTempQuery = (scope, type?: string, code: string = '', autorun = false) => { return openPopup(` `, scope, { type, code, autorun } ); } ================================================ FILE: quix-frontend/client/src/services/resources.ts ================================================ import { mapValues } from 'lodash'; import { inject, Config } from '../lib/core'; import { IFile, IFolder, INotebook, SearchResult, IUser, IHistory, IDeletedNotebook, } from '@wix/quix-shared'; export const config = new Config<{ apiBasePath: string; }>(); const api = (endpoint: TemplateStringsArray) => `${config.get().apiBasePath}/api/` + endpoint[0]; const resource = ( action: 'get' | 'query', endpoint: string, params: Record ) => inject('$resource')( endpoint, mapValues(params, (v, k) => `@${k}`) )[action](params).$promise; const one = ( endpoint: string, params: Record = {} ): Promise => resource('get', endpoint, params); const many = ( endpoint: string, params: Record = {} ): Promise => resource('query', endpoint, params); export const users = () => many(api`users`); export const history = (options) => many(api`history`, { offset: options.offset, limit: options.limit, user: options.user, query: options.query, }); export const files = () => many(api`files`); export const folder = (id: string) => one(api`files/:id`, { id }); export const notebook = (id: string) => one(api`notebook/:id`, { id }); export const favorites = () => many(api`favorites`); export const search = (text: string, offset: number, total: number) => one(api`search/:text`, { text, offset, total, }); export const deletedNotebooks = () => many(api`deletedNotebooks`); export const db = (type: string) => many(api`db/:type/explore`, { type }); export const dbColumns = ( type: string, catalog: string, schema: string, table: string ) => one(api`db/:type/explore/:catalog/:schema/:table`, { type, catalog, schema, table, }); export const dbSearch = (type: string, q: string) => many(api`db/:type/search`, { type, q }); ================================================ FILE: quix-frontend/client/src/services/runners.ts ================================================ import {fromPairs} from 'lodash'; import {App} from '../lib/app'; import {Store} from '../lib/store'; import {Runner} from '../lib/runner'; import {browserNotificationsManager} from '../services/notifications'; import {INotebook, INote} from '@wix/quix-shared'; import {hooks} from '../hooks'; const runners = new Map(); const computeFinishState = (runner: Runner) => { const status = runner.getState().getStatus(); if (status.error) { return 'error'; } if (status.killed) { return 'killed'; } return 'finished'; } export const addRunner = (app: App, store: Store, id: string, runner: Runner, note: INote, notebook: INotebook) => { hooks.note.runStart.call(app, store, note, runner); runner.on('finish', (r: Runner) => { const status = computeFinishState(r); if (status === 'finished') { browserNotificationsManager.notify('runnerFinished', note, notebook); } else { browserNotificationsManager.notify('runnerError', note, notebook); } hooks.note.runFinish.call(app, store, note, runner); }); runners.set(id, runner); } export const removeRunner = (id: string) => { runners.delete(id); } export const getRunner = (id: string) => { return runners.get(id); } export const getRunners = () => fromPairs([...runners.entries()]); ================================================ FILE: quix-frontend/client/src/services/scope.ts ================================================ import {mapValues} from 'lodash'; import {Store} from '../lib/store'; export function initEvents(scope, conf, app, store: Store, events) { conf.withEvents(mapValues(events, event => (event as any)(scope, store, app))); scope.$on('$destroy', () => scope.events.$onDestroy && scope.events.$onDestroy()) } ================================================ FILE: quix-frontend/client/src/services/search.ts ================================================ import {findIndex} from 'lodash'; export const extractTextAroundMatch = (text: string, match: string, numOfWrappingLines = 2) => { match = match.toLowerCase(); const lines = text.split('\n'); const index = findIndex(lines, line => line.toLowerCase().indexOf(match) !== -1); return lines .slice(Math.max(0, index - numOfWrappingLines), Math.min(lines.length, index + 1 + numOfWrappingLines)) .join('\n'); } ================================================ FILE: quix-frontend/client/src/services/state.ts ================================================ import {assign} from 'lodash'; const keys = e => Object.keys(e).filter(k => typeof e[k as any] === 'number'); const values = e => keys(e).map(k => e[k as any]); class State { constructor(public index: number = -1) {} } export class StateManager { private current: State; private readonly val = {}; constructor(private readonly states: E) { this.current = new State(values(states)[0]); } is(state: keyof E) { return this.states[state] === this.current.index as any; } before(state: keyof E) { return this.current.index as any < this.states[state] as any; } after(state: keyof E) { return this.current.index as any > this.states[state] as any; } get() { return this.states[this.current.index]; } set(state: keyof E, condition: boolean | Function = true, value: Record | Function = null) { if (this.after(state) || (typeof condition === 'function' ? !condition(this.val) : !condition)) { return new NullStateManager(); } this.current = new State(this.states[state] as any); this.value(value); return this; } force(state: keyof E, condition: boolean | Function = true, value: Record | Function = null) { if ((typeof condition === 'function' ? !condition(this.val) : !condition)) { return new NullStateManager(); } this.current = new State(this.states[state] as any); this.value(value); return this; } value(val?: Record | Function) { if (typeof val === 'undefined') { return this.val; } assign(this.val, typeof val === 'function' ? val(this.val) : val); return this; } then(fn: Function) { fn(this); return this; } else(fn: Function) { return this; } } class NullStateManager { is() { return this; } before() { return this; } after() { return this; } set() { return this; } value() { return null; } then() { return this; } else(fn: Function) { fn(); return this; } } ================================================ FILE: quix-frontend/client/src/services/subscription.ts ================================================ import {ClientConfigHelper} from '@wix/quix-shared'; import {Store, sessionId} from '../lib/store'; import {App} from '../lib/app'; export const subscribeToStateChanges = (app: App, store: Store) => { const ws = new WebSocket(`${location.protocol.replace('http', 'ws')}//${location.host}${app.getConfig().getClientTopology().apiBasePath}/subscription`); ws.onopen = () => { ws.onmessage = (message: MessageEvent) => { store.dispatch(JSON.parse(message.data).data); }; ws.send(JSON.stringify({ event: 'subscribe', data: {sessionId} })); }; } ================================================ FILE: quix-frontend/client/src/state-components/base/base.html ================================================
    ================================================ FILE: quix-frontend/client/src/state-components/base/base.ts ================================================ import template from './base.html'; import {ClientConfigHelper} from '@wix/quix-shared'; import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {setUrlSearchText, setSearchPage} from '../../store/app/app-actions'; import {openSearchResults, closePopup, hasQueuedNotes, subscribeToStateChanges} from '../../services'; export default (app: App, store: Store) => ({ name: '', abstract: true, template, url: { urlSearchText: setUrlSearchText, searchPage: page => setSearchPage(page && parseInt(page, 10)) }, scope: {}, controller: (scope, params, {syncUrl}) => { syncUrl(); subscribeToStateChanges(app, store); store.subscribe('app.inputSearchText', text => text ? openSearchResults(scope) : closePopup(), scope); window.onbeforeunload = () => hasQueuedNotes(store) || undefined; }, link: (scope) => { } }) as IStateComponentConfig; ================================================ FILE: quix-frontend/client/src/state-components/embed/embed.ts ================================================ import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IStateComponentConfig} from '../../lib/app/services/plugin-builder'; export default (app: App, store: Store) => ({ name: 'embed', abstract: true, template: '
    ', url: {}, scope: {}, controller: (scope, params, {syncUrl}) => { }, link: (scope) => { }, onEnter() { app.toggleHeader(false); app.toggleMenu(false); } }) as IStateComponentConfig; ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note-events.ts ================================================ import { takeWhile } from 'lodash'; import { utils } from '../../../lib/core'; import { Store } from '../../../lib/store'; import { toast } from '../../../lib/ui'; import { App } from '../../../lib/app'; import { INote, NotebookActions, IFile, NoteActions, INotebook, IFilePathItem, } from '@wix/quix-shared'; import { FileType } from '@wix/quix-shared/dist/entities/file'; import { IScope } from './embed-note-types'; import { setNotebook, setNote, queueNote, toggleMark, unmarkAll, } from '../../../store/notebook/notebook-actions'; import { saveQueuedNotes, deleteNotebook, copyNotebook, goToFile, goToRoot, prompt, copyNote, } from '../../../services'; import { removeRunner, addRunner } from '../../../store/app/app-actions'; import { addNote } from '../../../services/notebook'; export const onBreadcrumbClick = (scope: IScope, store: Store, app: App) => ( file: IFilePathItem ) => { const { notebook: { owner, path }, } = scope.vm.state.value(); goToFile(app, { ...file, owner, type: FileType.folder, path: takeWhile(path, (item) => item.id !== file.id), }); }; export const onGoToRootClick = ( scope: IScope, store: Store, app: App ) => () => { goToRoot(app); }; export const onNameChange = (scope: IScope, store: Store, app: App) => ( file: IFile ) => { if (!scope.permissions.edit) { return; } const { id, name } = file; store.dispatchAndLog(NotebookActions.updateName(id, name)); }; export const onDelete = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { if (!scope.permissions.edit) { return; } deleteNotebook(store, app, notebook).then(() => toast.showToast( { text: `Deleted notebook "${notebook.name}"`, type: 'success', }, 3000 ) ); }; export const onClone = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { prompt( { title: 'Clone notebook', subTitle: 'Choose destination folder', yes: 'clone', content: ``, onConfirm: ({ model: { folder } }) => copyNotebook(store, app, folder, { ...notebook, notes: scope.vm.state.value().notes, }), }, scope, { model: { folder: null } } ).then((res) => toast.showToast( { text: `Cloned notebook as "${res.name}"`, type: 'success', }, 3000 ) ); }; export const onShare = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { utils.copyToClipboard(app.getNavigator().getUrl(null, { id: notebook.id })); toast.showToast( { text: 'Copied notebook url to clipboard', type: 'success', }, 3000 ); }; export const onLikeToggle = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { const { id, isLiked } = notebook; store .dispatchAndLog(NotebookActions.toggleIsLiked(id, !isLiked)) .then((action) => toast.showToast( { text: action.isLiked ? 'Added notebook to favorites' : 'Removed notebook from favorites', type: 'success', }, 3000 ) ); }; export const onSave = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onRun = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onNoteSave = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onNoteRun = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onNoteAdd = (scope: IScope, store: Store, app: App) => ( type: any = scope.vm.noteTypes[0] ) => { if (!scope.permissions.edit) { return; } const { notebook } = scope.vm.state.value(); addNote(store, notebook.id, type, {}, (note) => { scope.vm.notes.get(note).focusName = true; store.dispatch(setNote(note)); }); }; export const onNoteClone = (scope: IScope, store: Store, app: App) => ( note: INote ) => { prompt( { title: 'Clone note', subTitle: 'Choose destination notebook', yes: 'clone', content: ``, onConfirm: ({ model: { notebook } }) => copyNote(store, app, notebook, note), }, scope, { model: { notebook: null } } ).then((res) => toast.showToast( { text: `Cloned note as "${res.name}"`, type: 'success', }, 3000 ) ); }; export const onNoteShare = (scope: IScope, store: Store, app: App) => ( note: INote ) => { const { notebook } = scope.vm.state.value(); utils.copyToClipboard( app.getNavigator().getUrl(null, { id: notebook.id, note: note.id }) ); toast.showToast( { text: 'Copied note url to clipboard', type: 'success', }, 3000 ); }; export const onNoteDelete = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatchAndLog(NoteActions.deleteNote(note.id)).then(() => toast.showToast( { text: `Deleted note "${note.name}"`, type: 'success', }, 3000 ) ); }; export const onNoteContentChange = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatch(queueNote(note)); }; export const onNoteNameChange = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatchAndLog(NoteActions.updateName(note.id, note.name)); }; export const onNoteReorder = (scope: IScope, store: Store, app: App) => ( e: any, { item }: any ) => { if (!scope.permissions.edit) { return; } const { model: note, dropindex: index } = item.sortable; if (typeof index !== 'undefined') { store.dispatchAndLog(NoteActions.reorderNote(note.id, index)); } }; export const onMarkToggle = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatch(toggleMark(note)); }; export const onMarkedNotesDelete = (scope: IScope, store: Store, app: App) => ( notes: INote[] ) => { if (!scope.permissions.edit) { return; } store .dispatchAndLog(notes.map((note) => NoteActions.deleteNote(note.id))) .then(() => toast.showToast( { text: `Deleted ${notes.length} notes`, type: 'success', }, 3000 ) ); }; export const onUnmarkAll = (scope: IScope, store: Store, app: App) => () => { store.dispatch(unmarkAll()); }; export const onRunnerCreated = (scope: IScope, store: Store) => ( note, runner ) => { store.dispatch( addRunner(note.id, runner, note, scope.vm.state.value().notebook) ); }; export const onRunnerDestroyed = (scope: IScope, store: Store) => (note) => { store.dispatch(removeRunner(note.id)); }; export const $onDestroy = (scope: IScope, store: Store, app: App) => () => { if (scope.permissions.edit) { saveQueuedNotes(store); } store.dispatch(setNotebook(null)); }; ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note-reactions.ts ================================================ import {INote} from '@wix/quix-shared'; export function setError(scope: ng.IScope, error: any) { scope.vm.state.force('Error', !!error, {error}); } export function setNote(scope: ng.IScope, note: INote) { scope.vm.state.set('Content', !!note, {note}); } ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note-scope.ts ================================================ import * as Reactions from './embed-note-reactions'; export const error = (scope, value) => Reactions.setError(scope, value); export const permissions = x => x; export const view = { note: (scope, value) => Reactions.setNote(scope, value), }; ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note-url.ts ================================================ import {find} from 'lodash'; import {INote} from '@wix/quix-shared'; import {setNote} from '../../../store/notebook/notebook-actions'; export const note = (id: string, notes: INote[]) => setNote(id && find(notes, {id})); ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note-vm.ts ================================================ import {StateManager} from '../../../services/state'; import {App} from '../../../lib/app'; enum States { Initial, Error, Content } export default (app: App) => ({ $init() { this.state = new StateManager(States); } }); ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note.html ================================================
    Loading note...
    {{::vm.state.value().error.message}}
    ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note.scss ================================================ @import '../../../lib/ui/assets/css/def/colors.def'; quix-notebook { .quix-note-container { position: relative; &.quix-note-container--editable { padding-left: 8px; } } } ================================================ FILE: quix-frontend/client/src/state-components/embed/note/embed-note.ts ================================================ import template from './embed-note.html'; import './embed-note.scss'; import {initNgScope} from '../../../lib/core'; import {Store} from '../../../lib/store'; import {App} from '../../../lib/app'; import {IStateComponentConfig} from '../../../lib/app/services/plugin-builder'; import {cache} from '../../../store'; import VM from './embed-note-vm'; import * as Url from './embed-note-url'; import * as Scope from './embed-note-scope'; export default (app: App, store: Store) => ({ name: 'embed.notebook:id', template, url: Url, scope: Scope, controller: async (scope: ng.IScope, params, {syncUrl}) => { await cache.notebook.fetch(params.id); syncUrl(() => [store.getState('notebook.notes') || []]); store.subscribe('notebook', ({error, permissions, view}) => { scope.error = error; scope.permissions = permissions; scope.view = view; }, scope); }, link: scope => { initNgScope(scope).withVM(VM(app)); } }) as IStateComponentConfig; ================================================ FILE: quix-frontend/client/src/state-components/favorites/FavoritesComponent.tsx ================================================ import React, {useEffect} from 'react'; import {IFile} from '@wix/quix-shared'; import {cloneDeep} from 'lodash'; import {favoritesTableFields} from './favorites-table-fields'; import {useViewState} from '../../services/hooks'; import {Table} from '../../lib/ui/components/table/Table'; import {EmptyState, ErrorState, InitialState} from '../../lib/ui/components/states'; export interface FavoritesProps { favorites: IFile[]; error: {message: string}; onFavoriteClick(favorite: IFile): void; onLikeToggle(favorite: IFile): void; emptyStateImgSrc: string; } const States = [ 'Initial', 'Error', 'Empty', 'Content', ]; export function Favorites(props: FavoritesProps) { const {favorites: serverFavorites, error, onFavoriteClick, onLikeToggle: onLikeToggleServer} = props; const [stateData, viewState] = useViewState(States, { favorites: [], emailFilter: '', errorMessage: '', }); useEffect(() => { if (!error && serverFavorites?.length >= 0) { viewState.set(serverFavorites?.length ? 'Content' : 'Empty', {favorites: serverFavorites || []}); } },[serverFavorites]); useEffect(() => { if (error) { viewState.set('Error', {errorMessage: error.message}); } }, [error]); const onLikeToggle = (file: IFile) => { const tempFavorites = cloneDeep(stateData.favorites); const currentFile = tempFavorites.find(favorite => favorite.id === file.id); currentFile.isLiked = !currentFile.isLiked; onLikeToggleServer(file); viewState.set('Content', {favorites: tempFavorites}); } const renderContentState = () => ( ({ header: field.title || field.name, render: row => field.filter(undefined, row), accessor: field.name, className: field.className, }))} data={stateData.favorites} onRowClicked={row => onFavoriteClick(row)} /> ); return (
    Favorites {viewState.min('Empty') && ({stateData.favorites.length})}
    { (() => { switch(viewState.get()) { case 'Initial': return ; case 'Error': return ; case 'Empty': return ; case 'Content': return renderContentState(); default: } })() }
    ); } ================================================ FILE: quix-frontend/client/src/state-components/favorites/favorites-events.ts ================================================ import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IFile, NotebookActions} from '@wix/quix-shared'; import {goToFile} from '../../services'; import {toast} from '../../lib/ui'; export const onFavoriteClick = (app: App) => (favorite: IFile) => { goToFile(app, favorite); }; export const onLikeToggle = (store: Store) => (file: IFile) => { const {id, isLiked} = file; store .dispatchAndLog(NotebookActions.toggleIsLiked(id, !isLiked)) .then(action => toast.showToast( { text: action.isLiked ? 'Added notebook to favorites' : 'Removed notebook from favorites', type: 'success' }, 3000 ) ); }; ================================================ FILE: quix-frontend/client/src/state-components/favorites/favorites-table-fields.tsx ================================================ import * as React from 'react'; import {IFile} from '@wix/quix-shared'; import {RowConfig} from '../../lib/ui/components/table/TableRow'; import classNames from 'classnames'; import { UserAvatarAndName } from '../../components/User/UserAvatarAndName'; export const favoritesTableFields = (onLikeToggle): RowConfig[] => [ { name: 'name', title: 'Name', filter(_, file: IFile) { return (
    insert_drive_file {file.name}
    ); } }, { name: 'ownerDetails', title: 'User', filter(_, file: IFile) { return ; } }, { name: 'isLiked', title: ' ', filter(_, file: IFile) { return (
    { e.stopPropagation(); onLikeToggle(file); }} > {file.isLiked ? 'favorite' : 'favorite_border'}
    ); } } ]; ================================================ FILE: quix-frontend/client/src/state-components/favorites/favorites-testkit.ts ================================================ import { TableTestkit } from '../../lib/ui/components/table/table-testkit'; const enum Hooks { Table = 'favorites-table' } export class FavoritesTestkit extends TableTestkit { favoritesTableExists = async () => { return (await this.query.hook(Hooks.Table)) !== null; } } ================================================ FILE: quix-frontend/client/src/state-components/favorites/favorites.scss ================================================ @import '../../lib/ui/assets/css/def/colors.def'; quix-favorites { } ================================================ FILE: quix-frontend/client/src/state-components/favorites/favorites.ts ================================================ import './favorites.scss'; import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IReactStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {cache} from '../../store'; import {Favorites, FavoritesProps} from './FavoritesComponent'; import {onFavoriteClick, onLikeToggle} from './favorites-events'; import _noop from 'lodash/noop'; export default (app: App, store: Store): IReactStateComponentConfig => ({ name: 'favorites', template: Favorites, url: {}, scope: { favorites: _noop, error: _noop, onFavoriteClick: _noop, onLikeToggle: _noop }, controller: async (scope: FavoritesProps, params, {syncUrl, setTitle}) => { await cache.favorites.fetch(params.id); syncUrl(); setTitle(); store.subscribe( 'favorites', ({favorites, error}) => { scope.favorites = favorites; scope.error = error; }, scope ); scope.onFavoriteClick = onFavoriteClick(app); scope.onLikeToggle = onLikeToggle(store); } }); ================================================ FILE: quix-frontend/client/src/state-components/files/files-events.ts ================================================ import { takeWhile } from 'lodash'; import { Store } from '../../lib/store'; import { utils } from '../../lib/core'; import { toast } from '../../lib/ui'; import { App } from '../../lib/app'; import { IScope } from './files-types'; import { IFile, FileActions, NotebookActions, FileType, IFilePathItem, TrashBinActions, } from '@wix/quix-shared'; import { addNotebook, goToNotebook } from '../../services/notebook'; import { addFolder, deleteFolder, goToFile, goToRoot, } from '../../services/files'; import { setFolder, toggleMark, unmarkAll, } from '../../store/folder/folder-actions'; export const onNameChange = (scope: IScope, store: Store, app: App) => ( folder: IFile ) => { const { id, name } = folder; store.dispatchAndLog(FileActions.updateName(id, name)); }; export const onChildNameChange = (scope: IScope, store: Store, app: App) => ( file: IFile ) => { onNameChange(scope, store, app)(file); }; export const onDelete = (scope: IScope, store: Store, app: App) => ( folder: IFile ) => { deleteFolder(store, app, folder).then(() => toast.showToast( { text: `Deleted folder "${folder.name}"`, type: 'success', }, 3000 ) ); }; export const onShare = (scope: IScope, store: Store, app: App) => ( folder: IFile ) => { const { id } = folder; utils.copyToClipboard(app.getNavigator().getUrl(null, { id })); toast.showToast( { text: 'Copied folder url to clipboard', type: 'success', }, 3000 ); }; export const onLikeToggle = (scope: IScope, store: Store, app: App) => ( file: IFile ) => { const { id, isLiked } = file; store.dispatchAndLog( file.type === FileType.folder ? FileActions.toggleIsLiked(id, !isLiked) : NotebookActions.toggleIsLiked(id, !isLiked) ); }; export const onBreadcrumbClick = (scope: IScope, store: Store, app: App) => ( file: IFilePathItem ) => { const { folder: { owner, path }, } = scope.vm.state.value(); goToFile(app, { ...file, owner, type: FileType.folder, path: takeWhile(path, (item) => item.id !== file.id), }); }; export const onFileClick = (scope: IScope, store: Store, app: App) => ( file: IFile ) => { goToFile(app, file); }; export const onGoToRootClick = ( scope: IScope, store: Store, app: App ) => () => { goToRoot(app); }; export const onFolderAdd = (scope: IScope, store: Store, app: App) => () => { const { folder } = scope.vm.state.value(); addFolder(store, app, folder).then( (newFolder) => (scope.vm.files.get(newFolder).isNew = true) ); }; export const onNotebookAdd = (scope: IScope, store: Store, app: App) => () => { const { folder } = scope.vm.state.value(); addNotebook(store, app, folder, { addNote: true }).then((notebook) => { return goToNotebook(app, notebook, { isNew: true }); }); }; export const onMarkToggle = (scope: IScope, store: Store, app: App) => ( file: IFile ) => { store.dispatch(toggleMark(file)); }; export const onUnmarkAll = (scope: IScope, store: Store, app: App) => () => { store.dispatch(unmarkAll()); }; export const onMarkedDelete = (scope: IScope, store: Store, app: App) => ( files: IFile[] ) => { store .dispatchAndLog( files.map((file) => file.type === FileType.folder ? TrashBinActions.moveFolderToTrashBin(file.id) : TrashBinActions.moveNotebookToTrashBin(file.id) ) ) .then(() => toast.showToast( { text: `Deleted ${files.length} items`, type: 'success', }, 3000 ) ); }; export const $onDestroy = (scope: IScope, store: Store, app: App) => () => { store.dispatch(setFolder(null)); }; ================================================ FILE: quix-frontend/client/src/state-components/files/files-reactions.ts ================================================ import {IScope} from './files-types'; import {initTableFields} from './files-table-fields'; import {IFolder, IFile} from '@wix/quix-shared'; export function setFolder(scope: IScope, folder: IFolder) { scope.vm.state .set('Result', !!folder, {folder}) .then(() => { scope.vm.breadcrumbs = [...folder.path, {id: folder.id, name: folder.name}]; if (!scope.permissions.edit) { scope.vm.breadcrumbs[0].name = `${folder.ownerDetails.name}'s notebooks`; } }) .else(() => scope.vm.state.value({folder})); } export function setFiles(scope: IScope, files: IFile[]) { scope.vm.state .force('Result', !!files, {files}) .set('Content', () => !!files.length, {files}) .then(() => scope.vm.fields = initTableFields(scope)); } export function setError(scope: IScope, error: any) { scope.vm.state.force('Error', !!error, {error}); } export function setMarkedMap(scope: IScope, markedMap: Record) { scope.vm.marked.map = markedMap; } export function setMarkedList(scope: IScope, markedList: IFile[]) { scope.vm.marked.list = markedList; scope.vm.marked.toggle(!!markedList.length); } ================================================ FILE: quix-frontend/client/src/state-components/files/files-scope.ts ================================================ import * as Reactions from './files-reactions'; export const folder = (scope, value) => Reactions.setFolder(scope, value); export const files = (scope, value) => Reactions.setFiles(scope, value); export const error = (scope, value) => Reactions.setError(scope, value); export const permissions = x => x; export const isRoot = x => x; export const view = { fileError: (scope, value) => Reactions.setError(scope, value), markedMap: (scope, value) => Reactions.setMarkedMap(scope, value), markedList: (scope, value) => Reactions.setMarkedList(scope, value), }; ================================================ FILE: quix-frontend/client/src/state-components/files/files-table-fields.ts ================================================ import {IFile} from '@wix/quix-shared'; export const initTableFields = scope => { const fields = []; if (scope.permissions.edit) { fields.push({ name: 'mark', title: ' ', sort: false, filter(_, file, index, compile) { return compile(` check_box_outline check_box_outline_blank `, {file}, scope); } }); } return [...fields, ...[{ name: 'name', sort(_, file) { return `${file.type === 'folder' ? 0 : 1}${file.name}`; }, filter(_, file: IFile, index, compile) { return compile(`
    {{::file.type === 'folder' ? 'folder' : 'insert_drive_file'}} {{::file.name}}
    `, {file, vm: scope.vm.files}, scope); } }, { name: 'dateCreated', filter(_, file: IFile, index, compile) { return compile(` {{::file.dateCreated | biRelativeDate}} `, {file}, scope); } }, { name: 'dateUpdated', filter(_, file: IFile, index, compile) { return compile(` {{::file.dateUpdated | biRelativeDate}} `, {file}, scope); } } // { // name: 'liked', // title: ' ', // sort: false, // filter(_, file: IFile, index, compile) { // return compile(` //
    // {{::file.isLiked ? 'favorite' :'favorite_border'}} //
    // `, {file}, scope); // } // } ]]; }; ================================================ FILE: quix-frontend/client/src/state-components/files/files-testkit.ts ================================================ import {Testkit} from '../../../test/e2e/driver'; import {BreadcrumbsTestkit} from '../../components/breadcrumbs/breadcrumbs-testkit'; import {ActionsTestkit} from '../../components/actions/actions-testkit'; const enum Hooks { Empty = 'files-empty', Error = 'files-error', Content = 'files-content', AddFolder = 'files-add-folder', AddNotebook = 'files-add-notebook', } export class FilesTestkit extends Testkit { async getBreadcrumbsTestkit() { return new BreadcrumbsTestkit(await this.query.$('quix-breadcrumbs')); } async getActionsTestkit() { return new ActionsTestkit(await this.query.$('quix-actions')); } async hasEmptyState() { return (await this.query.hook(Hooks.Empty)) !== null; } async hasErrorState() { return (await this.query.hook(Hooks.Error)) !== null; } async hasContent() { return (await this.query.hook(Hooks.Content)) !== null; } async clickAddFolder() { return this.click.hook(Hooks.AddFolder); } async clickAddNotebook() { return this.click.hook(Hooks.AddNotebook); } async clickFile(index) { return this.click.attr('bi-tbl-row', `:nth-child(${index})`); } async numOfFiles() { return (await this.query.attrs('bi-tbl-row')).length; } async isAddFolderEnabled() { return this.evaluate.hook(Hooks.AddFolder, el => !el.hasAttribute('disabled')); } async isAddNotebookEnabled() { return this.evaluate.hook(Hooks.AddNotebook, el => !el.hasAttribute('disabled')); } async isBulkSelectEnabled() { return this.evaluate.attr('bi-tbl-row', el => el.querySelector('[data-hook="files-mark-column"]') !== null); } } ================================================ FILE: quix-frontend/client/src/state-components/files/files-types.ts ================================================ export interface IScope extends angular.IScope { notebooks: any[]; } ================================================ FILE: quix-frontend/client/src/state-components/files/files-url.ts ================================================ ================================================ FILE: quix-frontend/client/src/state-components/files/files-vm.ts ================================================ import {StateManager} from '../../services/state'; enum States { Initial, Error, Result, Content } export default () => ({ fields: null, breadcrumbs: [{name: 'My notebooks'}], marked: {}, $init() { this.state = new StateManager(States); this.marked.map = {}; this.marked.list = []; this.files = this.createItemsVm({ isNew: null }); } }); ================================================ FILE: quix-frontend/client/src/state-components/files/files.html ================================================
    {{vm.marked.list.length}} items selected
    Loading notebooks...
    {{::vm.state.value().error.message}}
    {{::isRoot ? 'You dont have any notebooks' : 'Folder is empty'}}
    ================================================ FILE: quix-frontend/client/src/state-components/files/files.scss ================================================ @import '../../lib/ui/assets/css/def/colors.def'; quix-folder { } ================================================ FILE: quix-frontend/client/src/state-components/files/files.ts ================================================ import template from './files.html'; import './files.scss'; import {initNgScope} from '../../lib/core'; import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {cache} from '../../store'; import {initEvents} from '../../services/scope'; import {IScope} from './files-types'; import VM from './files-vm'; // import * as Url from './files-url'; import * as Scope from './files-scope'; import * as Events from './files-events'; export default (app: App, store: Store) => ({ name: 'files:id', template, url: {}, scope: Scope, options: {isNew: false}, controller: async (scope: IScope, params, {syncUrl, setTitle}) => { await cache.folder.fetch(params.id); syncUrl(); scope.isRoot = !params.id; store.subscribe('folder', ({folder, files, error, view, permissions}) => { scope.folder = folder; scope.files = files; scope.error = error; scope.view = view; scope.permissions = permissions; }, scope); store.subscribe('folder.folder.name', (name: string) => { setTitle(() => params.id ? [name] : [app.getTitle(), 'My notebooks']); }, scope); store.subscribe('folder.error', error => { if (error) { setTitle(() => ['Error']); } }, scope); }, link: scope => { const conf = initNgScope(scope) .withOptions('$stateOptions', {isNew: false}) .withVM(VM()); initEvents(scope, conf, app, store, Events); } }) as IStateComponentConfig; ================================================ FILE: quix-frontend/client/src/state-components/history/HistoryComponent.scss ================================================ @import '../../lib/ui/assets/css/def/state.def'; @import '../../lib/ui/assets/css/text.scss'; .history-component { .hc-filters { background-color: transparent; } .bi-table-cell-query { max-width: 300px; } } ================================================ FILE: quix-frontend/client/src/state-components/history/HistoryComponent.tsx ================================================ import './HistoryComponent.scss'; import React, { useEffect } from 'react'; import { IHistory } from '@wix/quix-shared'; import { historyTableFields } from './history-table-fields'; import { User } from '../../lib/app/services/user'; import { useViewState } from '../../services/hooks'; import { debounceAsync } from '../../utils'; import makePagination from '../../lib/ui/components/hoc/makePagination'; import { Table } from '../../lib/ui/components/table/Table'; import { Highlighter } from '../../lib/ui/components/Highlighter'; import { Input } from '../../lib/ui/components/input/Input'; import { Autocomplete } from '../../lib/ui/components/autocomplete/Autocomplete'; import { FilterInitialState, InitialState, EmptyState, ErrorState } from '../../lib/ui/components/states'; export interface HistoryProps { error: { message: string }; user: User; onHistoryClicked(history: IHistory): void; loadMore({ offset, limit, filters }: { offset: number; limit: number; filters: object }): Promise; getUsers(): User[]; } export const CHUNK_SIZE = 100; const PaginatedTable = makePagination(Table); const search = debounceAsync((loadMore, { offset, limit, filters }) => { return loadMore({ offset, limit, filters }); }); const States = [ 'Initial', 'Error', 'Empty', 'Content', 'FilterInitial', ]; export function History(props: HistoryProps) { const { error, onHistoryClicked, loadMore, user, getUsers: storageGetUsers } = props; const [stateData, viewState] = useViewState(States, { rows: [], size: 0, userFilter: user.getEmail(), users: [], queryFilter: '', errorMessage: '', }); const getChunk = (offset: number, limit: number) => { return search(loadMore, { offset, limit, filters: { user: stateData.userFilter, query: stateData.queryFilter } }); } const getUsers = () => { if (!stateData.users.length) { (storageGetUsers as any)(). then((users: User[]) => viewState.update({users})); } } useEffect(() => { if (error) { viewState.set('Error', { errorMessage: error.message }); } }, [error]); useEffect(() => { if (viewState.get() !== 'Error') { getChunk(0, CHUNK_SIZE + 1)(res => { viewState.set(res.length > 0 ? 'Content' : 'Empty', {rows: res}); }); } }, [stateData.queryFilter, stateData.userFilter]); const highlightQuery = (columnName: string) => (term: string) => { const text = term.replace(/\s+/g,' '); if (columnName === 'query') { return ; } return text; } const handleUserFilterChange = (option) => { if (viewState.get() !== 'Error') { viewState.set('FilterInitial', { userFilter: option.id }); } } const handleQueryFilterChange = (e) => { if (viewState.get() !== 'Error') { viewState.set('FilterInitial', { queryFilter: e.target.value }); } } const renderContentState = () => ( ({ header: field.title, render: row => field.filter(undefined, row, 0, highlightQuery(field.name)), accessor: field.name, className: field.className, }))} paginationSize={CHUNK_SIZE} tableSize={(size) => viewState.update({ size })} /> ); const renderFilters = () => (
    getUsers()} title="email" primaryOption={{email: "All users"}} onSelect={handleUserFilterChange} inputDataHook="history-filter-user-select" liDataHook="history-filter-user-select-option" />
    ); return (
    History {viewState.min('Empty') && ({stateData.size})}
    {viewState.min('Error') && renderFilters()} { (() => { switch(viewState.get()) { case 'Initial': return ; case 'Error': return ; case 'Empty': return ; case 'Content': return renderContentState(); case 'FilterInitial': return ; default: } })() }
    ); } ================================================ FILE: quix-frontend/client/src/state-components/history/history-events.ts ================================================ import { Store } from '../../lib/store'; import { App } from '../../lib/app'; import { IHistory } from '@wix/quix-shared'; import { openTempQuery } from '../../services/popup'; export const onHistoryClick = (scope, store: Store, app: App) => ( history: IHistory ) => { openTempQuery( scope, history.moduleType, history.query.join(';\n') + ';', false, ); }; ================================================ FILE: quix-frontend/client/src/state-components/history/history-table-fields.tsx ================================================ import * as React from 'react'; import { IHistory } from '@wix/quix-shared'; import relativeDate from '../../lib/ui/filters/relative-date'; import absoluteDate from '../../lib/ui/filters/absolute-date'; import toHumanCase from '../../lib/ui/filters/to-human-case'; import { HighlightedRowConfig } from '../../lib/ui/components/table/TableRow'; export const historyTableFields: HighlightedRowConfig[] = [ { name: 'email', title: 'User', filter(_, history: IHistory, index, highlight) { return {highlight(history.email)}; } }, { name: 'query', title: 'Query', filter(_, history: IHistory, index, highlight) { const hasQuery = history.query.length > 0; const fullQuery = hasQuery ? history.query.join(';\n') + ';' : ''; return ( {highlight(fullQuery)} ) } }, { name: 'moduleType', title: 'Type', filter(_, history: IHistory, index, highlight) { return ( {highlight(toHumanCase()(history.moduleType))} ); } }, { name: 'startedAt', title: 'Started At', filter(_, history: IHistory, index) { return (
    {relativeDate()(history.startedAt as any)} ({absoluteDate()(history.startedAt as any)})
    ); } } ]; ================================================ FILE: quix-frontend/client/src/state-components/history/history-testkit.ts ================================================ import { TableTestkit } from '../../lib/ui/components/table/table-testkit'; const enum Hooks { Table = 'history-table', UserFilterSelect = 'history-filter-user-select', UserFilterSelectOption = 'history-filter-user-select-option', QueryFilterInput = 'history-filter-query-input', } export class HistoryTestkit extends TableTestkit { historyTableExists = async () => { return (await this.query.hook(Hooks.Table)) !== null; } userFilter = { clickOnDropdown: () => { return this.click.hook(Hooks.UserFilterSelect); }, clickOnOption: () => { return this.click.hook(Hooks.UserFilterSelectOption); }, hasOptions: async () => { return (await this.query.hooks(Hooks.UserFilterSelectOption)).length > 0; }, value: () => { return this.evaluate.hook(Hooks.UserFilterSelect, (e: HTMLInputElement) => e.value); }, } queryFilter = { click: () => { return this.click.hook(Hooks.QueryFilterInput); }, set: (value: string) => { return this.keyboard.type(Hooks.QueryFilterInput, value); }, get: () => { return this.evaluate.hook(Hooks.QueryFilterInput, (e: HTMLInputElement) => e.value); }, } } ================================================ FILE: quix-frontend/client/src/state-components/history/history.ts ================================================ import { Store } from '../../lib/store'; import { App } from '../../lib/app'; import { IReactStateComponentConfig } from '../../lib/app/services/plugin-builder'; import { History, HistoryProps } from './HistoryComponent'; import { cache } from '../../store'; import { onHistoryClick } from './history-events'; export default (app: App, store: Store): IReactStateComponentConfig => ({ name: 'history', template: History, url: {}, scope: { filter: () => {}, user: () => {}, error: () => {}, onHistoryClicked: () => {}, loadMore: () => {}, getUsers: () => {}, }, controller: async (scope: HistoryProps, params, { syncUrl, setTitle }) => { syncUrl(); setTitle(); store.subscribe( 'history', ({ error }) => { scope.user = app.getUser(); scope.loadMore = ({ offset, limit, filters }: {offset: number; limit: number; filters: object}) => { return cache.history.fetch({ offset, limit, ...filters }); }; scope.getUsers = () => { return cache.users.fetch(); } scope.error = error; }, scope ); scope.onHistoryClicked = onHistoryClick(scope, store, app); } }); ================================================ FILE: quix-frontend/client/src/state-components/home/HomeComponent.tsx ================================================ import * as React from 'react'; import './home.scss'; export interface HomeProps { events: { onNotebooksClick(): void; onExamplesClick(): void; onNotebookAdd(): void; }; vm: any; } export function Home(props: HomeProps) { const {events, vm} = props; return (
    QUIX NOTEBOOK MANAGER
    A shared space for your company's BI insights and know-how
    { vm.examples.enabled ? : '' }
    ); } ================================================ FILE: quix-frontend/client/src/state-components/home/home-testkit.ts ================================================ import {Testkit} from '../../../test/e2e/driver'; export class HomeTestkit extends Testkit { async hasNotebooksAction() { return (await this.query.hook('home-notebooks')) !== null; } async hasAddNotebookAction() { return (await this.query.hook('home-add-notebook')) !== null; } async clickNotebooks() { return this.click.hook('home-notebooks'); } async clickExamples() { return this.click.hook('home-examples'); } async clickAddNotebook() { return this.click.hook('home-add-notebook'); } } ================================================ FILE: quix-frontend/client/src/state-components/home/home.scss ================================================ @import '../../lib/ui/assets/css/def/colors.def'; quix-home { .quix-home-welcome { margin-bottom: 100px; padding: 60px 0 60px; text-align: center; .quix-home-welcome-title { font-size: 50px; font-weight: 200; } } .quix-home-actions { > * { &:not(:last-child) { margin-right: 50px; img { } } } } } ================================================ FILE: quix-frontend/client/src/state-components/home/home.ts ================================================ import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IReactStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {Home, HomeProps} from './HomeComponent'; import {initNgScope} from '../../lib/core'; import {addNotebook, goToExamples, goToRoot} from '../../services'; import { goToNotebook } from '../../services/notebook'; export default (app: App, store: Store): IReactStateComponentConfig => ({ name: 'home', template: Home, url: {}, scope: { events: () => {}, vm: () => {} }, controller: (scope: HomeProps, params, {setTitle}) => { initNgScope(scope) .withVM({ examples: {} }) .withEvents({ onNotebooksClick() { goToRoot(app); }, onNotebookAdd() { addNotebook(store, app, [], {addNote: true}) .then(notebook => goToNotebook(app, notebook, {isNew: true})); }, onExamplesClick() { goToExamples(app); } }); scope.vm.examples.toggle(!!app.getConfig().getMode().demo); return setTitle(); }, }); ================================================ FILE: quix-frontend/client/src/state-components/import/import.html ================================================
    Importing note...
    Failed to import note
    {{::error}}
    ================================================ FILE: quix-frontend/client/src/state-components/import/import.ts ================================================ import template from './import.html'; import moment from 'moment'; import {initNgScope, utils} from '../../lib/core'; import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {setImportType, setImportValue} from '../../store/app/app-actions'; import { Import, Time } from '../../config'; import { addNotebookByNamePath, addNote, goToNotebook } from '../../services/notebook'; import { showToast } from '../../lib/ui/services/toast'; import { pluginManager } from '../../plugins'; const importNote = async (scope, app: App, store: Store, {type, value}) => { if (!type || !value) { app.getNavigator().goHome(); return; } if (!pluginManager.module('note').plugin(type)) { scope.error = `"${type}" doesn't match any known note type`; return; } const notebook = await addNotebookByNamePath(store, app, [Import.FolderName, type]); const note = await addNote(store, notebook.id, type, { name: moment().format(Time.Format) }); pluginManager.hooks.import.promise(store, note, value) .then(() => { goToNotebook(app, notebook, {note: note.id}, {location: 'replace'}); showToast({ text: `Imported a "${type}" note`, type: 'success', hideDelay: 3000, }); }) .catch(e => utils.scope.safeDigest(scope, () => scope.error = e)); } const destroy = (store: Store) => store.dispatch([ setImportType(null), setImportValue(null), ]); export default (app: App, store: Store) => ({ name: 'import', template, url: { importType: setImportType, importValue: setImportValue, }, scope: { import: (scope, imp) => importNote(scope, app, store, imp), }, controller: (scope, params, {syncUrl}) => { syncUrl(); store.subscribe('app.import', imp => { scope.import = imp; }, scope); }, link: (scope) => { initNgScope(scope) .withEvents({}); scope.$on('$destory', () => destroy(store)); } }) as IStateComponentConfig; ================================================ FILE: quix-frontend/client/src/state-components/index.ts ================================================ export { default as base } from './base/base'; export { default as embed } from './embed/embed'; export { default as embedNote } from './embed/note/embed-note'; export { default as files } from './files/files'; export { default as notebook } from './notebook/notebook'; export { default as import } from './import/import'; export { default as home } from './home/home'; export { default as user } from './users/users'; export { default as history } from './history/history'; export { default as favorites } from './favorites/favorites'; export { default as trashBin } from './trash-bin/trash-bin'; ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-events.ts ================================================ import { takeWhile } from 'lodash'; import { utils } from '../../lib/core'; import { Store } from '../../lib/store'; import { dialog, toast } from '../../lib/ui'; import { App } from '../../lib/app'; import { INote, NotebookActions, IFile, NoteActions, INotebook, IFilePathItem, FileType, } from '@wix/quix-shared'; import { IScope } from './notebook-types'; import { setNotebook, setNote, queueNote, toggleMark, unmarkAll, } from '../../store/notebook/notebook-actions'; import { saveQueuedNotes, deleteNotebook, copyNotebook, goToFile, goToRoot, prompt, copyNote, } from '../../services'; import { removeRunner, addRunner } from '../../store/app/app-actions'; import { addNote } from '../../services/notebook'; export const onBreadcrumbClick = (scope: IScope, store: Store, app: App) => ( file: IFilePathItem ) => { const { notebook: { owner, path }, } = scope.vm.state.value(); goToFile(app, { ...file, owner, type: FileType.folder, path: takeWhile(path, (item) => item.id !== file.id), }); }; export const onGoToRootClick = ( scope: IScope, store: Store, app: App ) => () => { goToRoot(app); }; export const onNameChange = (scope: IScope, store: Store, app: App) => ( file: IFile ) => { if (!scope.permissions.edit) { return; } const { id, name } = file; store.dispatchAndLog(NotebookActions.updateName(id, name)); }; export const onDelete = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { if (!scope.permissions.edit) { return; } deleteNotebook(store, app, notebook).then(() => toast.showToast( { text: `"${notebook.name}" moved to Trash Bin`, type: 'success', }, 3000 ) ); }; export const onClone = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { prompt( { title: 'Clone notebook', subTitle: 'Choose destination folder', yes: 'clone', content: ``, onConfirm: ({ model: { folder } }) => copyNotebook(store, app, folder, { ...notebook, notes: scope.vm.state.value().notes, }), }, scope, { model: { folder: null } } ).then((res) => toast.showToast( { text: `Cloned notebook as "${res.name}"`, type: 'success', }, 3000 ) ); }; export const onShare = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { utils.copyToClipboard(app.getNavigator().getUrl(null, { id: notebook.id })); toast.showToast( { text: 'Copied notebook url to clipboard', type: 'success', }, 3000 ); }; export const onLikeToggle = (scope: IScope, store: Store, app: App) => ( notebook: INotebook ) => { const { id, isLiked } = notebook; store .dispatchAndLog(NotebookActions.toggleIsLiked(id, !isLiked)) .then((action) => toast.showToast( { text: action.isLiked ? 'Added notebook to favorites' : 'Removed notebook from favorites', type: 'success', }, 3000 ) ); }; export const onSave = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onRun = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onNoteSave = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onNoteRun = (scope: IScope, store: Store, app: App) => () => { if (!scope.permissions.edit) { return; } saveQueuedNotes(store); }; export const onNoteAdd = (scope: IScope, store: Store, app: App) => ( type: any = scope.vm.noteTypes[0] ) => { if (!scope.permissions.edit) { return; } const { notebook } = scope.vm.state.value(); addNote(store, notebook.id, type, {}, (note) => { scope.vm.notes.get(note).focusName = true; store.dispatch(setNote(note)); }); }; export const onNoteClone = (scope: IScope, store: Store, app: App) => ( note: INote ) => { prompt( { title: 'Clone note', subTitle: 'Choose destination notebook', yes: 'clone', content: ``, onConfirm: ({ model: { notebook } }) => copyNote(store, app, notebook, note), }, scope, { model: { notebook: null } } ).then((res) => toast.showToast( { text: `Cloned note as "${res.name}"`, type: 'success', }, 3000 ) ); }; export const onNoteShare = (scope: IScope, store: Store, app: App) => ( note: INote, params: string ) => { const { notebook } = scope.vm.state.value(); dialog( { title: 'Share note', html: '', icon: 'share', }, scope, { note, notebook, params, } ); }; export const onNoteDelete = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatchAndLog(NoteActions.deleteNote(note.id)).then(() => toast.showToast( { text: `Deleted note "${note.name}"`, type: 'success', }, 3000 ) ); }; export const onNoteContentChange = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatch(queueNote(note)); }; export const onNoteNameChange = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatchAndLog(NoteActions.updateName(note.id, note.name)); }; export const onNoteReorder = (scope: IScope, store: Store, app: App) => ( e: any, { item }: any ) => { if (!scope.permissions.edit) { return; } const { model: note, dropindex: index } = item.sortable; if (typeof index !== 'undefined') { store.dispatchAndLog(NoteActions.reorderNote(note.id, index)); } }; export const onMarkToggle = (scope: IScope, store: Store, app: App) => ( note: INote ) => { if (!scope.permissions.edit) { return; } store.dispatch(toggleMark(note)); }; export const onMarkedNotesDelete = (scope: IScope, store: Store, app: App) => ( notes: INote[] ) => { if (!scope.permissions.edit) { return; } store .dispatchAndLog(notes.map((note) => NoteActions.deleteNote(note.id))) .then(() => toast.showToast( { text: `Deleted ${notes.length} notes`, type: 'success', }, 3000 ) ); }; export const onUnmarkAll = (scope: IScope, store: Store, app: App) => () => { store.dispatch(unmarkAll()); }; export const onRunnerCreated = (scope: IScope, store: Store) => ( note, runner ) => { store.dispatch( addRunner(note.id, runner, note, scope.vm.state.value().notebook) ); }; export const onRunnerDestroyed = (scope: IScope, store: Store) => (note) => { store.dispatch(removeRunner(note.id)); }; export const $onDestroy = (scope: IScope, store: Store, app: App) => () => { if (scope.permissions.edit) { saveQueuedNotes(store); } store.dispatch(setNotebook(null)); }; ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-reactions.ts ================================================ import {IScope} from './notebook-types'; import {INotebook, INote} from '@wix/quix-shared'; export function setNotebook(scope: IScope, notebook: INotebook) { scope.vm.state .set('Result', !!notebook, {notebook}) .then(() => { if (scope.vm.breadcrumbs.length === 1) { scope.vm.breadcrumbs = [...notebook.path, {id: notebook.id, name: notebook.name}]; if (!scope.permissions.edit) { scope.vm.breadcrumbs[0].name = `${notebook.ownerDetails.name}'s notebooks`; } } }) .else(() => scope.vm.state.value({notebook})); } export function setError(scope: IScope, error: any) { scope.vm.state.force('Error', !!error, {error}); } export function setNotes(scope: IScope, notes: INote[]) { scope.vm.state .force('Result', !!notes, {notes}) .set('Content', () => !!notes.length, {notes}) .then(() => { const vm = scope.vm.notes.get(notes[0]); vm.fold = vm.fold === null ? notes.length > 1 : vm.fold; }); } export function setHasChanges(scope: IScope, hasChanges: boolean) { scope.vm.view.hasChanges = hasChanges; } export function setSaving(scope: IScope, saving: boolean) { scope.vm.view.saving = saving; } export function setMarkedMap(scope: IScope, markedMap: Record) { scope.vm.marked.map = markedMap; } export function setMarkedList(scope: IScope, markedList: INote[]) { scope.vm.marked.list = markedList; scope.vm.marked.toggle(!!markedList.length); } export function setNote(scope: IScope, note: INote) { scope.vm.state.value({note}); if (note) { scope.vm.notes.get(note).fold = false; } } ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-scope.ts ================================================ import * as Reactions from './notebook-reactions'; export const notebook = (scope, value) => Reactions.setNotebook(scope, value); export const notes = (scope, value) => Reactions.setNotes(scope, value); export const error = (scope, value) => Reactions.setError(scope, value); export const runners = x => x; export const permissions = x => x; export const queue = { size: (scope, value) => Reactions.setHasChanges(scope, value > 0), }; export const view = { markedMap: (scope, value) => Reactions.setMarkedMap(scope, value), markedList: (scope, value) => Reactions.setMarkedList(scope, value), note: (scope, value) => Reactions.setNote(scope, value), saving: (scope, value) => Reactions.setSaving(scope, value), }; ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-testkit.ts ================================================ import {Testkit} from '../../../test/e2e/driver'; import {NoteTestkit} from '../../components/note/note-testkit'; import {BreadcrumbsTestkit} from '../../components/breadcrumbs/breadcrumbs-testkit'; import {ActionsTestkit} from '../../components/actions/actions-testkit'; const enum Hooks { Empty = 'notebook-empty', Error = 'notebook-error', Content = 'notebook-content', Note = 'notebook-note', AddNote = 'notebook-add-note', AddNoteDropdown = 'notebook-add-note-dropdown', } export class NotebookTestkit extends Testkit { async getBreadcrumbsTestkit() { return new BreadcrumbsTestkit(await this.query.$('quix-breadcrumbs')); } async getActionsTestkit() { return new ActionsTestkit(await this.query.$('quix-actions')); } async getNoteTestkit(index: number) { return new NoteTestkit(await this.query.hook(Hooks.Note, `:nth-child(${index})`)); } async hasEmptyState() { return (await this.query.hook(Hooks.Empty)) !== null; } async hasErrorState() { return (await this.query.hook(Hooks.Error)) !== null; } async hasNotes() { return (await this.query.hook(Hooks.Content)) !== null; } async clickAddNote() { return this.click.hook(Hooks.AddNote, ':first-child'); } async clickAddNoteDropdown() { await this.click.hook(Hooks.AddNoteDropdown); } async numOfNotes() { return (await this.query.hooks(Hooks.Note)).length; } async isAddNoteEnabled() { return this.evaluate.hook(Hooks.AddNoteDropdown, el => !el.hasAttribute('disabled')); } } ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-types.ts ================================================ import {INotebook} from '@wix/quix-shared'; export interface IScope extends angular.IScope { notebook: INotebook; } ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-url.ts ================================================ import {find} from 'lodash'; import {INote} from '@wix/quix-shared'; import {setNote} from '../../store/notebook/notebook-actions'; export const note = (id: string, notes: INote[]) => setNote(id && find(notes, {id})); ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook-vm.ts ================================================ import {StateManager} from '../../services/state'; import {App} from '../../lib/app'; import {pluginManager} from '../../plugins'; enum States { Initial, Error, Result, Content, } export default (app: App) => ({ note: null, breadcrumbs: [{name: 'My notebooks'}], view: { hasChanges: false, saving: false, }, marked: {}, $init() { this.notes = this.createItemsVm({ fold: null, scrollTo: false, focusName: false, }); this.noteTypes = pluginManager .module('note') .plugins() .filter(plugin => plugin.getConfig().canCreate) .map(plugin => plugin.getId()); this.state = new StateManager(States); this.marked.map = {}; this.marked.list = []; }, }); ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook.html ================================================
    • {{::type | biToHumanCase}}
    {{vm.marked.list.length}} notes selected
    Loading notebook...
    {{::vm.state.value().error.message}}
    Notebook is empty
    ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook.scss ================================================ @import '../../lib/ui/assets/css/def/colors.def'; quix-notebook { .quix-note-container { position: relative; &.quix-note-container--editable { padding-left: 8px; } } } ================================================ FILE: quix-frontend/client/src/state-components/notebook/notebook.ts ================================================ import template from './notebook.html'; import './notebook.scss'; import {initNgScope} from '../../lib/core'; import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {cache} from '../../store'; import {initEvents} from '../../services/scope'; import {IScope} from './notebook-types'; import VM from './notebook-vm'; import {getRunners} from '../../services'; import * as Url from './notebook-url'; import * as Scope from './notebook-scope'; import * as Events from './notebook-events'; export default (app: App, store: Store) => ({ name: 'notebook:id', template, url: Url, scope: Scope, options: {isNew: false}, controller: async (scope: IScope, params, {syncUrl, setTitle}) => { await cache.notebook.fetch(params.id); syncUrl(() => [store.getState('notebook.notes') || []]); store.subscribe('notebook', ({notebook, notes, error, queue, view, permissions}) => { scope.notebook = notebook; scope.notes = notes; scope.error = error; scope.queue = queue; scope.view = view; scope.permissions = permissions; }, scope); store.subscribe('notebook.notebook.name', name => { setTitle(({stateName}) => [name]); }, scope); store.subscribe('notebook.error', error => { if (error) { setTitle(() => ['Error']); } }, scope); store.subscribe('app.runners', () => { scope.runners = getRunners(); }, scope); }, link: scope => { const conf = initNgScope(scope) .withOptions('$stateOptions', {isNew: false}) .withVM(VM(app)); initEvents(scope, conf, app, store, Events); } }) as IStateComponentConfig; ================================================ FILE: quix-frontend/client/src/state-components/trash-bin/TrashBinComponent.tsx ================================================ import { IDeletedNotebook } from '@wix/quix-shared'; import React, { useEffect } from 'react'; import { EmptyState, ErrorState, InitialState, } from '../../lib/ui/components/states'; import { Table } from '../../lib/ui/components/table/Table'; import { useViewState } from '../../services/hooks'; import { trashBinTableFields } from './trash-bin-table-fields'; export interface TrashBinProps { deletedNotebooks: IDeletedNotebook[]; error: { message: string }; onPermanentlyDeleteClicked(deletedNotebook: IDeletedNotebook): void; onRestoreClicked(deletedNotebook: IDeletedNotebook, folderId: string); onEmptyTrashBinClicked(); } const States = ['Initial', 'Error', 'Empty', 'Content']; export const TrashBin = (props: TrashBinProps) => { const { deletedNotebooks, error, onPermanentlyDeleteClicked, onRestoreClicked, onEmptyTrashBinClicked, } = props; const [stateData, viewState] = useViewState(States, { deletedNotebooks: [], size: 0, totalDeletedNotebooks: 0, errorMessage: '', }); useEffect(() => { if (error) { viewState.set('Error', { errorMessage: error.message }); } }, [error]); useEffect(() => { if (!error && deletedNotebooks?.length >= 0) { viewState.set(deletedNotebooks?.length ? 'Content' : 'Empty', { deletedNotebooks: deletedNotebooks || [], size: deletedNotebooks.length || 0, }); } }, [deletedNotebooks]); const renderContentState = () => (
    ({ header: field.title || field.name, render: (row) => field.filter(undefined, row), accessor: field.name, className: field.className, }))} data={stateData.deletedNotebooks} /> ); return (
    Trash Bin {viewState.min('Empty') && ( {' '}({stateData.size}) )}
    {viewState.get() === 'Content' && (
    )}
    {(() => { switch (viewState.get()) { case 'Initial': return ; case 'Error': return ; case 'Empty': return ; case 'Content': return renderContentState(); default: } })()}
    ); }; ================================================ FILE: quix-frontend/client/src/state-components/trash-bin/trash-bin-events.ts ================================================ import { Store } from '../../lib/store'; import { IDeletedNotebook, TrashBinActions } from '@wix/quix-shared'; import { toast } from '../../lib/ui'; import { confirmAction, prompt } from '../../services/dialog'; export const onPermanentlyDeleteClick = (store: Store) => ( deletedNotebook: IDeletedNotebook ) => { confirmAction('delete', 'notebook', deletedNotebook, '', () => { store .logAndDispatch( TrashBinActions.permanentlyDeleteNotebook(deletedNotebook.id) ) .then(() => successToast(`Deleted notebook "${deletedNotebook.name}".`)); }); }; export const onEmptyTrashBinClicked = (scope, store: Store) => () => { confirmAction('delete', 'notebook', scope.deletedNotebooks, '', () => { store .dispatchAndLog( scope.deletedNotebooks.map((n) => TrashBinActions.permanentlyDeleteNotebook(n.id) ) ) .then(() => successToast(`Trash Bin is empty`)); }); }; export const onRestoreClick = (scope, store: Store) => ( deletedNotebook: IDeletedNotebook ) => { let restoreFolder = ''; prompt( { title: 'Restore notebook', subTitle: 'Choose destination folder', yes: 'restore', content: /*html*/ ` `, onConfirm: ({ model: { folder } }) => { restoreFolder = folder.name; return store.logAndDispatch( TrashBinActions.restoreDeletedNotebook(deletedNotebook.id, folder.id) ); }, }, scope, { model: { folder: null } } ).then(() => successToast(`"${deletedNotebook.name}" Restored to "${restoreFolder}."`) ); }; function successToast(text: string) { toast.showToast( { text, type: 'success', }, 3000 ); } ================================================ FILE: quix-frontend/client/src/state-components/trash-bin/trash-bin-table-fields.tsx ================================================ import * as React from 'react'; import { IDeletedNotebook } from '@wix/quix-shared'; import { RowConfig } from '../../lib/ui/components/table/TableRow'; import relativeDate from '../../lib/ui/filters/relative-date'; import absoluteDate from '../../lib/ui/filters/absolute-date'; export const trashBinTableFields = ( onPermanentlyDeleteClicked, onRestoreClicked ): RowConfig[] => { return [ { name: 'name', title: 'Name', filter(_, deletedNotebook: IDeletedNotebook) { return (
    insert_drive_file {deletedNotebook.name}
    ); }, }, { name: 'dateDeleted', title: 'Date Deleted', filter(_, deletedNotebook: IDeletedNotebook) { return (
    {relativeDate()(deletedNotebook.dateDeleted as any)} ({absoluteDate()(deletedNotebook.dateDeleted as any)})
    ); }, }, { name: '' as any, title: '', filter(_, deletedNotebook: IDeletedNotebook) { return (
    ); }, }, ]; }; ================================================ FILE: quix-frontend/client/src/state-components/trash-bin/trash-bin.ts ================================================ import { Store } from '../../lib/store'; import { App } from '../../lib/app'; import { IReactStateComponentConfig } from '../../lib/app/services/plugin-builder'; import { TrashBin, TrashBinProps } from './TrashBinComponent'; import { cache } from '../../store'; import { onEmptyTrashBinClicked, onPermanentlyDeleteClick, onRestoreClick, } from './trash-bin-events'; import _noop from 'lodash/noop'; export default (app: App, store: Store): IReactStateComponentConfig => ({ name: 'trashBin', template: TrashBin, url: {}, scope: { deletedNotebooks: _noop, error: _noop, onPermanentlyDeleteClicked: _noop, onRestoreClicked: _noop, onEmptyTrashBinClicked: _noop, }, controller: async (scope: TrashBinProps, params, { syncUrl, setTitle }) => { syncUrl(); setTitle(); scope.onPermanentlyDeleteClicked = onPermanentlyDeleteClick(store); scope.onRestoreClicked = onRestoreClick(scope, store); scope.onEmptyTrashBinClicked = onEmptyTrashBinClicked(scope, store); await cache.deletedNotebooks.fetch(params.id); store.subscribe( 'deletedNotebooks', ({ deletedNotebooks, error }) => { scope.deletedNotebooks = deletedNotebooks; scope.error = error; }, scope ); }, }); ================================================ FILE: quix-frontend/client/src/state-components/users/UsersComponent.tsx ================================================ import React, {useEffect} from 'react'; import _ from 'lodash'; import {IUser} from '@wix/quix-shared'; import {Highlighter} from '../../lib/ui/components/Highlighter'; import {Table} from '../../lib/ui/components/table/Table'; import {useViewState} from '../../services/hooks'; import {usersTableFields} from './users-table-fields'; import makePagination from '../../lib/ui/components/hoc/makePagination'; import {Input} from '../../lib/ui/components/input/Input'; import {FilterInitialState, InitialState, EmptyState, ErrorState} from '../../lib/ui/components/states'; import {debounceAsync} from '../../utils'; import './users.scss'; export interface UsersProps { users: IUser[]; error: {message: string}; onUserClicked(user: IUser): void; } export const CHUNK_SIZE = 100; const PaginatedTable = makePagination(Table); const search = debounceAsync((loadMore, { offset, limit, users, emailFilter }) => { return new Promise(res => res(users?.filter(user => user.email.includes(emailFilter)).slice(offset, offset + limit) || []) ); }); const States = [ 'Initial', 'Error', 'Empty', 'Content', 'FilterInitial', ]; export function Users(props: UsersProps) { const {users: serverUsers, error, onUserClicked} = props; const [stateData, viewState] = useViewState(States, { users: [], size: 0, totalUsers: 0, emailFilter: '', errorMessage: '', }); useEffect(() => { if (error) { viewState.set('Error', { errorMessage: error.message }); } }, [error]); useEffect(() => { if (!error) { viewState.set('Initial', {users: serverUsers?.slice(0, CHUNK_SIZE) || []}); } },[serverUsers]); useEffect(() => { if (viewState.get() !== 'Error' && serverUsers?.length >= 0) { loadMore(0, CHUNK_SIZE + 1)(res => { if (!_.isEqual(res, stateData.users) || viewState.is('Initial') || viewState.is('FilterInitial')) { if (res.length > 0) { viewState.set('Content', { users: res, totalUsers: serverUsers.filter(user => user.email.includes(stateData.emailFilter)).length, }); } else { viewState.set('Empty', { users: [], totalUsers: 0, size: 0, }); } } else if (stateData.users?.length > 0 && !viewState.is('Content')) { viewState.set('Content'); } }); } }, [stateData.emailFilter, stateData.users]); const highlightQuery = (columnName: string) => (term: string) => { const text = term.replace(/\s+/g,' '); if (columnName === 'email') { return ; } return text; } const loadMore = (offset: number, limit: number) => { return search(null, { offset, limit, users: serverUsers, emailFilter: stateData.emailFilter, }); } const renderContentState = () => ( ({ header: field.title, render: row => field.filter(undefined, row, 0, highlightQuery(field.name)), accessor: field.name, className: field.className, }))} initialData={stateData.users} loadMore={loadMore} onRowClicked={onUserClicked} paginationSize={CHUNK_SIZE} tableSize={(size) => viewState.update({ size })} /> ); const handleEmailFilterChange = (e) => { if (viewState.get() !== 'Error') { viewState.set('FilterInitial', { emailFilter: e.target.value }); } } const renderFilter = () => (
    ); return (
    Users {viewState.min('Empty') && ({stateData.size} / {stateData.totalUsers})}
    {viewState.min('Error') && renderFilter()} { (() => { switch(viewState.get()) { case 'Initial': return ; case 'Error': return ; case 'Empty': return ; case 'Content': return renderContentState(); case 'FilterInitial': return ; default: } })() }
    ); } ================================================ FILE: quix-frontend/client/src/state-components/users/users-events.ts ================================================ import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IUser} from '@wix/quix-shared'; export const onUserClick = (scope, store: Store, app: App) => (user: IUser) => { app.go('files', {id: user.rootFolder}); }; ================================================ FILE: quix-frontend/client/src/state-components/users/users-table-fields.tsx ================================================ import * as React from 'react'; import {IUser} from '@wix/quix-shared'; import biRelativeDate from '../../../src/lib/ui/filters/relative-date'; import { HighlightedRowConfig } from '../../lib/ui/components/table/TableRow'; import { UserAvatarAndName } from '../../components/User/UserAvatarAndName'; export const usersTableFields: HighlightedRowConfig[] = [ { name: 'name', title: 'User', filter(_, user: IUser, index) { return ; } }, { name: 'email', title: 'Email', filter(_, user: IUser, index, highlight) { return (
    {highlight(user.email)}
    ); } }, { name: 'dateCreated', title: 'Join Date', filter(_, user: IUser, index) { return ( {biRelativeDate()(user.dateCreated as any)} ); } }, { name: 'dateUpdated', title: 'Last Login', filter(_, user: IUser, index) { return ( {biRelativeDate()(user.dateUpdated as any)} ); } } ]; ================================================ FILE: quix-frontend/client/src/state-components/users/users-testkit.ts ================================================ import { TableTestkit } from '../../lib/ui/components/table/table-testkit'; const enum Hooks { Content = 'users-table', FilterUsersInput = 'users-filter-users-input', } export class UsersTestkit extends TableTestkit { usersTableExists = async () => { return (await this.query.hook(Hooks.Content)) !== null; } usersFilter = { click: () => { return this.click.hook(Hooks.FilterUsersInput); }, set: (value: string) => { return this.keyboard.type(Hooks.FilterUsersInput, value); }, get: () => { return this.evaluate.hook(Hooks.FilterUsersInput, (e: HTMLInputElement) => e.value); }, } } ================================================ FILE: quix-frontend/client/src/state-components/users/users.scss ================================================ quix-users { .bi-transparent { background-color: transparent; } } ================================================ FILE: quix-frontend/client/src/state-components/users/users.ts ================================================ import {Store} from '../../lib/store'; import {App} from '../../lib/app'; import {IReactStateComponentConfig} from '../../lib/app/services/plugin-builder'; import {Users, UsersProps} from './UsersComponent'; import {cache} from '../../store'; import {onUserClick} from './users-events'; export default (app: App, store: Store): IReactStateComponentConfig => ({ name: 'users', template: Users, url: {}, scope: { users: () => {}, error: () => {}, onUserClicked: () => {} }, controller: async (scope: UsersProps, params, {syncUrl, setTitle}) => { await cache.users.fetch(params.id); syncUrl(); setTitle(); store.subscribe( 'users', ({users, error}) => { scope.users = users; scope.error = error; }, scope ); scope.onUserClicked = onUserClick(scope, store, app); }, }); ================================================ FILE: quix-frontend/client/src/store/app/app-actions.ts ================================================ import {Runner} from '../../lib/runner'; import {INotebook, INote} from '@wix/quix-shared'; export const setInputSearchText = (inputSearchText: string, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.setInputSearchText', inputSearchText, origin }); export const setUrlSearchText = (urlSearchText: string, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.setUrlSearchText', urlSearchText, origin }); export const setSearchPage = (searchPage: number, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.setSearchPage', searchPage, origin }); export const setImportType = (importType: string, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.setImportType', importType, origin }); export const setImportValue = (importValue: string, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.setImportValue', importValue, origin }); export const addRunner = (id: string, runner: Runner, note: INote, notebook: INotebook, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.addRunner', id, origin, runner, note, notebook }) export const removeRunner = (id: string, origin: 'user' | 'machine' = 'machine') => ({ type: 'app.removeRunner', id, origin }); export const setStats = (stats: { trashBinCount: number }) => ({ type: 'app.setStats', stats, }); ================================================ FILE: quix-frontend/client/src/store/app/app-branch.ts ================================================ import { IBranch } from '../../lib/store'; import { App } from '../../lib/app'; import { Middleware } from 'redux'; import * as Runners from '../../services/runners'; import { DeletedNotebookActionTypes } from '@wix/quix-shared'; export interface IApp { searchPage?: number; inputSearchText?: string; urlSearchText?: string; runners?: Record; stats: { trashBinCount: number }; import: { type?: string; value?: string; }; } export default (app: App): IBranch => (register) => { const runnerMiddleware: Middleware = () => (next) => (action: any) => { switch (action.type) { case 'app.addRunner': Runners.addRunner( app, null, action.id, action.runner, action.note, action.notebook ); break; case 'app.removeRunner': Runners.removeRunner(action.id); break; default: } return next(action); }; const appReducer = ( state: IApp = { runners: {}, import: {}, stats: { trashBinCount: 0 }, }, action ): IApp => { switch (action.type) { case 'app.setSearchPage': return { ...state, searchPage: action.searchPage }; case 'app.setInputSearchText': return { ...state, inputSearchText: action.inputSearchText }; case 'app.setUrlSearchText': if (action.urlSearchText !== state.urlSearchText) { return { ...state, urlSearchText: action.urlSearchText, inputSearchText: action.origin === 'machine' ? action.urlSearchText : state.inputSearchText, }; } break; case 'app.setImportType': return { ...state, import: { ...state.import, type: action.importType }, }; case 'app.setImportValue': return { ...state, import: { ...state.import, value: action.importValue }, }; case 'app.setStats': return { ...state, stats: { ...action.stats } }; case DeletedNotebookActionTypes.createDeletedNotebook: return { ...state, stats: { ...state.stats, trashBinCount: state.stats.trashBinCount + 1, }, }; case DeletedNotebookActionTypes.deleteDeletedNotebook: case DeletedNotebookActionTypes.restoreDeletedNotebook: return { ...state, stats: { ...state.stats, trashBinCount: state.stats.trashBinCount - 1, }, }; case 'app.addRunner': case 'app.removeRunner': return { ...state, runners: {} }; // just to trigger subscribers default: } return state; }; register(appReducer, runnerMiddleware); }; ================================================ FILE: quix-frontend/client/src/store/db/db-actions.ts ================================================ export const setDb = (db: any[], origin: 'user' | 'machine' = 'machine') => ({ type: 'db.set', db, origin }); export const setError = (error: any, origin: 'user' | 'machine' = 'machine') => ({ type: 'db.setError', error, origin }); ================================================ FILE: quix-frontend/client/src/store/db/db-branch.ts ================================================ import {combineReducers} from 'redux'; import {IBranch} from '../../lib/store'; import {App} from '../../lib/app'; export default (app: App): IBranch => register => { function db(state: any[] = null, action) { switch (action.type) { case 'db.set': return action.db; default: } return state; } const error = (state: any = null, action: any) => { switch (action.type) { case 'db.set': return null; case 'db.setError': return action.error; default: } return state; } register(combineReducers({db, error})); }; ================================================ FILE: quix-frontend/client/src/store/db/db-cache.ts ================================================ import {StoreCache} from '../../lib/store'; import {setDb, setError} from './db-actions'; import {db} from '../../services/resources'; export default store => new StoreCache(store, 'db.db') .cacheWith(setDb) .catchWith(setError) .fetchWith(db); ================================================ FILE: quix-frontend/client/src/store/deleted-notebook/deleted-notebook-actions.ts ================================================ import { IDeletedNotebook } from '@wix/quix-shared'; export const setDeletedNotebooks = (deletedNotebooks: IDeletedNotebook[]) => ({ type: 'deletedNotebooks.set', deletedNotebooks }); export const setError = (error: any) => ({ type: 'deletedNotebooks.setError', error }); ================================================ FILE: quix-frontend/client/src/store/deleted-notebook/deleted-notebook-branch.ts ================================================ import { combineReducers } from 'redux'; import { IBranch } from '../../lib/store'; import { App } from '../../lib/app'; import { composeReducers, IDeletedNotebook, clientDeletedNotebookReducer, } from '@wix/quix-shared'; export default (app: App): IBranch => (register) => { const deletedNotebooks = composeReducers( clientDeletedNotebookReducer, (state: IDeletedNotebook[] = [], action: any) => { switch (action.type) { case 'deletedNotebooks.set': return action.deletedNotebooks; default: } return state; } ); const error = (state: any = null, action: any) => { switch (action.type) { case 'deletedNotebooks.set': return null; case 'deletedNotebooks.setError': return action.error; default: } return state; }; register(combineReducers({ deletedNotebooks, error })); }; ================================================ FILE: quix-frontend/client/src/store/deleted-notebook/deleted-notebook-cache.ts ================================================ import { StoreCache } from '../../lib/store'; import { IDeletedNotebook } from '@wix/quix-shared'; import { setDeletedNotebooks, setError } from './deleted-notebook-actions'; import { deletedNotebooks } from '../../services/resources'; export default store => new StoreCache(store, 'deletedNotebooks.deletedNotebooks') .cacheWith(setDeletedNotebooks) .catchWith(setError) .fetchWith(deletedNotebooks); ================================================ FILE: quix-frontend/client/src/store/favorites/favorites-actions.ts ================================================ import {IFile} from '@wix/quix-shared'; export const setFavorites = (favorites: IFile[]) => ({ type: 'favorites.set', favorites }); export const setError = (error: any) => ({ type: 'favorites.setError', error }); ================================================ FILE: quix-frontend/client/src/store/favorites/favorites-branch.ts ================================================ import {combineReducers} from 'redux'; import {IBranch} from '../../lib/store'; import {App} from '../../lib/app'; import {IFile, composeReducers, clientFileListReducer} from '@wix/quix-shared'; export default (app: App): IBranch => register => { const favorites = composeReducers( clientFileListReducer, (state: IFile[] = null, action: any) => { switch (action.type) { case 'favorites.set': return action.favorites; default: } return state; }); const error = (state: any = null, action: any) => { switch (action.type) { case 'favorites.set': return null; case 'favorites.setError': return action.error; default: } return state; } register(combineReducers({favorites, error})); }; ================================================ FILE: quix-frontend/client/src/store/favorites/favorites-cache.ts ================================================ import {StoreCache} from '../../lib/store'; import {setFavorites, setError} from './favorites-actions'; import {favorites} from '../../services/resources'; import {IFile} from '@wix/quix-shared'; export default store => new StoreCache(store, 'favorites.favorites') .cacheWith(setFavorites) .catchWith(setError) .fetchWith(favorites); ================================================ FILE: quix-frontend/client/src/store/files/files-actions.ts ================================================ import {IFile} from '@wix/quix-shared'; export const setFiles = (files: IFile[]) => ({ type: 'files.set', files }); export const setError = (error: any) => ({ type: 'files.setError', error }); ================================================ FILE: quix-frontend/client/src/store/files/files-branch.ts ================================================ import {combineReducers} from 'redux'; import {IBranch} from '../../lib/store'; import {App} from '../../lib/app'; import { IFolder, clientFileListReducer, composeReducers, } from '@wix/quix-shared'; export interface IPermissions { edit: boolean; } export default (app: App): IBranch => register => { const files = composeReducers( (state: IFolder = null, action: any) => { switch (action.type) { case 'files.set': return action.files; default: } return state; }, clientFileListReducer, ); const error = (state: any = null, action: any) => { switch (action.type) { case 'files.set': return null; case 'files.setError': return action.error; default: } return state; } register(combineReducers({files, error})); }; ================================================ FILE: quix-frontend/client/src/store/files/files-cache.ts ================================================ import {StoreCache} from '../../lib/store'; import {setFiles, setError} from './files-actions'; import {files} from '../../services/resources'; import {IFile} from '@wix/quix-shared'; export default store => new StoreCache(store, 'files.files') .cacheWith(setFiles) .catchWith(setError) .fetchWith(files); ================================================ FILE: quix-frontend/client/src/store/folder/folder-actions.ts ================================================ import {IFile, IFolder} from '@wix/quix-shared'; export const setFolder = (folder: IFolder) => ({ type: 'folder.set', folder }); export const setError = (error: any) => ({ type: 'folder.setError', error }); export const setFileError = (error: any) => ({ type: 'folder.view.setFileError', error }); export const toggleMark = (file: IFile) => ({ type: 'folder.view.toggleMark', file }); export const unmarkAll = () => ({ type: 'folder.view.unmarkAll' }); ================================================ FILE: quix-frontend/client/src/store/folder/folder-branch.ts ================================================ import {values, reject} from 'lodash'; import {combineReducers} from 'redux'; import {IBranch} from '../../lib/store'; import {App} from '../../lib/app'; import { IFile, IFolder, NotebookActionTypes, FileActionTypes, clientFileReducer, clientFileListReducer, composeReducers } from '@wix/quix-shared'; import {getFolderPermissions, getDefaultPermissions, IPermissions} from '../../services'; export interface IView { markedMap: Record; markedList: IFile[]; } export default (app: App): IBranch => register => { const folder = composeReducers( clientFileReducer, (state: IFolder = null, action: any) => { switch (action.type) { case 'folder.set': return action.folder; default: } return state; }, ); const files = composeReducers( clientFileListReducer, (state: IFile[] = null, action: any) => { switch (action.type) { case 'folder.set': return action.folder && action.folder.files; case FileActionTypes.moveFile: case NotebookActionTypes.moveNotebook: return state && reject(state, {id: action.id}); default: } return state; }, ); const error = (state: any = null, action: any) => { switch (action.type) { case 'folder.set': return null; case 'folder.setError': return action.error; default: } return state; } const view = (state: IView = { markedMap: {}, markedList: [] }, action: any): IView => { switch (action.type) { case 'folder.set': case 'folder.view.unmarkAll': return { markedMap: {}, markedList: [] }; case FileActionTypes.deleteFile: case NotebookActionTypes.deleteNotebook: // tslint:disable-next-line: no-dynamic-delete delete state.markedMap[action.id]; return {...state, markedList: values(state.markedMap).filter(n => !!n)}; case 'folder.view.toggleMark': state.markedMap[action.file.id] = state.markedMap[action.file.id] ? undefined : action.file; return {...state, markedList: values(state.markedMap).filter(f => !!f)}; default: } return state; } const permissions = (state: IPermissions = getDefaultPermissions(), action: any): IPermissions => { switch (action.type) { case 'folder.set': return action.folder ? getFolderPermissions(app, action.folder) : getDefaultPermissions(); default: } return state; } register(combineReducers({folder, files, error, view, permissions})); }; ================================================ FILE: quix-frontend/client/src/store/folder/folder-cache.ts ================================================ import {StoreCache} from '../../lib/store'; import {IFolder, createFolderPayload} from '@wix/quix-shared'; import {setFolder, setError} from './folder-actions'; import * as Resources from '../../services/resources'; import {createQuixFolder} from '../../data'; import {QuixFolder} from '../../config'; export default store => new StoreCache(store, 'folder.folder') .cacheWith(setFolder) .catchWith(setError) .fetchWith(id => { if (id) { if (id === QuixFolder.id) { return Promise.resolve(createQuixFolder()); } return Resources.folder(id); } return Resources.files().then(files => { const root = files.find(file => !file.path.length); const children = files.filter(file => file.path.length === 1); return createFolderPayload([], { ...root, files: children }); }); }); ================================================ FILE: quix-frontend/client/src/store/history/history-actions.ts ================================================ import { IHistory } from '@wix/quix-shared'; export const setHistory = (history: IHistory[]) => ({ type: 'history.set', history }); export const setError = (error: any) => ({ type: 'history.setError', error }); ================================================ FILE: quix-frontend/client/src/store/history/history-branch.ts ================================================ import { combineReducers } from 'redux'; import { IBranch } from '../../lib/store'; import { App } from '../../lib/app'; import { IHistory } from '@wix/quix-shared'; export default (app: App): IBranch => register => { const history = (state: IHistory[] = null, action: any) => { switch (action.type) { case 'history.set': return action.history; default: } return state; }; const error = (state: any = null, action: any) => { switch (action.type) { case 'history.set': return null; case 'history.setError': return action.error; default: } return state; }; register(combineReducers({ history, error })); }; ================================================ FILE: quix-frontend/client/src/store/history/history-cache.ts ================================================ import { StoreCache } from '../../lib/store'; import { setHistory, setError } from './history-actions'; import { history } from '../../services/resources'; import { IHistory } from '@wix/quix-shared'; export default store => new StoreCache(store, 'history.history') .cacheWith(setHistory) .catchWith(setError) .fetchWith(history); ================================================ FILE: quix-frontend/client/src/store/index.ts ================================================ import { Store } from '../lib/store'; import { IEntity } from '@wix/quix-shared'; import { default as app } from './app/app-branch'; import { default as notebook } from './notebook/notebook-branch'; import { default as deletedNotebooks } from './deleted-notebook/deleted-notebook-branch'; import { default as notebookCache } from './notebook/notebook-cache'; import { default as deletedNotebooksCache } from './deleted-notebook/deleted-notebook-cache'; import { default as files } from './files/files-branch'; import { default as foldersCache } from './files/files-cache'; import { default as db } from './db/db-branch'; import { default as dbCache } from './db/db-cache'; import { default as folder } from './folder/folder-branch'; import { default as folderCache } from './folder/folder-cache'; import { default as users } from './users/users-branch'; import { default as usersCache } from './users/users-cache'; import { default as history } from './history/history-branch'; import { default as historyCache } from './history/history-cache'; import { default as favorites } from './favorites/favorites-branch'; import { default as favoritesCache } from './favorites/favorites-cache'; export const branches = { app, users, history, notebook, deletedNotebooks, files, db, folder, favorites }; export let cache = null; export const initCache = (store: Store) => { cache = { users: usersCache(store), history: historyCache(store), notebook: notebookCache(store), deletedNotebooks: deletedNotebooksCache(store), files: foldersCache(store), db: dbCache(store), folder: folderCache(store), favorites: favoritesCache(store) }; }; export const waitForEntity = ( scope, store: Store, id: string, entity: string ) => new Promise((resolve, reject) => { const unsubscribe = store.subscribe( `${entity}`, state => { if ( (state[entity] && (!id || state[entity].id === id)) || state.error ) { if (unsubscribe) { unsubscribe(); } return state[entity] ? resolve(state[entity]) : reject(state.error); } }, scope ); }); ================================================ FILE: quix-frontend/client/src/store/notebook/notebook-actions.ts ================================================ import {INotebook, INote} from '@wix/quix-shared'; export const setNotebook = (notebook: INotebook) => ({ type: 'notebook.set', notebook }); export const setError = (error: any) => ({ type: 'notebook.setError', error }); export const queueNote = (note: INote) => ({ type: 'notebook.queue.note', note }); export const setNote = (note: INote) => ({ type: 'notebook.view.setNote', note }); export const toggleMark = (note: INote) => ({ type: 'notebook.view.toggleMark', note }); export const unmarkAll = () => ({ type: 'notebook.view.unmarkAll' }); export const setSaving = (saving: boolean) => ({ type: 'notebook.view.setSaving', saving }); ================================================ FILE: quix-frontend/client/src/store/notebook/notebook-branch.ts ================================================ import {values} from 'lodash'; import {combineReducers} from 'redux'; import {IBranch} from '../../lib/store'; import {App} from '../../lib/app'; import { INotebook, INote, composeReducers, clientNotebookReducer, noteListReducer, NoteActionTypes } from '@wix/quix-shared'; import {getNotebookPermissions, getDefaultPermissions, IPermissions} from '../../services'; export interface IQueue { notes: Record; size: number; } export interface IView { markedMap: Record; markedList: INote[]; note: INote; saving: boolean; } export default (app: App): IBranch => register => { const notebook = composeReducers( clientNotebookReducer, (state: INotebook = null, action: any) => { switch (action.type) { case 'notebook.set': return action.notebook; default: } return state; }, ); const notes = composeReducers( noteListReducer, (state: INote[] = [], action: any) => { switch (action.type) { case 'notebook.set': return action.notebook ? action.notebook.notes : []; default: } return state; }, ); const error = (state: any = null, action: any) => { switch (action.type) { case 'notebook.set': return null; case 'notebook.setError': return action.error; default: } return state; } const queue = (state: IQueue = {notes: {}, size: 0}, action: any): IQueue => { switch (action.type) { case 'notebook.queue.note': state.notes = {...state.notes, [action.note.id]: action.note}; return {...state, size: Object.keys(state.notes).length}; case NoteActionTypes.updateContent: case NoteActionTypes.deleteNote: // tslint:disable-next-line: no-dynamic-delete delete state.notes[action.id]; return {...state, size: Object.keys(state.notes).length}; default: } return state; } const view = (state: IView = { markedMap: {}, markedList: [], note: null, saving: false, }, action: any): IView => { switch (action.type) { case 'notebook.set': return { markedMap: {}, markedList: [], note: null, saving: false, }; case 'notebook.view.unmarkAll': return { ...state, markedMap: {}, markedList: [] }; case NoteActionTypes.deleteNote: // tslint:disable-next-line: no-dynamic-delete delete state.markedMap[action.id]; return {...state, markedList: values(state.markedMap).filter(n => !!n)}; case 'notebook.view.toggleMark': state.markedMap[action.note.id] = state.markedMap[action.note.id] ? undefined : action.note; return {...state, markedList: values(state.markedMap).filter(n => !!n)}; case 'notebook.view.setNote': return {...state, note: action.note}; case 'notebook.view.setSaving': return {...state, saving: action.saving}; default: } return state; } const permissions = (state: IPermissions = { edit: false }, action: any): IPermissions => { switch (action.type) { case 'notebook.set': return action.notebook ? getNotebookPermissions(app, action.notebook) : getDefaultPermissions(); default: } return state; } register(combineReducers({notebook, notes, error, queue, view, permissions})); }; ================================================ FILE: quix-frontend/client/src/store/notebook/notebook-cache.ts ================================================ import {StoreCache} from '../../lib/store'; import {INotebook} from '@wix/quix-shared'; import {setNotebook, setError} from './notebook-actions'; import {notebook} from '../../services/resources'; import {createExamplesNotebook} from '../../data'; import {ExamplesNotebook} from '../../config'; export default store => new StoreCache(store, 'notebook.notebook') .cacheWith(setNotebook) .catchWith(setError) .fetchWith(id => { return id === ExamplesNotebook.id ? Promise.resolve(createExamplesNotebook()) : notebook(id) }); ================================================ FILE: quix-frontend/client/src/store/users/users-actions.ts ================================================ import {IUser} from '@wix/quix-shared'; export const setUsers = (users: IUser[]) => ({ type: 'users.set', users }); export const setError = (error: any) => ({ type: 'users.setError', error }); ================================================ FILE: quix-frontend/client/src/store/users/users-branch.ts ================================================ import {combineReducers} from 'redux'; import {IBranch} from '../../lib/store'; import {App} from '../../lib/app'; import {IUser} from '@wix/quix-shared'; export default (app: App): IBranch => register => { const users = (state: IUser[] = null, action: any) => { switch (action.type) { case 'users.set': return action.users; default: } return state; }; const error = (state: any = null, action: any) => { switch (action.type) { case 'users.set': return null; case 'users.setError': return action.error; default: } return state; } register(combineReducers({users, error})); }; ================================================ FILE: quix-frontend/client/src/store/users/users-cache.ts ================================================ import {StoreCache} from '../../lib/store'; import {setUsers, setError} from './users-actions'; import {users} from '../../services/resources'; import {IUser} from '@wix/quix-shared'; export default store => new StoreCache(store, 'users.users') .cacheWith(setUsers) .catchWith(setError) .fetchWith(users); ================================================ FILE: quix-frontend/client/src/types.ts ================================================ ================================================ FILE: quix-frontend/client/src/utils.ts ================================================ import { inject } from './lib/core'; export const singletone = () => { let state: any[] = null; const instance = (getter?: (...args: any) => any, ...args) => { if (typeof getter === 'undefined') { return state; } if (typeof getter !== 'function') { state = getter ? [getter, ...args] : null; return instance; } if (state) { const res = getter(...state); if (res === null) { state = null; } return res; } return instance; } return instance; } export const debounceAsync = (req: Function, __id = 0) => (...args) => (res: Function, ___id = ++__id) => inject('$timeout')(() => __id === ___id && req(...args).then(dres => __id === ___id && res(dres)) , 300); ================================================ FILE: quix-frontend/client/test/dev/localhost.crt ================================================ -----BEGIN CERTIFICATE----- MIIC5TCCAc2gAwIBAgIJALRUBBqde2FDMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV BAMMCWxvY2FsaG9zdDAeFw0xODA2MTgxMzIyMjZaFw0xODA3MTgxMzIyMjZaMBQx EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALmkjGjRgddZIED9xl0qMWdVL6zEsQIFlr1XqsQcKfYLjY2HsT9z1N8mc1C8 7dKqFwTKya6dC9PmLhJsE3Q1+kdNRDiDJMJEL+FZVZAK6q8qZMRRYw3XORgcQ5KG kArgZXcg+1IHTpM8SXx7h9dkngvneUXlkK8Ou0B0ZcrYG4P7smB+/+QtHOtyLhUM AQ9vciYFMpTvRfjx0ezgnP08+q8QaShIu5nk67TkL+FtwKAzSvcnr3Usm6xkOgsP nPQcWTY6l8SocDMrifcxsF+f0Js9Ak0f4FcGccr0aCCsZEmBsUoyFTOnFjsjNDyB ii9+6OLcJoLUFUumxIXGCc0UZJcCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B AQsFAAOCAQEAejf4ByF2KYjUCDGzfqIZ3+iPJQenrG3JfOZNXv6Pet1+WlP10cX5 esPrxI9kHl9JXMgR5KCis2bUm8psxZvdY3G8Y9lEZ1QCIM2ANQSqeu7MuJKwzqjn xDz8gAPPanLUjoVW8LXhovPmrJ13XVqyH1uVQnzGacfoun3fBTh3yLPjftLQ281M fl/VhCXZciqe7HkvRoReLfphyg9BccSdPREOcoIDDY2b9dvQ9ZjX5LlK3XcruxyR xkLf1SFBm27mqOuke6Tq2C/aitWPE+qZ10WvmyCSyshT38Bg6RVE3ioWfMEKwMPx 2FfMXWaYgyfeXpwIVPuu7TbFiIRIZ7PNUQ== -----END CERTIFICATE----- ================================================ FILE: quix-frontend/client/test/dev/localhost.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAuaSMaNGB11kgQP3GXSoxZ1UvrMSxAgWWvVeqxBwp9guNjYex P3PU3yZzULzt0qoXBMrJrp0L0+YuEmwTdDX6R01EOIMkwkQv4VlVkArqrypkxFFj Ddc5GBxDkoaQCuBldyD7UgdOkzxJfHuH12SeC+d5ReWQrw67QHRlytgbg/uyYH7/ 5C0c63IuFQwBD29yJgUylO9F+PHR7OCc/Tz6rxBpKEi7meTrtOQv4W3AoDNK9yev dSybrGQ6Cw+c9BxZNjqXxKhwMyuJ9zGwX5/Qmz0CTR/gVwZxyvRoIKxkSYGxSjIV M6cWOyM0PIGKL37o4twmgtQVS6bEhcYJzRRklwIDAQABAoIBAQCYdsvaSjaY5lnX BpUjbsOkWhINknzNbEmgt59H8NmFeXeIBSlNM5RgsPOEG6Y2nfrJtMJu5gwQu7qa 5qgTiUFDzfF5eDt4UQgBy5y58D1OH0Mi+LShaWE6q/vTGzCxvhmW/T9q3xVpVtoD onCuNbSXkkPHZAKvwymGhhITxejTOzw++wYjKgcSiXAf5X8NWlDgm+EBW9yGYpth 7G5yOJRJBG33nC74rFW7akMX2R6x6iMEaWhp0E9S4qJsYesGEFF830v2b1vu94e6 NYMGmlHMiCrgn8XdT+e5vWprVe9dB5zKktduzW6hC2l+i3KXIi0Jt5qKYMGSojIp mvbT9SgBAoGBAPA3zOXCAbd+VViyxDrDB/nt9zeKUPkBsJxMppijPC08y7arBP4Z wRFA9CYrX+OxKa/Hw8JDM79YyL9XN26Y6xjKQTFDYKeztrhyb6wfUExRzY+NlsnK ZRTfK7EK9yVzN80Wo2axOY/i+8ZrMoCJn5l//DrgN+oMEyoHnOhQiYXxAoGBAMXW 2pAYzvZWNEJ3fEnckaMp1uBrbqwUezBt9qq2Wt+z5q4/HmuEk3/bbvrJGN3LYXpk meV+aTd6oyPgkg7QGp0zbaOWAHdiJDJiraKOtMQGpfoDD8EG5ThY4wakxiozLGTg Os9gdtI5IjQ9HmeK/IM60vaVixDTWDkHYeY1tmsHAoGBALU6M+AGzMrFidgADmES sJrS+BazyEEEEFzqyykOxaCPZFUskvitL2Y37bo6MP6TsxKFkF+n2Yt7jQAl6ZEL 1xn9xM9IuMvsnmZrF2rwuODLOl0aAe+9PSNQ9yJ7VlevpCKa+K3J+NZf9XkNeK1W pszkrMMyU5zEfVTRJ4Rw9j/RAoGAFUB/OftwQAYClyE+uLB49I4KBxGDUfjhQtKN LMlp+Z3Zqd4d5m7XaWSpB0eS5EB0uDEWVxC9PLhvzerRxcWVFk3v+SKj6i8gtEjl XhD2Whhcu/6YMqQK+4KQ4KXSo7XbjvqHVr+GBA8fHX1zRqwnc/FduB9YUPZjA71H RvN+JQECgYAHwwB7dgyRiZkBWwpGsMsfcvS9tf1G0x5LNwr582YyXJ4M+3jb6tlY wnjSmC8kU0Mbun+4h6NWAbsnCLfTRqFw94r5fwvaShEHX2lpQbQ/1oEBXejbacPU KgxwOLxShe6nmZ7LHm0+CnDqK4GzOayXxIdgbiL53JPTjuG+eQft0w== -----END RSA PRIVATE KEY----- ================================================ FILE: quix-frontend/client/test/dev/server.ts ================================================ import express from 'express'; import request from 'request'; import http from 'http'; import { renderVM } from './vm'; import { mock, reset } from '../mocks'; import expressWs from 'express-ws'; import {setupMockWs, setupSubscriptionMockWs} from './websocket-mock'; const proxyBaseUrl = 'http://localhost:3000'; export function start(port = process.env.PORT || '3000') { const app = express(); const server = http.createServer(app); expressWs(app, server); app.use(express.json()); app.post('/mock/pattern', (req, res) => { const { pattern, payload, options } = req.body; mock(pattern, payload, options); res.status(200).send('OK'); }); app.get('/mock/reset', (req, res) => { reset(); res.status(200).send('OK'); }); setupMockWs(app); setupSubscriptionMockWs(app); app.all('/api/*', async (req, res) => { if (port === '3000' || port === '3100') { const [status, payload] = await mock(req.path); res.status(status).json(payload); } else { const url = proxyBaseUrl + req.url; req.pipe(request[req.method.toLowerCase()](url)).pipe(res); } }); app.get('/', (req, res) => { const quixConfig = { modules: [ { id: 'presto', name: 'presto', components: { db: {}, note: {} }, engine: 'presto', syntax: 'presto' }, { id: 'athena', name: 'athena', components: { db: {}, note: {} }, engine: 'athena', syntax: 'presto' }, { id: 'python', name: 'athena', components: { note: {} }, engine: 'python', syntax: 'python' } ], auth: { googleClientId: '' }, clientTopology: { executeBaseUrl: `localhost:${port}/mock`, staticsBaseUrl: '//localhost:3200/', apiBasePath: '' }, mode: { debug: true, demo: false } }; res.send( renderVM('./src/index.vm', { quixConfig: JSON.stringify(quixConfig, null, 2) }) ); }); return server.listen(port, () => { console.info(`Fake server is running on port ${port}`); }); } ================================================ FILE: quix-frontend/client/test/dev/vm.ts ================================================ import * as fs from 'fs'; import {Engine} from 'velocity'; function loadData(file) { try { return JSON.parse(fs.readFileSync(file, 'utf-8').toString()); } catch (ex) { throw ex; } } export function renderVM(template, data) { const engine = new Engine({template}); const velocityData = loadData('./velocity.data.json'); const velocityDataPrivate = loadData('./velocity.private.data.json'); return engine.render({...velocityData, ...velocityDataPrivate, ...data}); } ================================================ FILE: quix-frontend/client/test/dev/websocket-mock.ts ================================================ import * as WebSocket from 'ws'; import {Router, Application} from 'express'; import {MockNoteContent} from '../mocks' const successEvents = [ {event:'start',data:{id:'d85eed1e-fec8-4f1c-abba-5ab8593ea46b', 'numOfQueries':1}}, {event:'query-start',data:{id:'20190507_155320_00041_s9xam'}}, {event:'query-details',data:{id:'20190507_155320_00041_s9xam', code: 'first query'}}, {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':0}}, {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':0}}, {event:'fields',data:{id:'20190507_155320_00041_s9xam','fields':['date_created','num','category']}}, {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':30}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-01',100,'A']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-02',100,'A']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',200,'A']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',100,'A']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-04',250,'A']}}, {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':60}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-01',150,'B']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-02',150,'B']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',250,'B']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',150,'B']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-04',250,'B']}}, {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':100}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-01',120,'C']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-02',120,'C']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',220,'C']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',120,'C']}}, {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-04',220,'C']}}, {event: 'log', data: {id: '20190507_155320_00041_s9xa', level: 'INFO', line: 'INFO message'}}, {event: 'log', data: {id: '20190507_155320_00041_s9xa', level: 'ERROR', line: 'ERROR message'}}, {event:'query-end',data:{id:'20190507_155320_00041_s9xam'}}, {event:'query-start',data:{id:'second'}}, {event:'query-details',data:{id:'second', code: 'second query'}}, {event:'fields',data:{id:'second','fields':['a','b']}}, {event:'query-details',data:{id:'second','code':'select 1'}}, {event:'row',data:{id:'second',values:[1,2]}}, {event:'row',data:{id:'second',values:[3,4]}}, {event:'query-end',data:{id:'second'}}, {event:'end',data:{id:'d85eed1e-fec8-4f1c-abba-5ab8593ea46b'}} ]; const failEvents = [ {event: 'start', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2', 'numOfQueries': 1}}, {event: 'query-start', data: {id: '20190506_152226_00201_xps63'}}, {event: 'query-details', data: {id: '20190506_152226_00201_xps63', 'code': 'select a'}}, {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}}, {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}}, {event: 'error', data: {id: '20190506_152226_00201_xps63', 'message': `UnknownException(UnknownException exception, code: 1002, host: foo.goo.net, port: 3000; Code: 20. DB::Exception: Syntax error: failed at position 249 ('a') (line 8, col 5): a, b, c FROM foo.goo WHERE (1 = 0 or toDateTime(a) > now() - INTERVAL 1 DAY) AND b = 'ERROR' . Expected one of: token, Comma, FROM, PREWHERE, WHERE, GROUP BY, WITH, HAVING, WINDOW, ORDER BY, LIMIT, OFFSET, SETTINGS, UNION, EXCEPT, INTERSECT, INTO OUTFILE, FORMAT, end of query. (SYNTAX_ERROR) (version 1.1.1 (official build)) )`}}, {event: 'query-end', data: {id: '20190506_152226_00201_xps63'}}, {event: 'end', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2'}} ]; const permissionFailEvents = [ {event: 'start', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2', 'numOfQueries': 1}}, {event: 'query-start', data: {id: '20190506_152226_00201_xps63'}}, {event: 'query-details', data: {id: '20190506_152226_00201_xps63', 'code': 'select a'}}, {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}}, {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}}, {event: 'error', data: {id: '20190506_152226_00201_xps63', 'message': 'permission denied'}}, {event: 'query-end', data: {id: '20190506_152226_00201_xps63'}}, {event: 'end', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2'}} ]; const sqlResultEvents = [ {'event':'start', 'data': { 'id': 'd5301f06-9c89-41f5-82e0-5974fb0de6fe', "numOfQueries": 1 } }, {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': "SELECT *", 'level': 'INFO' } }, {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': "FROM WorldHistory as h", 'level': 'INFO' } }, {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': "WHERE", 'level': 'INFO' } }, {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': "h.year = 1984", 'level': 'INFO' } }, {'event':'end', 'data': { 'id': 'd5301f06-9c89-41f5-82e0-5974fb0de6fe' } } ] export const setupMockWs = (app: Application) => { const router = Router(); router.ws('/:type', (ws, req) => { ws.on('message', async (msg) => { const payload: {data: {code: string}; event: string} = JSON.parse(msg.toString()); const match = payload.data.code.match(/timeout=(\d+)/) const timeout = match && match[1] ? parseInt(match[1], 10) : 0; if (payload.event === 'execute') { const code = payload.data.code; if (code.includes(MockNoteContent.success)) { sendEvents(ws, successEvents, timeout); } else if (code.includes(MockNoteContent.error)) { sendEvents(ws, failEvents, timeout); } else if (code.includes(MockNoteContent.permissionError)) { sendEvents(ws, permissionFailEvents, timeout); } else if (code.includes(MockNoteContent.sql)) { sendEvents(ws, sqlResultEvents, timeout); } else { ws.close(); } } }); }); app.use('/mock/api/v1/execute/', router); } export const setupSubscriptionMockWs = (app: Application) => { const sockets = []; const router = Router(); router.ws('/', (ws, req) => { ws.on('message', async (msg) => { const {event} = JSON.parse(msg.toString()); if (event === 'subscribe') { sockets.push(ws); } }); }); router.post('/mock-broadcast', (req, res) => { const payload = req.body; sockets.forEach(ws => { sendEvents(ws, payload, 0); }); res.status(200).send('OK'); }); app.use('/subscription', router); } const promisifiedSend = (WS: WebSocket) => (data: any) => new Promise((resolve, reject) => { WS.send(data, (err) => { if (err) { reject(err); } else { resolve(void 0) } }); }); const sendEvents = (WS: WebSocket, events: any[], timeout: number) => { const send = promisifiedSend(WS); events.reduce((res, event) => { return new Promise(resolve => res.then(() => setTimeout(() => send(JSON.stringify(event)).then(resolve), timeout))); }, Promise.resolve() as any); }; ================================================ FILE: quix-frontend/client/test/e2e/dbExplorer.e2e.ts ================================================ import {expect} from 'chai'; import {Driver} from './driver'; import {createMockDbExplorer, createMockDbExplorerItem} from '../mocks'; import {FileExplorerTestkit} from '../../src/react-components/file-explorer/file-explorer-testkit'; import {ServerTreeItem} from '../../src/components/db-sidebar/db-sidebar-types'; const COMPONENT_ANIMATION_TIME = 350; describe('FileExplorer ::', () => { let driver: Driver, testkit: FileExplorerTestkit; const goToDbExplorer = async (items: ServerTreeItem[] = [], delay = 0) => { const tree = createMockDbExplorer(items); await driver.mock.http(`/api/db/:type/explore`, tree, {delay}); await driver.mock.http(`/api/db/:type/search`, tree, {delay}); await driver.goto('/home'); } const mockTableResponse = async (tableName: string, delay = 0) => { const columns = { children: [{ dataType: 'varchar', name: 'column_of_' + tableName }] } await driver.mock.http(`/api/db/:type/explore/:catalog/:schema/:table`, columns, {delay}) } const ToggleTreeItemByName = async (name: string, wait = true) => { await testkit.clickOnItemByName(name); if (wait) { await driver.sleep(COMPONENT_ANIMATION_TIME); } } beforeEach(async () => { driver = new Driver(); await driver.init(); testkit = driver.createTestkit(FileExplorerTestkit); }); it('should display tree', async () => { await goToDbExplorer([createMockDbExplorerItem({name: 'test'})]); await testkit.toggleFileExplorerTab(); expect(await testkit.numOfTreeItems()).to.eq(1); expect(await testkit.isTreeItemExistsByName('test')).to.be.true; }); it('should check toggle tree item works', async () => { await goToDbExplorer( [ createMockDbExplorerItem({ name: 'parentTest', children: [ createMockDbExplorerItem({ name: 'childTest', type: 'schema' }) ] }) ] ); await testkit.toggleFileExplorerTab(); expect(await testkit.numOfTreeItems()).to.eq(1); expect(await testkit.isTreeItemExistsByName('parentTest')).to.be.true; await ToggleTreeItemByName('parentTest'); expect(await testkit.numOfTreeItems()).to.eq(2); expect(await testkit.isTreeItemExistsByName('childTest')).to.be.true; await ToggleTreeItemByName('parentTest'); expect(await testkit.numOfTreeItems()).to.eq(1); expect(await testkit.isTreeItemExistsByName('parentTest')).to.be.true; }); it('should check toggle tree item recursively', async () => { await goToDbExplorer( [ createMockDbExplorerItem({ name: 'parentTest', children: [ createMockDbExplorerItem({ name: 'childTest1', type: 'schema', children: [ createMockDbExplorerItem({ name: 'childTest2', type: 'table' }) ] }), ] }) ] ); await testkit.toggleFileExplorerTab(); await ToggleTreeItemByName('parentTest'); expect(await testkit.numOfTreeItems()).to.eq(2); await ToggleTreeItemByName('childTest1'); expect(await testkit.numOfTreeItems()).to.eq(3); expect(await testkit.isTreeItemExistsByName('childTest2')).to.be.true; await ToggleTreeItemByName('parentTest'); expect(await testkit.numOfTreeItems()).to.eq(1); expect(await testkit.isTreeItemExistsByName('parentTest')).to.be.true; }); it('should close all tree items when reopening fileExplorer tab', async () => { await goToDbExplorer( [ createMockDbExplorerItem({ name: 'parentTest', children: [ createMockDbExplorerItem({ name: 'childSchemaTest1', type: 'schema', children: [ createMockDbExplorerItem({ name: 'childTableTest1', type: 'table' }), ] }), ] }) ] ); await testkit.toggleFileExplorerTab(); await ToggleTreeItemByName('parentTest'); await ToggleTreeItemByName('childSchemaTest1'); await ToggleTreeItemByName('childTableTest1'); await testkit.toggleFileExplorerTab(); await driver.sleep(COMPONENT_ANIMATION_TIME); await testkit.toggleFileExplorerTab(); expect(await testkit.numOfTreeItems()).to.eq(1); }); it('should load when clicking on table', async () => { await goToDbExplorer( [ createMockDbExplorerItem({ name: 'parentTest', children: [ createMockDbExplorerItem({ name: 'childSchemaTest1', type: 'schema', children: [ createMockDbExplorerItem({ name: 'childTableTest1', type: 'table' }), createMockDbExplorerItem({ name: 'childTableTest2', type: 'table' }) ] }), ] }) ] ); mockTableResponse('childTableTest1', 1000); mockTableResponse('childTableTest2', 1000); await testkit.toggleFileExplorerTab(); await ToggleTreeItemByName('parentTest'); await ToggleTreeItemByName('childSchemaTest1'); await ToggleTreeItemByName('childTableTest1'); expect(await testkit.numOfLoadingTreeItems()).to.eq(1); await ToggleTreeItemByName('childTableTest2'); expect(await testkit.numOfLoadingTreeItems()).to.eq(2); }); it.skip("shouldn't load twice when clicking on same table", async () => { await goToDbExplorer( [ createMockDbExplorerItem({ name: 'parentTest', children: [ createMockDbExplorerItem({ name: 'childSchemaTest1', type: 'schema', children: [ createMockDbExplorerItem({ name: 'childTableTest1', type: 'table' }), ] }), ] }) ] ); await testkit.toggleFileExplorerTab(); await ToggleTreeItemByName('parentTest'); await ToggleTreeItemByName('childSchemaTest1'); await ToggleTreeItemByName('childTableTest1'); expect(await testkit.numOfTreeItems()).to.eq(4); await ToggleTreeItemByName('childTableTest1'); mockTableResponse('childTableTest1', 10000); await ToggleTreeItemByName('childTableTest1', false); expect(await testkit.numOfOpenedTreeItems()).to.eq(3); }); it('should expand all tree items after searching', async () => { await goToDbExplorer( [ createMockDbExplorerItem({ name: 'parentTest', children: [ createMockDbExplorerItem({ name: 'childTest1', type: 'schema', children: [ createMockDbExplorerItem({ name: 'childTest2', type: 'table' }) ] }), ] }) ] ); await testkit.toggleFileExplorerTab(); await driver.sleep(COMPONENT_ANIMATION_TIME); await testkit.search('bla'); await driver.sleep(2 * COMPONENT_ANIMATION_TIME); expect(await testkit.numOfTreeItems()).to.eq(4); // 3 visible and 1 hidden by angular }); }); ================================================ FILE: quix-frontend/client/test/e2e/driver.ts ================================================ import {Browser, Page, ElementHandle} from 'puppeteer'; import {baseURL} from './e2e-common'; import fetch from 'node-fetch'; import { Class } from 'utility-types'; const WAIT_TIMEOUT = 5000; const element = async (page: Page, selector) => { if (page.waitForSelector) { await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT}); } return page.$(selector); } const elements = async (page: Page, selector) => { if (page.waitForSelector) { await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT}); } return page.$$(selector); } const evalOne = async (page: Page, selector, fn: (element: Element) => any) => { if (page.waitForSelector) { await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT}); } return page.$eval(selector, fn); } const evalMany = async (page: Page, selector, fn: (elements: Element[], args) => any, args = {}) => { if (page.waitForSelector) { await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT}); } return page.$$eval(selector, fn, args); } export class Driver { private readonly browser: Browser = browser; private page: Page; public mock: Mock; public url: URL; public query: Query; public click: Click; public evaluate: Evaluate; public log: Log; async init() { this.page = await this.browser.newPage(); this.mock = new Mock(); this.url = new URL(this.page); this.query = new Query(this.page); this.click = new Click(this.page); this.evaluate = new Evaluate(this.page); this.log = new Log(this.page); await this.mock.reset(); return this; } goto(state: string) { return this.page.goto(`${baseURL}/#${state}`); } sleep(ms: number) { return this.page.waitFor(ms); } execute(fn: Function) { return this.page.evaluate(fn as any); } createTestkit>(TestkitCtor: T): InstanceType { return new TestkitCtor(this.page); } } export class Mock { constructor () {} async http(pattern: string, payload: any, options?: {}) { return fetch(`${baseURL}/mock/pattern`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({pattern, payload, options}) }); } async reset() { return fetch(`${baseURL}/mock/reset`); } async wsBroadcast(message: any) { const messages = Array.isArray(message) ? message : [message]; return fetch(`${baseURL}/subscription/mock-broadcast`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(messages) }); } } export class URL { constructor (private readonly page: Page) {} async matches(pattern: string) { const fn = (p) => { const url = document.location.hash.replace('#', ''); return (new ((window as any).UrlPattern)(p)).match(url) !== null; }; await this.page.waitForFunction(fn, {timeout: WAIT_TIMEOUT}, pattern); return true; } } export class Query { constructor (private readonly page: Page) {} async hook(hook: string, pseudoClass: string = '') { return element(this.page, `[data-hook="${hook}"]${pseudoClass}`); } async hooks(hook: string, pseudoClass: string = '') { return elements(this.page, `[data-hook="${hook}"]${pseudoClass}`); } async attr(attr: string, pseudoClass: string = '') { return element(this.page, `[${attr}]${pseudoClass}`); } async attrs(attr: string, pseudoClass: string = '') { return elements(this.page, `[${attr}]${pseudoClass}`); } async $(selector: string) { return element(this.page, selector); } async $$(selector: string) { return elements(this.page, selector); } } export class Click { constructor (private readonly page: Page) {} async hook(hook: string, pseudoClass: string = '') { const el = await element(this.page, `[data-hook="${hook}"]${pseudoClass}`); if (el) { await el.click(); } } async attr(attr: string, pseudoClass: string = '') { const el = await element(this.page, `[${attr}]${pseudoClass}`); if (el) { await el.click(); } } async $(selector: string) { const el = await element(this.page, selector); if (el) { await el.click(); } } } export class Evaluate { constructor (private readonly page: Page) {} async hook(hook: string, fn: (element: Element) => any) { return evalOne(this.page, `[data-hook="${hook}"]`, fn); } async hooks(hook: string, fn: (element: Element[], args) => any, args = {}) { return evalMany(this.page, `[data-hook="${hook}"]`, fn, args); } async attr(attr: string, fn: (element: Element) => any) { return evalOne(this.page, `[${attr}]`, fn); } async attrs(attr: string, fn: (element: Element[]) => any) { return evalMany(this.page, `[${attr}]`, fn); } async $(selector: string, fn: (element: Element) => any) { return evalOne(this.page, selector, fn); } async $$(selector: string, fn: (element: Element[]) => any) { return evalMany(this.page, selector, fn); } } export class Log { constructor (private readonly page: Page) {} async url() { /* tslint:disable-next-line:no-console */ console.log(`Current page url is "${(await this.page.evaluate(() => document.location.hash)).replace('#', '')}"`); } async html() { /* tslint:disable-next-line:no-console */ console.log(await this.page.evaluate(() => document.body.innerHTML)); } } export class Keyboard { constructor (private readonly page: Page) {} type(hook: string, value: string) { return this.page.type(`[data-hook="${hook}"]`, value, { delay: 10 }); } } export class Testkit { public query: Query; public click: Click; public evaluate: Evaluate; public keyboard: Keyboard; constructor(pageOrElement: Page | ElementHandle) { if (!pageOrElement) { throw new Error('Got null page or element'); } this.query = new Query(pageOrElement as Page); this.click = new Click(pageOrElement as Page); this.evaluate = new Evaluate(pageOrElement as Page); this.keyboard = new Keyboard(pageOrElement as Page); } } ================================================ FILE: quix-frontend/client/test/e2e/e2e-common.ts ================================================ import puppeteer from 'puppeteer'; import {start} from '../dev/server'; before(async () => { start('3100'); global.browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], headless: true }); }); after(async () => { await global.browser.close(); }); export const baseURL = `http://localhost:3100`; ================================================ FILE: quix-frontend/client/test/e2e/favorites.e2e.ts ================================================ import {expect} from 'chai'; import {Driver} from './driver'; import {createMockFile} from '../mocks'; import {FavoritesTestkit} from '../../src/state-components/favorites/favorites-testkit'; describe('Favorites ::', () => { let driver: Driver, testkit: FavoritesTestkit; const gotoFavoritesWithError = async () => { await driver.mock.http('/api/favorites', [404, {message: 'Failed to fetch favorites'}]); await driver.goto(`/favorites`); } const gotoFavorites = async (mock = [createMockFile()]) => { await driver.mock.http('/api/favorites', mock); await driver.goto('/favorites'); return mock; } beforeEach(async () => { driver = new Driver(); await driver.init(); testkit = driver.createTestkit(FavoritesTestkit); }); it('should display error state when failed to fetch favorites', async () => { await gotoFavoritesWithError(); expect(await testkit.tableStates.hasError()).to.be.true; }); it('should display empty state', async () => { await gotoFavorites([]); expect(await testkit.tableStates.hasEmptyResult()).to.be.true; }); it('should display content', async () => { await gotoFavorites(); expect(await testkit.favoritesTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(1); }); }); ================================================ FILE: quix-frontend/client/test/e2e/files.e2e.ts ================================================ import {expect} from 'chai'; import {Driver} from './driver'; import {createMockFiles, createMockFile, createMockFolderPayload, createMockFolder} from '../mocks'; import {FilesTestkit} from '../../src/state-components/files/files-testkit'; describe('Files ::', () => { let driver: Driver, testkit: FilesTestkit; const gotoErrorFiles = async () => { await driver.mock.http('/api/files', [404, {message: 'Failed to fetch files'}]); await driver.goto(`/files/`); } const gotoErrorFolder = async () => { await driver.mock.http('/api/files/:id', [404, {message: 'Folder not found'}]); await driver.goto(`/files/1`); } const gotoEditableRootFolder = async (files = [createMockFolder(), createMockFile()]) => { const mock = createMockFiles(files); await driver.mock.http('/api/files', mock); await driver.goto('/files/'); return mock; } const gotoEditableFolder = async (files = [createMockFolder(), createMockFile()]) => { const mock = createMockFolderPayload(files); await driver.mock.http('/api/files/:id', mock); await driver.goto('/files/1'); return mock; } const gotoReadonlyFolder = async (files = [createMockFolder(), createMockFile()]) => { const mock = createMockFolderPayload(files, {owner: 'readonly@quix.com'}); await driver.mock.http('/api/files/:id', mock); await driver.goto('/files/1'); return mock; } beforeEach(async () => { driver = new Driver(); await driver.init(); testkit = driver.createTestkit(FilesTestkit); }); it('should display error state when failed to fetch files', async () => { await gotoErrorFiles(); expect(await testkit.hasErrorState()).to.be.true; }); it('should display error state when folder is not found', async () => { await gotoErrorFolder(); expect(await testkit.hasErrorState()).to.be.true; }); it('should display empty state in root folder when user does not have folders/notebooks', async () => { await gotoEditableRootFolder([]); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.numOfFiles()).to.equal(1); expect(await testkit.hasEmptyState()).to.be.true; }); it('should display empty state when folder does not have folders/notebooks', async () => { await gotoEditableFolder([]); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2); expect(await testkit.hasEmptyState()).to.be.true; }); it('should display content in root folder when user has folders/notebooks', async () => { await gotoEditableRootFolder(); expect(await testkit.hasContent()).to.be.true; }); it('should display content when folder has folders/notebooks', async () => { await gotoEditableFolder(); expect(await testkit.hasContent()).to.be.true; }); it('should navigate to a notebook in the root folder', async () => { const files = await gotoEditableRootFolder(); await testkit.clickFile(2); expect(await driver.url.matches(`/notebook/${files[2].id}`)).to.be.true; }); it('should navigate to a notebook in a folder', async () => { const folder = await gotoEditableFolder(); await testkit.clickFile(2); expect(await driver.url.matches(`/notebook/${folder.files[1].id}`)).to.be.true; }); it('should navigate to a folder in the root folder', async () => { const files = await gotoEditableRootFolder(); await testkit.clickFile(1); expect(await driver.url.matches(`/files/${files[1].id}`)).to.be.true; }); it('should navigate to a folder in a folder', async () => { const folder = await gotoEditableFolder(); await testkit.clickFile(1); expect(await driver.url.matches(`/files/${folder.files[0].id}`)).to.be.true; }); it('should create a folder in a root folder', async () => { await gotoEditableRootFolder([]); await testkit.clickAddFolder(); expect(await testkit.numOfFiles()).to.equal(1); }); it('should create a folder in a folder', async () => { await gotoEditableFolder([]); await testkit.clickAddFolder(); expect(await testkit.numOfFiles()).to.equal(1); }); it('should create a notebook in a root folder and navigate to it', async () => { await gotoEditableRootFolder([]); await testkit.clickAddNotebook(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2); expect(await driver.url.matches('/notebook/:id')).to.be.true; }); it('should create a notebook in a folder and navigate to it', async () => { await gotoEditableFolder([]); await testkit.clickAddNotebook(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2); expect(await driver.url.matches('/notebook/:id')).to.be.true; }); it('should navigate to the root after navigating to a folder and clicking the root folder', async () => { await gotoEditableRootFolder(); await testkit.clickFile(1); expect(await driver.url.matches('/files/:id')).to.be.true; const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); await breadcrumbsTestkit.clickFile(1); expect(await driver.url.matches('/files/')).to.be.true; }); describe('Permissions ::', () => { describe('Name ::', () => { it('should allow to edit name if user is owner', async () => { await gotoEditableFolder(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.true; }); it('should not allow to edit name if user is not owner', async () => { await gotoReadonlyFolder(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.false; }); }); describe('Add folder | Add notebook ::', () => { it('should enable "Add folder" and "Add notebook" buttons if user is owner', async () => { await gotoEditableFolder(); expect(await testkit.isAddFolderEnabled()).to.be.true; expect(await testkit.isAddNotebookEnabled()).to.be.true; }); it('should disable "Add folder" and "Add notebook" buttons if user is not owner', async () => { await gotoReadonlyFolder(); expect(await testkit.isAddFolderEnabled()).to.be.false; expect(await testkit.isAddNotebookEnabled()).to.be.false; }); }); describe('Delete ::', () => { it('should enable the delete action if user is owner', async () => { await gotoEditableFolder(); const actionsTestkit = await testkit.getActionsTestkit(); expect(await actionsTestkit.isDeleteEnabled()).to.be.true; }); it('should disable the delete action if user is not owner', async () => { await gotoReadonlyFolder(); const actionsTestkit = await testkit.getActionsTestkit(); expect(await actionsTestkit.isDeleteEnabled()).to.be.false; }); }); describe('Bulk select ::', () => { it('should enable bulk selection if user is owner', async () => { await gotoEditableFolder(); expect(await testkit.isBulkSelectEnabled()).to.be.true; }); it('should disable bulk selection if user is not owner', async () => { await gotoReadonlyFolder(); expect(await testkit.isBulkSelectEnabled()).to.be.false; }); }); }); describe('Synchronization ::', () => { const createNotebookEvents = [ { "event": "action", "data": { "type": "notebook.create", "notebook": { "id": "bfeeabd8-e69d-4380-8bb7-25f18e92855f", "name": "New notebook", "notes": [], "isLiked": false, "path": [{ "id": "c682d9db-2028-4fea-a5a9-eafa1fa58314", "name": "My notebooks" }], "owner": "user@quix.com", "ownerDetails": { "id": "", "name": "", "email": "", "avatar": "", "rootFolder": "", "dateCreated": 0, "dateUpdated": 0 }, "dateCreated": 1577967426084, "dateUpdated": 1577967426084 }, "id": "bfeeabd8-e69d-4380-8bb7-25f18e92855f" } }, { "event": "action", "data": { "type": "note.create", "id": "c5ef5489-6ad2-44f6-b76f-ac2864f0db79", "note": { "id": "c5ef5489-6ad2-44f6-b76f-ac2864f0db79", "notebookId": "bfeeabd8-e69d-4380-8bb7-25f18e92855f", "name": "New note", "type": "presto", "content": "\n", "owner": "", "dateCreated": 1577967426084, "dateUpdated": 1577967426084 } } } ]; it('should subscribe to event sourcing mechanism', async function() { await gotoEditableRootFolder([]); expect(await testkit.hasEmptyState()).to.be.true; await driver.mock.wsBroadcast(createNotebookEvents); expect(await testkit.hasContent()).to.be.true; }); }) }); ================================================ FILE: quix-frontend/client/test/e2e/history.e2e.ts ================================================ import {expect} from 'chai'; import {Driver} from './driver'; import {createMockHistory} from '../mocks'; import {HistoryTestkit} from '../../src/state-components/history/history-testkit'; describe('History ::', () => { let driver: Driver, testkit: HistoryTestkit; const gotoHistoryWithError = async () => { await driver.mock.http('/api/history', [404, { message: 'Failed to fetch history' }]); await driver.goto(`/history`); } const gotoHistory = async (mock = [createMockHistory()]) => { await driver.mock.http('/api/history', mock); await driver.goto('/history'); } beforeEach(async () => { driver = new Driver(); await driver.init(); testkit = driver.createTestkit(HistoryTestkit); }); it('should display error state when failed to fetch history', async () => { await gotoHistoryWithError(); expect(await testkit.tableStates.hasError()).to.be.true; }); it('should display content', async () => { await gotoHistory(); expect(await testkit.historyTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(1); }); it('should display empty result', async () => { await gotoHistory([]); expect(await testkit.tableStates.hasEmptyResult()).to.be.true; }); it('should display user options', async () => { await gotoHistory(); expect(await testkit.tableStates.hasLoading()).to.be.true; await testkit.userFilter.clickOnDropdown(); expect(await testkit.userFilter.hasOptions()).to.be.true; }); it('should filter by user', async () => { await gotoHistory(); expect(await testkit.historyTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(1); await driver.mock.reset(); await testkit.userFilter.clickOnDropdown(); await testkit.userFilter.clickOnOption(); expect(await testkit.tableStates.hasFilterLoading()).to.be.true; expect(await testkit.historyTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(100); }); it('should filter by query', async () => { await gotoHistory(); expect(await testkit.historyTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(1); await driver.mock.reset(); await testkit.queryFilter.click(); await testkit.queryFilter.set('example'); expect(await testkit.tableStates.hasFilterLoading()).to.be.true; expect(await testkit.historyTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(100); }); }); ================================================ FILE: quix-frontend/client/test/e2e/home.e2e.ts ================================================ import {expect} from 'chai'; import {Driver} from './driver'; import {HomeTestkit} from '../../src/state-components/home/home-testkit'; import {NotebookTestkit} from '../../src/state-components/notebook/notebook-testkit'; describe('Home ::', () => { let driver: Driver, testkit: HomeTestkit; beforeEach(async () => { driver = new Driver(); await driver.init(); await driver.goto('/home'); testkit = driver.createTestkit(HomeTestkit); }); it('should navigate to notebooks state', async () => { await testkit.clickNotebooks(); expect(await driver.url.matches('/files/')).to.be.true; }); it('should create a notebook and navigate to it', async () => { await testkit.clickAddNotebook(); expect(await driver.url.matches('/notebook/:id')).to.be.true; }); it('should focus the newly created notebook name', async () => { await testkit.clickAddNotebook(); const notebookTestkit = driver.createTestkit(NotebookTestkit); const breadcrumbsTestkit = await notebookTestkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2); expect(await breadcrumbsTestkit.isFileNameFocused()).to.be.true; }); }); ================================================ FILE: quix-frontend/client/test/e2e/notebook.e2e.ts ================================================ import {expect} from 'chai'; import {Driver} from './driver'; import {createMockNotebook, createMockNote, MockNoteContent} from '../mocks'; import {NotebookTestkit} from '../../src/state-components/notebook/notebook-testkit'; import {ConsoleResultTestkit} from '../../src/lib/runner/directives/results/console/console-result-testkit'; describe('Notebook ::', () => { let driver: Driver, testkit: NotebookTestkit; const gotoEditableNotebook = async (notes = [createMockNote('1')]) => { const notebook = createMockNotebook(notes); await driver.mock.http(`/api/notebook/:id`, notebook); await driver.goto('/notebook/1'); }; const gotoReadonlyNotebook = async () => { const notebook = createMockNotebook([createMockNote('1')], { owner: 'readonly@quix.com' }); await driver.mock.http(`/api/notebook/:id`, notebook); await driver.goto('/notebook/1'); }; const gotoErrorNotebook = async () => { await driver.mock.http('/api/notebook/:id', [404, { message: 'Notebook not found' }]); await driver.goto(`/notebook/1`); }; beforeEach(async () => { driver = new Driver(); await driver.init(); testkit = driver.createTestkit(NotebookTestkit); }); it('should display error state when notebook is not found', async () => { await gotoErrorNotebook(); expect(await testkit.hasErrorState()).to.be.true; }); it('should display empty state when notebook is empty', async () => { await gotoEditableNotebook([]); expect(await testkit.hasEmptyState()).to.be.true; }); it('should display notes if notebook has at least one note', async () => { await gotoEditableNotebook(); expect(await testkit.hasNotes()).to.be.true; }); it('should navigate to the files state', async () => { await gotoEditableNotebook(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); await breadcrumbsTestkit.clickFile(1); expect(await driver.url.matches('/files/')).to.be.true; }); it('should not focus the name input of existing note', async () => { await gotoEditableNotebook(); expect(await testkit.numOfNotes()).to.equal(1); const noteTestkit = await testkit.getNoteTestkit(1); expect(await noteTestkit.isNameFocused()).to.be.false; }); it('should add a note and focus the name input', async () => { await gotoEditableNotebook(); expect(await testkit.numOfNotes()).to.equal(1); await testkit.clickAddNoteDropdown(); await driver.sleep(500); await testkit.clickAddNote(); expect(await testkit.numOfNotes()).to.equal(2); const noteTestkit = await testkit.getNoteTestkit(2); expect(await noteTestkit.isNameFocused()).to.be.true; }); describe('Permissions ::', () => { describe('Name ::', () => { it('should allow to edit name if user is owner', async () => { await gotoEditableNotebook(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.true; }); it('should not allow to edit name if user is not owner', async () => { await gotoReadonlyNotebook(); const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit(); expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.false; }); }); describe('Add note ::', () => { it('should enable "Add note" button if user is owner', async () => { await gotoEditableNotebook(); expect(await testkit.isAddNoteEnabled()).to.be.true; }); it('should disable "Add note" button if user is not owner', async () => { await gotoReadonlyNotebook(); expect(await testkit.isAddNoteEnabled()).to.be.false; }); }); describe('Delete ::', () => { it('should enable the delete action if user is owner', async () => { await gotoEditableNotebook(); const actionsTestkit = await testkit.getActionsTestkit(); expect(await actionsTestkit.isDeleteEnabled()).to.be.true; }); it('should disable the delete action if user is not owner', async () => { await gotoReadonlyNotebook(); const actionsTestkit = await testkit.getActionsTestkit(); expect(await actionsTestkit.isDeleteEnabled()).to.be.false; }); }); describe('Note ::', () => { describe('Name ::', () => { it('should allow to edit note name if user is owner', async () => { await gotoEditableNotebook(); const noteTestkit = await testkit.getNoteTestkit(1); expect(await noteTestkit.isNameEditable()).to.be.true; }); it('should not allow to edit note name if user is not owner', async () => { await gotoReadonlyNotebook(); const noteTestkit = await testkit.getNoteTestkit(1); expect(await noteTestkit.isNameEditable()).to.be.false; }); }); describe('Select ::', () => { it('should allow to select note if user is owner', async () => { await gotoEditableNotebook(); const noteTestkit = await testkit.getNoteTestkit(1); expect(await noteTestkit.isSelectEnabled()).to.be.true; }); it('should not allow to select note if user is not owner', async () => { await gotoReadonlyNotebook(); const noteTestkit = await testkit.getNoteTestkit(1); expect(await noteTestkit.isSelectEnabled()).to.be.false; }); }); describe('Delete ::', () => { it('should allow to delete note if user is owner', async () => { await gotoEditableNotebook(); const noteTestkit = await testkit.getNoteTestkit(1); const actionsTestkit = await noteTestkit.getActionsTestkit(); expect(await actionsTestkit.isDeleteEnabled()).to.be.true; }); it('should not allow to delete note if user is not owner', async () => { await gotoReadonlyNotebook(); const noteTestkit = await testkit.getNoteTestkit(1); const actionsTestkit = await noteTestkit.getActionsTestkit(); expect(await actionsTestkit.isDeleteEnabled()).to.be.false; }); }); describe('Result ::', () => { describe('Console ::', () => { it('should merge lines with same timestamp into group', async () => { await gotoEditableNotebook([ createMockNote('1', { type: 'python', content: MockNoteContent.sql, }), ]); const noteTestkit = await testkit.getNoteTestkit(1); const runnerTestkit = await noteTestkit.getRunnerTestkit(); await runnerTestkit.clickRun(); const consoleResultTestkit = driver.createTestkit(ConsoleResultTestkit); expect(await consoleResultTestkit.getTimestampsCount()).to.equal(2); expect(await consoleResultTestkit.getValueRowsCount()).to.equal(4); }); }); }); }); }); }); ================================================ FILE: quix-frontend/client/test/e2e/users.e2e.ts ================================================ import {expect} from 'chai'; import {IUser} from '@wix/quix-shared'; import {Driver} from './driver'; import {createMockUser} from '../mocks'; import {UsersTestkit} from '../../src/state-components/users/users-testkit'; describe('Users ::', () => { let driver: Driver, testkit: UsersTestkit; const gotoUsersWithError = async () => { await driver.mock.http('/api/users', [404, {message: 'Failed to fetch users'}]); await driver.goto(`/users`); } const gotoUsers = async (mock: Partial[] = [createMockUser()]) => { await driver.mock.http('/api/users', mock); await driver.goto('/users'); return mock; } beforeEach(async () => { driver = new Driver(); await driver.init(); testkit = driver.createTestkit(UsersTestkit); }); it('should display error state when failed to fetch users', async () => { await gotoUsersWithError(); expect(await testkit.tableStates.hasError()).to.be.true; }); it('should display content', async () => { await gotoUsers(); expect(await testkit.usersTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(1); }); it('should display empty result', async () => { await gotoUsers([]); expect(await testkit.tableStates.hasEmptyResult()).to.be.true; }); it('should filter by users', async () => { await gotoUsers([ {email: 'email0@bla.bla'}, {email: 'email1@bla.bla'}, {email: 'email2@bla.bla'}, ]); expect(await testkit.usersTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(3); await driver.mock.reset(); await testkit.usersFilter.click(); await testkit.usersFilter.set('1'); expect(await testkit.tableStates.hasFilterLoading()).to.be.true; expect(await testkit.usersTableExists()).to.be.true; expect(await testkit.tableTotalRows()).to.equal(1); }); }); ================================================ FILE: quix-frontend/client/test/mocha-setup.ts ================================================ ================================================ FILE: quix-frontend/client/test/mocks.ts ================================================ import UrlPattern from 'url-pattern'; import { IUser, IHistory, IFile, INotebook, INote, IFolder, createUser, createHistory, createNotebook, createFolder, createFile, createNote, createFolderPayload, createDeletedNotebook, } from '@wix/quix-shared'; import * as moment from 'moment'; import { ServerTreeItem } from '../src/components/db-sidebar/db-sidebar-types'; import { v4 as uuidv4 } from 'uuid'; export const MockNoteContent = { success: 'do success', error: 'do error', permissionError: 'do permission error', sql: 'do SQL', }; const mocks = { '/api/user': () => { return { ...createUser(), stats: { trashBinCount: trashBin.length } }; }, '/api/events': () => [200], '/api/users': () => [...Array(200).keys()].map((key) => createMockUser({ id: uuidv4(), email: 'valery' + key + '@wix.com', avatar: 'http://quix.wix.com/assets/user.svg', name: 'Valery Frolov' + key, rootFolder: '6c98fe9a-39f7-4674-b003-70f9061bbee5', dateCreated: Date.now(), dateUpdated: Date.now(), }) ), '/api/history': () => { return [...Array(101).keys()].map((key) => createMockHistory({ id: '' + key, email: 'valery' + key + '@wix.com', query: ['SELECT 1', 'SELECT 2'], moduleType: key % 2 ? 'presto' : 'athena', startedAt: moment.utc().format(), }) ); }, // '/api/files': () => [404, {message: 'Couldn\'t fetch notebooks'}], // '/api/files': () => [500, {message: 'Failed to fetch files'}], '/api/files': () => createMockFiles(), // '/api/files': () => createMockFiles([createMockFolder({id: '10'}), createMockFile({id: '11'})]), '/api/files/404': () => [404, { message: 'Folder not found' }], '/api/files/500': () => [500, { message: "Couldn't fetch folder" }], '/api/files/:id': ({ id }) => createMockFolderPayload( [createMockFolder({ id: '100' }), createMockFile({ id: '101' })], { id, ownerDetails: { avatar: 'http://quix.wix.com/assets/user.svg', } as any, } ), '/api/notebook/404': () => [404, { message: 'Notebook not found' }], '/api/notebook/500': () => [500, { message: "Couldn't fetch notebook" }], '/api/notebook/:id': ({ id }) => { let noteId = 1001; return createMockNotebook( [ createMockNote(id, { id: `${noteId++}`, name: 'Runnable', content: MockNoteContent.success, }), createMockNote(id, { id: `${noteId++}`, name: 'Runnable', content: MockNoteContent.success, type: 'python', }), createMockNote(id, { id: `${noteId++}`, name: 'Runnable (timeout)', content: `${MockNoteContent.success} timeout=200`, }), createMockNote(id, { id: `${noteId++}`, name: 'Runnable (error)', content: MockNoteContent.error, }), createMockNote(id, { id: `${noteId++}`, name: 'Runnable (permission error)', content: MockNoteContent.permissionError, }), createMockNote(id, { id: `${noteId++}`, name: 'Runnable SQL+JSON Result (Timeout)', content: MockNoteContent.sql, type: 'python', }), ], { id, ownerDetails: { avatar: 'http://quix.wix.com/assets/user.svg', } as any, } ); }, '/api/favorites': () => [ createMockFile({ id: '100', isLiked: true, ownerDetails: { id: 'valery@wix.com', email: 'valery@wix.com', avatar: 'http://quix.wix.com/assets/user.svg', name: 'Valery Frolov', rootFolder: '6c98fe9a-39f7-4674-b003-70f9061bbee5', dateCreated: Date.now(), dateUpdated: Date.now(), }, }), createMockFile({ id: '101', isLiked: true, ownerDetails: { id: 'anton@wix.com', email: 'anton@wix.com', avatar: 'http://quix.wix.com/assets/user.svg', name: 'Anton Podolsky', rootFolder: 'de6908dd-7f1e-4803-ab0d-5f9d6a496609', dateCreated: Date.now(), dateUpdated: Date.now(), }, }), ], '/api/search/none': () => ({ count: 0, notes: [] }), '/api/search/500': () => [500, { message: 'Search error' }], '/api/search/:text': ({ text }) => { const res = [createMockNote('1'), createMockNote('2'), createMockNote('3')]; const term = { fullText: text, content: [{ type: 1, text }] }; res.forEach( (note) => (note.content = `SELECT date_trunc('year', shipdate) as ${text} , shipmode , sum(quantity) quantity FROM $schema.lineitem GROUP BY 1, 2 ORDER BY 1 `) ); // return {notes: [], count: 0}; return { notes: res, count: 365, term }; }, // '/api/db/presto/explore': () => [500, {message: 'Failed to fetch DB tree'}], // '/api/db/presto/explore': () => [], '/api/db/:type/explore': ({ type }) => { if (type === 'presto') { const response = []; for (let i = 0; i < 50; i++) { response.push({ name: 'catalog' + i, type: 'catalog', children: [ { name: 'schema' + i, type: 'schema', children: [ { name: 'table' + i, type: 'table', children: [], }, ], }, ], }); } return response; } return [ { name: '__root', type: 'catalog', children: [ { name: 'schema', type: 'schema', children: [ { name: 'table_with_a_very_looooooooooooooooong_name', type: 'table', children: [], }, ], }, { name: 'schema2', type: 'schema', children: [], }, ], }, ]; }, '/api/db/:type/explore/:catalog/:schema/:table': ({ table }) => ({ children: [ {name: { name: `colA`, dataType: 'varchar' }}, {name: { name: `colB`, dataType: 'varchar' }}, {name: { name: `colC`, dataType: 'varchar' }}, {name: { name: `colD`, dataType: 'varchar' }}, {name: { name: `colSmallObject`, dataType: 'row(food row(pizza varchar, pasta varchar), drinks row(beer varchar, vodka varchar))' }}, {name: { name: `collBigObject`, dataType: 'row(movies row(action row(The_Dark_Knight varchar, Mad_Max varchar, Die_Hard varchar), comedy row(The_Big_Lebowski varchar, Superbad varchar, The_Grand_Budapest_Hotel varchar), drama row(The_Shawshank_Redemption varchar, Titanic varchar, Forrest_Gump varchar)), tvSeries row(HBO row(Game_of_Thrones varchar, The_Sopranos varchar, Westworld varchar), netflix row(Stranger_Things varchar, The_Crown varchar, Narcos varchar), amazon row(The_Boys varchar, Fleabag varchar, The_Marvelous_MrsMaisel varchar)))' }}, ], }), '/api/db/:type/autocomplete': () => ({ catalogs: ['catalog', 'catalog2'], schemas: ['schema'], tables: ['table'], columns: ['column'], }), '/api/autocomplete/:type': () => [ { value: 'apollo', meta: 'table' }, { value: 'prod', meta: 'table' }, { value: 'wt_metasites', meta: 'table' }, ], // '/api/db/:type/search': () => [], '/api/db/:type/search': () => { const response = []; for (let i = 0; i < 10; i++) { response.push({ name: 'catalog' + i, type: 'catalog', children: [ { name: 'schema' + i, type: 'schema', children: [ { name: 'table' + i, type: 'table', children: [], }, ], }, ], }); } return response; }, '/api/deletedNotebooks': () => [...trashBin], }; const createMockDeletedNotebook = (name?: string) => { return name ? { ...createDeletedNotebook(), name } : createMockDeletedNotebook(); }; const trashBin = []; // We can use this loop to simulate different counts on trash bin icon badge for (let i = 0; i < 1; i++) { trashBin.push( ...[ createMockDeletedNotebook('Removed 1'), createMockDeletedNotebook('Bad Queries'), createMockDeletedNotebook('By Mistake'), createMockDeletedNotebook('Trash'), ] ); } let mockOverrides = {}; export const createMockUser = (props: Partial = {}) => { return createUser(props); }; export const createMockHistory = (props: Partial = {}) => { return createHistory(props); }; export const createMockRootFolder = (props: Partial = {}) => { return createFolder([], { id: '1', name: 'My notebooks', owner: 'local@quix.com', ownerDetails: { avatar: 'http://quix.wix.com/assets/user.svg', } as any, ...props, }); }; export const createMockFile = (props: Partial = {}) => { return createFile([{ id: '1', name: 'My notebooks' }], { owner: 'local@quix.com', ...props, }); }; export const createMockFolder = (props: Partial = {}) => { return createFolder([{ id: '1', name: 'My notebooks' }], { owner: 'local@quix.com', ...props, }); }; export const createMockFiles = (children = []) => { return [ createMockRootFolder(), ...children.map((child) => ({ ...child, })), ]; }; export const createMockFolderPayload = ( children = [], props: Partial = {} ) => { return createFolderPayload([{ id: '1', name: 'My notebooks' }], { owner: 'local@quix.com', files: children.map((child, index) => ({ ...child, // tslint:disable-next-line: restrict-plus-operands id: `${index + 100}`, })), ...props, }); }; export const createMockNotebook = ( notes = [], props: Partial = {} ) => { return createNotebook([{ id: '1', name: 'My notebooks' }], { owner: 'local@quix.com', notes, ...props, }); }; export const createMockNote = ( notebookId: string = '1', props: Partial = {} ) => { return createNote(notebookId, { owner: 'local@quix.com', ...props }); }; export const createMockDbExplorer = ( items: ServerTreeItem[] = [] ): ServerTreeItem[] => { return items.length > 0 ? items : [createMockDbExplorerItem()]; }; export const createMockDbExplorerItem = ( props: Partial = {} ): ServerTreeItem => { return { name: props.name || 'treeItem', type: props.type || 'catalog', children: props.children || [], }; }; export const mock = async ( patternOrUrl: string, patternPayload?: any, options?: {} ) => { if (patternPayload) { mockOverrides[patternOrUrl] = { options, getPayload: () => patternPayload }; } else { const [status, payload, delay] = Object.keys(mocks).reduce((res, key) => { if (!res) { const match = new UrlPattern(key).match(patternOrUrl); if (match) { let payloadResult = (mockOverrides[key]?.getPayload || mocks[key])( match ); if (payloadResult && typeof payloadResult[0] !== 'number') { payloadResult = [200, payloadResult]; } return [...payloadResult, mockOverrides[key]?.options?.delay]; } } return res; }, null) || [404, { message: 'Mock not found' }]; if (delay) { await new Promise((res) => setTimeout(res, delay)); } return [status, payload]; } }; export const reset = () => { mockOverrides = {}; }; ================================================ FILE: quix-frontend/client/test/test-common.ts ================================================ export const baseURL = `http://localhost:5554`; ================================================ FILE: quix-frontend/client/tsconfig.json ================================================ { "compilerOptions": { "sourceMap": true, "declaration": true, "noImplicitAny": false, "module": "commonjs", "moduleResolution": "node", "target": "es5", "noUnusedLocals": true, "lib": ["dom", "es2016"], "esModuleInterop": true, "downlevelIteration": true, "skipLibCheck": true, "outDir": "./dist", "jsx": "react" }, "include": [ "./test/**/*.ts", "./src/custom.d.ts" ], "files": [ "src/app.ts", "./src/external-types.d.ts" ], "references": [{ "path": "../shared" }] } ================================================ FILE: quix-frontend/client/tslint.json ================================================ { "extends": ["tslint-config-yoshi-base"], "linterOptions": { "exclude": ["./src/lib/language-parsers/presto-grammar/lang/presto/*.ts"] }, "rules": { "prettier": false, "no-invalid-this": false, "no-floating-promises": false, "restrict-plus-operands": false } } ================================================ FILE: quix-frontend/client/velocity.data.json ================================================ { "clientTopology": { "staticsBaseUrl": "//localhost:3200/", "executeBaseUrl": "//localhost:3000/mock", "apiBasePath": "" }, "mode": { "debug": true, "demo": false } } ================================================ FILE: quix-frontend/client/velocity.private.data.json ================================================ { } ================================================ FILE: quix-frontend/client/wallaby.js ================================================ module.exports = function (wallaby) { return Object.assign({}, require('yoshi/config/wallaby-mocha')(wallaby), { // set to undefined to let Wallaby decide the number of processes based on the system's capacity workers: undefined }); }; ================================================ FILE: quix-frontend/lerna.json ================================================ { "packages": [ "client", "shared", "service" ], "version": "independent", "npmClient": "npm" } ================================================ FILE: quix-frontend/npm-deploy.sh ================================================ #!/bin/bash echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc lerna publish from-package --no-verify-access -y --loglevel=debug ================================================ FILE: quix-frontend/package.json ================================================ { "name": "quix-frontend", "private": true, "devDependencies": { "lerna": "^3.22.1" }, "scripts": { "version": "lerna --version", "test": "lerna run test:ci --parallel false --concurrency 1", "bootstrap": "lerna bootstrap --concurrency 2 --force-local", "postinstall": "npm run bootstrap", "build": "lerna run build --parallel false --concurrency 1", "build:ci": "(cd service; npm run build)", "clean": "lerna clean --yes", "publish": "lerna publish from-package --no-verify-access -y --loglevel=debug" }, "workspaces": { "packages": [ "client", "shared", "service" ], "nohoist": [ "**/@types/**", "**/lodash*", "**/lodash/**", "**/@nestjs/**", "**/passport/**", "**/typeorm", "**/typeorm/**" ] } } ================================================ FILE: quix-frontend/service/.gitignore ================================================ node_modules dist statics .env ormconfig.generated* .fnm-node ================================================ FILE: quix-frontend/service/.npmrc ================================================ package-lock=true registry=https://registry.npmjs.org/ ================================================ FILE: quix-frontend/service/.nvmrc ================================================ 14 ================================================ FILE: quix-frontend/service/.prettierrc ================================================ { "singleQuote": true, "trailingComma": "all", "bracketSpacing": false, "arrowParens": "avoid" } ================================================ FILE: quix-frontend/service/.quixroot ================================================ magic file for scripts to get root folder ================================================ FILE: quix-frontend/service/.testenv ================================================ #QUIX_ENV=TEST DB_NAME=quixtest DB_USER=root DB_HOST=localhost DB_PASS= #DB_DEBUG=true ================================================ FILE: quix-frontend/service/.travis.yml ================================================ language: node_js node_js: - "11" services: - mysql cache: npm before_install: - mysql -e 'CREATE DATABASE IF NOT EXISTS Quix;' addons: apt: sources: - mysql-5.7-trusty packages: - mysql-server - mysql-client ================================================ FILE: quix-frontend/service/README.md ================================================ ## Installation ```bash $ npm install ``` ## Running the app ```bash # development $ npm run start # watch mode $ npm run start:dev # production mode $ npm run start:prod ``` ## Test ```bash # unit tests - against sqlite $ npm run test # unit tests - against mysql $ npm run test:mysql # e2e tests $ npm run test:e2e # test coverage $ npm run test:cov ``` ## Configuration The app expects the following enviorment variables: ```bash DB_NAME= DB_USER= DB_PASS= DB_HOST= DB_PORT= BACKEND_INTERNAL_URL= BACKEND_PUBLIC_URL= GOOGLE_SSO_CLIENT_ID= GOOGLE_SSO_SECRET= AUTH_COOKIE= AUTH_SECRET= COOKIE_MAX_AGE= DB_TYPE= AUTH_TYPE= DB_AUTO_MIGRATE= MINIFIED_STATICS= ``` You can set those in `.env` file. When testing, values are read from `.testenv`. This app is built using ![Nest.js](https://raw.githubusercontent.com/nestjs/docs.nestjs.com/master/src/assets/logo.png). ================================================ FILE: quix-frontend/service/ecosystem.config.js ================================================ module.exports = { apps : [{ name: "quix", script: "./index.js", env: { NODE_ENV: "development", }, env_production: { NODE_ENV: "production", }, output: '/logs/stdout.log', error: '/logs/stderr.log', instances: 2 }] } ================================================ FILE: quix-frontend/service/index.js ================================================ const path = require('path'); require(path.resolve('./', 'dist', 'main')); ================================================ FILE: quix-frontend/service/nest-cli.json ================================================ { "language": "ts", "collection": "@nestjs/schematics", "sourceRoot": "src" } ================================================ FILE: quix-frontend/service/nodemon-debug.json ================================================ { "watch": ["src"], "ext": "ts", "ignore": ["src/**/*.spec.ts"], "exec": "node --inspect-brk -r tsconfig-paths/register src/main.ts" } ================================================ FILE: quix-frontend/service/nodemon.json ================================================ { "watch": ["src"], "ext": "ts", "ignore": ["src/**/*.spec.ts"], "exec": "ts-node --files src/main.ts" } ================================================ FILE: quix-frontend/service/ormconfig.json ================================================ { "type": "mysql", "host": "localhost", "port": 3306, "username": "root", "password": "", "database": "quix", "entities": ["./src/**/*.entity{.ts,.js}"], "migrations": ["./src/migrations/*.ts"], "synchronize": false, "cli": { "migrationsDir": "./src/migrations" } } ================================================ FILE: quix-frontend/service/package.json ================================================ { "name": "@wix/quix-service", "version": "1.0.33", "description": "", "author": "", "license": "MIT", "scripts": { "build:ts": "tsc -b tsconfig.build.json", "build": "npm run build:ts && npm run update-statics", "build:start": "npm run build && npm start", "start": "DB_HOST=localhost ts-node --files scripts/start.ts", "update-statics": "ts-node scripts/update-statics.ts", "start:dev": "nodemon", "start:debug": "nodemon --config nodemon-debug.json", "start:prod": "node index.js", "lint": "tslint -p tsconfig.json -c tslint.json", "lint:fix": "tslint -p tsconfig.json -c tslint.json --fix", "test": "jest", "test:ci": "npm run test && npm run test:mysql && npm run test:e2e", "test:mysql": "DB_TYPE=mysql jest --runInBand", "test:build:mysql": "npm run build && npm run test:mysql", "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r ts-node/register node_modules/.bin/jest --runInBand", "test:debug:mysql": "DB_TYPE=mysql node --inspect-brk -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "npm run test:e2e:sqlite && npm run test:e2e:mysql", "test:e2e:sqlite": "jest --runInBand --config ./test/jest-e2e.js", "test:e2e:mysql": "DB_TYPE=mysql jest --runInBand --config ./test/jest-e2e.js", "fnm": "fnm exec which node | xargs -I % ln -sf % ./.fnm-node && chmod +x ./.fnm-node", "link:shared": "cd ../shared && npm link && cd ../service && npm link @wix/quix-shared" }, "dependencies": { "@nestjs/common": "^7.0.0", "@nestjs/core": "^7.0.0", "@nestjs/jwt": "^7.0.0", "@nestjs/platform-express": "^7.0.0", "@nestjs/platform-ws": "^7.0.0", "@nestjs/typeorm": "^7.0.0", "@nestjs/websockets": "^7.0.0", "@types/node-fetch": "^2.5.0", "@types/ws": "^6.0.4", "@wix/quix-shared": "^1.0.15", "axios": "^0.21.0", "cookie": "^0.4.1", "cookie-parser": "^1.4.4", "dotenv": "^7.0.0", "fp-ts": "^2.0.1", "google-auth-library": "^6.1.6", "http-proxy-middleware": "^0.19.1", "lodash": "^4.17.19", "mysql2": "^2.1.0", "node-fetch": "^2.6.1", "reflect-metadata": "^0.1.13", "rimraf": "^2.6.2", "rxjs": "^6.3.3", "tapable": "^1.1.1", "ts-node": "^7.0.1", "tsconfig-paths": "^3.8.0", "typeorm": "0.2.45", "typescript": "^4.0.0", "uuid": "^3.3.2", "velocity": "^0.7.2", "ws": "^7.2.1" }, "devDependencies": { "@nestjs/testing": "^7.0.0", "@types/chance": "^1.0.4", "@types/cookie": "^0.4.0", "@types/cookie-parser": "^1.4.1", "@types/dotenv": "^6.1.1", "@types/express": "^4.16.0", "@types/http-proxy-middleware": "^0.19.2", "@types/jest": "^26.0.0", "@types/lodash": "^4.14.123", "@types/mysql": "^2.15.6", "@types/nock": "^9.3.1", "@types/node": "^12.0.0", "@types/shelljs": "^0.8.3", "@types/supertest": "^2.0.7", "@types/tapable": "^1.0.4", "@types/uuid": "^3.4.4", "chance": "^1.0.18", "jest": "^26.0.0", "nock": "^10.0.6", "nodemon": "^1.18.9", "prettier": "^2.0.0", "shelljs": "^0.8.3", "sql.js": "^1.0.0", "supertest": "^6.0.0", "ts-jest": "^26.0.0", "tslint": "^6.0.0", "tslint-config-prettier": "^1.18.0", "tslint-plugin-prettier": "^2.0.1" }, "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" }, "files": [ "dist" ], "jest": { "moduleFileExtensions": [ "js", "json", "ts" ], "rootDir": "src", "testRegex": ".spec.ts$", "transform": { "^.+\\.ts$": "ts-jest" }, "transformIgnorePatterns": [ "/node_modules/", "/quix-frontend\\shared/" ], "globals": { "ts-jest": { "tsconfig": { "target": "esnext" } } }, "coverageDirectory": "../coverage", "testEnvironment": "node" } } ================================================ FILE: quix-frontend/service/scripts/create_migrations.sh ================================================ #!/usr/bin/env bash usage() { printf '**** usage: ****\n' printf 'create_migrations.sh \e[4mversion_number\e[0m\n' exit -2 } if [ -z $1 ]; then usage else DEFAULTPORT=3306 DEFAULTDB="quix" DEFAULTPASS="" DEFAULTPUSER="root" DEFAULTHOST="localhost" export DB_HOST=${DB_HOST:-$DEFAULTHOST} export DB_USER=${DB_USER:-$DEFAULTPUSER} export DB_PASS=${DB_PASS:-$DEFAULTPASS} export DB_NAME=${DB_NAME:-$DEFAULTDB} export DB_PORT=${DB_PORT:-$DEFAULTPORT} sed -e "s/:dbhost:/$DB_HOST/" \ -e "s/:dbuser:/$DB_USER/" \ -e "s/:dbpass:/$DB_PASS/" \ -e "s/:dbname:/$DB_NAME/" \ -e "s/:dbport:/$DB_PORT/" \ scripts/ormconfig.json.template > ormconfig.generated.migration-generate.json ./node_modules/.bin/ts-node -O '{"strict":false}' -r tsconfig-paths/register node_modules/.bin/typeorm migration:generate -n v$1 -f ormconfig.generated.migration-generate fi ================================================ FILE: quix-frontend/service/scripts/helpers/copy-statics.ts ================================================ import {exec, ExecOutputReturnValue, cp} from 'shelljs'; import path from 'path'; export function buildAndCopyStatics(projectDir: string, clientDir: string) { const build = exec('npm run build', { cwd: clientDir, }) as ExecOutputReturnValue; if (build.code) { process.exit(-1); } const copy = cp('-R', path.resolve(clientDir, 'dist', 'statics'), projectDir); if (copy.code) { process.exit(-1); } } ================================================ FILE: quix-frontend/service/scripts/ormconfig.json.template ================================================ { "type": "mysql", "host": ":dbhost:", "port": :dbport:, "username": ":dbuser:", "password": ":dbpass:", "database": ":dbname:", "entities": ["src/**/*.entity{.ts,.js}"], "migrations": ["./src/migrations/*.ts"], "synchronize": false, "cli": { "migrationsDir": "./src/migrations" }, "logging": true } ================================================ FILE: quix-frontend/service/scripts/run_migrations.sh ================================================ #!/usr/bin/env bash if [ ! -f .quixroot ]; then echo "This script must be run from quix/quix-frontend/service folder" exit -1 fi DEFAULTPORT=3306 DEFAULTDB="quix" DEFAULTPASS="" DEFAULTPUSER="root" DEFAULTHOST="db" export DB_HOST=${DB_HOST:-$DEFAULTHOST} export DB_USER=${DB_USER:-$DEFAULTPUSER} export DB_PASS=${DB_PASS:-$DEFAULTPASS} export DB_NAME=${DB_NAME:-$DEFAULTDB} export DB_PORT=${DB_PORT:-$DEFAULTPORT} sed -e "s/:dbhost:/$DB_HOST/" \ -e "s/:dbuser:/$DB_USER/" \ -e "s/:dbpass:/$DB_PASS/" \ -e "s/:dbname:/$DB_NAME/" \ -e "s/:dbport:/$DB_PORT/" \ scripts/ormconfig.json.template > ormconfig.generated.migration-run.json ./node_modules/.bin/ts-node -O '{"strict":false}' -r tsconfig-paths/register node_modules/.bin/typeorm migration:run -f ormconfig.generated.migration-run ================================================ FILE: quix-frontend/service/scripts/start.ts ================================================ import path from 'path'; import fs from 'fs'; import {buildAndCopyStatics} from './helpers/copy-statics'; async function main() { const projectDir = path.resolve(__dirname, '..'); const clientDir = path.resolve(__dirname, '..', '..', 'client'); const mainFile = path.resolve(projectDir, 'src', 'main.ts'); if (!fs.existsSync(path.resolve(projectDir, 'statics', 'index.vm'))) { buildAndCopyStatics(projectDir, clientDir); } require(mainFile); } main(); ================================================ FILE: quix-frontend/service/scripts/update-statics.ts ================================================ import path from 'path'; import {buildAndCopyStatics} from './helpers/copy-statics'; function main() { const projectDir = path.resolve(__dirname, '..'); const clientDir = path.resolve(__dirname, '..', '..', 'client'); buildAndCopyStatics(projectDir, clientDir); } main(); ================================================ FILE: quix-frontend/service/src/app.controller.spec.ts ================================================ import {Test, TestingModule} from '@nestjs/testing'; import {getConnectionToken} from '@nestjs/typeorm'; import {AppController} from './app.controller'; import {ConfigModule} from './config'; import {ValueProvider} from '@nestjs/common/interfaces'; const fakeConnection = { provide: getConnectionToken(), useValue: {}, }; describe('AppController', () => { let appController: AppController; let app: TestingModule | null = null; async function preTest(mocked?: ValueProvider) { const testingModule = Test.createTestingModule({ controllers: [AppController], providers: [fakeConnection], imports: [ConfigModule.create()], }); if (mocked) { testingModule.overrideProvider(mocked.provide).useValue(mocked.useValue); } app = await testingModule.compile(); appController = app.get(AppController); } // beforeEach(async () => preTest()); afterEach(async () => { if (app) { await app.close(); app = null; } }); describe('index.vm', () => { it('should return valid render view model', async () => { await preTest(); const vm = appController.getIndex(); expect(vm).toMatchObject({ clientTopology: { staticsBaseUrl: '/', }, }); }); it('should parse module configuration correctly', async () => { const mockedGlobalEnv = { MODULES: 'presto,was,athena', MODULES_PRESTO_ENGINE: 'presto', MODULES_PRESTO_API: 'http://presto:8181/v1/', MODULES_WAS_ENGINE: 'jdbc', MODULES_WAS_SYNTAX: 'someSqlSyntax', MODULES_WAS_API: 'http://presto:8181/v1/', MODULES_ATHENA_ENGINE: 'athena', MODULES_ATHENA_SYNTAX: 'ansi_sql', MODULES_ATHENA_DATABASE: 'default', }; await preTest({provide: 'GLOBAL_ENV', useValue: mockedGlobalEnv}); const quixConfig = JSON.parse(appController.getIndex().quixConfig); expect(quixConfig.modules).toContainEqual( expect.objectContaining({ id: 'presto', engine: 'presto', syntax: 'presto', }), ); expect(quixConfig.modules).toContainEqual( expect.objectContaining({ id: 'was', engine: 'jdbc', syntax: 'someSqlSyntax', }), ); expect(quixConfig.modules).toContainEqual( expect.objectContaining({ id: 'athena', engine: 'athena', syntax: 'athena', }), ); }); it('should parse old style configuration correctly', async () => { const mockedGlobalEnv = { MODULES: 'presto,athena', }; await preTest({provide: 'GLOBAL_ENV', useValue: mockedGlobalEnv}); const quixConfig = JSON.parse(appController.getIndex().quixConfig); expect(quixConfig.modules).toContainEqual( expect.objectContaining({ id: 'presto', engine: 'presto', syntax: 'presto', }), ); expect(quixConfig.modules).toContainEqual( expect.objectContaining({ id: 'athena', engine: 'athena', syntax: 'athena', }), ); }); }); }); ================================================ FILE: quix-frontend/service/src/app.controller.ts ================================================ import { Controller, Get, Render, Res, Req, OnApplicationShutdown, } from '@nestjs/common'; import {ConfigService, EnvSettings} from './config'; import {InjectConnection} from '@nestjs/typeorm'; import {Connection} from 'typeorm'; import {Response} from 'express'; import {ClientConfigHelper} from '@wix/quix-shared'; @Controller() export class AppController implements OnApplicationShutdown { private clientConfig: ClientConfigHelper | undefined; private timer: NodeJS.Timer; constructor( private configService: ConfigService, @InjectConnection() private conn: Connection, ) { this.fetchClientConfig(); this.timer = setInterval( () => this.fetchClientConfig.bind(this), 1000 * 60 * 10, ); } onApplicationShutdown() { clearInterval(this.timer); } private fetchClientConfig() { this.clientConfig = this.configService.getClientConfig(); } @Get() @Render('index.vm') getIndex() { if (!this.clientConfig) { throw new Error('Server not up yet'); } const clientTopology = this.clientConfig.getClientTopology(); const mode = this.clientConfig.getMode(); return { clientTopology, mode, quixConfig: this.clientConfig.serialize(), }; } @Get('/health/is_alive') async healthCheck(@Res() response: Response) { await this.conn .query(`SELECT 'health-check' FROM dual LIMIT 1`) .then(() => response.sendStatus(200).end()) .catch(() => response.sendStatus(500).end()); } } ================================================ FILE: quix-frontend/service/src/app.module.ts ================================================ import {Module} from '@nestjs/common'; import {AppController} from './app.controller'; import {BaseModule} from './base.module'; import {ConfigModule, ConfigService} from './config'; import {AuthModuleConfiguration} from './modules/auth/auth.module'; import {AuthTypes} from './modules/auth/types'; @Module({ imports: [ BaseModule, ConfigModule.create(), AuthModuleConfiguration.createAsync({ injects: [ConfigService], imports: [], useFactory: (configService: ConfigService) => { const env = configService.getEnvSettings(); if (env.AuthType === 'fake') { return { type: AuthTypes.FAKE, cookieName: env.AuthCookieName, }; } else if (env.AuthType === 'google') { return { type: AuthTypes.GOOGLE, cookieEncKey: env.AuthEncKey, cookieName: env.AuthCookieName, cookieTTL: env.CookieAge, googleAuthSecret: env.GoogleAuthSecret, googleClientId: env.GoogleClientId, }; } throw new Error('unknown auth type'); }, }), ], controllers: [AppController], }) export class AppModule {} ================================================ FILE: quix-frontend/service/src/base.module.ts ================================================ import {Module} from '@nestjs/common'; import {AppController} from './app.controller'; import {TypeOrmModule} from '@nestjs/typeorm'; import {SearchModule} from './modules/search/search.module'; import {EventSourcingModule} from './modules/event-sourcing/event-sourcing.module'; import {WebApiModule} from './modules/web-api/web-api.module'; import {ConfigService} from './config'; import { DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbUser, DbFavorites, DbMetadata, DbDeletedNotebook, } from './entities'; import {DbAction} from './modules/event-sourcing/infrastructure/action-store/entities/db-action.entity'; import {ProxyDbApiBackend} from './modules/proxy-backend/proxy-backend.module'; @Module({ imports: [ TypeOrmModule.forRootAsync({ imports: [], useFactory: async (cs: ConfigService) => cs.getDbConnection([ DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbDeletedNotebook, DbAction, DbUser, DbFavorites, DbMetadata, ]), inject: [ConfigService], }), EventSourcingModule, WebApiModule, ProxyDbApiBackend, SearchModule, ], controllers: [AppController], }) export class BaseModule { } ================================================ FILE: quix-frontend/service/src/common/demo-mode-interceptor.ts ================================================ /* removes owner from responses */ import { Injectable, NestInterceptor, ExecutionContext, CallHandler, } from '@nestjs/common'; import {Observable} from 'rxjs'; import {map} from 'rxjs/operators'; import {EnvSettings} from '../config'; import {ConfigService} from '../config'; import {sanitizeUserEmail, sanitizeUserName} from './user-sanitizer'; import {IUser} from '@wix/quix-shared'; @Injectable() export class DemoModeInterceptor implements NestInterceptor { private env: EnvSettings; constructor(private configService: ConfigService) { this.env = this.configService.getEnvSettings(); } intercept(context: ExecutionContext, next: CallHandler): Observable { if (!this.env.DemoMode) { return next.handle(); } const email = context.switchToHttp().getRequest().user.email; return next.handle().pipe(map(removeOwnerNested.bind(null, email))); } } function removeOwnerNested(user: string, item: any): any { if (Array.isArray(item)) { return item.map(removeOwnerNested.bind(null, user)); } if (item && typeof item === 'object') { if (item.owner) { item.owner = item.owner === user ? user : sanitizeUserEmail(item.owner); } if (item.ownerDetails) { const {email, id, name} = item.ownerDetails as IUser; item.ownerDetails = Object.assign(item.ownerDetails, { name: sanitizeUserName(name), id: sanitizeUserEmail(id), email: sanitizeUserEmail(email), avatar: 'http://quix.wix.com/assets/user.svg', }); } for (const key of Object.keys(item)) { if (typeof item === 'object') { item[key] = removeOwnerNested(user, item[key]); } } } return item; } ================================================ FILE: quix-frontend/service/src/common/entity-type.enum.ts ================================================ export enum EntityType { Notebook = 'notebook', Note = 'note', Folder = 'folder', } ================================================ FILE: quix-frontend/service/src/common/user-sanitizer.ts ================================================ export const sanitizeUserEmail = (email: string) => { const [user, domain] = (email || 'dummy@dummy.com').split('@'); return ['***', domain].join('@'); }; export const sanitizeUserName = (name: string) => { return 'Quix User'; }; ================================================ FILE: quix-frontend/service/src/config/config.module.ts ================================================ import {DynamicModule, Module} from '@nestjs/common'; import {ConfigService, DefaultConfigService} from './config.service'; import {EnvSettings} from './env'; const configServiceProvider = { provide: ConfigService, useClass: DefaultConfigService, }; const globalEnvProvider = { provide: 'GLOBAL_ENV', useValue: process.env, }; @Module({ imports: [], controllers: [], providers: [configServiceProvider, globalEnvProvider], exports: [configServiceProvider], }) export class ConfigModule { static create(overrides: Partial = {}): DynamicModule { return { module: ConfigModule, global: true, providers: [ { provide: 'CONFIG_OVERRIDES', useValue: overrides, }, ], }; } } ================================================ FILE: quix-frontend/service/src/config/config.service.ts ================================================ import {Inject, Injectable, Optional} from '@nestjs/common'; import {ConnectionOptions} from 'typeorm'; import * as dbConnection from './db-connection'; import {EnvSettings, loadEnv, getEnv} from './env'; import {ClientConfigHelper} from '@wix/quix-shared'; export type DbTypes = 'mysql' | 'sqlite'; loadEnv(); export abstract class ConfigService { private env: EnvSettings; constructor( @Inject('GLOBAL_ENV') globalEnv: any, @Inject('CONFIG_OVERRIDES') overrides: Partial, ) { this.env = {...getEnv(globalEnv), ...overrides}; /* tslint:disable-next-line */ console.log(`****** Current Environment:: DbType:${this.env.DbType}/AuthType:${this.env.AuthType} ******`); } getEnvSettings(): EnvSettings { return this.env; } getDbType(): DbTypes { const env = this.getEnvSettings(); return env.DbType; } getDbConnection(entities: any[]): ConnectionOptions { switch (this.env.DbType) { case 'sqlite': return dbConnection.createInMemConf(entities, this.getEnvSettings()); case 'mysql': { return dbConnection.createMysqlConf(entities, this.getEnvSettings()); } } } getClientConfig() { const env = this.getEnvSettings(); const clientConfig = new ClientConfigHelper(); const staticsBaseUrl = env.remoteStaticsPath ? env.remoteStaticsPath : `${env.MountPath}/`; clientConfig .setAuth({ googleClientId: env.GoogleClientId, }) .setClientTopology({ executeBaseUrl: env.QuixBackendPublicUrl, staticsBaseUrl, apiBasePath: env.MountPath, }) .setMode({ debug: !env.UseMinifiedStatics, demo: env.DemoMode, }); env.Modules.forEach(m => clientConfig.addModule({ id: m, name: m, components: env.moduleSettings[m].components, engine: env.moduleSettings[m].engine as any, syntax: env.moduleSettings[m].syntax, }), ); return clientConfig; } } @Injectable() export class DefaultConfigService extends ConfigService {} ================================================ FILE: quix-frontend/service/src/config/db-conf.ts ================================================ import {ColumnOptions, PrimaryColumnOptions} from 'typeorm'; import {getEnv} from './env/env'; import {FileType} from '@wix/quix-shared/entities/file'; import {ContentSearch, SearchTextType} from '@wix/quix-shared'; import {escape} from 'mysql2'; import {EntityType} from '../common/entity-type.enum'; /* A compatibility layer between MySql and Sqlite (sqljs), should handle everything that typeorm doesn't handle for us */ interface DbColumnConf { json: ColumnOptions; shortTextField: ColumnOptions; nameField: ColumnOptions; noteContent: ColumnOptions; dateUpdated: ColumnOptions; dateCreated: ColumnOptions; dateDeleted: ColumnOptions; idColumn: PrimaryColumnOptions; eventsTimestamp: ColumnOptions; fileTypeEnum: ColumnOptions; entityTypeEnum: ColumnOptions; userAvatar: ColumnOptions; concat: (s1: string, s2: string) => string; fullTextSearch: ( columnName: string, textToLookFor: ContentSearch[], ) => string; } const MySqlConf: DbColumnConf = { json: {type: 'json', nullable: true}, shortTextField: {type: 'varchar', length: 64}, nameField: {type: 'varchar', length: 512}, noteContent: {type: 'mediumtext', nullable: true}, dateUpdated: { transformer: { from: (d?: Date) => d && d.valueOf(), to: (v?: number) => (v !== undefined ? new Date(v) : undefined), }, readonly: true, name: 'date_updated', }, dateCreated: { transformer: { from: (d?: Date) => d && d.valueOf(), to: (v?: number) => (v !== undefined ? new Date(v) : undefined), }, readonly: true, name: 'date_created', }, dateDeleted: { transformer: { from: (d?: Date) => d && d.valueOf(), to: (v?: number) => (v !== undefined ? new Date(v) : undefined), }, readonly: true, name: 'date_deleted', }, eventsTimestamp: { type: 'timestamp', precision: 4, default: () => 'CURRENT_TIMESTAMP(4)', }, idColumn: {nullable: false, unique: true, type: 'varchar', length: 36}, fileTypeEnum: { type: 'enum', enum: FileType, default: FileType.folder, }, entityTypeEnum: { type: 'enum', enum: EntityType, default: EntityType.Notebook, }, userAvatar: {nullable: true, type: 'varchar', length: 255}, concat: (s1, s2) => `CONCAT(${s1}, ${s2})`, fullTextSearch(columnName, contentSearchList) { return `MATCH(${columnName}) AGAINST (${escape( contentSearchList .map(contentSearch => contentSearch.type === SearchTextType.PHRASE ? `"${contentSearch.text}"` : `${contentSearch.text}*`, ) .join(' '), )} IN BOOLEAN MODE)`; }, }; const SqliteConf: DbColumnConf = { json: {type: 'simple-json', nullable: true}, shortTextField: {type: 'varchar', length: 64}, nameField: {type: 'varchar', length: 512}, noteContent: {type: 'text', nullable: true}, dateUpdated: { type: 'integer', name: 'date_updated', transformer: { from: (d: number) => { const date = new Date(d); return Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), ).valueOf(); }, to: (v?: number) => v, }, }, dateCreated: { type: 'integer', name: 'date_created', transformer: { from: (d: number) => { const date = new Date(d); return Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), ).valueOf(); }, to: (v?: number) => v, }, }, dateDeleted: { type: 'integer', name: 'date_deleted', transformer: { from: (d: number) => { const date = new Date(d); return Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), ).valueOf(); }, to: (v?: number) => v, }, }, eventsTimestamp: { type: 'integer', default: () => `CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER)`, transformer: { from: (d: number) => d, to: (d?: Date) => d && d.valueOf(), }, }, idColumn: {nullable: false, unique: true, type: 'varchar', length: 36}, fileTypeEnum: {type: 'varchar', length: 32, default: FileType.folder}, entityTypeEnum: {type: 'integer', default: EntityType.Notebook}, userAvatar: {nullable: true, type: 'varchar', length: 255}, concat: (s1, s2) => `(${s1} || ${s2})`, fullTextSearch(columnName, contentSearchList) { return contentSearchList .map(searchItem => `${columnName} LIKE '%${searchItem.text}%'`) .join(' OR '); }, }; export const dbConf = getEnv().DbType === 'mysql' ? MySqlConf : SqliteConf; ================================================ FILE: quix-frontend/service/src/config/db-connection.ts ================================================ import {ConnectionOptions} from 'typeorm'; import {EnvSettings} from './env'; import {isTsNode} from './utils'; type ClassConstructor = new (...args: any[]) => any; export const createInMemConf = ( entities: ClassConstructor[] | string[], settings: EnvSettings, ): ConnectionOptions => { return { type: 'sqljs', synchronize: settings.AutoMigrateDb, entities, logger: 'advanced-console', logging: settings.DbDebug, }; }; export const createMysqlConf = ( entities: ClassConstructor[] | string[], settings: EnvSettings, ): ConnectionOptions => { return { type: 'mysql', host: settings.DbHost, port: settings.DbPort, username: settings.DbUser, password: settings.DbPass, database: settings.DbName, synchronize: settings.AutoMigrateDb, entities, logger: 'advanced-console', logging: settings.DbDebug, migrations: isTsNode() ? ['./src/migrations/*.ts'] : ['./dist/migrations/*.js'], }; }; ================================================ FILE: quix-frontend/service/src/config/env/computed-settings.ts ================================================ /* tslint:disable:no-console */ import {ComputedSettings} from './types'; import {ModuleEngineType, ModuleEngineToSyntaxMap} from '@wix/quix-shared'; import {engineToClientComponents} from './engine-settings'; export const computedSettingsDefaults: ComputedSettings = { moduleSettings: { presto: { syntax: 'ansi_sql', engine: 'presto', components: {db: {}, note: {}}, }, }, }; const getModuleSettings = (moduleName: string, globalEnv: any) => { const syntaxEnvVar = `MODULES_${moduleName.toUpperCase()}_SYNTAX`; const engineEnvVar = `MODULES_${moduleName.toUpperCase()}_ENGINE`; let engine = globalEnv[engineEnvVar]; let syntax: string = ''; /* backwards compatibility */ if (engine === undefined) { switch (moduleName) { case 'presto': engine = ModuleEngineType.Presto; break; case 'athena': engine = ModuleEngineType.Athena; break; default: } } /* end */ if (!Object.values(ModuleEngineType).includes(engine)) { console.error( `Bad configuration. Missing or bad 'engine' declaration for module '${moduleName}'. Possible values: ${Object.values( ModuleEngineType, ).join(',')}`, ); return undefined; } switch (engine) { case ModuleEngineType.Presto: syntax = ModuleEngineToSyntaxMap[ModuleEngineType.Presto]; break; case ModuleEngineType.Athena: syntax = ModuleEngineToSyntaxMap[ModuleEngineType.Athena]; break; case ModuleEngineType.BigQuery: syntax = ModuleEngineToSyntaxMap[ModuleEngineType.BigQuery]; break; case ModuleEngineType.Python: syntax = ModuleEngineToSyntaxMap[ModuleEngineType.BigQuery]; break; default: { syntax = globalEnv[syntaxEnvVar] as string; } } if (!syntax) { console.error( `Bad configuration. Missing 'syntax' declaration for module '${moduleName}'`, ); return undefined; } const components = engineToClientComponents(engine); return {syntax, engine, components}; }; export const getComputedSettings = ( modules: string[], globalEnv: Record = process.env, ): ComputedSettings => { const computedSettings: ComputedSettings = computedSettingsDefaults; modules.forEach(moduleName => { const moduleSettings = getModuleSettings(moduleName, globalEnv); if (moduleSettings) { computedSettings.moduleSettings[moduleName] = moduleSettings; } }); return computedSettings; }; ================================================ FILE: quix-frontend/service/src/config/env/engine-settings.ts ================================================ import {ModuleEngineType, ComponentConfiguration} from '@wix/quix-shared'; export const engineToClientComponents = (engine: string) => { return moduleToComponentsMap[engine as ModuleEngineType] || {}; }; const moduleToComponentsMap: Record< ModuleEngineType, ComponentConfiguration > = { [ModuleEngineType.Athena]: {db: {}, note: {}}, [ModuleEngineType.BigQuery]: {db: {}, note: {}}, [ModuleEngineType.Jdbc]: {db: {}, note: {}}, [ModuleEngineType.Presto]: {db: {}, note: {}}, [ModuleEngineType.Python]: {note: {}}, }; ================================================ FILE: quix-frontend/service/src/config/env/env.spec.ts ================================================ import {getEnv} from './env'; import {testingDefaults} from './static-settings'; describe('configuration parsing', () => { it('should override empty strings with defaults', () => { const mockEnv = { DB_HOST: '', DB_USER: '', }; const env = getEnv(); expect(env.DbHost).toBe(testingDefaults.DbHost); expect(env.DbUser).toBe(testingDefaults.DbUser); }); }); ================================================ FILE: quix-frontend/service/src/config/env/env.ts ================================================ import dotenv from 'dotenv'; import {isJestTest} from '../utils'; import path from 'path'; import {defaults} from 'lodash'; import {BaseConnectionOptions} from 'typeorm/connection/BaseConnectionOptions'; import {StaticSettings, EnvSettings} from './types'; import { envSettingsMap, testingDefaults, envSettingsDefaults, } from './static-settings'; import {getComputedSettings} from './computed-settings'; let environmentLoaded = false; export const loadEnv = () => { if (!environmentLoaded) { if (isJestTest()) { dotenv.config({path: path.resolve(process.cwd(), '.testenv')}); } else { dotenv.config(); } environmentLoaded = true; } }; const identity = (x: T) => x; const stringParse = (s: string | undefined) => (s === '' ? undefined : s); const backendUrlParse = (s: string | undefined) => { if (s === undefined) { return undefined; } return s.replace('https://', '').replace('http://', ''); }; const numberParse = (s: string | undefined) => s ? parseInt(s, 10) : undefined; const booleanParse = (s: string | undefined) => s !== undefined ? s.toLowerCase() === 'false' || s === '' ? false : true : undefined; const stringListParse = (s: string | undefined) => s !== undefined ? s.split(',') : undefined; const transforms: { [K in keyof StaticSettings]: ( s: string | undefined, ) => StaticSettings[K] | undefined; } = { DbType: s => { switch (s) { case 'sqlite': case 'mysql': return s; case undefined: case '': return undefined; default: throw new Error('Unknown DB type.'); } }, AuthType: s => { switch (s) { case 'google': case 'fake': return s; case undefined: case '': return undefined; default: throw new Error('Unknown Auth type.'); } }, DbName: stringParse, DbUser: stringParse, DbPass: identity, DbHost: stringParse, DbPort: numberParse, QuixBackendInternalUrl: backendUrlParse, QuixBackendPublicUrl: backendUrlParse, GoogleClientId: stringParse, GoogleAuthSecret: stringParse, AuthCookieName: stringParse, AuthEncKey: stringParse, CookieAge: numberParse, AutoMigrateDb: booleanParse, UseMinifiedStatics: booleanParse, DemoMode: booleanParse, DbDebug: s => { if (s === undefined) { return undefined; } if (s === '') { return false; } if (s.toLowerCase() === 'true') { return true; } if (s.toLowerCase() === 'false') { return false; } return s.split(',') as BaseConnectionOptions['logging']; }, Modules: stringListParse, HttpPort: numberParse, MountPath: identity, localStaticsPath: identity, remoteStaticsPath: identity, }; export const getEnv = ( globalEnv: Record = process.env, ): EnvSettings => { loadEnv(); const staticSettings: StaticSettings = defaults( Object.entries(envSettingsMap).reduce((settings, [key, envVar]) => { settings[key] = transforms[key as keyof StaticSettings]( globalEnv[envVar], ); return settings; }, {} as any), isJestTest() ? testingDefaults : envSettingsDefaults, ); const computedSettings = getComputedSettings( staticSettings.Modules, globalEnv, ); const env = {...computedSettings, ...staticSettings}; return env; }; ================================================ FILE: quix-frontend/service/src/config/env/index.ts ================================================ export {EnvSettings} from './types'; export {getEnv, loadEnv} from './env'; ================================================ FILE: quix-frontend/service/src/config/env/static-settings.ts ================================================ import {BaseConnectionOptions} from 'typeorm/connection/BaseConnectionOptions'; import * as path from 'path'; import {StaticSettings} from './types'; export const envSettingsMap: {[K in keyof StaticSettings]: string} = { DbName: 'DB_NAME', DbUser: 'DB_USER', DbPass: 'DB_PASS', DbHost: 'DB_HOST', DbPort: 'DB_PORT', QuixBackendInternalUrl: 'BACKEND_INTERNAL_URL', QuixBackendPublicUrl: 'BACKEND_PUBLIC_URL', GoogleClientId: 'GOOGLE_SSO_CLIENT_ID', GoogleAuthSecret: 'GOOGLE_SSO_SECRET', AuthCookieName: 'AUTH_COOKIE', AuthEncKey: 'AUTH_SECRET', CookieAge: 'COOKIE_MAX_AGE', DbType: 'DB_TYPE', AuthType: 'AUTH_TYPE', AutoMigrateDb: 'DB_AUTO_MIGRATE', UseMinifiedStatics: 'MINIFIED_STATICS', DemoMode: 'DEMO_MODE', DbDebug: 'DB_DEBUG', Modules: 'MODULES', HttpPort: 'HTTP_PORT', MountPath: 'MOUNT_PATH', localStaticsPath: 'LOCAL_STATICS_PATH', remoteStaticsPath: 'REMOTE_STATICS_PATH', }; export const envSettingsDefaults = { DbType: 'mysql' as 'mysql' | 'sqlite', AuthType: 'fake' as 'fake' | 'google', DbName: 'quix', DbUser: 'root', DbPass: '', DbHost: 'db', DbPort: 3306, QuixBackendInternalUrl: 'backend:8081', QuixBackendPublicUrl: 'localhost:8081', GoogleClientId: '', GoogleAuthSecret: '', AuthCookieName: '__quix', AuthEncKey: '123456', CookieAge: 30 * 24 * 60 * 60 * 1000 /* 30 days */, AutoMigrateDb: false, UseMinifiedStatics: true, DemoMode: false, DbDebug: ['error', 'schema', 'warn'] as BaseConnectionOptions['logging'], Modules: ['presto'], HttpPort: 3000, MountPath: '', localStaticsPath: path.resolve('.', 'statics'), remoteStaticsPath: '', }; export const testingDefaults: StaticSettings = { ...envSettingsDefaults, DbName: 'quixtest', DbHost: 'localhost', QuixBackendInternalUrl: 'localhost:8081', QuixBackendPublicUrl: 'localhost:8081', AuthEncKey: '', DbType: 'sqlite', AuthType: 'fake', AutoMigrateDb: true, UseMinifiedStatics: false, DbDebug: false, Modules: ['presto'], HttpPort: 3000, MountPath: '', }; ================================================ FILE: quix-frontend/service/src/config/env/types.ts ================================================ import {envSettingsDefaults} from './static-settings'; import {ComponentConfiguration} from '@wix/quix-shared'; export type StaticSettings = typeof envSettingsDefaults; export interface ComputedSettings { moduleSettings: Record< string, { syntax: string; engine: string; components: ComponentConfiguration; } >; } export type EnvSettings = StaticSettings & ComputedSettings; ================================================ FILE: quix-frontend/service/src/config/index.ts ================================================ export {ConfigService, DbTypes, DefaultConfigService} from './config.service'; export {EnvSettings} from './env'; export {ConfigModule} from './config.module'; ================================================ FILE: quix-frontend/service/src/config/utils.ts ================================================ export function isJestTest() { return process.env.JEST_WORKER_ID !== undefined; } export function isTsNode() { return !!require.extensions['.ts'] || __filename.slice(-2) === 'ts'; } ================================================ FILE: quix-frontend/service/src/consts.ts ================================================ export const QUIX_SCHEMA = `QUIX_SCHEMA`; export const CURRENT_QUIX_SCHEMA_VERSION = 5; ================================================ FILE: quix-frontend/service/src/entities/deleted-notebook/dbdeleted-notebook.entity.ts ================================================ import {IFilePathItem} from '@wix/quix-shared'; import {IDeletedNotebook} from '@wix/quix-shared'; import {dbConf} from '../../config/db-conf'; import { Column, CreateDateColumn, Entity, OneToMany, OneToOne, PrimaryColumn, UpdateDateColumn, } from 'typeorm'; import {DbFileTreeNode} from '../filenode/filenode.entity'; import {convertDbNote, DbNote} from '../note/dbnote.entity'; import {DbUser} from '../user/user.entity'; import {extractOwnerDetails} from '../utils'; @Entity('deleted_notebooks') export class DbDeletedNotebook { @PrimaryColumn({...dbConf.idColumn}) id!: string; @Column(dbConf.nameField) name!: string; @Column(dbConf.shortTextField) owner!: string; ownerDetails?: DbUser; @UpdateDateColumn(dbConf.dateUpdated) dateUpdated!: number; @CreateDateColumn(dbConf.dateCreated) dateCreated!: number; @CreateDateColumn(dbConf.dateDeleted) dateDeleted!: number; @Column({...dbConf.json, name: 'json_content'}) jsonContent: any; @OneToMany(type => DbNote, n => n.notebook, {onDelete: 'CASCADE'}) notes?: DbNote[]; @OneToOne(type => DbFileTreeNode, node => node.notebook, { onDelete: 'CASCADE', }) fileNode?: DbFileTreeNode; constructor(base?: DbDeletedNotebook) { if (base) { const {id, dateCreated, dateUpdated, name, notes, owner} = base; this.id = id; this.dateCreated = dateCreated; this.dateUpdated = dateUpdated; this.dateDeleted = this.dateDeleted; this.name = name; this.notes = notes; this.owner = owner; } this.jsonContent = this.jsonContent || {}; } } export const convertDbDeletedNotebook = ( dbDeletedNotebook: DbDeletedNotebook, computedPath?: IFilePathItem[], isLiked?: boolean, ): IDeletedNotebook => { const { dateCreated, dateUpdated, dateDeleted, id, name, owner, notes, } = dbDeletedNotebook; const ownerDetails = extractOwnerDetails(dbDeletedNotebook); return { id, dateCreated, dateUpdated, dateDeleted, name, owner, isLiked: isLiked !== undefined ? isLiked : false, notes: notes ? notes.map(convertDbNote) : [], path: computedPath || [], ownerDetails, }; }; export const covertDeletedNotebookToDb = ( notebook: IDeletedNotebook, ): DbDeletedNotebook => { const { id, name, owner, notes, dateCreated, dateUpdated, dateDeleted, } = notebook; return new DbDeletedNotebook({ id, dateCreated, dateUpdated, dateDeleted, name, owner, jsonContent: {}, }); }; ================================================ FILE: quix-frontend/service/src/entities/deleted-notebook/deleted-notebook.repository.ts ================================================ import {EntityRepository, Repository} from 'typeorm'; import {DbDeletedNotebook} from './dbdeleted-notebook.entity'; @EntityRepository(DbDeletedNotebook) export class DeletedNotebookRepository extends Repository {} ================================================ FILE: quix-frontend/service/src/entities/favorites/favorites.entity.ts ================================================ import {EntityType} from '../../common/entity-type.enum'; import {dbConf} from '../../config/db-conf'; import {Column, Entity, Index} from 'typeorm'; @Entity({name: 'favorites'}) @Index(['entityId']) export class DbFavorites { @Column({...dbConf.shortTextField, primary: true, unique: false}) owner!: string; @Column({...dbConf.idColumn, unique: false, primary: true, name: 'entity_id'}) entityId!: string; @Column({...dbConf.entityTypeEnum, name: 'entity_type'}) entityType!: EntityType; } ================================================ FILE: quix-frontend/service/src/entities/filenode/filenode.entity.ts ================================================ import { Column, Entity, Index, PrimaryColumn, OneToOne, JoinColumn, ManyToOne, CreateDateColumn, UpdateDateColumn, } from 'typeorm'; import {IFile, FileType} from '@wix/quix-shared/entities/file'; import {DbNotebook} from '../notebook/dbnotebook.entity'; import {DbFolder} from '../folder/folder.entity'; import {dbConf} from '../../config/db-conf'; import {IUser} from '@wix/quix-shared'; @Entity({name: 'tree_nodes'}) export class DbFileTreeNode { constructor(id?: string, rest: Partial = {}) { if (id) { this.id = id; Object.assign(this, rest); } } @PrimaryColumn({...dbConf.idColumn}) id!: string; @Index() @Column(dbConf.shortTextField) owner!: string; ownerDetails?: IUser; @UpdateDateColumn(dbConf.dateUpdated) dateUpdated!: number; @CreateDateColumn(dbConf.dateCreated) dateCreated!: number; @Column(dbConf.fileTypeEnum) type!: FileType; @ManyToOne(type => DbFileTreeNode, {onDelete: 'CASCADE'}) @JoinColumn() parent?: DbFileTreeNode; @Column({nullable: true}) parentId?: string; @OneToOne(type => DbNotebook, notebook => notebook.fileNode, { onDelete: 'CASCADE', }) @JoinColumn() notebook?: DbNotebook; @Column({nullable: true}) notebookId?: string; @OneToOne(type => DbFolder, { cascade: true, onDelete: 'CASCADE', }) @JoinColumn() folder?: DbFolder; @Column({nullable: true, type: 'varchar', length: 1024}) mpath!: string; } ================================================ FILE: quix-frontend/service/src/entities/filenode/filenode.repository.ts ================================================ import { EntityRepository, Repository, SaveOptions, DeepPartial, EntityManager, } from 'typeorm'; import {DbFileTreeNode} from './filenode.entity'; import {dbConf} from '../../config/db-conf'; import assert from 'assert'; import {FileType} from '@wix/quix-shared'; import {DbNotebook} from '../notebook/dbnotebook.entity'; import {DbFolder} from '../folder/folder.entity'; import {DbFavorites} from '../favorites/favorites.entity'; /** * This custom repository saves a tree structure in sql, using path enumeration/materialized path. * We don't use the built in solution by typeorm as it doesn't support moving/deletions yet. */ @EntityRepository(DbFileTreeNode) export class FileTreeRepository extends Repository { save( entities: DeepPartial[], options?: SaveOptions & { reload: false; }, ): Promise; save( entity: DeepPartial, options?: SaveOptions & { reload: false; }, ): Promise; async save( itemOrItems: DeepPartial | DeepPartial[], options?: SaveOptions, ) { if (Array.isArray(itemOrItems)) { const items = itemOrItems; for (const item of items) { await this.setMpathByParent(item); } return super.save(items, options); } else { const item = itemOrItems; await this.setMpathByParent(item); return super.save(item, options); } } private async getParentPath(item: DeepPartial) { if (item.parent && item.parent.mpath) { return item.parent.mpath; } const parentId = getParentId(item); if (parentId) { return this.findOneOrFail(parentId) .then(parent => parent.mpath) .catch(() => { throw new Error( `saving file item ${item.id}:: Can't find parent node ${item.parentId}`, ); }); } return ''; } /** * Given a node with it's parent or parentId set, * set the mpath correctly for it. * @param item */ private async setMpathByParent(item: DeepPartial) { const base = await this.getParentPath(item); item.mpath = base + (base ? '.' : '') + item.id; } /** * given a list of ids, return a list of matching tree nodes, joined with name from folder/notebook. * @param ids */ getNamesByIds(ids: string[]) { return this.createQueryBuilder('node') .select([ 'node.id', 'node.type', 'node.parentId', 'notebook.name', 'folder.name', ]) .leftJoin('node.notebook', 'notebook') .leftJoin('node.folder', 'folder') .where('node.id IN (:...ids)', {ids}) .getMany(); } /** * Get a list of first level children * @returns {Promise} */ async getChildren(rootId: string) { return this.createQueryBuilder('node') .leftJoinAndSelect('node.notebook', 'notebook') .leftJoinAndSelect('node.folder', 'folder') .where('node.parentId = :rootId', {rootId}) .getMany(); } /** * Get a list of all children * @returns {Promise} */ async getDeepChildren(root: DbFileTreeNode, entityManager?: EntityManager) { const baseMpath = root.mpath; assert(baseMpath && baseMpath.length > 0, 'mpath is empty/undefined'); const qb = entityManager ? entityManager.createQueryBuilder(DbFileTreeNode, 'node') : this.createQueryBuilder('node'); return qb .where(`node.mpath LIKE ${dbConf.concat(`('${baseMpath}')`, `'%'`)}`) .getMany(); } async moveTree(root: DbFileTreeNode, newParentNode: DbFileTreeNode) { if (root.id === newParentNode.id) { throw new Error( `Illegal request: can't move folder to itself, or to it's parent`, ); } if (root.parentId === newParentNode.id) { return; } const baseMpath = root.mpath; assert(baseMpath && baseMpath.length > 0, 'mpath is empty/undefined'); const newBasePath = newParentNode.mpath + '.' + root.id; return this.manager.transaction(async em => { await em .createQueryBuilder() .update(DbFileTreeNode) .set({ mpath: () => `replace(\`mpath\`, '${baseMpath}', '${newBasePath}')`, }) .where(`mpath LIKE ${dbConf.concat(`('${baseMpath}')`, `'%'`)}`) .execute(); await em .createQueryBuilder() .update(DbFileTreeNode) .set({parentId: newParentNode.id}) .where('id = :id', {id: root.id}) .execute(); }); } async deleteTree(root: DbFileTreeNode) { const baseMpath = root.mpath; assert(baseMpath && baseMpath.length > 0, 'mpath is empty/undefined'); const children = await this.getDeepChildren(root); const [foldersToDelete, notebooksToDelete] = children.reduce( ([foldersIds, notebookIds], node) => { (node.type === FileType.folder ? foldersIds : notebookIds).push(node); return [foldersIds, notebookIds]; }, [[], []] as DbFileTreeNode[][], ); return this.manager.transaction(async em => { if (notebooksToDelete.length) { await em .createQueryBuilder() .delete() .from(DbNotebook) .whereInIds(notebooksToDelete) .execute(); await em .createQueryBuilder() .delete() .from(DbFavorites) .where('entity_id in (:...ids)', { ids: notebooksToDelete.map(({id}) => id), }) .execute(); } if (foldersToDelete.length) { await em .createQueryBuilder() .delete() .from(DbFolder) .whereInIds(foldersToDelete) .execute(); } }); } } function getParentId(node: DeepPartial) { return node.parent && node.parent.id !== undefined ? node.parent.id : node.parentId; } ================================================ FILE: quix-frontend/service/src/entities/folder/folder.entity.ts ================================================ import { Column, CreateDateColumn, Entity, PrimaryColumn, UpdateDateColumn, } from 'typeorm'; import {dbConf} from '../../config/db-conf'; @Entity({name: 'folders'}) export class DbFolder { @PrimaryColumn({...dbConf.idColumn}) id!: string; @Column(dbConf.nameField) name!: string; @Column(dbConf.shortTextField) owner!: string; @UpdateDateColumn(dbConf.dateUpdated) dateUpdated!: number; @CreateDateColumn(dbConf.dateCreated) dateCreated!: number; @Column({...dbConf.json, name: 'json_content'}) jsonContent: any = {}; isLiked!: boolean; } ================================================ FILE: quix-frontend/service/src/entities/index.ts ================================================ export {DbNote} from './note/dbnote.entity'; export {DbNotebook} from './notebook/dbnotebook.entity'; export {DbFileTreeNode} from './filenode/filenode.entity'; export {DbFolder} from './folder/folder.entity'; export {FileTreeRepository} from './filenode/filenode.repository'; export {NoteRepository} from './note/note.repository'; export {DbUser} from './user/user.entity'; export {DbFavorites} from './favorites/favorites.entity'; export {DbMetadata} from './version-metadata.entity'; export {NotebookRepository} from './notebook/notebook.repository'; export {DbAction} from '../modules/event-sourcing/infrastructure/action-store/entities/db-action.entity'; export {DbDeletedNotebook} from './deleted-notebook/dbdeleted-notebook.entity'; export {DeletedNotebookRepository} from './deleted-notebook/deleted-notebook.repository'; ================================================ FILE: quix-frontend/service/src/entities/note/dbnote.entity.ts ================================================ import { Column, Entity, Index, PrimaryColumn, ManyToOne, UpdateDateColumn, CreateDateColumn, } from 'typeorm'; import {INote, IBaseNote} from '@wix/quix-shared/entities/note'; import {DbNotebook} from '../notebook/dbnotebook.entity'; import {dbConf} from '../../config/db-conf'; @Entity({name: 'notes'}) export class DbNote { @PrimaryColumn({...dbConf.idColumn}) id!: string; /** for any extra properties that might be added in the future */ @Column({...dbConf.json, name: 'json_content'}) jsonContent!: any; /** for note data */ @Column({...dbConf.json, name: 'rich_content'}) richContent!: any; @Index({fulltext: true}) @Column(dbConf.noteContent) textContent!: string; @Column(dbConf.shortTextField) type!: string; @Column(dbConf.nameField) name!: string; @Index() @Column(dbConf.shortTextField) owner!: string; @UpdateDateColumn(dbConf.dateUpdated) dateUpdated!: number; @CreateDateColumn(dbConf.dateCreated) dateCreated!: number; @ManyToOne(type => DbNotebook, n => n.notes, { createForeignKeyConstraints: false, }) notebook?: DbNotebook; @Column() notebookId!: string; @Column({type: 'integer'}) rank?: number; constructor(base?: DbNote) { if (base) { Object.assign(this, base); } } } export const convertDbNote = (dbNote: DbNote): INote => { const { dateCreated, dateUpdated, id, name, notebookId, owner, textContent, jsonContent, richContent, type, } = dbNote; return { type, id, content: textContent, richContent: richContent || {}, dateCreated, dateUpdated, name, notebookId, owner, }; }; export const convertNoteToDb = (note: INote): DbNote => { const { id, name, notebookId, owner, type, content, dateCreated, dateUpdated, richContent, } = note; return new DbNote({ type, id, textContent: note.content, jsonContent: {}, richContent, name, notebookId, owner, dateCreated, dateUpdated, rank: undefined, }); }; ================================================ FILE: quix-frontend/service/src/entities/note/note.repository.ts ================================================ import {EntityRepository, Repository} from 'typeorm'; import {DbNote} from './dbnote.entity'; @EntityRepository(DbNote) export class NoteRepository extends Repository { async insertNewWithRank(note: DbNote) { const currentCount = await this.count({notebookId: note.notebookId}); note.rank = currentCount; return this.insert(note); } async deleteOneAndOrderRank(item: string | DbNote) { const note = typeof item === 'string' ? await this.findOneOrFail(item) : item; return this.manager.transaction(async em => { await em .createQueryBuilder() .update(DbNote) .set({ rank: () => '`rank` - 1', }) .where(`notebookId = :notebookId`, {notebookId: note.notebookId}) .andWhere(`\`rank\` > :rank`, {rank: note.rank}) .execute(); await em.delete(DbNote, note.id); }); } async reorder(note: DbNote, to: number) { return this.manager.transaction(async em => { const from = note.rank; if (from === undefined) { throw new Error('invalid note state, missing rank property'); } if (from === to) { return; } if (from > to) { await em .createQueryBuilder() .update(DbNote) .set({ rank: () => '`rank` + 1', }) .where(`notebookId = :notebookId`, {notebookId: note.notebookId}) .andWhere(`\`rank\` between :to and :from`, {from: from - 1, to}) .execute(); } else if (from < to) { await em .createQueryBuilder() .update(DbNote) .set({ rank: () => '`rank` - 1', }) .where(`notebookId = :notebookId`, {notebookId: note.notebookId}) .andWhere(`\`rank\` between :from and :to`, {from: from + 1, to}) .execute(); } await em.update(DbNote, note.id, {rank: to}); }); } } ================================================ FILE: quix-frontend/service/src/entities/notebook/dbnotebook.entity.ts ================================================ import {IFilePathItem, INotebook} from '@wix/quix-shared'; import { BeforeInsert, BeforeUpdate, Column, CreateDateColumn, Entity, OneToMany, OneToOne, PrimaryColumn, UpdateDateColumn, } from 'typeorm'; import {dbConf} from '../../config/db-conf'; import {convertDbNote, convertNoteToDb, DbNote} from '../note/dbnote.entity'; import {DbFileTreeNode} from '../filenode/filenode.entity'; import {DbUser} from '../user/user.entity'; import {extractOwnerDetails} from '../utils'; @Entity({name: 'notebooks'}) export class DbNotebook { @PrimaryColumn({...dbConf.idColumn}) id!: string; @Column(dbConf.nameField) name!: string; @Column(dbConf.shortTextField) owner!: string; ownerDetails?: DbUser; @UpdateDateColumn(dbConf.dateUpdated) dateUpdated!: number; @CreateDateColumn(dbConf.dateCreated) dateCreated!: number; @Column({...dbConf.json, name: 'json_content'}) jsonContent: any; @OneToMany(type => DbNote, n => n.notebook, { createForeignKeyConstraints: false, }) notes?: DbNote[]; @OneToOne(type => DbFileTreeNode, node => node.notebook, { onDelete: 'CASCADE', }) fileNode?: DbFileTreeNode; constructor(base?: DbNotebook) { if (base) { const {id, dateCreated, dateUpdated, name, notes, owner} = base; this.id = id; this.dateCreated = dateCreated; this.dateUpdated = dateUpdated; this.name = name; this.notes = notes; this.owner = owner; } this.jsonContent = this.jsonContent || {}; } } export const convertDbNotebook = ( dbNotebook: DbNotebook, computedPath?: IFilePathItem[], isLiked?: boolean, ): INotebook => { const {dateCreated, dateUpdated, id, name, owner, notes} = dbNotebook; const ownerDetails = extractOwnerDetails(dbNotebook); return { id, dateCreated, dateUpdated, name, owner, isLiked: isLiked !== undefined ? isLiked : false, notes: notes ? notes.map(convertDbNote) : [], path: computedPath || [], ownerDetails, }; }; export const covertNotebookToDb = (notebook: INotebook): DbNotebook => { const {id, name, owner, notes, dateCreated, dateUpdated} = notebook; return new DbNotebook({ id, dateCreated, dateUpdated, name, owner, jsonContent: {}, }); }; ================================================ FILE: quix-frontend/service/src/entities/notebook/notebook.repository.ts ================================================ import {EntityRepository, Repository} from 'typeorm'; import {DbNotebook} from './dbnotebook.entity'; @EntityRepository(DbNotebook) export class NotebookRepository extends Repository {} ================================================ FILE: quix-frontend/service/src/entities/user/user.entity.ts ================================================ import { Column, Entity, PrimaryColumn, UpdateDateColumn, CreateDateColumn, } from 'typeorm'; import {dbConf} from '../../config/db-conf'; import {IUser} from '@wix/quix-shared'; @Entity({name: 'users'}) export class DbUser { @PrimaryColumn('varchar', {length: 64}) id!: string; @Column({...dbConf.shortTextField, nullable: true}) name?: string; @Column(dbConf.userAvatar) avatar?: string; @Column({...dbConf.idColumn, name: 'root_folder', unique: false}) rootFolder!: string; @Column({...dbConf.json, name: 'json_content'}) jsonContent?: any; @UpdateDateColumn(dbConf.dateUpdated) dateUpdated!: number; @CreateDateColumn(dbConf.dateCreated) dateCreated!: number; constructor(base: Partial) { Object.assign(this, base); } } export const dbUserToUser = (dbUser: DbUser): IUser => { const { jsonContent, avatar, name, rootFolder, id, dateCreated, dateUpdated, } = dbUser; return { id, avatar: avatar || '', name: name || '', rootFolder, email: id, dateCreated, dateUpdated, }; }; export const userToDbUser = (user: IUser) => { const {avatar, email, id, name, rootFolder, dateCreated, dateUpdated} = user; const dbUser = new DbUser({ avatar, id, name, rootFolder, }); if (dateCreated !== undefined) { dbUser.dateCreated = dateCreated; } if (dateUpdated !== undefined) { dbUser.dateUpdated = dateUpdated; } return dbUser; }; ================================================ FILE: quix-frontend/service/src/entities/utils.ts ================================================ import {DbUser, dbUserToUser} from './user/user.entity'; import { fromNullable, getOrElse, option, some, none, chain, map, } from 'fp-ts/lib/Option'; import {pipe} from 'fp-ts/lib/pipeable'; import {createEmptyIUser, IUser} from '@wix/quix-shared'; interface IMaybeHasOwnerDetails { owner: string; ownerDetails?: DbUser; } export const extractOwnerDetails = ({ owner: ownerId, ownerDetails, }: IMaybeHasOwnerDetails): IUser => { const userDetails: IUser = pipe( fromNullable(ownerDetails), chain(dbUser => (dbUser.id ? some(dbUser) : none)), // make sure Id is set map(dbUser => dbUserToUser(dbUser)), getOrElse(() => createEmptyIUser(ownerId)), ); return userDetails; }; ================================================ FILE: quix-frontend/service/src/entities/version-metadata.entity.ts ================================================ import {Column, Entity, PrimaryGeneratedColumn} from 'typeorm'; import {dbConf} from '../config/db-conf'; @Entity({name: 'version_metadata'}) export class DbMetadata { @PrimaryGeneratedColumn() id!: number; @Column() name!: string; @Column({type: 'double'}) version!: number; @Column(dbConf.json) jsonContent: any = {}; constructor(name: string, version: number, jsonContent = {}) { this.name = name; this.version = version; this.jsonContent = jsonContent; } } ================================================ FILE: quix-frontend/service/src/errors/exceptions.ts ================================================ type Ctor = new (...args: any[]) => any; class ItemNotFoundT extends Error { private itemType: string; constructor(type: Ctor | string, private id: string) { super(); if (typeof type === 'string') { this.itemType = type; } else { this.itemType = type.name; } this.message = `item of type:${this.itemType} and id:${id} not found.`; this.name = `ITEM_NOT_FOUND`; } } export const ItemNotFound = (type: Ctor | string, id: string) => new ItemNotFoundT(type, id); class BadActionT extends Error { constructor(type: string, customMsg: string) { super(); this.message = `type ${type}. ${customMsg}`; this.name = `BAD_ACTION`; } } export const BadAction = (type: string, msg: string) => new BadActionT(type, msg); ================================================ FILE: quix-frontend/service/src/errors/index.ts ================================================ export {ItemNotFound, BadAction} from './exceptions'; ================================================ FILE: quix-frontend/service/src/main.ts ================================================ import {json} from 'express'; import {NestFactory} from '@nestjs/core'; import {AppModule} from './app.module'; import {NestExpressApplication} from '@nestjs/platform-express'; import velocityEngine from './template-engine/velocity'; import cookieParser from 'cookie-parser'; import {createConnection} from 'typeorm'; import {createMysqlConf} from './config/db-connection'; import {getEnv} from './config/env/env'; import {DbMetadata} from './entities/version-metadata.entity'; import {Logger} from '@nestjs/common'; import { checkSchemaVersion, createInitialSchemaIfNeeded, isMasterProcess, } from './utils/create-schema-helpers'; import {retry} from './utils/retry-promise'; import {WsAdapter} from '@nestjs/platform-ws'; async function bootstrap() { const logger = new Logger(); const env = getEnv(); if (isMasterProcess()) { if (!env.AutoMigrateDb && env.DbType === 'mysql') { const conf = createMysqlConf([DbMetadata], env); const conn = await retry(() => createConnection(conf)) .forNTimes(5) .andWaitXMilliseconds(2000); await createInitialSchemaIfNeeded(conn, env.DbName, logger); await checkSchemaVersion(conn, logger); await conn.close(); } } else { await new Promise(resolve => setTimeout(resolve, 3000)); // let master process do it's thing, create schema and all; } const app = await NestFactory.create(AppModule, { bodyParser: false, }); app.useStaticAssets(env.localStaticsPath); app.setBaseViewsDir(env.localStaticsPath); app.engine('.vm', velocityEngine()); app.use(cookieParser()); app.use(json({limit: '2mb'})); app.useWebSocketAdapter(new WsAdapter(app)); await app.listen(env.HttpPort); } bootstrap(); ================================================ FILE: quix-frontend/service/src/migrations/1558528771647-v1.ts ================================================ /* tslint:disable */ import {MigrationInterface, QueryRunner} from "typeorm"; export class v11558528771647 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query("CREATE TABLE `folders` (`id` varchar(36) NOT NULL, `name` varchar(64) NOT NULL, `owner` varchar(64) NOT NULL, `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `date_created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `json_content` json NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `tree_nodes` (`id` varchar(36) NOT NULL, `owner` varchar(64) NOT NULL, `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `date_created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `type` enum ('folder', 'notebook') NOT NULL DEFAULT 'folder', `parentId` varchar(255) NULL, `notebookId` varchar(255) NULL, `mpath` varchar(1024) NULL, `folderId` varchar(36) NULL, INDEX `IDX_8954b75175bd5cbc43630e1c52` (`owner`), UNIQUE INDEX `REL_88797ade322e1717a3824fa0ec` (`notebookId`), UNIQUE INDEX `REL_cf0b457e67294f4b1155568441` (`folderId`), PRIMARY KEY (`id`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `notebooks` (`id` varchar(36) NOT NULL, `name` varchar(64) NOT NULL, `owner` varchar(64) NOT NULL, `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `date_created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `json_content` json NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `notes` (`id` varchar(36) NOT NULL, `json_content` json NULL, `textContent` mediumtext NULL, `type` varchar(64) NOT NULL, `name` varchar(64) NOT NULL, `owner` varchar(64) NOT NULL, `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `date_created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `notebookId` varchar(255) NOT NULL, `rank` int NOT NULL, FULLTEXT INDEX `IDX_5c83f1c4e3f3db5ea424438946` (`textContent`), INDEX `IDX_8e91b277f0f9ca503d8bf88390` (`owner`), PRIMARY KEY (`id`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `favorites` (`owner` varchar(64) NOT NULL, `entity_id` varchar(36) NOT NULL, `entity_type` enum ('notebook', 'note', 'folder') NOT NULL DEFAULT 'notebook', INDEX `IDX_e42953e6be13870839a04a3fa8` (`entity_id`), PRIMARY KEY (`owner`, `entity_id`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `users` (`id` varchar(64) NOT NULL, `name` varchar(64) NULL, `avatar` varchar(255) NULL, `root_folder` varchar(36) NOT NULL, `json_content` json NULL, UNIQUE INDEX `IDX_22bc9f47a6d39a6c3a868321ba` (`root_folder`), PRIMARY KEY (`id`, `root_folder`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `version_metadata` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `version` double NOT NULL, `jsonContent` json NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"); await queryRunner.query("CREATE TABLE `actions` (`id` varchar(36) NOT NULL, `data` json NULL, `user` varchar(64) NOT NULL, `date_created` timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4), `type` varchar(255) NOT NULL, INDEX `IDX_733a22dda689fe10e5fa29d93f` (`date_created`), INDEX `IDX_28d49fb1d1f565ea98929f69a0` (`id`, `type`), PRIMARY KEY (`id`, `date_created`)) ENGINE=InnoDB"); await queryRunner.query("ALTER TABLE `tree_nodes` ADD CONSTRAINT `FK_8aff7aa6aa930ffd5f259b27da7` FOREIGN KEY (`parentId`) REFERENCES `tree_nodes`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION"); await queryRunner.query("ALTER TABLE `tree_nodes` ADD CONSTRAINT `FK_88797ade322e1717a3824fa0eca` FOREIGN KEY (`notebookId`) REFERENCES `notebooks`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION"); await queryRunner.query("ALTER TABLE `tree_nodes` ADD CONSTRAINT `FK_cf0b457e67294f4b11555684416` FOREIGN KEY (`folderId`) REFERENCES `folders`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION"); await queryRunner.query("ALTER TABLE `notes` ADD CONSTRAINT `FK_d84382f58ca053c3532fe78b05b` FOREIGN KEY (`notebookId`) REFERENCES `notebooks`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION"); } public async down(queryRunner: QueryRunner): Promise { // await queryRunner.query("ALTER TABLE `notes` DROP FOREIGN KEY `FK_d84382f58ca053c3532fe78b05b`"); // await queryRunner.query("ALTER TABLE `tree_nodes` DROP FOREIGN KEY `FK_cf0b457e67294f4b11555684416`"); // await queryRunner.query("ALTER TABLE `tree_nodes` DROP FOREIGN KEY `FK_88797ade322e1717a3824fa0eca`"); // await queryRunner.query("ALTER TABLE `tree_nodes` DROP FOREIGN KEY `FK_8aff7aa6aa930ffd5f259b27da7`"); await queryRunner.query("DROP INDEX `IDX_28d49fb1d1f565ea98929f69a0` ON `actions`"); await queryRunner.query("DROP INDEX `IDX_733a22dda689fe10e5fa29d93f` ON `actions`"); await queryRunner.query("DROP TABLE `actions`"); await queryRunner.query("DROP TABLE `version_metadata`"); await queryRunner.query("DROP INDEX `IDX_22bc9f47a6d39a6c3a868321ba` ON `users`"); await queryRunner.query("DROP TABLE `users`"); await queryRunner.query("DROP INDEX `IDX_e42953e6be13870839a04a3fa8` ON `favorites`"); await queryRunner.query("DROP TABLE `favorites`"); await queryRunner.query("DROP INDEX `IDX_8e91b277f0f9ca503d8bf88390` ON `notes`"); await queryRunner.query("DROP INDEX `IDX_5c83f1c4e3f3db5ea424438946` ON `notes`"); await queryRunner.query("DROP TABLE `notes`"); await queryRunner.query("DROP TABLE `notebooks`"); await queryRunner.query("DROP INDEX `REL_cf0b457e67294f4b1155568441` ON `tree_nodes`"); await queryRunner.query("DROP INDEX `REL_88797ade322e1717a3824fa0ec` ON `tree_nodes`"); await queryRunner.query("DROP INDEX `IDX_8954b75175bd5cbc43630e1c52` ON `tree_nodes`"); await queryRunner.query("DROP TABLE `tree_nodes`"); await queryRunner.query("DROP TABLE `folders`"); } } ================================================ FILE: quix-frontend/service/src/migrations/1558528771648-v1-metadata.ts ================================================ import {MigrationInterface, QueryRunner} from 'typeorm'; import {DbMetadata} from '../entities/version-metadata.entity'; import {QUIX_SCHEMA} from '../consts'; const PREVIOUS_QUIX_SCHEMA = 0; const CURRENT_QUIX_SCHEMA_VERSION = 1; export class VersionMetadata1558528771648 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { const metadata = new DbMetadata(QUIX_SCHEMA, CURRENT_QUIX_SCHEMA_VERSION); const manager = queryRunner.manager; await manager.save(DbMetadata, metadata); } public async down(queryRunner: QueryRunner): Promise { const metadata = new DbMetadata(QUIX_SCHEMA, PREVIOUS_QUIX_SCHEMA); const manager = queryRunner.manager; await manager.save(DbMetadata, metadata); } } ================================================ FILE: quix-frontend/service/src/migrations/1562174176877-v2.ts ================================================ import {MigrationInterface, QueryRunner} from 'typeorm'; import {DbMetadata} from '../entities/version-metadata.entity'; import {QUIX_SCHEMA} from '../consts'; const PREVIOUS_QUIX_SCHEMA = 1; const CURRENT_QUIX_SCHEMA_VERSION = 2; export class v21562174176877 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `users` ADD `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `users` ADD `date_created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'DROP INDEX `IDX_22bc9f47a6d39a6c3a868321ba` ON `users`', ); await queryRunner.query( 'ALTER TABLE `users` DROP primary key, ADD primary key(`id`)', ); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: CURRENT_QUIX_SCHEMA_VERSION}, ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `users` DROP primary key, ADD primary key(`id`, `root_folder`)', ); await queryRunner.query( 'CREATE UNIQUE INDEX `IDX_22bc9f47a6d39a6c3a868321ba` ON `users` (`root_folder`)', ); await queryRunner.query('ALTER TABLE `users` DROP COLUMN `date_created`'); await queryRunner.query('ALTER TABLE `users` DROP COLUMN `date_updated`'); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: PREVIOUS_QUIX_SCHEMA}, ); } } ================================================ FILE: quix-frontend/service/src/migrations/1614173960671-v3.ts ================================================ import {MigrationInterface, QueryRunner} from 'typeorm'; import {DbMetadata} from '../entities/version-metadata.entity'; import {QUIX_SCHEMA} from '../consts'; const PREVIOUS_QUIX_SCHEMA = 2; const CURRENT_QUIX_SCHEMA_VERSION = 3; export class v31614173960671 implements MigrationInterface { name = 'v31614173960671'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('ALTER TABLE `notes` ADD `rich_content` json NULL'); await queryRunner.query( 'ALTER TABLE `notes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `users` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `notebooks` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `folders` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `tree_nodes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)', ); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: CURRENT_QUIX_SCHEMA_VERSION}, ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `tree_nodes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `folders` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `notebooks` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `users` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query( 'ALTER TABLE `notes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)', ); await queryRunner.query('ALTER TABLE `notes` DROP COLUMN `rich_content`'); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: PREVIOUS_QUIX_SCHEMA}, ); } } ================================================ FILE: quix-frontend/service/src/migrations/1614712161318-v4.ts ================================================ import {MigrationInterface, QueryRunner} from 'typeorm'; import {DbMetadata} from '../entities/version-metadata.entity'; import {QUIX_SCHEMA} from '../consts'; const PREVIOUS_QUIX_SCHEMA = 3; const CURRENT_QUIX_SCHEMA_VERSION = 4; export class v41614712161318 implements MigrationInterface { name = 'v41614712161318'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `notes` MODIFY COLUMN `name` varchar(512) NOT NULL', ); await queryRunner.query( 'ALTER TABLE `notebooks` MODIFY COLUMN `name` varchar(512) NOT NULL', ); await queryRunner.query( 'ALTER TABLE `folders` MODIFY COLUMN `name` varchar(512) NOT NULL', ); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: CURRENT_QUIX_SCHEMA_VERSION}, ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query( 'ALTER TABLE `notes` MODIFY COLUMN `name` varchar(64) NOT NULL', ); await queryRunner.query( 'ALTER TABLE `notebooks` MODIFY COLUMN `name` varchar(64) NOT NULL', ); await queryRunner.query( 'ALTER TABLE `folders` MODIFY COLUMN `name` varchar(64) NOT NULL', ); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: PREVIOUS_QUIX_SCHEMA}, ); } } ================================================ FILE: quix-frontend/service/src/migrations/1634023683491-v5.ts ================================================ import {DbMetadata} from '../entities/version-metadata.entity'; import {MigrationInterface, QueryRunner} from 'typeorm'; import {QUIX_SCHEMA} from '../consts'; const PREVIOUS_QUIX_SCHEMA = 4; const CURRENT_QUIX_SCHEMA_VERSION = 5; export class v51634023683491 implements MigrationInterface { name = 'v51634023683491'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( `ALTER TABLE \`notes\` DROP FOREIGN KEY \`FK_d84382f58ca053c3532fe78b05b\``, ); await queryRunner.query( `CREATE TABLE \`deleted_notebooks\` (\`id\` varchar(36) NOT NULL, \`name\` varchar(512) NOT NULL, \`owner\` varchar(64) NOT NULL, \`date_updated\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), \`date_created\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`date_deleted\` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), \`json_content\` json NULL, PRIMARY KEY (\`id\`)) ENGINE=InnoDB`, ); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: CURRENT_QUIX_SCHEMA_VERSION}, ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(`DROP TABLE \`deleted_notebooks\``); await queryRunner.query( `ALTER TABLE \`notes\` ADD CONSTRAINT \`FK_d84382f58ca053c3532fe78b05b\` FOREIGN KEY (\`notebookId\`) REFERENCES \`quix\`.\`notebooks\`(\`id\`) ON DELETE CASCADE ON UPDATE NO ACTION`, ); const manager = queryRunner.manager; await manager.update( DbMetadata, {name: QUIX_SCHEMA}, {version: PREVIOUS_QUIX_SCHEMA}, ); } } ================================================ FILE: quix-frontend/service/src/modules/auth/auth.controller.ts ================================================ import { Controller, Get, Logger, Query, Res, Req, UseGuards, } from '@nestjs/common'; import {AuthGuard} from './user-decorator'; import {Response, Request} from 'express'; import {LoginService} from './login.service'; import {IExternalUser} from './types'; import {User} from './user-decorator'; import {UsersService} from './users.service'; import {DeletedNotebooksService} from '../web-api/deleted-notebooks/deleted-notebook.service'; @Controller('/api/') export class AuthController { private readonly logger = new Logger(AuthController.name); constructor( private readonly authService: LoginService, private readonly userService: UsersService, private readonly deletedNotebooksService: DeletedNotebooksService, ) {} @Get('user') @UseGuards(AuthGuard) async getUser(@User() user: IExternalUser) { this.userService.doUserLogin(user).catch(e => { this.logger.error('error updating user', e); }); const count = await this.deletedNotebooksService.getCountDeletedNotebooksForUser( user.email, ); return {...user, stats: {trashBinCount: count}}; } @Get('authenticate') async doAuth( @Query('code') code: string, @Req() req: Request, @Res() res: Response, ) { try { const up = await this.authService.login(code, req, res); if (up) { await this.userService.doUserLogin(up); res.json(up); return; } res.sendStatus(401).send(); } catch (e) { this.logger.error(e); res.sendStatus(500).send(); } } } ================================================ FILE: quix-frontend/service/src/modules/auth/auth.module.ts ================================================ import {DynamicModule, Module} from '@nestjs/common'; import {JwtModule, JwtService} from '@nestjs/jwt'; import {TypeOrmModule} from '@nestjs/typeorm'; import { DbDeletedNotebook, DbUser, DeletedNotebookRepository, } from '../../entities'; import {EventSourcingModule} from '../../modules/event-sourcing/event-sourcing.module'; import {DeletedNotebooksService} from '../web-api/deleted-notebooks/deleted-notebook.service'; import {AuthController} from './auth.controller'; import { CustomLoginService, FakeLoginService, GoogleLoginService, LoginService, } from './login.service'; import {AuthAsyncOptions, AuthOptions, AuthTypes} from './types'; import {UsersService} from './users.service'; /** read about nest.js dynamic modules to understand this */ @Module({}) export class AuthModuleConfiguration { static createAsync(authAsyncOptions: AuthAsyncOptions): DynamicModule { return { global: true, // feels like workaround, couldn't get injection to work otherwise module: AuthModuleConfiguration, imports: authAsyncOptions.imports, providers: [ { provide: AuthOptions, inject: authAsyncOptions.injects, useFactory: authAsyncOptions.useFactory, }, ], exports: [AuthOptions], }; } static create(authOption: AuthOptions): DynamicModule { return { global: true, module: AuthModuleConfiguration, providers: [ { provide: AuthOptions, useValue: authOption, }, ], exports: [AuthOptions], }; } } @Module({ imports: [ TypeOrmModule.forFeature([DbUser, DbDeletedNotebook]), EventSourcingModule, AuthModuleConfiguration, JwtModule.registerAsync({ imports: [AuthModuleConfiguration], inject: [AuthOptions], useFactory: (authOptions: AuthOptions) => { switch (authOptions.type) { case AuthTypes.GOOGLE: return { secret: authOptions.cookieEncKey, signOptions: { algorithm: 'HS256', expiresIn: authOptions.cookieTTL, }, }; case AuthTypes.CUSTOM: return authOptions.jwtServiceOptions || {secret: '12345'}; case AuthTypes.FAKE: default: return {secret: '12345'}; } }, }), ], controllers: [AuthController], providers: [UsersService, DeletedNotebooksService], exports: [UsersService], }) export class AuthModule { static create(): DynamicModule { return { module: AuthModule, providers: [ { provide: LoginService, inject: [AuthOptions, JwtService], useFactory: (authOptions: AuthOptions, jwtService: JwtService) => { switch (authOptions.type) { case AuthTypes.CUSTOM: return new CustomLoginService(authOptions); case AuthTypes.GOOGLE: return new GoogleLoginService(authOptions, jwtService); case AuthTypes.FAKE: return new FakeLoginService(authOptions); } }, }, ], exports: [LoginService], }; } } ================================================ FILE: quix-frontend/service/src/modules/auth/common-auth.ts ================================================ import {IExternalUser} from './types'; import {isJestTest} from '../../config/utils'; const defaultUser: IExternalUser = { email: 'user@quix.com', id: '1', name: 'Default User', }; export const fakeAuth = (token: string): IExternalUser | undefined => { try { const user = JSON.parse(Buffer.from(token, 'base64').toString()); return user; } catch (e) { if (isJestTest()) { return undefined; } // tslint:disable-next-line: no-console console.debug(`Can't parse cookie, using default user.`); return defaultUser; } }; ================================================ FILE: quix-frontend/service/src/modules/auth/index.ts ================================================ export {IExternalUser} from './types'; export {User, AuthGuard} from './user-decorator'; export {UsersService} from './users.service'; ================================================ FILE: quix-frontend/service/src/modules/auth/login.service.ts ================================================ import {Injectable, Inject} from '@nestjs/common'; import {Response, Request} from 'express'; import {ConfigService} from '../../config'; import {JwtService} from '@nestjs/jwt'; import { AuthOptions, AuthTypes, CustomAuthOptions, FakeAuthOptions, GoogleAuthOptions, IExternalUser, } from './types'; import {OAuth2Client} from 'google-auth-library'; import {fakeAuth} from './common-auth'; export abstract class LoginService { abstract login( clientPayload: string, req: Request, res: Response, ): Promise; abstract verify(token: string): IExternalUser | undefined; } export class FakeLoginService extends LoginService { constructor( @Inject(AuthOptions) private readonly authOptions: FakeAuthOptions, ) { super(); } verify(token: string) { return fakeAuth(token); } login( authCode: string, req: Request, res: Response, ): Promise { const up: IExternalUser = JSON.parse(authCode); res.cookie( this.authOptions.cookieName, Buffer.from(JSON.stringify(up)).toString('base64'), { maxAge: 24 * 60 * 1000, }, ); return Promise.resolve(up); } } export class CustomLoginService extends LoginService { constructor( @Inject(AuthOptions) private readonly authOptions: CustomAuthOptions, ) { super(); } verify(token: string) { return this.authOptions.auth.verify(token); } login( authCode: string, req: Request, res: Response, ): Promise { return this.authOptions.auth.login(authCode, req, res); } } export class GoogleLoginService extends LoginService { constructor( @Inject(AuthOptions) private readonly authOptions: GoogleAuthOptions, private jwtService: JwtService, ) { super(); } verify(token: string) { return this.jwtService.verify(token); } async login( authCode: string, req: Request, res: Response, ): Promise { { const clientId = this.authOptions.googleClientId; const clientSecret = this.authOptions.googleAuthSecret; const authClient = new OAuth2Client({ clientId, clientSecret, redirectUri: 'postmessage', }); const r = await authClient.getToken(authCode); authClient.setCredentials(r.tokens); const verify = await authClient.verifyIdToken({ idToken: r.tokens.id_token || '', audience: clientId, }); const payload = (verify && verify.getPayload()) || null; if (payload && payload.email && payload.sub) { const up: IExternalUser = { avatar: payload.picture, name: payload.name, email: payload.email, id: payload.sub, }; const jwtToken = await this.jwtService.signAsync(up); res.cookie(this.authOptions.cookieName, jwtToken, { maxAge: this.authOptions.cookieTTL, }); return up; } } } } ================================================ FILE: quix-frontend/service/src/modules/auth/types.ts ================================================ import {ModuleMetadata, Type} from '@nestjs/common'; import {Response, Request} from 'express'; import {JwtModuleOptions} from '@nestjs/jwt'; import http from 'http'; /** * Quix authentication works by authenticating the user vs some external service (currently just google, openconnect in the future) * Then writing this identity into a cookie (JWT or otherwise) and into an internal user entity persisted in db * This is the payload we expect from an external service */ export interface IExternalUser { id: string; email: string; avatar?: string; name?: string; } export interface CustomAuth { login( clientPayload: string, req: Request, res: Response, ): Promise; verify(token: string): IExternalUser | undefined; // currently websocket code prevent us from using promise here getTokenFromRequest(request: http.IncomingMessage): string; } export enum AuthTypes { CUSTOM = 0, FAKE = 1, GOOGLE = 2, } export type FakeAuthOptions = { type: AuthTypes.FAKE; cookieName: string; }; export type GoogleAuthOptions = { type: AuthTypes.GOOGLE; cookieName: string; cookieTTL: number; cookieEncKey: string; googleClientId: string; googleAuthSecret: string; }; export type CustomAuthOptions = { type: AuthTypes.CUSTOM; auth: CustomAuth; jwtServiceOptions?: JwtModuleOptions; }; export type AuthOptions = | FakeAuthOptions | GoogleAuthOptions | CustomAuthOptions; // export interface AuthOptionsFactory { // createAuthOptions(): Promise | AuthOptions; // } export interface AuthAsyncOptions extends Pick { // useExisting?: Type; //To implement later, if needed // useClass?: Type; useFactory: (...args: any[]) => Promise | AuthOptions; injects?: any[]; } export const AuthOptions = 'AuthOptions'; ================================================ FILE: quix-frontend/service/src/modules/auth/user-decorator.ts ================================================ import { CanActivate, createParamDecorator, ExecutionContext, Inject, Injectable, } from '@nestjs/common'; import {Request} from 'express'; import {LoginService} from './login.service'; import {AuthOptions, AuthTypes, IExternalUser} from './types'; export const User = createParamDecorator((data, ctx: ExecutionContext) => { return ctx.switchToHttp().getRequest().user; }); const getTokenFromRequestByCookie = (cookieName: string) => (req: Request) => req.cookies[cookieName]; @Injectable() export class AuthGuard implements CanActivate { private getTokenFromRequest: (req: Request) => string; constructor( @Inject(AuthOptions) authOptions: AuthOptions, private loginService: LoginService, ) { if (authOptions.type === AuthTypes.CUSTOM) { this.getTokenFromRequest = authOptions.auth.getTokenFromRequest; } else { this.getTokenFromRequest = getTokenFromRequestByCookie( authOptions.cookieName, ); } } canActivate(context: ExecutionContext): boolean | Promise { const request: Request = context.switchToHttp().getRequest(); const token = this.getTokenFromRequest(request); return Promise.resolve(this.loginService.verify(token)).then(user => { request.user = user; return !!user; }); } } declare module 'express' { interface Request { user?: IExternalUser; } } ================================================ FILE: quix-frontend/service/src/modules/auth/users.service.ts ================================================ import {Injectable, Logger} from '@nestjs/common'; import {QuixEventBus} from '../../modules/event-sourcing/quix-event-bus'; import {Repository} from 'typeorm'; import {DbUser} from '../../entities'; import {InjectRepository} from '@nestjs/typeorm'; import {dbUserToUser} from '../../entities/user/user.entity'; import {IExternalUser} from './types'; import {FileActions, createFolder} from '@wix/quix-shared/entities/file'; import uuid from 'uuid/v4'; import {UserActions, createUser} from '@wix/quix-shared/entities/user'; @Injectable() export class UsersService { private logger = new Logger('UsersService'); constructor( @InjectRepository(DbUser) private userRepo: Repository, private quixEventBus: QuixEventBus, ) {} async doUserLogin(userFromLogin: IExternalUser) { const user = await this.userRepo.findOne({id: userFromLogin.email}); if (!user) { await this.doFirstTimeLogin(userFromLogin); } else { await this.doLogin(userFromLogin, user); } } private async doFirstTimeLogin(userFromLogin: IExternalUser) { const rootFolderId = await this.createRootFolder(userFromLogin.email); const {avatar, email: id, email, name} = userFromLogin; const user = createUser({ avatar, email, id, name, rootFolder: rootFolderId, }); return this.quixEventBus.emit({ ...UserActions.createNewUser(id, user), user: id, ethereal: true, }); } private async doLogin(userFromLogin: IExternalUser, dbUser: DbUser) { const {avatar, name, email: id, email} = userFromLogin; /* small hack when migrating users, creating users with epoch 1000 (1970-01-01 00:00:01) */ /* once they login, change dateCreated */ const changeUserCreated = dbUser.dateCreated.valueOf() === 1000 ? new Date() : undefined; return this.quixEventBus.emit({ ...UserActions.updateUser( id, avatar || '', name || '', email, changeUserCreated, ), user: id, ethereal: true, }); } private async createRootFolder(user: string) { const id = uuid(); await this.quixEventBus.emit({ ...FileActions.createFile( id, createFolder([], {id, name: 'My notebooks'}), ), user, reason: 'first login', }); return id; } async getListOfUsers() { const dbUsers = await this.userRepo.find(); return dbUsers.map(dbUserToUser); } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/base-action-validation.ts ================================================ import {PipeTransform, Injectable, ArgumentMetadata} from '@nestjs/common'; const isValidAction = (maybeAction: any) => { if ( typeof maybeAction.type !== 'string' && typeof maybeAction.id !== 'string' ) { throw new Error('Invalid action ' + JSON.stringify(maybeAction)); } }; @Injectable() export class BaseActionValidation implements PipeTransform { transform(action: any, metadata: ArgumentMetadata) { if (metadata.type === 'query' && metadata.data === 'sessionId') { return action; } if (Array.isArray(action)) { action.forEach(isValidAction); } else { isValidAction(action); } return action; } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/event-sourcing.module.ts ================================================ import {Module} from '@nestjs/common'; import {TypeOrmModule} from '@nestjs/typeorm'; import { DbFileTreeNode, DbFolder, DbNote, DbNotebook, FileTreeRepository, NoteRepository, DbFavorites, DbUser, DbDeletedNotebook, DeletedNotebookRepository, } from '../../entities'; import {QuixEventBus} from './quix-event-bus'; import {DbActionStore} from './infrastructure/action-store'; import {DbAction} from './infrastructure/action-store/entities/db-action.entity'; import {NotePlugin} from './plugins/note-plugin'; import {NotebookPlugin} from './plugins/notebook-plugin'; import {DeletedNotebookPlugin} from './plugins/deleted-notebook-plugin'; import {FileTreePlugin} from './plugins/file-tree-plugin'; import {FavoritesPlugin} from './plugins/favorites-plugin'; import {UserPlugin} from './plugins/user-plugin'; import {NotebookRepository} from '../../entities/notebook/notebook.repository'; import {EventsService} from './events.service'; import {EventsPlugin} from './plugins/events-plugin'; import {TrashBinPlugin} from './plugins/trash-bin-plugin'; @Module({ imports: [ TypeOrmModule.forFeature([ DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbDeletedNotebook, DbAction, FileTreeRepository, NoteRepository, DbFavorites, NotebookRepository, DbUser, DeletedNotebookRepository, ]), ], controllers: [], providers: [ QuixEventBus, DbActionStore, NotePlugin, NotebookPlugin, DeletedNotebookPlugin, TrashBinPlugin, FileTreePlugin, FavoritesPlugin, UserPlugin, EventsPlugin, EventsService, ], exports: [QuixEventBus, DbActionStore, EventsService], }) export class EventSourcingModule {} ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/events.service.ts ================================================ import {Injectable} from '@nestjs/common'; import {IAction} from './infrastructure/types'; import {Observable, Subscriber} from 'rxjs'; @Injectable() export class EventsService { userIdToSessionIds: {[userId: string]: string[]} = {}; subscribers: {[sessionId: string]: Subscriber} = {}; logEvent(action: IAction) { this.sendMessage(action); } getEventStream(sessionId: string, userId: string): Observable { return new Observable(subscriber => { this.subscribers[sessionId] = subscriber; this.associateSessionIdWithUserId(sessionId, userId); }); } closeEventStream(sessionId: string, userId: string) { const subscriber = this.subscribers[sessionId]; if (subscriber) { subscriber.complete(); delete this.subscribers[sessionId]; } if (this.userIdToSessionIds[userId]) { const subscribers = this.userIdToSessionIds[userId].filter( s => s !== sessionId, ); if (subscribers.length) { this.userIdToSessionIds[userId] = subscribers; } else { delete this.userIdToSessionIds[userId]; } } } associateSessionIdWithUserId(sessionId: string, userId: string) { if (!this.userIdToSessionIds[userId]) { this.userIdToSessionIds[userId] = []; } this.userIdToSessionIds[userId].push(sessionId); } sendMessage(data: IAction) { const {userId, sessionId: sessionIdToExclude} = data; if (userId && this.userIdToSessionIds[userId]) { this.userIdToSessionIds[userId] .filter(sessionId => sessionId !== sessionIdToExclude) .forEach(sessionId => { this.subscribers[sessionId].next(data); }); } } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/action-store.spec.ts ================================================ import {Test, TestingModule} from '@nestjs/testing'; import {getRepositoryToken, TypeOrmModule} from '@nestjs/typeorm'; import 'reflect-metadata'; import {Repository} from 'typeorm'; import * as uuid from 'uuid'; import {ConfigService, ConfigModule} from '../../../../config'; import {DbActionStore} from './action-store'; import {DbAction} from './entities/db-action.entity'; import {IActionStore} from './types'; describe('action store', () => { let actionStore: IActionStore; let module: TestingModule; beforeEach(async () => { module = await Test.createTestingModule({ imports: [ ConfigModule.create(), TypeOrmModule.forRootAsync({ imports: [], useFactory: async (configService: ConfigService) => configService.getDbConnection([DbAction]), inject: [ConfigService], }), TypeOrmModule.forFeature([DbAction]), ], providers: [DbActionStore], exports: [DbActionStore], }).compile(); actionStore = module.get(DbActionStore); await module .get>(getRepositoryToken(DbAction)) .clear(); }); afterEach(() => { module.close(); }); it('should store and retrieve the action correctly', async () => { const id = uuid.v4(); const base = { id, user: 'foo@wix.com', type: 'bla.bla', isDeleted: false, }; await actionStore.pushAction(base); const fromDb = await actionStore.get(id); expect(fromDb).toHaveLength(1); const {dateCreated, ...rest} = fromDb[0]; expect(rest).toEqual(base); }); }); ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/action-store.ts ================================================ import {Repository, In} from 'typeorm'; import {IAction} from '../types'; import {DbAction} from './entities/db-action.entity'; import {IActionStore, IDBAction} from './types'; import {InjectRepository} from '@nestjs/typeorm'; import {Injectable} from '@nestjs/common'; const convertDbActionToAction = (input: IDBAction): IAction => { const {data, ...rest} = input; return {...rest, ...data}; }; const convertActionToDbAction = (input: IAction): IDBAction => { const {id, dateCreated, type, user, ...rest} = input; return { data: rest, id, type, user, dateCreated: input.dateCreated || new Date(), }; // TODO: fix me, happens because of typeorm change // Prefer to use db default value time rather than setting it in app }; @Injectable() export class DbActionStore implements IActionStore { constructor(@InjectRepository(DbAction) private repo: Repository) {} async pushAction(action: IAction | IAction[]) { const actions: IAction[] = Array.isArray(action) ? action : [action]; // not using simple .insert() or .save() to suppress excessive select typeorm does await this.repo .createQueryBuilder() .insert() .values(actions.map(convertActionToDbAction)) .updateEntity(false) .execute(); // await this.repo.insert(actions.map(convertActionToDbAction)); return actions; } // TODO: implement orderBy async get(aggId?: string | string[], orderBy?: string) { const ids = !!aggId ? (Array.isArray(aggId) ? aggId : [aggId]) : undefined; const results = await (!ids ? this.repo.find() : this.repo.find({id: In(ids)})); return results.map(convertDbActionToAction); } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/entities/db-action.entity.ts ================================================ import {Column, Entity, Index} from 'typeorm'; import {IAction, IEventData} from '../../types'; import {IDBAction} from '../types'; import {dbConf} from '../../../../../config/db-conf'; @Entity({name: 'actions'}) @Index(['id', 'type'], {unique: false}) export class DbAction implements IDBAction { @Column({...dbConf.idColumn, primary: true, unique: false}) id!: string; @Column(dbConf.json) // @ts-ignore data!: T; @Column(dbConf.shortTextField) user!: string; @Index() @Column({...dbConf.eventsTimestamp, primary: true, name: 'date_created'}) dateCreated?: Date; @Column({type: 'varchar', width: 64}) type!: N; constructor(base?: IAction) { if (base) { const {id, dateCreated, user, type, ...data} = base; this.dateCreated = dateCreated; this.user = user; this.type = type; this.data = data as any; this.id = id; } } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/index.ts ================================================ export {IActionStore} from './types'; import {DbActionStore} from './action-store'; import {DbAction} from './entities/db-action.entity'; export {DbActionStore}; ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/types.ts ================================================ import {IAction, IEventData} from '../types'; export abstract class IActionStore { abstract pushAction(action: IAction | IAction[]): Promise; abstract get(aggId?: string | string[], orderBy?: string): Promise; } export interface IDBAction { id: string; user: string; dateCreated?: Date; type: N; data: T; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/api.ts ================================================ import { HookFn, IPluginApi as IMiddlewareApi, HookApi, PluginDescriptor, EventFilter, PluginOptions, } from './types'; import {ContextFactory} from './context'; import {Dictionary} from '../../../../types'; import {IAction} from '../types'; export class RegisterApi { constructor(private descriptor: PluginDescriptor) {} hooks = { listen: ( name: string, fn: HookFn, ): RegisterApi => { this.descriptor.hooks.set(name, {name, fn}); return this; }, }; setPluginOptions(options: PluginOptions) { Object.assign(this.descriptor.options, options); return this; } setEventFilter(fn: EventFilter) { this.descriptor.eventFilter = fn; } } export class MiddlewareApi implements IMiddlewareApi { private contextFactory: ContextFactory; private loggedActions: IAction[] = []; constructor( private plugins: PluginDescriptor[], baseContext: Dictionary, ) { this.contextFactory = new ContextFactory(baseContext); } getLoggedActions() { return [...this.loggedActions]; } pushLoggedActions(actions: IAction[]) { this.loggedActions.push(...actions); } hooks = { call: ( name: string, action: A, extraContext?: Dictionary, ) => { const promises = this.plugins .filter(plugin => plugin.eventFilter(action.type)) .map(plugin => { const hook = plugin.hooks.get(name); if (hook) { const hookApi: HookApi = { context: this.contextFactory.setExtra(extraContext).create(), }; try { return Promise.resolve(hook.fn(action, hookApi)); } catch (e) { return Promise.reject(e); } } return Promise.resolve(action); }); return Promise.all(promises); }, }; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/context.ts ================================================ export class ContextFactory { private extra: object = {}; constructor(private base: object = {}) {} setExtra(extra?: object) { if (extra) { this.extra = extra; } return this; } create() { return new Context(this.base, this.extra); } } export class Context { constructor(private base: object, private extra: object) {} set(data: object) { return Object.assign(this.base, data); } get(): any { return {...this.extra, ...this.base}; } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus-builder.ts ================================================ import {RegisterApi} from './api'; import { EventBusMiddleware, EventBusMiddlewareDescriptor, PluginDescriptor, EventBusPluginFn, defaultPluginDescriptor, EventBusPlugin, } from './types'; import {EventBus} from './event-bus'; import {Dictionary} from '../../../../types'; interface AddPluginOptions { priority?: number; } const isPlugin = (obj: any): obj is EventBusPlugin => typeof obj.name === 'string' && typeof obj.registerFn === 'function'; export const EventBusBuilder = () => new EventBusBuilderT(); class EventBusBuilderT { private middlewares: EventBusMiddlewareDescriptor[] = []; private plugins: PluginDescriptor[] = []; addPlugin( plugins: Dictionary | EventBusPlugin, ): EventBusBuilderT; addPlugin(name: string, registerCB: EventBusPluginFn): EventBusBuilderT; addPlugin( arg1: string | Dictionary | EventBusPlugin, registerCB?: EventBusPluginFn, ) { let plugins: Dictionary = {}; if (typeof arg1 === 'string') { plugins = registerCB ? {[arg1]: {name: arg1, registerFn: registerCB}} : {}; } else { if (isPlugin(arg1)) { plugins = {[arg1.name]: arg1}; } else { /* dictionary of plugins */ plugins = arg1; } } Object.entries(plugins).forEach(([_, plugin]) => { const pluginDescriptor = defaultPluginDescriptor(plugin.name); const api = new RegisterApi(pluginDescriptor); plugin.registerFn(api); this.plugins.push(pluginDescriptor); }); return this; } addMiddleware( middleware: EventBusMiddleware, options: AddPluginOptions = {}, ) { let {priority} = options; priority = this.computeMiddlewarePriority(priority); this.middlewares.push({fn: middleware, priority}); return this; } private computeMiddlewarePriority(priority?: number) { priority = typeof priority === 'number' ? priority : (Object.keys(this.middlewares).length > 0 ? Math.max.apply( null, this.middlewares.map(m => m.priority), ) : 0) + 1; return priority; } build(options: {timeout: number} = {timeout: 30000}) { return new EventBus(this.middlewares, this.plugins, options.timeout); } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus.drawio ================================================ ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus.spec.ts ================================================ import {EventBusBuilder} from './event-bus-builder'; import { EventBusPluginFn, EventBusMiddleware as Middleware, HookFn, } from './types'; import {Dictionary} from '../../../../types'; import {Context} from './context'; describe('event bus', () => { describe('basic functionality', () => { it('should call handler on emit', async () => { const spy = jest.fn(); const bus = EventBusBuilder().build(); bus.on('foo.create', spy); await bus.emit({type: 'foo.create', id: '1', user: 'foo'}); expect(spy.mock.calls).toHaveLength(1); }); }); const expectedMiddlewareArgs = (action: any) => [ {type: 'foo.create', id: '1'}, expect.objectContaining({hooks: {call: expect.any(Function)}}), expect.any(Function), ]; describe('middlewares', () => { it('should call a middleware', async () => { const spy = jest.fn((action, api, next) => next(action)); const bus = EventBusBuilder().addMiddleware(spy).build(); await bus.emit({type: 'foo.create', id: '1', user: 'foo'}); expect(spy.mock.calls).toHaveLength(1); expect(spy.mock.calls[0]).toMatchObject( expectedMiddlewareArgs({type: 'foo.create', id: '1', user: 'foo'}), ); }); it('should reject on timeout if callback is not called', async () => { const spy = jest.fn(); const bus = EventBusBuilder().addMiddleware(spy).build({timeout: 300}); const rv = bus.emit({type: 'foo.create', id: '1', user: 'foo'}); return rv.catch((e: Error) => { expect(e.message).toEqual('Event Bus: timeout'); }); }); it('should pass exceptions upwards', () => { const bus = EventBusBuilder() .addMiddleware(() => { throw new Error('Some Error msg'); }) .build(); const rv = bus.emit({type: 'foo.create', id: '1', user: 'foo'}); return rv.catch((e: Error) => { expect(e.message).toEqual('Some Error msg'); }); }); it('calling next() should pass the action to the next middleware', async () => { const middleware1 = jest.fn((arg, api, next) => next()); const middleware2 = jest.fn((arg, api, next) => next()); const bus = EventBusBuilder() .addMiddleware(middleware1) .addMiddleware(middleware2) .build(); await bus.emit({type: 'foo.create', id: '1', user: 'foo'}); expect(middleware2.mock.calls).toHaveLength(1); expect(middleware2.mock.calls[0]).toMatchObject( expectedMiddlewareArgs({type: 'foo.create', id: '1'}), ); }); it('calling next(result) should pass `result` of one middleware to the next', async () => { const middleware1 = jest.fn((arg, api, next) => next({...arg, foo: 'bar'}), ); const middleware2 = jest.fn((arg, api, next) => next(arg)); const bus = EventBusBuilder() .addMiddleware(middleware1) .addMiddleware(middleware2) .build(); await bus.emit({type: 'foo.create', id: '1', user: 'foo'}); expect(middleware2.mock.calls).toHaveLength(1); expect(middleware2.mock.calls[0]).toMatchObject( expectedMiddlewareArgs({ type: 'foo.create', id: '1', foo: 'bar', user: 'foo', }), ); }); it('calling next(error) should stop middlewares and return a rejected promise', () => { const bus = EventBusBuilder() .addMiddleware((arg, api, next) => { next(new Error('Some Error msg')); }) .build(); const rv = bus.emit({type: 'foo.create', id: '1', user: 'foo'}); return rv.catch((e: Error) => { expect(e.message).toEqual('Some Error msg'); }); }); it('should call lower priority middlewares first', async () => { const middleware1 = jest.fn((arg, api, next) => next({...arg, foo: 'bar'}), ); const middleware2 = jest.fn((arg, api, next) => next(arg)); const bus = EventBusBuilder() .addMiddleware(middleware2, {priority: 1}) .addMiddleware(middleware1, {priority: 0}) .build(); await bus.emit({type: 'foo.create', id: '1', user: 'foo'}); expect(middleware2.mock.calls).toHaveLength(1); expect(middleware2.mock.calls[0]).toMatchObject( expectedMiddlewareArgs({type: 'foo.create', id: '1', foo: 'bar'}), ); }); }); describe('plugins + hooks', () => { let busBuilder: ReturnType; let mockStorage: any[]; const exampleHooks: Dictionary = { validateHook: (action, hookApi) => { switch (action.type) { case 'doError': throw new Error('some validation failed'); default: return; } }, saveHook: (action, hookApi) => { mockStorage.push(action); }, }; const validateSpy = jest.spyOn(exampleHooks, 'validateHook'); const saveSpy = jest.spyOn(exampleHooks, 'saveHook'); beforeEach(() => { mockStorage = []; const plugin: EventBusPluginFn = api => { api.hooks .listen('validate', exampleHooks.validateHook) .hooks.listen('save', exampleHooks.saveHook); }; const validationMiddleware: Middleware = async (action, api, next) => { api.hooks .call('validate', action) .then(() => next(action)) .catch(e => next(e)); }; busBuilder = EventBusBuilder() .addPlugin('someEntity', plugin) .addMiddleware(validationMiddleware); }); afterEach(() => { validateSpy.mockClear(); saveSpy.mockClear(); }); it('middleware should be able to call plugin hooks', async () => { const action = {type: 'bla', id: '1', user: 'foo'}; const bus = busBuilder.build(); await bus.emit(action); expect(validateSpy.mock.calls).toHaveLength(1); expect(validateSpy.mock.calls[0]).toMatchObject([ action, {context: expect.any(Context)}, ]); }); describe('hook failure/errors', () => { it('on error, emit() should return rejected promise', async () => { const action = {type: 'doError', id: '1', user: 'foo'}; const bus = busBuilder.build(); const error: Error = await bus.emit(action).catch(e => e); expect(error.message).toBe('some validation failed'); }); }); }); }); ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus.ts ================================================ import {EventEmitter} from 'events'; import {defer} from '../../../../utils/deferred-promise'; import { EventBusMiddlewareDescriptor, PluginDescriptor, EventBusNextFn, } from './types'; import {MiddlewareApi} from './api'; import {IAction} from '../types'; /** * @name EventBus * @description * acts as an enhanced event emitter, with the added notion of middlewares, and plugins. * - event will be emitted only if all middlewares pass (== don't throw) the event * - all middlewares are called for all events, in a row. * - every middleware gets the action and can: * ## call the next middleware with next() function * ## can pass a new action to next function * ## can call a "hook" on all registered plugins * * - a plugin is a collection of hooks - different phases that can be called by middlewares * a hook gets a context object, where it can pass data to the next hook. * use case: avoid fetching data twice, if fetch data from DB on Validation, use it later. */ export class EventBus { private middlewares: EventBusMiddlewareDescriptor[]; constructor( middlewaresUnsorted: EventBusMiddlewareDescriptor[], private plugins: PluginDescriptor[], private timeout = 4000, ) { this.middlewares = middlewaresUnsorted.sort( (m1, m2) => m1.priority - m2.priority, ); } private emitter = new EventEmitter(); emit(action: A) { const {promise, reject, resolve} = defer(); const context: any = {}; const loggedEvents: IAction[] = []; const waitForResolution = setTimeout(() => { reject(new Error('Event Bus: timeout')); }, this.timeout); let cachedAction = action; const next = (i: number) => { return (nextAction?: A | Error) => { if (nextAction instanceof Error) { reject(nextAction); clearTimeout(waitForResolution); return; } cachedAction = nextAction ? nextAction : cachedAction; if (i === this.middlewares.length) { resolve(cachedAction); clearTimeout(waitForResolution); return; } setImmediate(() => { const middleware = this.middlewares[i]; try { const api = new MiddlewareApi(this.plugins, context); middleware.fn(cachedAction, api, (...args) => { loggedEvents.push(...api.getLoggedActions()); return next(i + 1)(...(args as any)); }); } catch (e) { reject(e); clearTimeout(waitForResolution); } }); }; }; next(0)(action); return promise.then((finalAction: A) => { this.emitter.emit(finalAction.type, finalAction); return loggedEvents; }); } on(type: string, handler: (...args: any[]) => any) { this.emitter.on(type, handler); } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/index.ts ================================================ export { EventBusNextFn, EventBusPluginFn, EventBusMiddleware, EventBusPlugin, } from './types'; export {EventBus} from './event-bus'; export {EventBusBuilder} from './event-bus-builder'; ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/types.ts ================================================ import {RegisterApi, MiddlewareApi} from './api'; import {Context} from './context'; import {IAction} from '../types'; export type EventBusMiddleware = ( action: A, api: MiddlewareApi, next: EventBusNextFn, ) => any; export type EventBusNextFn = ( action?: A | Error, ) => void; export type EventBusPluginFn = (api: RegisterApi) => void; export interface EventBusPlugin { name: string; registerFn: EventBusPluginFn; } /**** Middleware ****/ export interface EventBusMiddlewareDescriptor { fn: EventBusMiddleware; priority: number; } /**** Plugins ****/ export type EventFilter = (type: string) => boolean; export interface PluginDescriptor { name: string; eventFilter: EventFilter; options: PluginOptions; hooks: Map>; } export const defaultPluginDescriptor = (name: string): PluginDescriptor => ({ name, eventFilter: () => true, options: { isTransaction: true, }, hooks: new Map(), }); export interface PluginOptions { isTransaction: boolean; } export type Plugins = Map; /**** PluginApi ****/ export interface IPluginApi { hooks: { call( name: string, action: A, extraContext?: Record, ): Promise; }; } /**** Hooks ****/ export type HookFn = ( action: A, api: HookApi, ) => PromiseLike | any; interface Hook { name: string; fn: HookFn; } export interface HookApi { context: Context; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/infrastructure/types.ts ================================================ import {BaseAction} from '@wix/quix-shared/entities/common/common-types'; export interface IEventData { [key: string]: any; } export interface HasId { id: string; } interface ServerFields { dateCreated?: Date; user: string; userId?: string; sessionId?: string; } export type IAction = BaseAction & { type: N; ethereal?: boolean; syncClients?: boolean; } & T & ServerFields; ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/deleted-notebook-plugin.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectEntityManager} from '@nestjs/typeorm'; import {DbDeletedNotebook} from '../../../entities'; import { convertDbDeletedNotebook, covertDeletedNotebookToDb, } from '../../../entities/deleted-notebook/dbdeleted-notebook.entity'; import { DeletedNotebookActions, DeletedNotebookActionTypes, deletedNotebookReducer, } from '@wix/quix-shared'; import {EntityManager} from 'typeorm'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {IAction} from '../infrastructure/types'; import {QuixHookNames} from '../types'; import {assertOwner} from './utils'; @Injectable() export class DeletedNotebookPlugin implements EventBusPlugin { name = 'deletedNotebook'; constructor(@InjectEntityManager() private em: EntityManager) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = [ DeletedNotebookActionTypes.createDeletedNotebook, DeletedNotebookActionTypes.deleteDeletedNotebook, ]; api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.VALIDATION, async (action: IAction) => { switch (action.type) { case DeletedNotebookActionTypes.deleteDeletedNotebook: { const deletedNotebook = await this.em.findOneOrFail( DbDeletedNotebook, action.id, ); assertOwner(deletedNotebook, action); break; } } }, ); api.hooks.listen( QuixHookNames.PROJECTION, async (action: IAction) => this.em.transaction(async transactionManager => { await this.projectDeletedNotebook(action, transactionManager); }), ); }; private async projectDeletedNotebook( action: IAction, entityManager: EntityManager, ) { const dbModel = action.type === DeletedNotebookActionTypes.createDeletedNotebook ? undefined : await entityManager.findOne(DbDeletedNotebook, action.id); const model = dbModel ? convertDbDeletedNotebook(dbModel) : undefined; const newModel = deletedNotebookReducer(model, action); if (newModel && model !== newModel) { return entityManager.save(covertDeletedNotebookToDb(newModel), { reload: false, }); } else if ( action.type === DeletedNotebookActionTypes.deleteDeletedNotebook ) { await entityManager.delete(DbDeletedNotebook, {id: action.id}); } } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/events-plugin.ts ================================================ import {Inject, Injectable} from '@nestjs/common'; import {EventsService} from '../events.service'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {IAction} from '../infrastructure/types'; import {QuixHookNames} from '../types'; @Injectable() export class EventsPlugin implements EventBusPlugin { name = 'events'; constructor(@Inject(EventsService) private eventsService: EventsService) {} registerFn: EventBusPluginFn = api => { api.hooks.listen(QuixHookNames.PROJECTION, async (action: IAction) => { if (!action.ethereal && action.syncClients !== false) { this.eventsService.logEvent(action); } }); }; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/favorites-plugin.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectEntityManager} from '@nestjs/typeorm'; import {EntityType} from '../../../common/entity-type.enum'; import {DbFavorites} from '../../../entities'; import { NotebookActions, NotebookActionTypes, } from '@wix/quix-shared/entities/notebook'; import {EntityManager} from 'typeorm'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {QuixHookNames} from '../types'; import {IAction} from '../infrastructure/types'; @Injectable() export class FavoritesPlugin implements EventBusPlugin { name = 'favorites'; constructor(@InjectEntityManager() private em: EntityManager) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = [NotebookActionTypes.toggleIsLiked]; api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.VALIDATION, (action: IAction) => { switch (action.type) { case NotebookActionTypes.toggleIsLiked: } }, ); api.hooks.listen( QuixHookNames.PROJECTION, async (action: IAction) => this.em.transaction(async transactionManager => { await this.projectFavorites(action, transactionManager); }), ); }; private async projectFavorites( action: IAction, tm: EntityManager, ) { switch (action.type) { case NotebookActionTypes.toggleIsLiked: { const favorite = { entityId: action.id, entityType: EntityType.Notebook, owner: (action as any).user, }; if (action.isLiked) { return tm.save(Object.assign(new DbFavorites(), favorite)); } else { return tm.delete(DbFavorites, favorite); } } default: } } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/file-tree-plugin.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {DbFolder, DbFileTreeNode} from '../../../entities'; import {Repository} from 'typeorm'; import { FileActions, FileActionTypes, IFile, } from '@wix/quix-shared/entities/file'; import { NotebookActions, NotebookActionTypes, } from '@wix/quix-shared/entities/notebook'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {QuixHookNames} from '../types'; import {last} from 'lodash'; import {FileType} from '@wix/quix-shared/entities/file'; import {FileTreeRepository} from '../../../entities/filenode/filenode.repository'; import {IAction} from '../infrastructure/types'; import { extractEventNames, assertOwner, lastAndAssertExist, assert, } from './utils'; @Injectable() export class FileTreePlugin implements EventBusPlugin { name = 'fileTree'; constructor( @InjectRepository(DbFolder) private folderRepo: Repository, @InjectRepository(FileTreeRepository) private fileTreeNodeRepo: FileTreeRepository, ) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = extractEventNames( FileActionTypes, NotebookActionTypes, ); api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.VALIDATION, async (action: IAction, hookApi) => { switch (action.type) { case FileActionTypes.createFile: { const {file} = action; assertNodeNotNotebook( file, action, 'Notebooks should be created directly', ); const parentPath = last(file.path); const parent = parentPath ? await this.fileTreeNodeRepo.findOneOrFail({id: parentPath.id}) : undefined; if (parent) { assertOwner( parent, action, `Can't add folder, parent folder owner is a different user`, ); } hookApi.context.set({parent}); break; } case FileActionTypes.deleteFile: { const node = await this.fileTreeNodeRepo.findOneOrFail(action.id); assertOwner(node, action); assertNodeNotNotebook( node, action, 'Notebooks should be deleted directly', ); hookApi.context.set({fileNode: node}); break; } case FileActionTypes.moveFile: { const node = await this.fileTreeNodeRepo.findOneOrFail(action.id); assertOwner(node, action); assertNodeNotNotebook( node, action, 'Notebooks should be moved directly', ); hookApi.context.set({fileNode: node}); break; } default: } }, ); api.hooks.listen( QuixHookNames.PROJECTION, async (action: IAction, hookApi) => { switch (action.type) { case FileActionTypes.createFile: { const {file} = action; const parent: DbFileTreeNode | undefined = hookApi.context.get().parent; const folder = new DbFolder(); Object.assign(folder, { id: file.id, owner: action.user, name: file.name, dateCreated: action.dateCreated, dateUpdated: action.dateCreated, }); const node = new DbFileTreeNode(); Object.assign(node, { id: file.id, owner: action.user, parent, folder, }); // we should use .insert() here, but looks like it doesn't cascade folder row return this.fileTreeNodeRepo.save(node, {reload: false}); } case FileActionTypes.updateName: { const {id} = action; const folder = await this.folderRepo.findOneOrFail(id, { loadRelationIds: true, }); folder.name = action.name; return this.folderRepo.save(folder, {reload: false}); } case NotebookActionTypes.moveNotebook: { const {id, path} = action; const parent = lastAndAssertExist(path, action); const node = new DbFileTreeNode(id, {parentId: parent.id}); return this.fileTreeNodeRepo.save(node, {reload: false}); } case FileActionTypes.moveFile: { const {id, path} = action; const parent = lastAndAssertExist(path, action); const parentNode = await this.fileTreeNodeRepo.findOneOrFail( parent.id, ); const fileNode: DbFileTreeNode = hookApi.context.get().fileNode; return this.fileTreeNodeRepo.moveTree(fileNode, parentNode); } case FileActionTypes.toggleIsLiked: break; case FileActionTypes.deleteFile: { const fileNode: DbFileTreeNode = hookApi.context.get().fileNode; return this.fileTreeNodeRepo.deleteTree(fileNode); } } }, ); }; } function assertNodeNotNotebook( node: DbFileTreeNode | IFile, action: IAction, msg: string, ) { assert(node, action, ({type}) => type !== FileType.notebook, msg); } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/note-plugin.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {DbNote, NoteRepository, DbNotebook} from '../../../entities'; import { convertDbNote, convertNoteToDb, } from '../../../entities/note/dbnote.entity'; import { IBaseNote, NoteActions, NoteActionTypes, noteReducer, } from '@wix/quix-shared/entities/note'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {QuixHookNames} from '../types'; import {IAction} from '../infrastructure/types'; import {extractEventNames, assertOwner} from './utils'; import {NotebookRepository} from '../../../entities/notebook/notebook.repository'; import {isEqual, omit} from 'lodash'; @Injectable() export class NotePlugin implements EventBusPlugin { name = 'note'; constructor( @InjectRepository(NoteRepository) private noteRepository: NoteRepository, @InjectRepository(NotebookRepository) private notebookRepository: NotebookRepository, ) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = extractEventNames(NoteActionTypes); api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.VALIDATION, async (action: IAction) => { let entity: DbNotebook | DbNote | null = null; switch (action.type) { case NoteActionTypes.addNote: entity = await this.notebookRepository.findOneOrFail( action.note.notebookId, ); break; case NoteActionTypes.deleteNote: case NoteActionTypes.move: case NoteActionTypes.updateContent: case NoteActionTypes.updateName: entity = await this.noteRepository.findOneOrFail(action.id); } if (entity) { assertOwner(entity, action); } }, ); api.hooks.listen( QuixHookNames.PROJECTION, async (action: IAction) => { if (action.type === NoteActionTypes.addNote) { const note = await noteReducer(undefined, action); if (note) { return this.noteRepository.insertNewWithRank(convertNoteToDb(note)); } return; } const dbModel = await this.noteRepository.findOneOrFail(action.id); switch (action.type) { case NoteActionTypes.reorderNote: { return this.noteRepository.reorder(dbModel, action.to); } case NoteActionTypes.deleteNote: { return this.noteRepository.deleteOneAndOrderRank(dbModel); } default: { const model = convertDbNote(dbModel); const newModel = noteReducer(model, action); if (newModel && this.modelHasChanged(action, model, newModel)) { return await this.noteRepository.save(convertNoteToDb(newModel), { reload: false, }); } } } }, ); }; modelHasChanged = ( action: IAction, model: IBaseNote, newModel: IBaseNote, ) => { switch (action.type) { case NoteActionTypes.updateContent: { const contentChanged = newModel.content && model.content !== newModel.content; const richContentChanged = newModel.richContent && !isEqual(model.richContent, newModel.richContent); return contentChanged || richContentChanged; } default: { const valuesToOmit = ['dateUpdated', 'content', 'richContent']; const modelToCompare = omit(model, valuesToOmit); const newModelToCompare = omit(newModel, valuesToOmit); return !isEqual(modelToCompare, newModelToCompare); } } }; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/notebook-plugin.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectEntityManager} from '@nestjs/typeorm'; import { DbFavorites, DbFileTreeNode, DbNote, DbNotebook, } from '../../../entities'; import {FileTreeRepository} from '../../../entities/filenode/filenode.repository'; import { convertDbNotebook, covertNotebookToDb, } from '../../../entities/notebook/dbnotebook.entity'; import {last} from 'lodash'; import {FileType} from '@wix/quix-shared/entities/file'; import { NotebookActions, NotebookActionTypes, notebookReducer, } from '@wix/quix-shared/entities/notebook'; import {EntityManager} from 'typeorm'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {IAction} from '../infrastructure/types'; import {QuixHookNames} from '../types'; import {assertOwner} from './utils'; @Injectable() export class NotebookPlugin implements EventBusPlugin { name = 'notebook'; constructor(@InjectEntityManager() private em: EntityManager) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = [ NotebookActionTypes.createNotebook, NotebookActionTypes.deleteNotebook, NotebookActionTypes.deleteNotebookNotes, NotebookActionTypes.updateName, ]; api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.VALIDATION, async (action: IAction) => { switch (action.type) { case NotebookActionTypes.updateName: case NotebookActionTypes.deleteNotebook: case NotebookActionTypes.deleteNotebookNotes: { const notebook = await this.em.findOneOrFail(DbNotebook, action.id); assertOwner(notebook, action); break; } case NotebookActionTypes.createNotebook: } }, ); api.hooks.listen( QuixHookNames.PROJECTION, async (action: IAction) => this.em.transaction(async transactionManager => { await this.projectNotebook(action, transactionManager); await this.projectNote(action, transactionManager); await this.projectFileTree(action, transactionManager); await this.projectFavorites(action, transactionManager); }), ); }; private async projectNotebook( action: IAction, tm: EntityManager, ) { const dbModel = action.type === NotebookActionTypes.createNotebook ? undefined : await tm.findOne(DbNotebook, action.id); const model = dbModel ? convertDbNotebook(dbModel) : undefined; const newModel = notebookReducer(model, action); if (newModel && model !== newModel) { return tm.save(covertNotebookToDb(newModel), {reload: false}); } else if (action.type === NotebookActionTypes.deleteNotebook) { await tm.delete(DbNotebook, {id: action.id}); } } async projectNote( action: IAction, tm: EntityManager, ) { switch (action.type) { case NotebookActionTypes.deleteNotebookNotes: { const {id} = action; await tm.delete(DbNote, {notebookId: id}); } } } private async projectFileTree( action: IAction, tm: EntityManager, ) { switch (action.type) { case NotebookActionTypes.createNotebook: { const {notebook} = action; const parent = last(notebook.path); const node = new DbFileTreeNode(); node.id = notebook.id; node.notebookId = notebook.id; node.owner = action.user; node.type = FileType.notebook; node.parent = parent ? new DbFileTreeNode(parent.id) : undefined; return tm .getCustomRepository(FileTreeRepository) .save(node, {reload: false}); } } } private async projectFavorites( action: IAction, tm: EntityManager, ) { switch (action.type) { case NotebookActionTypes.deleteNotebook: { return tm.delete(DbFavorites, { entityId: action.id, }); } default: } } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/trash-bin-plugin.ts ================================================ import {Inject, Injectable} from '@nestjs/common'; import {InjectEntityManager, InjectRepository} from '@nestjs/typeorm'; import { DeletedNotebookActions, FileActions, FileType, IDeletedNotebook, NoteActions, NotebookActions, TrashBinActionTypes, } from '@wix/quix-shared'; import { DbDeletedNotebook, DbFolder, DbNote, DbNotebook, FileTreeRepository, } from '../../../entities'; import {convertDbNotebook} from '../../../entities/notebook/dbnotebook.entity'; import {EntityManager} from 'typeorm'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {IAction} from '../infrastructure/types'; import {QuixHookNames} from '../types'; import {asUser} from './utils'; @Injectable() export class TrashBinPlugin implements EventBusPlugin { name = 'trashBin'; constructor( @InjectEntityManager() private em: EntityManager, @InjectRepository(FileTreeRepository) private fileTreeNodeRepo: FileTreeRepository, ) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = [ TrashBinActionTypes.moveNotebookToTrashBin, TrashBinActionTypes.moveFolderToTrashBin, TrashBinActionTypes.restoreDeletedNotebook, TrashBinActionTypes.permanentlyDeleteNotebook, ]; api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.REACTION, async (action: IAction) => { switch (action.type) { case TrashBinActionTypes.moveNotebookToTrashBin: return this.addNotebookReactions(action); case TrashBinActionTypes.moveFolderToTrashBin: return this.addFolderReactions(action); case TrashBinActionTypes.restoreDeletedNotebook: return this.restoreNotebookReactions(action); case TrashBinActionTypes.permanentlyDeleteNotebook: return this.permanentlyDeleteReactions(action); } }, ); }; private async restoreNotebookReactions( action: IAction, ) { const deletedNotebook = await this.em.findOneOrFail( DbDeletedNotebook, action.id, ); const folder = await this.em.findOneOrFail(DbFolder, { id: (action as any).folderId, }); const folderNode = await this.fileTreeNodeRepo.findOneOrFail(folder.id); const path = folderNode.mpath.split('.').map(n => ({id: n, name: ''})); const notebook = convertDbNotebook( { ...deletedNotebook, }, path, ); return [ asUser( NotebookActions.createNotebook(notebook.id, notebook), action.user, action.userId, ), asUser( DeletedNotebookActions.deleteDeletedNotebook(notebook.id), action.user, action.userId, ), ]; } private async addNotebookReactions( action: IAction, ) { return this.addNotebook(action.id, action.user, action.userId); } private async addNotebook(notebookId: string, user: string, userId?: string) { const notebook = await this.em.findOneOrFail(DbNotebook, notebookId); const deletedNotebook = { ...convertDbNotebook(notebook), dateDeleted: Date.now(), } as IDeletedNotebook; return [ asUser( DeletedNotebookActions.createDeletedNotebook( notebookId, deletedNotebook, ), user, userId, ), asUser(NotebookActions.deleteNotebook(notebookId), user, userId), ]; } async addFolderReactions( action: IAction, ): Promise { const node = await this.fileTreeNodeRepo.findOneOrFail({id: action.id}); const children = await this.fileTreeNodeRepo.getDeepChildren(node, this.em); const notebooks = children .filter(c => c.type === FileType.notebook) .map(n => this.addNotebook(n.id, action.user, action.userId)); const actions: any[] = []; for await (const a of notebooks) { actions.push(...a); } return [ ...actions, asUser(FileActions.deleteFile(action.id), action.user, action.userId), ]; } private async permanentlyDeleteReactions( action: IAction, ) { let result: any[] = [ asUser( DeletedNotebookActions.deleteDeletedNotebook(action.id), action.user, action.userId, ), asUser( NotebookActions.toggleIsLiked(action.id, false), action.user, action.userId, ), ]; const notes = await this.em.find(DbNote, {notebookId: action.id}); result = [ ...result, ...notes.map(n => asUser(NoteActions.deleteNote(n.id), action.user, action.userId), ), ]; return result; } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/user-plugin.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {DbUser, userToDbUser} from '../../../entities/user/user.entity'; import {UserActions, UserActionTypes} from '@wix/quix-shared/entities/user'; import {Repository} from 'typeorm'; import {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus'; import {IAction} from '../infrastructure/types'; import {QuixHookNames} from '../types'; import {extractEventNames} from './utils'; @Injectable() export class UserPlugin implements EventBusPlugin { name = 'user'; constructor( @InjectRepository(DbUser) private userRepository: Repository, ) {} registerFn: EventBusPluginFn = api => { const handledEvents: string[] = extractEventNames(UserActionTypes); api.setEventFilter(type => handledEvents.includes(type)); api.hooks.listen( QuixHookNames.VALIDATION, async (action: IAction) => { switch (action.type) { case UserActionTypes.createNewUser: case UserActionTypes.updateUser: } }, ); api.hooks.listen( QuixHookNames.PROJECTION, async (action: IAction) => { switch (action.type) { case UserActionTypes.createNewUser: { const dbUser = userToDbUser(action.newUser); return this.userRepository.insert(dbUser); } case UserActionTypes.updateUser: { const {id, avatar, email, name, changeUserCreated} = action; const dbUser = new DbUser({ id, avatar, name, }); if (changeUserCreated) { dbUser.dateCreated = changeUserCreated.valueOf(); } return this.userRepository.save(dbUser, {reload: false}); } } }, ); }; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/plugins/utils.ts ================================================ import {IAction} from '../infrastructure/types'; import {BadAction} from '../../../errors'; import {last} from 'lodash'; /** * gets enums, and extracts only the actual values from them * @param enums Enums or "Fake enums" (Record) */ export const extractEventNames = (...enums: Record[]) => enums .reduce( (result, anEnum) => result.concat(Object.entries(anEnum)), [] as [string, string][], ) .map(([typeSymbol, typeString]) => typeString); export function lastAndAssertExist( arr: T[], action: IAction, error?: string, ): T { const item = last(arr); if (!item) { throw BadAction(action.type, error || 'path property should be an array'); } return item; } export function assertOwner( obj: T, action: IAction, error?: string, ) { if (obj.owner !== action.user) { throw BadAction( action.type, error || 'entity owner is not the user dispatching the action', ); } } export function assert( t: T, action: A, fn: (t: T, action: A) => boolean, error: string, ) { if (!fn(t, action)) { throw BadAction(action.type, error); } } export function asUser(reAction: any, user: string, userId?: string) { return {...reAction, user: user, userId: userId}; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/quix-event-bus.driver.ts ================================================ /* Helper driver for event-bus tests */ /* tslint:disable:no-non-null-assertion */ import {Test, TestingModule} from '@nestjs/testing'; import { getConnectionToken, getRepositoryToken, TypeOrmModule, } from '@nestjs/typeorm'; import {ConfigModule, ConfigService} from '../../config'; import { DbFileTreeNode, DbFolder, DbNote, DbNotebook, FileTreeRepository, DbFavorites, DbUser, DbDeletedNotebook, } from '../../entities'; import {MockDataBuilder} from '../../../test/builder'; import {Connection, Repository} from 'typeorm'; import {EventSourcingModule} from './event-sourcing.module'; import {DbAction} from './infrastructure/action-store/entities/db-action.entity'; import {QuixEventBus} from './quix-event-bus'; import {EntityType} from '../../common/entity-type.enum'; import {EntityClassOrSchema} from '@nestjs/typeorm/dist/interfaces/entity-class-or-schema.type'; export class QuixEventBusDriver { public mockBuilder: MockDataBuilder; constructor( public eventBus: QuixEventBus, public module: TestingModule, public noteRepo: Repository, public notebookRepo: Repository, public deletedNotebookRepo: Repository, public eventsRepo: Repository, public folderRepo: Repository, public fileTreeRepo: Repository, public favoritesRepo: Repository, public userRepo: Repository, private conn: Connection, private configService: ConfigService, private defaultUserId: string, ) { this.mockBuilder = new MockDataBuilder(defaultUserId); } static async create(defaultUserId: string) { const module = await Test.createTestingModule({ imports: [ ConfigModule.create(), TypeOrmModule.forRootAsync({ imports: [], useFactory: async (cs: ConfigService) => cs.getDbConnection([ DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbDeletedNotebook, DbAction, DbFavorites, DbUser, ]), inject: [ConfigService], }), EventSourcingModule, ], providers: [], exports: [], }).compile(); const getRepository = (entity: EntityClassOrSchema) => module.get(getRepositoryToken(entity)); const eventBus: QuixEventBus = module.get(QuixEventBus); const notebookRepo: Repository = getRepository(DbNotebook); const deletedNotebookRepo: Repository = getRepository(DbDeletedNotebook); const noteRepo: Repository = getRepository(DbNote); const eventsRepo: Repository = getRepository(DbAction); const fileTreeRepo: FileTreeRepository = getRepository(FileTreeRepository); const folderRepo: Repository = getRepository(DbFolder); const favoritesRepo: Repository = getRepository(DbFavorites); const userRepo: Repository = getRepository(DbUser); const conn: Connection = module.get(getConnectionToken()); const configService: ConfigService = module.get(ConfigService); return new QuixEventBusDriver( eventBus, module, noteRepo, notebookRepo, deletedNotebookRepo, eventsRepo, folderRepo, fileTreeRepo, favoritesRepo, userRepo, conn, configService, defaultUserId, ); } async clearDb() { const dbType = this.configService.getDbType(); await this.clearEvents(); await this.clearNotes(); await this.clearFolders(); await this.clearNotebooks(); await this.clearDeletedNotebooks(); await this.clearFavorites(); await this.userRepo.clear(); } getNotebook(id: string) { return { and: { expectToBeDefined: async () => { const notebook = await this.notebookRepo.findOneOrFail(id); expect(notebook).toBeDefined(); return notebook; }, expectToBeUndefined: async () => { const notebook = await this.notebookRepo.findOne(id); expect(notebook).not.toBeDefined(); return undefined; }, }, }; } getDeletedNotebook(id: string) { return { and: { expectToBeDefined: async () => { const deletedNotebook = await this.deletedNotebookRepo.findOneOrFail( id, ); expect(deletedNotebook).toBeDefined(); return deletedNotebook; }, expectToBeUndefined: async () => { const deletedNotebook = await this.deletedNotebookRepo.findOne(id); expect(deletedNotebook).not.toBeDefined(); return undefined; }, }, }; } getFavorite(owner: string, entityId: string, entityType: EntityType) { return { and: { expectToBeDefined: async () => { const favorite = await this.favoritesRepo.findOneOrFail({ entityId, entityType, owner, }); expect(favorite).toBeDefined(); return favorite; }, expectToBeUndefined: async () => { const favorite = await this.favoritesRepo.findOne({ entityId, entityType, owner, }); expect(favorite).not.toBeDefined(); return undefined; }, }, }; } async getNotebookWithNotes(id: string) { const notebook = (await this.notebookRepo.findOne(id, { relations: ['notes'], }))!; return notebook; } async getNote(id: string) { return this.noteRepo.findOne(id); } async getNotesForNotebook(notebookId: string) { return this.noteRepo.find({notebookId}); } async getUsers() { return this.userRepo.find(); } async getUserFileTree(user: string) { const q = this.fileTreeRepo .createQueryBuilder('node') .where('node.owner = :user', {user}) .leftJoinAndSelect('node.folder', 'folder') .leftJoinAndSelect('node.notebook', 'notebook'); return q.getMany(); } clearEvents() { return this.eventsRepo.clear(); } async clearNotes() { return this.noteRepo.delete({}); } async clearNotebooks() { return this.notebookRepo.delete({}); } async clearDeletedNotebooks() { return this.deletedNotebookRepo.delete({}); } async clearFavorites() { return this.favoritesRepo.delete({}); } emitAsUser( eventBus: QuixEventBus, actions: any[], user = this.defaultUserId, ) { return eventBus.emit(actions.map(a => Object.assign(a, {user}))); } async clearFolders() { await this.folderRepo.delete({}); await this.fileTreeRepo.delete({}); } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/quix-event-bus.spec.ts ================================================ /* tslint:disable:no-shadowed-variable */ /* tslint:disable:no-non-null-assertion */ import {TestingModule} from '@nestjs/testing'; import 'reflect-metadata'; import {INote, NoteActions, createNote} from '@wix/quix-shared/entities/note'; import {NoteActionT} from '@wix/quix-shared/entities/note/actions'; import {NotebookActions} from '@wix/quix-shared/entities/notebook'; import {FileActions, FileType} from '@wix/quix-shared/entities/file'; import {QuixEventBus} from './quix-event-bus'; import {QuixEventBusDriver} from './quix-event-bus.driver'; import {range, reject, find} from 'lodash'; import {EntityType} from '../../common/entity-type.enum'; import {MockDataBuilder} from 'test/builder'; import {IAction, IEventData} from './infrastructure/types'; import { DeletedNotebookActions, TrashBinActions, UserActions, } from '@wix/quix-shared'; jest.setTimeout(300000); const defaultUser = 'someUser@wix.com'; describe('event sourcing', () => { let driver: QuixEventBusDriver; let eventBus: QuixEventBus; let module: TestingModule; let mockBuilder: MockDataBuilder; beforeAll(async () => { driver = await QuixEventBusDriver.create(defaultUser); ({eventBus, module, mockBuilder} = driver); }); beforeEach(() => driver.clearDb()); afterAll(() => driver.clearDb()); afterAll(() => module.close()); const createNoteAction = (notebookId: string): IAction => mockBuilder.createNoteAction(notebookId); describe('deleted-notebooks::', () => { let notebookId: string; let createDeletedNotebookAction: IAction; beforeEach(() => { [notebookId, createDeletedNotebookAction] = mockBuilder.createDeletedNotebookAction(); }); it('create deleted-notebook', async () => { await driver.emitAsUser(eventBus, [createDeletedNotebookAction]); driver.getDeletedNotebook(notebookId).and.expectToBeDefined(); }); it('delete deleted-notebook', async () => { await driver.emitAsUser(eventBus, [ createDeletedNotebookAction, DeletedNotebookActions.deleteDeletedNotebook(notebookId), ]); await driver.getDeletedNotebook(notebookId).and.expectToBeUndefined(); }); }); describe('trash-bin::', () => { describe('move notebook to Trash Bin', () => { let notebookId: string; let rootFolderId: string; let createRootFolderAction: any; let createNotebookAction: IAction; let addToTrashBinAction: IAction; beforeEach(() => { [rootFolderId, createRootFolderAction] = mockBuilder.createFolderAction( `rootFolder`, [], ); [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([ {id: rootFolderId}, ]); [notebookId, addToTrashBinAction] = mockBuilder.moveNotebookToTrashBinAction(undefined, notebookId); }); it('creates deleted notebook', async () => { await driver.emitAsUser(eventBus, [ createRootFolderAction, createNotebookAction, addToTrashBinAction, ]); await driver.getDeletedNotebook(notebookId).and.expectToBeDefined(); }); it('deletes notebook', async () => { await driver.emitAsUser(eventBus, [ createRootFolderAction, createNotebookAction, addToTrashBinAction, ]); await driver.getNotebook(notebookId).and.expectToBeUndefined(); }); it('keeps notes', async () => { await driver.emitAsUser(eventBus, [ createRootFolderAction, createNotebookAction, createNoteAction(notebookId), createNoteAction(notebookId), ]); let notes = await driver.getNotesForNotebook(notebookId); expect(notes).toHaveLength(2); await driver.emitAsUser(eventBus, [addToTrashBinAction]); notes = await driver.getNotesForNotebook(notebookId); expect(notes).toHaveLength(2); }); it('deletes file tree nodes', async () => { await driver.emitAsUser(eventBus, [ createRootFolderAction, createNotebookAction, ]); expect(await driver.fileTreeRepo.find({notebookId})).toHaveLength(1); await driver.emitAsUser(eventBus, [addToTrashBinAction]); expect(await driver.fileTreeRepo.find({notebookId})).toHaveLength(0); }); }); describe('move folder to Trash Bin', () => { let rootFolderId: string; let createFolderAction: any; let notebooksIds: string[]; let createNotebooksActions: any[]; let subFolders: string[]; let createSubFolderActions: any[]; beforeEach(() => { notebooksIds = []; createNotebooksActions = []; subFolders = []; createSubFolderActions = []; [rootFolderId, createFolderAction] = mockBuilder.createFolderAction( `rootFolder`, [], ); for (let i = 0; i < 3; i++) { [subFolders[i], createSubFolderActions[i]] = mockBuilder.createFolderAction(`subFolder${i}`, [ {id: rootFolderId}, ]); [notebooksIds[i], createNotebooksActions[i]] = mockBuilder.createNotebookAction([{id: subFolders[i]}]); } }); it('moves all child notebooks to Trash Bin', async () => { await driver.emitAsUser(eventBus, [ createFolderAction, ...createSubFolderActions, ...createNotebooksActions, TrashBinActions.moveFolderToTrashBin(rootFolderId), ]); await notebooksIds.forEach(async notebookId => { await driver.getNotebook(notebookId).and.expectToBeUndefined(); }); }); it('deletes all sub folders', async () => { await driver.emitAsUser(eventBus, [ createFolderAction, ...createSubFolderActions, ...createNotebooksActions, TrashBinActions.moveFolderToTrashBin(rootFolderId), ]); subFolders.forEach(async folderId => { const folder = await driver.folderRepo.findOne({id: folderId}); expect(folder).toBeUndefined(); }); }); it('deletes tree', async () => { await driver.emitAsUser(eventBus, [ createFolderAction, ...createSubFolderActions, ...createNotebooksActions, TrashBinActions.moveFolderToTrashBin(rootFolderId), ]); [...subFolders, ...notebooksIds].forEach(async nodeId => { const node = await driver.fileTreeRepo.findOne({id: nodeId}); expect(node).toBeUndefined(); }); }); }); it('restores notebook from Trash Bin', async () => { let rootFolderId: string; let createFolderAction: any; let notebookId: string; let createNotebookAction: any; [rootFolderId, createFolderAction] = mockBuilder.createFolderAction( 'rootFolder', [], ); [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([ {id: rootFolderId}, ]); let addToTrashBinAction: IAction; [notebookId, addToTrashBinAction] = mockBuilder.moveNotebookToTrashBinAction(undefined, notebookId); await driver.emitAsUser(eventBus, [ createFolderAction, createNotebookAction, addToTrashBinAction, ]); let restoreFromTrashBinAction: IAction; [notebookId, restoreFromTrashBinAction] = mockBuilder.restoreNotebookFromTrashBinAction( undefined, rootFolderId, notebookId, ); await driver.emitAsUser(eventBus, [restoreFromTrashBinAction]); await driver.getNotebook(notebookId).and.expectToBeDefined(); await driver.getDeletedNotebook(notebookId).and.expectToBeUndefined(); const tree = await driver.getUserFileTree(defaultUser); const node = tree.find(n => n.notebookId === notebookId); expect(node).toBeDefined(); expect(node?.parentId).toEqual(rootFolderId); }); describe('permanently delete notebook', () => { let notebookId: string; let createNotebookAction: IAction; let permanentlyDeleteTrashBinAction: IAction; let addToTrashBinAction: IAction; beforeEach(() => { [notebookId, createNotebookAction] = mockBuilder.createNotebookAction(); [notebookId, addToTrashBinAction] = mockBuilder.moveNotebookToTrashBinAction(undefined, notebookId); [notebookId, permanentlyDeleteTrashBinAction] = mockBuilder.permanentlyDeleteDeletedNotebookAction( undefined, notebookId, ); }); it('deletes the Deleted Notebook', async () => { await driver.emitAsUser(eventBus, [ createNotebookAction, addToTrashBinAction, permanentlyDeleteTrashBinAction, ]); await driver.getDeletedNotebook(notebookId).and.expectToBeUndefined(); }); it('deletes notes of the notebook', async () => { await driver.emitAsUser(eventBus, []); await eventBus.emit([ createNotebookAction, createNoteAction(notebookId), createNoteAction(notebookId), addToTrashBinAction, permanentlyDeleteTrashBinAction, ]); const notes = await driver.noteRepo.find({notebookId}); expect(notes).toHaveLength(0); }); }); }); describe('notebooks::', () => { let notebookId: string; let createNotebookAction: IAction; beforeEach(() => { [notebookId, createNotebookAction] = mockBuilder.createNotebookAction(); }); it('create notebook', async () => { await driver.emitAsUser(eventBus, [createNotebookAction]); const notebook = await driver .getNotebook(notebookId) .and.expectToBeDefined(); expect(notebook.id).toBe(createNotebookAction.id); }); it('set owner correctly', async () => { await driver.emitAsUser(eventBus, [createNotebookAction]); const notebook = await driver .getNotebook(notebookId) .and.expectToBeDefined(); expect(notebook.owner).toBe(defaultUser); }); it('update name', async () => { const note = createNote(notebookId); const addNoteAction = NoteActions.addNote(note.id, note); await driver.emitAsUser(eventBus, [ createNotebookAction, addNoteAction, NotebookActions.updateName(notebookId, 'newName'), ]); const notebook = await driver .getNotebook(notebookId) .and.expectToBeDefined(); expect(notebook.name).toBe('newName'); }); it('toggle isLiked', async () => { await driver.emitAsUser(eventBus, [ createNotebookAction, NotebookActions.toggleIsLiked(notebookId, true), ]); await driver .getFavorite(defaultUser, notebookId, EntityType.Notebook) .and.expectToBeDefined(); await driver.emitAsUser(eventBus, [ NotebookActions.toggleIsLiked(notebookId, false), ]); await driver .getFavorite(defaultUser, notebookId, EntityType.Notebook) .and.expectToBeUndefined(); }); describe('delete', () => { it('deletes notebook and keep notes', async () => { await driver.emitAsUser(eventBus, [ createNotebookAction, createNoteAction(notebookId), createNoteAction(notebookId), NotebookActions.deleteNotebook(notebookId), ]); await driver.getNotebook(notebookId).and.expectToBeUndefined(); const notes = await driver.getNotesForNotebook(notebookId); expect(notes).toHaveLength(2); }); it('delete notes', async () => { await driver.emitAsUser(eventBus, [ createNotebookAction, createNoteAction(notebookId), createNoteAction(notebookId), NotebookActions.deleteNotebookNotes(notebookId), ]); await driver.getNotebook(notebookId).and.expectToBeDefined(); const notes = await driver.getNotesForNotebook(notebookId); expect(notes).toHaveLength(0); }); it('delete favorite after deleting the notebook', async () => { await driver.emitAsUser(eventBus, [ createNotebookAction, NotebookActions.toggleIsLiked(notebookId, true), ]); await driver .getFavorite(defaultUser, notebookId, EntityType.Notebook) .and.expectToBeDefined(); await driver.emitAsUser(eventBus, [ NotebookActions.deleteNotebook(notebookId), ]); await driver .getFavorite(defaultUser, notebookId, EntityType.Notebook) .and.expectToBeUndefined(); }); it('delete only the favorite of the deleted notebook', async () => { const [id1, createAction1] = mockBuilder.createNotebookAction(); const [id2, createAction2] = mockBuilder.createNotebookAction(); await eventBus.emit([createAction1, createAction2]); await driver.emitAsUser(eventBus, [ NotebookActions.toggleIsLiked(id1, true), NotebookActions.toggleIsLiked(id2, true), ]); await driver.emitAsUser(eventBus, [ NotebookActions.deleteNotebook(id1), ]); await driver .getFavorite(defaultUser, id1, EntityType.Notebook) .and.expectToBeUndefined(); await driver .getFavorite(defaultUser, id2, EntityType.Notebook) .and.expectToBeDefined(); }); }); }); describe('notes::', () => { let notebookId: string; let createNotebookAction: NotebookActions; let addNoteAction: NoteActionT<'note.create'>; let note: INote; beforeEach(() => { [notebookId, createNotebookAction] = mockBuilder.createNotebookAction(); note = createNote(notebookId); addNoteAction = NoteActions.addNote(note.id, note); }); it('create note', async () => { await driver.emitAsUser(eventBus, [createNotebookAction]); await driver.emitAsUser(eventBus, [addNoteAction]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes).toHaveLength(1); }); it('create note, with content', async () => { await driver.emitAsUser(eventBus, [createNotebookAction]); addNoteAction = NoteActions.addNote( note.id, createNote(notebookId, {content: 'bla bla bla'}), ); await driver.emitAsUser(eventBus, [addNoteAction]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes).toHaveLength(1); expect(notebook.notes![0].textContent).toBe('bla bla bla'); }); it('create note with bulk actions', async () => { await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes).toHaveLength(1); const {id, name, notebookId: parent, type} = note; expect(notebook.notes![0]).toMatchObject( expect.objectContaining({ id, name, notebookId: parent, owner: defaultUser, type, }), ); }); it('update name', async () => { await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]); await driver.emitAsUser(eventBus, [ NoteActions.updateName(note.id, 'changedName'), ]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes![0].name).toBe('changedName'); }); it('delete note', async () => { await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]); await driver.emitAsUser(eventBus, [NoteActions.deleteNote(note.id)]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes).toHaveLength(0); }); it('update content', async () => { await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]); await driver.emitAsUser(eventBus, [ NoteActions.updateContent(note.id, 'select foo from bar'), ]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes![0].textContent).toBe('select foo from bar'); }); describe('note update', () => { beforeEach(async () => { await driver.emitAsUser(eventBus, [ createNotebookAction, addNoteAction, ]); }); it.each([ ['content', () => NoteActions.updateContent(note.id, 'content')], [ 'richContent', () => NoteActions.updateContent(note.id, '\n', {rich: 'content'}), ], ['name', () => NoteActions.updateName(note.id, 'name')], ])( 'should not update %s when there are no changes', async (_text, createAction) => { const action = createAction(); await driver.emitAsUser(eventBus, [action]); const firstNote = await driver.getNote(note.id); await new Promise(resolve => setTimeout(resolve, 1000)); await driver.emitAsUser(eventBus, [action]); const secondNote = await driver.getNote(note.id); expect(firstNote?.dateUpdated).toBe(secondNote?.dateUpdated); }, ); it.each([ [ 'content', () => NoteActions.updateContent(note.id, 'content'), () => NoteActions.updateContent(note.id, 'different'), ], [ 'richContent', () => NoteActions.updateContent(note.id, '\n', {rich: 'content'}), () => NoteActions.updateContent(note.id, '\n', {content: 'rich'}), ], [ 'name', () => NoteActions.updateContent(note.id, 'name'), () => NoteActions.updateContent(note.id, 'different'), ], ])( 'should update %s when there are changes', async (_text, createFirstAction, createSecondAction) => { await driver.emitAsUser(eventBus, [createFirstAction()]); const firstNote = await driver.getNote(note.id); await new Promise(resolve => setTimeout(resolve, 1000)); await driver.emitAsUser(eventBus, [createSecondAction()]); const secondNote = await driver.getNote(note.id); expect(secondNote?.dateUpdated).toBeGreaterThan( firstNote!.dateUpdated, ); }, ); }); it('move note between notebook', async () => { await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]); const [secondNotebookId, createNotebookAction2] = mockBuilder.createNotebookAction(); await driver.emitAsUser(eventBus, [createNotebookAction2]); await driver.emitAsUser(eventBus, [ NoteActions.move(note.id, secondNotebookId), ]); const notebook = await driver.getNotebookWithNotes(notebookId); expect(notebook.notes).toHaveLength(0); const secondNotebook = await driver.getNotebookWithNotes( secondNotebookId, ); expect(secondNotebook.notes).toHaveLength(1); }); describe('note rank/order', () => { let notes: INote[]; let createNoteActions: NoteActionT<'note.create'>[]; const howManyNotes = 6; beforeEach(async () => { const [notebookId2, createNotebookAction2] = mockBuilder.createNotebookAction(); const notes2 = range(2).map(() => createNote(notebookId2)); notes = range(howManyNotes).map(() => createNote(notebookId)); createNoteActions = notes.map(n => NoteActions.addNote(n.id, n)); const createNoteActions2 = notes2.map(n => NoteActions.addNote(n.id, n), ); /* creating notes in another notebook, just to make sure reorder is local inside a notebook */ await driver.emitAsUser(eventBus, [createNotebookAction2]); await driver.emitAsUser(eventBus, createNoteActions2); await driver.emitAsUser(eventBus, [createNotebookAction]); await driver.emitAsUser(eventBus, createNoteActions); }); it('should create new notes with correct order', async () => { const notebook = await driver.getNotebookWithNotes(notebookId); const doesRankMatchInsertOrder = notes.every( (note, index) => notebook.notes!.find(n => n.id === note.id)!.rank === index, ); expect(doesRankMatchInsertOrder).toBeTruthy(); }); const deleteCases = [ [0, 'start'], [howManyNotes - 1, 'end'], [3, 'middle'], ] as const; deleteCases.forEach(([noteIndexToDelete, testName]) => { it(`on delete should set order of remaining notes correctly, when removing from ${testName}`, async () => { const noteIdToDelete = notes[noteIndexToDelete].id; const deleteAction = NoteActions.deleteNote(noteIdToDelete); await driver.emitAsUser(eventBus, [deleteAction]); const filteredNotes = reject(notes, {id: noteIdToDelete}); const notebook = await driver.getNotebookWithNotes(notebookId); const doesRankMatchInsertOrder = filteredNotes.every( (note, index) => notebook.notes!.find(n => n.id === note.id)!.rank === index, ); expect(doesRankMatchInsertOrder).toBeTruthy(); }); }); const reorderCases = [ [4, 2, '"from" greater than "to"'], [1, 5, '"to" greater than "from"'], ] as const; reorderCases.forEach(([from, to, testName]) => { it(`reorder notes correctly, when ${testName}`, async () => { const noteIdMove = notes[from].id; const reorderAction = NoteActions.reorderNote(noteIdMove, to); await driver.emitAsUser(eventBus, [reorderAction]); const reorderedNotes = reorderPos(notes, from, to); const notebook = await driver.getNotebookWithNotes(notebookId); const doesRankMatchInsertOrder = reorderedNotes.every( (note, index) => notebook.notes!.find(n => n.id === note.id)!.rank === index, ); expect(doesRankMatchInsertOrder).toBeTruthy(); }); }); }); }); describe('folder tree::', () => { let rootFolderId: string; let createRootFolderAction: any; let notebookId: string; let createNotebookAction: any; beforeEach(() => { [rootFolderId, createRootFolderAction] = mockBuilder.createFolderAction( 'rootFolder', [], ); [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([ {id: rootFolderId}, ]); }); it('a single folder', async () => { await driver.emitAsUser(eventBus, [createRootFolderAction]); const list = await driver.getUserFileTree(defaultUser); expect(list[0].folder!.name).toBe('rootFolder'); }); it('rename folder', async () => { await driver.emitAsUser(eventBus, [createRootFolderAction]); await driver.emitAsUser(eventBus, [ FileActions.updateName(rootFolderId, 'a changedName'), ]); const list = await driver.getUserFileTree(defaultUser); expect(list[0].folder!.name).toBe('a changedName'); }); it('a notebook inside a single folder', async () => { await driver.emitAsUser(eventBus, [ createRootFolderAction, createNotebookAction, ]); const list = await driver.getUserFileTree(defaultUser); const notebookTreeItem = list.find( item => item.id === notebookId && item.parentId === rootFolderId, ); expect(notebookTreeItem).toBeDefined(); }); it('have multiple notebooks inside a single folder', async () => { const [notebookId2, createNotebookAction2] = mockBuilder.createNotebookAction([{id: rootFolderId}]); await driver.emitAsUser(eventBus, [ createRootFolderAction, createNotebookAction, createNotebookAction2, ]); const list = await driver.getUserFileTree(defaultUser); const notebookItems = list.filter( item => item.type === FileType.notebook, ); expect(notebookItems).toHaveLength(2); }); it('notebook move', async () => { const [subFolder1, createSubFolder1] = mockBuilder.createFolderAction( 'subFolder1', [{id: rootFolderId}], ); await driver.emitAsUser(eventBus, [ createRootFolderAction, createSubFolder1, createNotebookAction, ]); await driver.emitAsUser(eventBus, [ NotebookActions.moveNotebook(notebookId, [{id: subFolder1, name: ''}]), ]); const list = await driver.getUserFileTree(defaultUser); const notebook = list.find(item => item.id === notebookId); expect(notebook!.mpath).toBe( `${rootFolderId}.${subFolder1}.${notebookId}`, ); }); it('folder tree move', async () => { const [subFolder1, createSubFolder1] = mockBuilder.createFolderAction( 'subFolder1', [{id: rootFolderId}], ); const [subFolder2, createSubFolder2] = mockBuilder.createFolderAction( 'subFolder2', [{id: subFolder1}], ); const [subFolder3, createSubFolder3] = mockBuilder.createFolderAction( 'subFolder3', [{id: rootFolderId}], ); const [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([{id: subFolder2}]); await driver.emitAsUser(eventBus, [ createRootFolderAction, createSubFolder1, createSubFolder2, createSubFolder3, createNotebookAction, ]); /** * structure: * rootFolder -> * folder1 -> * folder2-> * notebook * folder3 */ await driver.emitAsUser(eventBus, [ FileActions.moveFile(subFolder1, [{id: subFolder3, name: ''}]), ]); /** * structure: * rootFolder -> * folder3 -> * folder1 -> * folder2-> * notebook */ const list = await driver.getUserFileTree(defaultUser); expect(find(list, {id: subFolder1})).toMatchObject({ parentId: subFolder3, }); expect(find(list, {id: notebookId})).toMatchObject({ mpath: [ rootFolderId, subFolder3, subFolder1, subFolder2, notebookId, ].join('.'), }); expect(find(list, {id: subFolder2})).toMatchObject({ mpath: [rootFolderId, subFolder3, subFolder1, subFolder2].join('.'), }); }); it('delete an empty folder', async () => { const [subFolder1, createSubFolder1] = mockBuilder.createFolderAction( 'subFolder1', [{id: rootFolderId}], ); await driver.emitAsUser(eventBus, [ createRootFolderAction, createSubFolder1, ]); const beforeList = await driver.getUserFileTree(defaultUser); expect(beforeList).toHaveLength(2); await driver.emitAsUser(eventBus, [FileActions.deleteFile(subFolder1)]); const afterList = await driver.getUserFileTree(defaultUser); expect(afterList).toMatchObject([ expect.objectContaining({id: rootFolderId}), ]); }); it('delete notebook favorite after deleting the parent folder', async () => { const [subFolderId, createSubFolder] = mockBuilder.createFolderAction( 'subFolder', [{id: rootFolderId}], ); const [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([{id: subFolderId}]); await driver.emitAsUser(eventBus, [ createRootFolderAction, createSubFolder, createNotebookAction, ]); await driver.emitAsUser(eventBus, [ NotebookActions.toggleIsLiked(notebookId, true), ]); await driver.emitAsUser(eventBus, [FileActions.deleteFile(subFolderId)]); await driver .getFavorite(defaultUser, notebookId, EntityType.Notebook) .and.expectToBeUndefined(); }); }); describe('user list::', () => { it('should add user with dateCreated in the past', async () => { const createAction = UserActions.createNewUser('foo', { avatar: '', dateCreated: 1000, dateUpdated: 1000, email: 'foo', id: 'foo', name: '', rootFolder: '', }); await driver.emitAsUser(eventBus, [createAction], 'foo'); const users = await driver.getUsers(); expect(users[0]).toMatchObject({dateCreated: 1000, dateUpdated: 1000}); }); }); describe('error handling::', () => { it('should throw an error on invalid action', async () => { const error = await driver .emitAsUser(eventBus, [{type: 'foo'}]) .catch(e => e); await new Promise(resolve => setTimeout(resolve, 1000)); expect(error instanceof Error).toBe(true); }); }); }); function reorderPos(items: T[], from: number, to: number) { const clone = items.slice(); const [item] = clone.splice(from, 1); clone.splice(to, 0, item); return clone; } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/quix-event-bus.ts ================================================ import { EventBus, EventBusBuilder, EventBusPlugin, } from './infrastructure/event-bus'; import {Injectable, Inject, Logger} from '@nestjs/common'; import {QuixHookNames} from './types'; import {IActionStore, DbActionStore} from './infrastructure/action-store'; import {NotebookPlugin} from './plugins/notebook-plugin'; import {NotePlugin} from './plugins/note-plugin'; import {FileTreePlugin} from './plugins/file-tree-plugin'; import {FavoritesPlugin} from './plugins/favorites-plugin'; import {IAction, IEventData} from './infrastructure/types'; import {UserPlugin} from './plugins/user-plugin'; import {EventsPlugin} from './plugins/events-plugin'; import {DeletedNotebookPlugin} from './plugins/deleted-notebook-plugin'; import {TrashBinPlugin} from './plugins/trash-bin-plugin'; import {EventsService} from './events.service'; @Injectable() export class QuixEventBus { private bus: EventBus; private logger = new Logger(QuixEventBus.name); constructor( @Inject(DbActionStore) private actionStore: IActionStore, @Inject(NotebookPlugin) private notebookPlugin: EventBusPlugin, @Inject(NotePlugin) private notePlugin: EventBusPlugin, @Inject(FileTreePlugin) private fileTreePlugin: EventBusPlugin, @Inject(FavoritesPlugin) private favoritesPlugin: EventBusPlugin, @Inject(UserPlugin) private userPlugin: EventBusPlugin, @Inject(DeletedNotebookPlugin) private deletedNotebookPlugin: EventBusPlugin, @Inject(TrashBinPlugin) private trashBinPlugin: EventBusPlugin, @Inject(EventsPlugin) private eventsPlugin: EventBusPlugin, @Inject(EventsService) private eventsService: EventsService, ) { this.bus = EventBusBuilder() .addPlugin(this.notebookPlugin) .addPlugin(this.deletedNotebookPlugin) .addPlugin(this.trashBinPlugin) .addPlugin(this.notePlugin) .addPlugin(this.fileTreePlugin) .addPlugin(this.favoritesPlugin) .addPlugin(this.userPlugin) .addPlugin(this.eventsPlugin) .addMiddleware(async (action, api, next) => { api.hooks .call(QuixHookNames.VALIDATION, action) .then(() => next()) .catch(e => next(e)); }) .addMiddleware(async (action, api, next) => { if (action.ethereal) { next(); } else { this.actionStore .pushAction(action) .then(() => next()) .catch(e => next(e)); } }) .addMiddleware(async (action, api, next) => { api.hooks .call(QuixHookNames.PROJECTION, action) .then(() => next()) .catch(e => next(e)); }) .addMiddleware(async (action, api, next) => { api.hooks .call(QuixHookNames.REACTION, action) .then(async props => { let [reactions] = props; if (reactions && Array.isArray(reactions) && reactions.length > 0) { reactions = reactions.map(r => ({...r, syncClients: false})); await this.emit(reactions); api.pushLoggedActions(reactions); } next(); }) .catch(e => next(e)); }) .build(); } async emit(action: A | A[]) { this.logger.log(`got action ${JSON.stringify(action)}`); if (Array.isArray(action)) { const result = []; for (const a of action) { result.push(...(await this.bus.emit(a))); } this.logger.log(`got ReActions ${JSON.stringify(result)}`); return result; } return this.bus.emit(action); } on(type: T, handler: (action: A & {type: T}) => any) { this.bus.on(type, handler); return this; } } ================================================ FILE: quix-frontend/service/src/modules/event-sourcing/types.ts ================================================ export enum QuixHookNames { VALIDATION = 'validation', PROJECTION = 'projection', REACTION = 'reaction', } ================================================ FILE: quix-frontend/service/src/modules/logger/logger.module.ts ================================================ import {Module} from '@nestjs/common'; import {Logger} from './logger.service'; @Module({ providers: [Logger], exports: [Logger], }) export class LoggerModule {} ================================================ FILE: quix-frontend/service/src/modules/logger/logger.service.ts ================================================ import {Logger as BaseLogger} from '@nestjs/common'; export class Logger extends BaseLogger {} ================================================ FILE: quix-frontend/service/src/modules/proxy-backend/proxy-backend.module.ts ================================================ import {MiddlewareConsumer, Module, NestModule} from '@nestjs/common'; import httpProxy from 'http-proxy-middleware'; import {ConfigService} from '../../config'; @Module({ imports: [], controllers: [], providers: [], }) export class ProxyDbApiBackend implements NestModule { constructor(private configService: ConfigService) {} configure(consumer: MiddlewareConsumer) { let backendUrl = this.configService.getEnvSettings().QuixBackendInternalUrl; if (['http://', 'https://'].every(s => !backendUrl.startsWith(s))) { backendUrl = 'http://' + backendUrl; } consumer .apply( httpProxy({ target: backendUrl, changeOrigin: true, }), ) .forRoutes('/api/db'); consumer .apply( httpProxy({ target: backendUrl, changeOrigin: true, pathRewrite: { '^/api/history': '/api/history/executions', }, }), ) .forRoutes('/api/history'); } } ================================================ FILE: quix-frontend/service/src/modules/search/index.ts ================================================ export {ISearch} from './types'; ================================================ FILE: quix-frontend/service/src/modules/search/parser.spec.ts ================================================ import {parse} from './parser'; import {SearchQuery, SearchTextType} from '@wix/quix-shared'; describe('search query parser', () => { describe('basic', () => { it('handle basic text search', () => { const input = 'select 1 from foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], }; expect(parse(input)).toEqual(expected); }); it('handle weird characters', () => { const input = 'select $START_TIME from foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '$START_TIME'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], }; expect(parse(input)).toEqual(expected); }); it('handle expression wrapped in quotes', () => { const input = '"select bar from" foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.PHRASE, text: 'select bar from'}, {type: SearchTextType.WORD, text: 'foo'}, ], }; expect(parse(input)).toEqual(expected); }); it('handle multiple spaces', () => { const input = 'select\t1 from\nfoo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], }; expect(parse(input)).toEqual(expected); }); }); describe('with special operators', () => { it('handle user operator', () => { const input = 'user:foo@wix.com select 1 from foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], owner: 'foo@wix.com', }; expect(parse(input)).toEqual(expected); }); it('handle user operator without any string', () => { const input = 'user:foo@wix.com'; const expected: SearchQuery = { fullText: input, content: [], owner: 'foo@wix.com', }; expect(parse(input)).toEqual(expected); }); it('do not handle user operator in the middle of a sentence', () => { const input = 'select bar user:foo@wix.com from foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: 'bar'}, {type: SearchTextType.WORD, text: 'user:foo wix.com'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], }; expect(parse(input)).toEqual(expected); }); it('do not handle user operator in the middle of a sentence', () => { const input = 'select bar from foo user:foo@wix.com'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: 'bar'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], owner: 'foo@wix.com', }; expect(parse(input)).toEqual(expected); }); it('handle name operator', () => { const input = 'name:anewnotebook select 1 from foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], name: 'anewnotebook', }; expect(parse(input)).toEqual(expected); }); it('handle name operator with spaces', () => { const input = 'name:"a new notebook" select 1 from foo'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], name: 'a new notebook', }; expect(parse(input)).toEqual(expected); }); it('handle type operator', () => { const input = 'type:python select 1 from foo'; const input2 = 'select 1 from foo type:python'; const expected1: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], type: 'python', }; const expected2: SearchQuery = {...expected1, fullText: input2}; expect(parse(input)).toEqual(expected1); expect(parse(input2)).toEqual(expected2); }); it('multiple operators', () => { const input = 'type:python name:"a new notebook" select 1 from foo user:foo@wix.com'; const expected: SearchQuery = { fullText: input, content: [ {type: SearchTextType.WORD, text: 'select'}, {type: SearchTextType.WORD, text: '1'}, {type: SearchTextType.WORD, text: 'from'}, {type: SearchTextType.WORD, text: 'foo'}, ], type: 'python', name: 'a new notebook', owner: 'foo@wix.com', }; expect(parse(input)).toEqual(expected); }); }); }); ================================================ FILE: quix-frontend/service/src/modules/search/parser.ts ================================================ import { SearchQuery, SearchTypes, SearchTextType, SpecialSearchTypes, } from '@wix/quix-shared'; const createRegExAtBeginningOrEnd = (regex: string | RegExp): RegExp[] => { const source = regex instanceof RegExp ? regex.source : regex; return [new RegExp('^' + source + ' '), new RegExp(source + '$')]; }; const searchRegexMap = { [SearchTypes.user]: createRegExAtBeginningOrEnd(/user:([(\w@\.-_)]*)/), [SearchTypes.type]: createRegExAtBeginningOrEnd(/type:(\w*)/), [SearchTypes.noteName]: [ ...createRegExAtBeginningOrEnd(/name:([\w-_\.]*)/), ...createRegExAtBeginningOrEnd(/name:"([\w-_\. ]*)"/), ], [SearchTypes.content]: [/(?:([^\s"]+)|"(.+)")/g], }; export const parse = (s: string): SearchQuery => { s = s.trim(); const [partialQuery, updatedString] = getSpecialOperators(s); const query: SearchQuery = { ...partialQuery, fullText: s, [SearchTypes.content]: getTextFromSearchQuery(updatedString), }; return query; }; const getSpecialOperators = ( s: string, operators: SpecialSearchTypes[] = [ SearchTypes.noteName, SearchTypes.type, SearchTypes.user, ], ): [Partial, string] => { const query: Partial = {}; operators.some(operator => searchRegexMap[operator].some(regex => { const match = regex.exec(s); if (match && match[1]) { const f = match[1]; query[operator] = match[1]; s = s.replace(match[0], ''); /* do another iteration, to handle other operators */ const [partialQuery, updatedString] = getSpecialOperators( s, operators.filter(name => name !== operator), ); s = updatedString; Object.assign(query, partialQuery); return true; } return false; }), ); return [query, s]; }; const fullTextSearchSpecialChars = /[+\-><\(\)~*\/"@]+/g; const getTextFromSearchQuery = (s: string) => { const result = []; let match = null; /* tslint:disable-next-line */ while ((match = searchRegexMap[SearchTypes.content][0].exec(s))) { result.push( match[1] ? { type: SearchTextType.WORD, text: match[1].replace(fullTextSearchSpecialChars, ' ').trim(), } : { type: SearchTextType.PHRASE, text: match[2].replace(fullTextSearchSpecialChars, ' ').trim(), }, ); } return result; }; export const isValidQuery = (query: SearchQuery) => query[SearchTypes.content].length > 0 || query[SearchTypes.noteName] || query[SearchTypes.type] || query[SearchTypes.user]; ================================================ FILE: quix-frontend/service/src/modules/search/search.module.ts ================================================ import {Module} from '@nestjs/common'; import {TypeOrmModule} from '@nestjs/typeorm'; import {DbFileTreeNode, DbFolder, DbNote, DbNotebook} from '../../entities'; import {ConfigModule} from '../../config/config.module'; import {SearchService} from './search'; @Module({ imports: [ TypeOrmModule.forFeature([DbFileTreeNode, DbFolder, DbNote, DbNotebook]), ], providers: [SearchService], controllers: [], exports: [SearchService], }) export class SearchModule {} ================================================ FILE: quix-frontend/service/src/modules/search/search.spec.ts ================================================ import {Test, TestingModule} from '@nestjs/testing'; import {getRepositoryToken, TypeOrmModule} from '@nestjs/typeorm'; import 'reflect-metadata'; import {Repository} from 'typeorm'; import uuid from 'uuid/v4'; import {ConfigService, ConfigModule} from '../../config'; import {DbFileTreeNode, DbFolder, DbNote, DbNotebook} from '../../entities'; import {SearchModule} from './search.module'; import {SearchService} from './search'; import {Chance} from 'chance'; import {range} from 'lodash'; import {INote} from '@wix/quix-shared'; const chance = new Chance(); describe('Search', () => { jest.setTimeout(60000); let module: TestingModule; let searchService: SearchService; let noteRepo: Repository; let notebookRepo: Repository; const defaultUser = 'foo@wix.com'; const secondUser = 'bar@wix.com'; beforeAll(async () => { module = await Test.createTestingModule({ imports: [ ConfigModule.create(), TypeOrmModule.forRootAsync({ imports: [], useFactory: async (configService: ConfigService) => configService.getDbConnection([ DbFileTreeNode, DbFolder, DbNote, DbNotebook, ]), inject: [ConfigService], }), SearchModule, ], providers: [], exports: [], }).compile(); searchService = module.get(SearchService); noteRepo = module.get(getRepositoryToken(DbNote)); notebookRepo = module.get(getRepositoryToken(DbNotebook)); }); beforeEach(async () => { await noteRepo.delete({}); await notebookRepo.delete({}); }); const createNotebook = async (user = defaultUser) => { const notebook = new DbNotebook({ id: uuid(), owner: user, name: 'new name', } as any); return notebookRepo.save(notebook); }; const createNote = async ( notebookId: string, template: Partial = {}, ) => { const base = Object.assign( { id: uuid(), name: 'New Note', owner: defaultUser, textContent: '', type: 'presto', }, template, ); const note = new DbNote({ id: base.id, owner: base.owner, type: base.type, textContent: base.textContent, name: base.name, dateCreated: 1, dateUpdated: 1, notebookId, jsonContent: undefined, richContent: {}, }); note.rank = 0; return noteRepo.save(note); }; const createRandomNotes = async (baseString = '', count = 5) => { const {id: notebookId} = await createNotebook(); const notes = []; // Due to usage of old TypeORM version, we can't use bulk insert. It can be changed since 0.2.45 for (let i = 0; i < count; i++) { const note = await createNote(notebookId, { textContent: baseString + chance.paragraph(), }); notes.push(note); } return notes; }; it('should return empty array for empty content', async () => { const [result] = await searchService.search(''); expect(result).toHaveLength(0); }); it('should get note by owner', async () => { const notebook = await createNotebook(); const note = await createNote(notebook.id); const [result] = await searchService.search(`user:${defaultUser}`); const [badResult] = await searchService.search('user: foo@wix.com'); expect(result[0].id).toBe(note.id); expect(badResult).toHaveLength(0); }); it('should get note by content', async () => { const notebook = await createNotebook(); const note = await createNote(notebook.id, { textContent: 'select someColumn from someCatalog.someTable', }); const note2 = await createNote(notebook.id, { textContent: 'select someColumn from someCatalog.someOtherTable', }); const [result] = await searchService.search(`someTable`); const [result2] = await searchService.search(`someOtherTable`); const [badResult] = await searchService.search('randomKeyword'); expect(result[0].id).toBe(note.id); expect(result2[0].id).toBe(note2.id); expect(badResult).toHaveLength(0); }); it('should actually return a proper note', async () => { const notebook = await createNotebook(); const note = await createNote(notebook.id, { textContent: 'select someColumn from someCatalog.someTable', }); const [result] = await searchService.search(`someTable`); expect(result).toHaveLength(1); expect(result[0]).toMatchObject({ content: note.textContent, id: note.id, } as Partial); }); it('should get note by content, partial keywords', async () => { const notebook = await createNotebook(); const note = await createNote(notebook.id, { textContent: 'select someColumn from someCatalog.someTable', }); const note2 = await createNote(notebook.id, { textContent: 'select someColumn from someCatalog.someOtherTable', }); const [notes, length] = await searchService.search(`someCa`); const badResult = await searchService.search('randomKeyword'); const [badNotes, badLength] = badResult; expect(length).toBe(2); expect(badLength).toBe(0); }); it('should get note by type', async () => { const notebook = await createNotebook(); const note = await createNote(notebook.id, { type: 'python' as any, }); const note2 = await createNote(notebook.id, { type: 'presto', }); const [result] = await searchService.search('type:presto'); expect(result).toMatchObject([expect.objectContaining({id: note2.id})]); }); it('should get note by user and type', async () => { const notebook = await createNotebook(defaultUser); const notebook2 = await createNotebook(secondUser); const note = await createNote(notebook.id, { owner: defaultUser, }); const note2 = await createNote(notebook2.id, { owner: secondUser, type: 'presto', }); const note3 = await createNote(notebook2.id, { owner: secondUser, type: 'python' as any, }); const [result] = await searchService.search( `user:${secondUser} type:python`, ); expect(result).toMatchObject([expect.objectContaining({id: note3.id})]); }); it('full phrase search', async () => { const notebook = await createNotebook(); const note = await createNote(notebook.id, { textContent: 'select col1, col2, col3 from foo where col1 = 1', }); const note2 = await createNote(notebook.id, { textContent: 'select col1, col2, col3 from foo where col2 = 1', }); const [result] = await searchService.search(`col1 = 1`); const [fullResult] = await searchService.search(`"col1 = 1"`); expect(result).toHaveLength(2); expect(fullResult).toMatchObject([expect.objectContaining({id: note.id})]); }); describe('pagination', () => { it('should return correct number of results', async () => { await createRandomNotes('searchStringFoo', 20); await createRandomNotes('searchStringBar', 10); const [_, count] = await searchService.search('searchStringFoo', 5, 0); expect(count).toBe(20); const [__, count2] = await searchService.search('searchStringBar', 5, 0); expect(count2).toBe(10); }); it('should handle request outside of range', async () => { await createRandomNotes('searchStringFoo', 20); await createRandomNotes('searchStringBar', 10); const [notes, count] = await searchService.search( 'searchStringFoo', 5, 20, ); expect(notes).toHaveLength(0); }); it('should return pages correctly', async () => { let notes = await createRandomNotes('searchStringFoo', 20); await createRandomNotes('searchStringBar', 10); let offset = 0; const count = 5; let pagesFetched = 0; while (notes.length) { const [returnedNotes, totalCount] = await searchService.search( 'searchStringFoo', count, offset, ); pagesFetched++; expect(totalCount).toBe(20); expect(returnedNotes).toHaveLength(count); offset += count; notes = notes.filter( note => !returnedNotes.find(n => n.id === note.id), ); } expect(pagesFetched).toBe(4); }); }); afterAll(() => { module.close(); }); }); ================================================ FILE: quix-frontend/service/src/modules/search/search.ts ================================================ import {dbConf} from '../../config/db-conf'; import {Repository} from 'typeorm'; import {DbNote} from '../../entities'; import {isValidQuery, parse} from './parser'; import {ISearch} from './types'; import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {convertDbNote} from '../../entities/note/dbnote.entity'; import {INote, SearchQuery} from '@wix/quix-shared'; @Injectable() export class SearchService implements ISearch { constructor(@InjectRepository(DbNote) private repo: Repository) {} async search( content: string, total = 50, offset = 0, ): Promise<[INote[], number, SearchQuery]> { if (!content) { return [[], 0, {fullText: content, content: []}]; } const searchQuery = parse(content); if (isValidQuery(searchQuery)) { let q = this.repo.createQueryBuilder('note'); const where: string[] = []; const whereArgs: any = {}; if (searchQuery.owner) { where.push('note.owner = :owner'); whereArgs.owner = searchQuery.owner; } if (searchQuery.type) { where.push('note.type = :type'); whereArgs.type = searchQuery.type; } if (searchQuery.name) { where.push('note.name = :name'); whereArgs.name = searchQuery.name; } if (searchQuery.content.length) { where.push( dbConf.fullTextSearch('note.textContent', searchQuery.content), ); } const whereSql = where.join(' AND '); q = q.take(total).skip(offset).where(whereSql, whereArgs); const [notes, count] = await q.getManyAndCount(); return [notes.map(convertDbNote), count, searchQuery]; } return [[], 0, {fullText: content, content: []}]; } } ================================================ FILE: quix-frontend/service/src/modules/search/types.ts ================================================ import {INote, SearchQuery} from '@wix/quix-shared'; export interface ISearch { search(content: string): Promise<[INote[], number, SearchQuery]>; } ================================================ FILE: quix-frontend/service/src/modules/web-api/autocomplete/autocomplete.controller.ts ================================================ import { Controller, Get, Param, UseGuards, } from '@nestjs/common'; import {AuthGuard} from '../../auth'; import {AutocompleteService} from './autocomplete.service'; @Controller('/api/autocomplete') export class AutocompleteController { constructor(private autocompleteService: AutocompleteService) {} @Get(':type') @UseGuards(AuthGuard) getAutocompletions(@Param('type') type: string) { return this.autocompleteService.getAutocompletions(type); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/autocomplete/autocomplete.service.ts ================================================ import {Injectable} from '@nestjs/common'; import axios from 'axios'; import { isArray } from 'lodash'; import { ConfigService } from '../../../config'; export interface TableAutocompleteItem { value: string; meta: 'table'; } @Injectable() export class AutocompleteService { constructor(private configService: ConfigService) {} async getAutocompletions(type: string) { let backendUrl = this.configService.getEnvSettings().QuixBackendInternalUrl; if (['http://', 'https://'].every(s => !backendUrl.startsWith(s))) { backendUrl = 'http://' + backendUrl; } const dbTree = await axios.get(`${backendUrl}/api/db/${type}/explore`); return this.flattenTables(dbTree.data); } flattenTables( treeNodes: any[], path: string[] = [], tables: TableAutocompleteItem[] = [], ) { if (!isArray(treeNodes)) { return tables; } return treeNodes.reduce((res, {name, type, children}: any) => { if (type === 'table') { res.push({value: [...path, name].join('.'), meta: type}); } else { this.flattenTables(children, [...path, name], res); } return res; }, tables); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/deleted-notebooks/deleted-notebook.controller.ts ================================================ import { Controller, Get, UseGuards, UseInterceptors } from '@nestjs/common'; import { IUser } from '@wix/quix-shared'; import { User } from '../../../modules/auth'; import { AuthGuard } from '../../auth'; import { DemoModeInterceptor } from '../../../common/demo-mode-interceptor'; import { DeletedNotebooksService } from './deleted-notebook.service'; @Controller('/api/deletedNotebooks') @UseInterceptors(DemoModeInterceptor) export class DeletedNotebooksController { constructor(private deletedNotebooksService: DeletedNotebooksService) { } @Get() @UseGuards(AuthGuard) async getUserDeletedNotebooks(@User() user: IUser) { return this.deletedNotebooksService.getDeletedNotebooksForUser(user.email); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/deleted-notebooks/deleted-notebook.service.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {Repository} from 'typeorm'; import {IDeletedNotebook} from '@wix/quix-shared'; import {DbUser, DbDeletedNotebook} from '../../../entities'; import {convertDbDeletedNotebook} from '../../../entities/deleted-notebook/dbdeleted-notebook.entity'; @Injectable() export class DeletedNotebooksService { constructor( @InjectRepository(DbDeletedNotebook) private deletedNotebooksRepo: Repository, ) {} async getDeletedNotebooksForUser(user: string): Promise { const query = this.deletedNotebooksRepo .createQueryBuilder('dn') .leftJoinAndMapOne( 'dn.ownerDetails', DbUser, 'user', 'dn.owner = user.id', ) .where('dn.owner = :user', {user}) .orderBy({'dn.name': 'ASC'}); const res = await query.getMany(); return res.map(dn => convertDbDeletedNotebook(dn)); } async getCountDeletedNotebooksForUser(user: string): Promise { return await this.deletedNotebooksRepo.count({owner: user}); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/events.controller.ts ================================================ import { Body, Controller, HttpCode, Logger, Post, Query, UseGuards, UsePipes, } from '@nestjs/common'; import {AuthGuard} from '../auth'; import {AnyAction} from '@wix/quix-shared/entities/common/common-types'; import {IExternalUser, User} from '../../modules/auth'; import {EventsService} from '../../modules/event-sourcing/events.service'; import { IAction, IEventData, } from '../../modules/event-sourcing/infrastructure/types'; import {BaseActionValidation} from '../event-sourcing/base-action-validation'; import {QuixEventBus} from '../event-sourcing/quix-event-bus'; @Controller('/api/events') export class EventsController { private readonly logger = new Logger(EventsController.name); constructor( private eventBus: QuixEventBus, private eventsService: EventsService, ) {} @Post() @UseGuards(AuthGuard) @UsePipes(BaseActionValidation) @HttpCode(200) async pushEvents( @Body() userAction: AnyAction | AnyAction[], @User() user: IExternalUser, @Query('sessionId') sessionId: string, ) { function withUserInfo(action: AnyAction): IAction { return { ...action, user: user.email, userId: user.id, sessionId, }; } let result: IAction | IAction[] = []; try { result = Array.isArray(userAction) ? await this.eventBus.emit(userAction.map(withUserInfo)) : await this.eventBus.emit(withUserInfo(userAction)); } catch (e: any) { this.logger.error('error emitting event', e); throw e; } return { reactions: Array.isArray(result) ? result : [], }; } } ================================================ FILE: quix-frontend/service/src/modules/web-api/events.gateway.ts ================================================ import { OnGatewayConnection, OnGatewayDisconnect, SubscribeMessage, WebSocketGateway, WebSocketServer, WsResponse, } from '@nestjs/websockets'; import {Observable, EMPTY, from} from 'rxjs'; import {map} from 'rxjs/operators'; import WebSocket, {Server} from 'ws'; import {EventsService} from '../../modules/event-sourcing/events.service'; import {IAction} from '../../modules/event-sourcing/infrastructure/types'; import {AnyAction} from '@wix/quix-shared/entities/common/common-types'; import {cloneDeep} from 'lodash'; import {LoginService} from '../auth/login.service'; import {IncomingMessage} from 'http'; import {parse} from 'cookie'; import {Inject} from '@nestjs/common'; import {AuthOptions, AuthTypes, IExternalUser} from '../auth/types'; import {cons} from 'fp-ts/lib/ReadonlyNonEmptyArray'; interface ExtendedWebSocket extends WebSocket { userId?: string; sessionId?: string; } @WebSocketGateway({path: '/subscription'}) export class EventsGateway implements OnGatewayDisconnect, OnGatewayConnection { @WebSocketServer() server!: Server; constructor( private eventsService: EventsService, private loginService: LoginService, @Inject(AuthOptions) private authOptions: AuthOptions, ) {} handleConnection(client: ExtendedWebSocket, msg: IncomingMessage) { let user: IExternalUser | undefined; if (this.authOptions.type === AuthTypes.CUSTOM) { const token = this.authOptions.auth.getTokenFromRequest(msg); user = this.loginService.verify(token); } else { const cookies = parse(msg.headers.cookie || ''); const token = cookies[this.authOptions.cookieName]; user = this.loginService.verify(token); } if (user) { /* mutating ws client feels weird, but apparently that's the way to go */ /* https://github.com/websockets/ws/issues/859 */ client.userId = user.id; } } handleDisconnect(client: ExtendedWebSocket) { const {userId, sessionId} = client; if (userId && sessionId) { this.eventsService.closeEventStream(sessionId, userId); } } @SubscribeMessage('subscribe') onSubscribe( client: ExtendedWebSocket, data: any, ): Observable> | undefined { const {sessionId} = data; try { const userId = client.userId; if (!userId) { client.terminate(); return; } client.sessionId = sessionId; return this.eventsService.getEventStream(sessionId, userId).pipe( map((action: IAction) => ({ event: 'action', data: this.sanitizeAction(action), })), ); } catch (e) { client.close(); return; } } sanitizeAction(action: IAction): AnyAction { const result = cloneDeep(action); delete (result as any).user; delete result.userId; delete result.sessionId; return result; } } ================================================ FILE: quix-frontend/service/src/modules/web-api/favorites/favorites.controller.ts ================================================ import {Controller, Get, UseGuards, UseInterceptors} from '@nestjs/common'; import {IUser} from '@wix/quix-shared'; import {User} from '../../../modules/auth'; import {FavoritesService} from './favorites.service'; import {AuthGuard} from '../../auth'; import {DemoModeInterceptor} from '../../../common/demo-mode-interceptor'; @Controller('/api/favorites') @UseInterceptors(DemoModeInterceptor) export class FavoritesController { constructor(private favoritesListService: FavoritesService) {} @Get() @UseGuards(AuthGuard) async getUserFavorites(@User() user: IUser) { return this.favoritesListService.getFavoritesForUser(user.email); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/favorites/favorites.service.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {Repository} from 'typeorm'; import {IFile, FileType} from '@wix/quix-shared'; import {DbNotebook, DbFavorites, DbUser} from '../../../entities'; import {extractOwnerDetails} from '../../../entities/utils'; type GetFavoritesQueryReturnValue = DbFavorites & { notebook: DbNotebook; notebookOwnerDetails?: DbUser; }; function favoriteToIFile(fav: GetFavoritesQueryReturnValue): IFile { const {notebook, notebookOwnerDetails} = fav; notebook.ownerDetails = notebookOwnerDetails; const {id, owner, dateCreated, dateUpdated, name} = notebook; const ownerDetails = extractOwnerDetails(notebook); return { isLiked: true, ownerDetails, owner, id, dateCreated, dateUpdated, path: [], name, type: FileType.notebook, }; } @Injectable() export class FavoritesService { constructor( @InjectRepository(DbFavorites) private favoritesRepo: Repository, ) {} async getFavoritesForUser(user: string): Promise { const favoritesQuery = this.favoritesRepo .createQueryBuilder('fav') .innerJoinAndMapOne( 'fav.notebook', DbNotebook, 'notebook', 'fav.entityId = notebook.id', ) .leftJoinAndMapOne( 'fav.notebookOwnerDetails', DbUser, 'user', 'notebook.owner = user.id', ) .where('fav.owner = :user', {user}) .orderBy({'notebook.name': 'ASC'}); const res = (await favoritesQuery.getMany()) as GetFavoritesQueryReturnValue[]; return res.map(favoriteToIFile); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/folders/folders.controller.ts ================================================ import { Controller, Get, Param, HttpException, HttpStatus, UseGuards, UseInterceptors, } from '@nestjs/common'; import {FoldersService} from './folders.service'; import {QuixEventBus} from '../../event-sourcing/quix-event-bus'; import {IExternalUser, User} from '../../../modules/auth'; import {AuthGuard} from '../../auth'; import {DemoModeInterceptor} from '../../../common/demo-mode-interceptor'; @Controller('/api') @UseGuards(AuthGuard) @UseInterceptors(DemoModeInterceptor) export class FoldersController { constructor( private foldersService: FoldersService, private quixEventBus: QuixEventBus, ) {} @Get('files') async getFullTree(@User() user: IExternalUser) { const {email} = user; const list = await this.foldersService.getFilesForUser(email); return list; } @Get('files/:id') async getSpecificFolder(@Param('id') id: string) { const folder = this.foldersService.getFolder(id); if (!folder) { throw new HttpException(`Can't find folder`, HttpStatus.NOT_FOUND); } return folder; } } ================================================ FILE: quix-frontend/service/src/modules/web-api/folders/folders.service.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectEntityManager} from '@nestjs/typeorm'; import {DbFileTreeNode, FileTreeRepository, DbUser} from '../../../entities'; import {fromNullable, getOrElse, map} from 'fp-ts/lib/Option'; import {pipe} from 'fp-ts/lib/pipeable'; import {IFile, IFilePathItem} from '@wix/quix-shared/entities/file'; import {IFolder} from '@wix/quix-shared/entities/folder'; import {EntityManager} from 'typeorm'; import { convertListDbNodeToIFileList, convertSingleNodeToIFile, extractPath, } from './utils'; @Injectable() export class FoldersService { private fileTreeRepo: FileTreeRepository; constructor( @InjectEntityManager() private entityManager: EntityManager, ) { this.fileTreeRepo = this.entityManager.getCustomRepository( FileTreeRepository, ); } /** * @returns {Promise} list of all user folders, in the format client expects. */ async getFilesForUser(user: string): Promise { const query = await this.fileTreeRepo .createQueryBuilder('fileNode') .leftJoinAndSelect('fileNode.notebook', 'notebook') .leftJoinAndSelect('fileNode.folder', 'folder') .leftJoinAndMapOne( 'fileNode.ownerDetails', DbUser, 'user', 'fileNode.owner = user.id', ) .where({owner: user}); const list = await query.getMany(); return convertListDbNodeToIFileList(list); } async getFolder(rootId: string): Promise { const getFileNodeQuery = this.fileTreeRepo .createQueryBuilder('fileNode') .leftJoinAndSelect('fileNode.notebook', 'notebook') .leftJoinAndSelect('fileNode.folder', 'folder') .leftJoinAndMapOne( 'fileNode.ownerDetails', DbUser, 'user', 'fileNode.owner = user.id', ) .where('fileNode.id = :rootId', {rootId}); const [node, children] = await Promise.all([ /* TODO: do this in one query */ getFileNodeQuery.getOne(), this.fileTreeRepo.getChildren(rootId), ] as const); /* remove as const when https://github.com/microsoft/TypeScript/issues/34937 is resolved */ if (node) { const path = await this.computePath(node); const nodeAsFile = convertSingleNodeToIFile(node, path); const files = convertListDbNodeToIFileList(children, [nodeAsFile]); return {...nodeAsFile, files}; } return undefined; } computePath(fileNode?: DbFileTreeNode): Promise { return pipe( fromNullable(fileNode), map(node => node.mpath.split('.').slice(0, -1)), map(async parentsIds => { if (parentsIds.length > 0) { const parents = await this.fileTreeRepo.getNamesByIds(parentsIds); return extractPath(parentsIds, parents); } return []; }), getOrElse(() => Promise.resolve([] as IFilePathItem[])), ); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/folders/utils.ts ================================================ import {FileType, IFile, IFilePathItem} from '@wix/quix-shared/entities/file'; import {DbFileTreeNode} from '../../../entities'; import {extractOwnerDetails} from '../../../entities/utils'; /** * @param list The list dbNodes you want to convert to a IFile * @param initialData if you have a parent node already converted to an IFile, this is where you pass it */ export function convertListDbNodeToIFileList( list: DbFileTreeNode[], initialData: IFile[] = [], ): IFile[] { const itemMap = new Map(list.map(child => [child.id, child])); const resultMap = new Map(initialData.map(file => [file.id, file])); return list.map(item => convertToIFile(item.id, itemMap, resultMap)); } /** * given a mapping of DbFileTreeNode items, and a resultCache - return an IFile */ function convertToIFile( id: string, noteMap: Map, resultMap: Map, ) { const alreadyConverted = resultMap.get(id); if (alreadyConverted) { return alreadyConverted; } const node = noteMap.get(id)!; const {dateCreated, dateUpdated, type, owner} = node; let path: IFilePathItem[]; if (!node.parentId) { path = []; } else { const parentFile = convertToIFile(node.parentId, noteMap, resultMap); path = parentFile.path.concat([{id: parentFile.id, name: parentFile.name}]); } const name = node.type === FileType.folder ? node.folder!.name : node.notebook!.name; const result: IFile = { id: node.type === FileType.folder ? id : node.notebookId!, dateCreated, dateUpdated, type, name, owner, ownerDetails: extractOwnerDetails(node), isLiked: false, path, }; resultMap.set(id, result); return result; } export function extractPath( parentsIds: string[], parents: DbFileTreeNode[], ): IFilePathItem[] { try { return parentsIds.map(id => { const item = parents.find(p => p.id === id)!; const name = computeName(item); return {name, id}; }); } catch (e) { throw new Error('Error in calculation path for notebook'); } } export function dbNodeToFileItem(node: DbFileTreeNode): IFilePathItem { const name = computeName(node); return {id: node.id, name}; } export function computeName(node: DbFileTreeNode): string { const name = node.type === FileType.folder ? node.folder && node.folder.name : node.notebook && node.notebook.name; return name || ''; } export function convertSingleNodeToIFile( node: DbFileTreeNode, path: IFilePathItem[], ) { const {id, dateCreated, dateUpdated, owner, type} = node; const name = computeName(node); const nodeAsFile: IFile = { id, name, path, dateCreated, dateUpdated, owner, ownerDetails: extractOwnerDetails(node), type, isLiked: false, }; return nodeAsFile; } ================================================ FILE: quix-frontend/service/src/modules/web-api/notebooks/notebooks.controller.ts ================================================ import { Controller, Get, Param, HttpException, HttpStatus, UseGuards, UseInterceptors, } from '@nestjs/common'; import {IUser} from '@wix/quix-shared'; import {User} from '../../../modules/auth'; import {NotebookService} from './notebooks.service'; import {AuthGuard} from '../../auth'; import {DemoModeInterceptor} from '../../../common/demo-mode-interceptor'; @Controller('/api/notebook') @UseInterceptors(DemoModeInterceptor) export class NotebookController { constructor(private notebookService: NotebookService) {} @Get(':id') @UseGuards(AuthGuard) async getNotebook(@User() user: IUser, @Param('id') id: string) { const notebook = await this.notebookService.getNotebook(user.email, id); if (!notebook) { throw new HttpException(`Can't find notebook`, HttpStatus.NOT_FOUND); } return notebook; } } ================================================ FILE: quix-frontend/service/src/modules/web-api/notebooks/notebooks.service.ts ================================================ import {Injectable} from '@nestjs/common'; import {InjectRepository} from '@nestjs/typeorm'; import {Repository} from 'typeorm'; import {INotebook} from '@wix/quix-shared'; import {DbNotebook, DbFavorites, DbUser} from '../../../entities'; import {FoldersService} from '../folders/folders.service'; import {EntityType} from '../../../common/entity-type.enum'; import {convertDbNotebook} from '../../../entities/notebook/dbnotebook.entity'; @Injectable() export class NotebookService { constructor( @InjectRepository(DbNotebook) private notebookRepo: Repository, @InjectRepository(DbFavorites) private favoritesRepo: Repository, private folderService: FoldersService, ) {} async getNotebook( user: string, notebookId: string, ): Promise { const notebookQuery = this.notebookRepo .createQueryBuilder('notebook') .leftJoinAndSelect('notebook.fileNode', 'fileNode') .leftJoinAndSelect('notebook.notes', 'note') .leftJoinAndMapOne( 'notebook.ownerDetails', DbUser, 'user', 'notebook.owner = user.id', ) .where('notebook.id = :id', {id: notebookId}) .orderBy({'note.rank': 'ASC'}); const [notebook, favorite] = await Promise.all([ notebookQuery.getOne(), this.favoritesRepo.findOne({ owner: user, entityId: notebookId, }), ]); if (!notebook) { return undefined; } const isLiked = !!favorite; const path = await this.folderService.computePath(notebook.fileNode); return convertDbNotebook(notebook, path, isLiked); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/search.controller.ts ================================================ import { Controller, Get, Param, Query, UseGuards, ParseIntPipe, UseInterceptors, } from '@nestjs/common'; import {SearchResult} from '@wix/quix-shared'; import {AuthGuard} from '../auth'; import {SearchService} from '../../modules/search/search'; import {DemoModeInterceptor} from '../../common/demo-mode-interceptor'; @Controller('/api/search') @UseInterceptors(DemoModeInterceptor) @UseGuards(AuthGuard) export class SearchController { constructor(private searchService: SearchService) {} @Get('/:term') async doSearch( @Param('term') query: string, @Query('offset', new ParseIntPipe()) offset: number, @Query('total', new ParseIntPipe()) count: number, ): Promise { const [notes, totalNotesInSearch, term] = await this.searchService.search( query, count, offset, ); return {notes, count: totalNotesInSearch, term}; } } ================================================ FILE: quix-frontend/service/src/modules/web-api/user-list.controller.ts ================================================ import {Controller, Get, Param, UseGuards} from '@nestjs/common'; import {AuthGuard} from '../auth'; import {UsersService, User, IExternalUser} from '../../modules/auth'; import {ConfigService, EnvSettings} from '../../config'; import {sanitizeUserName, sanitizeUserEmail} from '../../common/user-sanitizer'; @Controller('/api/users') @UseGuards(AuthGuard) export class UserListController { private env: EnvSettings; constructor( private usersService: UsersService, configService: ConfigService, ) { this.env = configService.getEnvSettings(); } @Get() async getUsers(@User() user: IExternalUser) { if (this.env.DemoMode) { return (await this.usersService.getListOfUsers()).map(u => { return u.id === user.email ? u : { name: sanitizeUserName(u.name), id: sanitizeUserEmail(u.id), email: sanitizeUserEmail(u.email), avatar: 'http://quix.wix.com/assets/user.svg', rootFolder: u.rootFolder, dateCreated: u.dateCreated, dateUpdated: u.dateUpdated, }; }); } else { return this.usersService.getListOfUsers(); } } } ================================================ FILE: quix-frontend/service/src/modules/web-api/web-api.driver.ts ================================================ import {Test, TestingModule} from '@nestjs/testing'; import { getConnectionToken, getRepositoryToken, TypeOrmModule, } from '@nestjs/typeorm'; import {FileType} from '@wix/quix-shared'; import {EntityType} from 'src/common/entity-type.enum'; import {ConfigModule, ConfigService} from '../../config/'; import { DbAction, DbDeletedNotebook, DbFavorites, DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbUser, FileTreeRepository, NoteRepository, } from '../../entities'; import {MockDataBuilder} from '../../../test/builder'; import {Connection, Repository} from 'typeorm'; import uuid from 'uuid'; import {AuthModuleConfiguration} from '../auth/auth.module'; import {AuthTypes} from '../auth/types'; import {DeletedNotebooksService} from './deleted-notebooks/deleted-notebook.service'; import {FavoritesService} from './favorites/favorites.service'; import {FoldersService} from './folders/folders.service'; import {NotebookService} from './notebooks/notebooks.service'; import {WebApiModule} from './web-api.module'; import {EntityClassOrSchema} from '@nestjs/typeorm/dist/interfaces/entity-class-or-schema.type'; const defaultEntityDate = new Date('1980-05-21T01:02:03').valueOf(); export class WebApiDriver { mockBuilder: MockDataBuilder; constructor( public userRepo: Repository, public module: TestingModule, public eventsRepo: Repository, public fileTreeRepo: FileTreeRepository, public notebookRepo: Repository, public notebookService: NotebookService, public noteRepo: NoteRepository, public deletedNotebookRepo: Repository, public deletedNotebookService: DeletedNotebooksService, public folderRepo: Repository, public folderService: FoldersService, public favoritesRepo: Repository, public favoritesService: FavoritesService, private configService: ConfigService, private conn: Connection, private defaultUserId: string, ) { this.mockBuilder = new MockDataBuilder(defaultUserId); } static async create(defaultUser: string) { const module = await Test.createTestingModule({ imports: [ AuthModuleConfiguration.create({ type: AuthTypes.FAKE, cookieName: 'foo', }), // consider restructuring web-api module so it won't import auth. feels wrong needing to importing authModule here WebApiModule, ConfigModule.create(), TypeOrmModule.forRootAsync({ imports: [], useFactory: async (cs: ConfigService) => cs.getDbConnection([ DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbDeletedNotebook, DbAction, DbUser, DbFavorites, ]), inject: [ConfigService], }), ], providers: [], exports: [], }).compile(); const getRepository = (entity: EntityClassOrSchema) => module.get(getRepositoryToken(entity)); const notebookRepo = getRepository(DbNotebook); const notebookService = module.get(NotebookService); const deletedNotebookRepo = getRepository(DbDeletedNotebook); const deletedNotebookService = module.get(DeletedNotebooksService); const favoritesService = module.get(FavoritesService); const favoritesRepo = getRepository(DbFavorites); const noteRepo = getRepository(NoteRepository); const folderRepo = getRepository(DbFolder); const folderService = module.get(FoldersService); const eventsRepo = getRepository(DbAction); const fileTreeRepo = getRepository(FileTreeRepository); const userRepo = getRepository(DbUser); const conn = module.get(getConnectionToken()); const configService = module.get(ConfigService); return new WebApiDriver( userRepo, module, eventsRepo, fileTreeRepo, notebookRepo, notebookService, noteRepo, deletedNotebookRepo, deletedNotebookService, folderRepo, folderService, favoritesRepo, favoritesService, configService, conn, defaultUser, ); } async clearDb() { const dbType = this.configService.getDbType(); await this.eventsRepo.delete({}); await this.noteRepo.delete({}); await this.folderRepo.delete({}); await this.notebookRepo.delete({}); await this.deletedNotebookRepo.delete({}); await this.fileTreeRepo.clear(); await this.favoritesRepo.clear(); await this.userRepo.clear(); } createUser(props?: Partial | undefined): DbUser { const defaultUser = { id: this.defaultUserId, name: 'some name', avatar: 'http://test-url.quix', rootFolder: 'someId', dateCreated: defaultEntityDate, dateUpdated: defaultEntityDate, }; return props ? {...defaultUser, ...props} : defaultUser; } createNotebook(notebookName = 'New notebook') { const notebook = new DbNotebook(); notebook.id = uuid(); notebook.owner = this.defaultUserId; notebook.name = notebookName; return notebook; } createDeletedNotebook(notebookName = 'Deleted notebook') { const deletedNotebook = new DbDeletedNotebook(); deletedNotebook.id = uuid(); deletedNotebook.owner = this.defaultUserId; deletedNotebook.name = notebookName; deletedNotebook.dateDeleted = defaultEntityDate; return deletedNotebook; } createNotebookNode(notebookName: string) { const notebook = this.createNotebook(notebookName); const notebookNode = new DbFileTreeNode(); notebookNode.id = uuid(); notebookNode.owner = this.defaultUserId; notebookNode.notebookId = notebook.id; notebookNode.type = FileType.notebook; return [notebookNode, notebook] as const; } createNote(noteName: string, notebookId: string) { const note = new DbNote({ id: uuid(), owner: this.defaultUserId, name: noteName, textContent: '', jsonContent: undefined, type: 'presto', notebookId, dateCreated: 1, dateUpdated: 1, richContent: {}, }); return note; } createFolderNode(folderName: string) { const folderNode = new DbFileTreeNode(); folderNode.id = uuid(); folderNode.owner = this.defaultUserId; folderNode.folder = Object.assign(new DbFolder(), { id: folderNode.id, name: folderName, owner: this.defaultUserId, }); return folderNode; } createFavorite(owner: string, entityId: string, entityType: EntityType) { return Object.assign(new DbFavorites(), { entityId, entityType, owner, }); } } ================================================ FILE: quix-frontend/service/src/modules/web-api/web-api.module.ts ================================================ import {Module} from '@nestjs/common'; import {TypeOrmModule} from '@nestjs/typeorm'; import { DbFileTreeNode, DbFolder, DbNote, DbNotebook, FileTreeRepository, NoteRepository, DbDeletedNotebook, DbUser, DbFavorites, } from '../../entities'; import {DbAction} from '../event-sourcing/infrastructure/action-store/entities/db-action.entity'; import {FoldersController} from './folders/folders.controller'; import {FoldersService} from './folders/folders.service'; import {NotebookController} from './notebooks/notebooks.controller'; import {NotebookService} from './notebooks/notebooks.service'; import {AuthModule} from '../auth/auth.module'; import {EventSourcingModule} from '../event-sourcing/event-sourcing.module'; import {EventsController} from './events.controller'; import {SearchController} from './search.controller'; import {SearchModule} from '../../modules/search/search.module'; import {UserListController} from './user-list.controller'; import {FavoritesService} from './favorites/favorites.service'; import {FavoritesController} from './favorites/favorites.controller'; import {DeletedNotebooksController} from './deleted-notebooks/deleted-notebook.controller'; import {EventsGateway} from './events.gateway'; import {AutocompleteService} from './autocomplete/autocomplete.service'; import {AutocompleteController} from './autocomplete/autocomplete.controller'; import {DeletedNotebooksService} from './deleted-notebooks/deleted-notebook.service'; import {QuixEventBus} from '../event-sourcing/quix-event-bus'; @Module({ imports: [ TypeOrmModule.forFeature([ DbFileTreeNode, DbFolder, DbNote, DbNotebook, DbAction, FileTreeRepository, NoteRepository, DbDeletedNotebook, DbUser, DbFavorites, ]), AuthModule.create(), EventSourcingModule, SearchModule, ], controllers: [ NotebookController, FoldersController, EventsController, SearchController, UserListController, FavoritesController, DeletedNotebooksController, AutocompleteController, ], providers: [ NotebookService, FoldersService, FavoritesService, EventsGateway, AutocompleteService, DeletedNotebooksService, ], exports: [], }) export class WebApiModule {} ================================================ FILE: quix-frontend/service/src/modules/web-api/web-api.spec.ts ================================================ /* tslint:disable:no-non-null-assertion */ import {FileType} from '@wix/quix-shared'; import {range} from 'lodash'; import {EntityType} from '../../common/entity-type.enum'; import {WebApiDriver} from './web-api.driver'; jest.setTimeout(60000); describe('web-api module :: ', () => { let driver: WebApiDriver; const defaultUserId = 'quix-default-user@wix.com'; beforeAll(async () => { driver = await WebApiDriver.create(defaultUserId); }); beforeEach(async () => await driver.clearDb()); afterAll(async () => await driver.module.close()); describe('foldersService :: ', () => { describe('getPathList', () => { it('get a path list with notebooks inside a folder', async () => { const user = driver.createUser(); await driver.userRepo.save(user); const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); const folderNode = driver.createFolderNode('folderName'); await driver.fileTreeRepo.save(folderNode); notebookNode.parent = folderNode; await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); const list = await driver.folderService.getFilesForUser(user.id); expect(list!.find(i => i.id === notebook.id)!).toMatchObject({ id: notebook.id, name: notebookName, path: [{name: 'folderName'}], }); }); it('get a path list, multiple items in root', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); const folderNode = driver.createFolderNode('folderName'); await driver.fileTreeRepo.save(folderNode); await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); const list = await driver.folderService.getFilesForUser(defaultUserId); expect(list).toHaveLength(2); }); it('get a path list, starting from a specific folder', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); const parentFolderNode = driver.createFolderNode('folderName'); const subFolderNode = driver.createFolderNode('folderName2'); const subSubFolderNode = driver.createFolderNode('folderName3'); subFolderNode.parent = parentFolderNode; subSubFolderNode.parent = subFolderNode; await driver.fileTreeRepo.save(parentFolderNode); await driver.fileTreeRepo.save(subFolderNode); await driver.fileTreeRepo.save(subSubFolderNode); await driver.notebookRepo.save(notebook); notebookNode.parent = subSubFolderNode; await driver.fileTreeRepo.save(notebookNode); const folder = await driver.folderService.getFolder(subFolderNode.id); const expected = { id: subFolderNode.id, name: 'folderName2', path: [ { name: 'folderName', id: parentFolderNode.id, }, ], dateCreated: expect.any(Number), dateUpdated: expect.any(Number), ownerDetails: {id: defaultUserId}, owner: defaultUserId, type: FileType.folder, files: [ { id: subSubFolderNode.id, dateCreated: expect.any(Number), dateUpdated: expect.any(Number), type: FileType.folder, name: 'folderName3', ownerDetails: {id: defaultUserId}, owner: defaultUserId, path: [ { name: 'folderName', id: parentFolderNode.id, }, { id: subFolderNode.id, name: 'folderName2', }, ], }, ], }; expect(folder).toMatchObject(expected); }); }); }); describe('notebook service :: ', () => { it('get a notebook, with valid path', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); const folderNode = driver.createFolderNode('folderName'); const folderNode2 = driver.createFolderNode('folderName2'); folderNode2.parent = folderNode; await driver.fileTreeRepo.save(folderNode); await driver.fileTreeRepo.save(folderNode2); notebookNode.parent = folderNode2; await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); const response = await driver.notebookService.getNotebook( defaultUserId, notebook.id, ); expect(response!.id).toBe(notebook.id); expect(response!.path).toEqual([ {name: 'folderName', id: folderNode.id}, {name: 'folderName2', id: folderNode2.id}, ]); }); it('get a notebook, with notes sorted in order', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); const notes = range(5).map(i => driver.createNote(`note${i}`, notebook.id), ); for (const note of notes) { await driver.noteRepo.insertNewWithRank(note); } const from = 3; const to = 1; await driver.noteRepo.reorder(notes[from], to); const response = await driver.notebookService.getNotebook( defaultUserId, notebook.id, ); expect(response!.notes[to].name).toBe(`note${from}`); }); it('get a notebook, with favorite indication', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); const favorite = driver.createFavorite( defaultUserId, notebook.id, EntityType.Notebook, ); await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); await driver.favoritesRepo.save(favorite); const response = await driver.notebookService.getNotebook( defaultUserId, notebook.id, ); expect(response!.id).toBe(notebook.id); expect(response!.isLiked).toBe(true); }); it('get a notebook, with user details', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); await driver.userRepo.save({ id: defaultUserId, name: 'some name', avatar: 'http://url', rootFolder: 'someId', }); await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); const response = await driver.notebookService.getNotebook( defaultUserId, notebook.id, ); expect(response!.id).toBe(notebook.id); expect(response!.ownerDetails).toMatchObject({ id: defaultUserId, name: 'some name', avatar: 'http://url', }); }); it('get a notebook, even when user does not exist', async () => { const notebookName = 'some new notebook'; const [notebookNode, notebook] = driver.createNotebookNode(notebookName); await driver.notebookRepo.save(notebook); await driver.fileTreeRepo.save(notebookNode); const response = await driver.notebookService.getNotebook( defaultUserId, notebook.id, ); expect(response!.id).toBe(notebook.id); expect(response!.ownerDetails).toMatchObject({ id: defaultUserId, name: '', }); }); }); describe('favorites service :: ', () => { it('get favorites per user', async () => { const user = driver.createUser(); await driver.userRepo.save(user); const user2 = driver.createUser({ id: 'secondUser@foo.com', rootFolder: 'someId2', name: '2ndUser', }); await driver.userRepo.save(user2); const notebook = driver.createNotebook(); const favorite = driver.createFavorite( user2.id, notebook.id, EntityType.Notebook, ); await driver.notebookRepo.save(notebook); await driver.favoritesRepo.save(favorite); const response = await driver.favoritesService.getFavoritesForUser( user2.id, ); expect(response).toEqual([ { id: notebook.id, name: notebook.name, type: FileType.notebook, owner: notebook.owner, ownerDetails: expect.objectContaining({ id: user.id, name: user.name, }), isLiked: true, path: [], dateCreated: notebook.dateCreated, dateUpdated: notebook.dateUpdated, }, ]); }); }); describe('deleted-notebooks service :: ', () => { it('gets all deleted notebooks per user', async () => { const user = driver.createUser(); await driver.userRepo.save(user); const deletedNotebook = driver.createDeletedNotebook(defaultUserId); await driver.deletedNotebookRepo.save(deletedNotebook); const response = await driver.deletedNotebookService.getDeletedNotebooksForUser( defaultUserId, ); expect(response).toEqual([ { id: deletedNotebook.id, name: deletedNotebook.name, owner: deletedNotebook.owner, ownerDetails: expect.objectContaining({ id: user.id, name: user.name, }), isLiked: false, path: [], notes: [], dateCreated: deletedNotebook.dateCreated, dateUpdated: deletedNotebook.dateUpdated, dateDeleted: deletedNotebook.dateDeleted, }, ]); }); }); }); ================================================ FILE: quix-frontend/service/src/template-engine/velocity.ts ================================================ import velocity from 'velocity'; function expressEngine() { return function render(template: string, data: any, cb: any) { const vm = new velocity.Engine({ template, }); cb(null, vm.render(data)); }; } export default expressEngine; ================================================ FILE: quix-frontend/service/src/types/3rd-party/uuid.d.ts ================================================ declare module 'uuid/v4' { const fn: () => string; export default fn; } ================================================ FILE: quix-frontend/service/src/types/3rd-party/velocity.d.ts ================================================ declare module 'velocity' { export class Engine { constructor(options: {template: string}); render(data: any): string; } } ================================================ FILE: quix-frontend/service/src/types/index.ts ================================================ export interface Dictionary { [key: string]: T; } ================================================ FILE: quix-frontend/service/src/utils/create-schema-helpers.ts ================================================ import cluster from 'cluster'; import {QUIX_SCHEMA, CURRENT_QUIX_SCHEMA_VERSION} from '../consts'; import {Connection} from 'typeorm'; import {DbMetadata} from '../entities/version-metadata.entity'; import {Logger} from '@nestjs/common'; export async function checkSchemaVersion(conn: Connection, logger: Logger) { const result = await conn .getRepository(DbMetadata) .findOne({name: QUIX_SCHEMA}) .catch(e => { logger.error(e); return undefined; }); if (!result || result.version !== CURRENT_QUIX_SCHEMA_VERSION) { logger.error( `Can't run Quix. DB schema version doesn't match. Please check how to upgrade the schema at https://wix.github.io/quix/docs/installation#upgrading-quix`, ); process.exit(-1); } } export async function createInitialSchemaIfNeeded( conn: Connection, dbName: string, logger: Logger, ) { try { const versionMetadataTableName = conn.getMetadata(DbMetadata).tableName; const [{cnt: doesTableExist}] = await conn.query(`SELECT count(*) as cnt FROM information_schema.TABLES WHERE (TABLE_SCHEMA = '${dbName}') AND (TABLE_NAME = '${versionMetadataTableName}')`); if (doesTableExist === '0') { logger.log( 'Looks like this is your first time running quix, setting up initial schema', ); await conn.runMigrations(); } } catch (e) { logger.error('failed creating initial schema'); logger.error(e); process.exit(-1); } } function isPm2() { return ( 'PM2_HOME' in process.env || 'PM2_JSON_PROCESSING' in process.env || 'PM2_CLI' in process.env ); } export function isMasterProcess() { if (isPm2()) { return process.env.pm_id === '0'; } else { return cluster.isMaster; } } ================================================ FILE: quix-frontend/service/src/utils/deferred-promise.ts ================================================ export function defer() { let resolve: any; let reject: any; const promise = new Promise((resolveFn, rejectFn) => { resolve = resolveFn; reject = rejectFn; }); return { resolve, reject, resolveByPromise(p: Promise) { p.then(v => resolve(v)).catch(e => reject(e)); }, promise, } as { resolve: (value?: T | PromiseLike) => void; reject: (reason: any) => void; promise: Promise; }; } ================================================ FILE: quix-frontend/service/src/utils/retry-promise.ts ================================================ export function retry(what: () => Promise) { return { forNTimes: (n: number) => ({ andWaitXMilliseconds: async (milliseconds: number) => { let counter = 0; let error: Error | null = null; let result: R = {} as any; while (counter < n) { await what() .then(r => { result = r; error = null; }) .catch(e => { error = e; return undefined; }); if (error) { counter++; await new Promise(resolve => setTimeout(resolve, milliseconds)); } else { return result; } } throw error; }, }), }; } ================================================ FILE: quix-frontend/service/test/app.e2e-spec.ts ================================================ /* tslint:disable:no-non-null-assertion */ import 'reflect-metadata'; import {Test, TestingModule} from '@nestjs/testing'; import {AppModule} from './../src/app.module'; import {INestApplication, Logger} from '@nestjs/common'; import {ConfigService, EnvSettings} from '../src/config'; import nock from 'nock'; import {IExternalUser} from '../src/modules/auth/types'; import {E2EDriver} from './driver'; import {E2EMockDataBuilder} from './builder'; import cookieParser = require('cookie-parser'); import {sanitizeUserEmail} from '../src/common/user-sanitizer'; import {getConnectionToken} from '@nestjs/typeorm'; import {Connection} from 'typeorm'; import WebSocket from 'ws'; import './custom-matchers'; import {WsAdapter} from '@nestjs/platform-ws'; import {serialize as serializeCookie} from 'cookie'; import {testingDefaults} from '../src/config/env/static-settings'; let envSettingsOverride: Partial = {}; class E2EConfigService extends ConfigService { getEnvSettings(): EnvSettings { const env = super.getEnvSettings(); return {...env, AutoMigrateDb: false, ...envSettingsOverride}; } } const user1profile: IExternalUser = { email: 'testing@quix.com', id: '111111111', name: 'Testing User', }; const user2profile: IExternalUser = { email: 'secondUser@quix.com', id: '222222222', name: 'second User', avatar: 'http://seconduseravatar.png', }; describe('Application (e2e)', () => { jest.setTimeout(60000); let app: INestApplication; let driver: E2EDriver; let builder: E2EMockDataBuilder; const beforeAndAfter = () => { beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }) .overrideProvider(ConfigService) .useClass(E2EConfigService) .compile(); app = moduleFixture.createNestApplication(); app.use(cookieParser()); app.useWebSocketAdapter(new WsAdapter(app)); await app.init(); const configService: ConfigService = moduleFixture.get(ConfigService); const conn: Connection = moduleFixture.get(getConnectionToken()); if (configService.getDbType() === 'mysql') { await conn.dropDatabase(); await conn.synchronize(); } else { await conn.dropDatabase(); await conn.synchronize(); } driver = new E2EDriver(app); builder = new E2EMockDataBuilder(); }); afterEach(async () => { envSettingsOverride = {}; return app.close(); }); }; beforeEach(() => { nock.cleanAll(); }); describe('backend proxy', () => { const fakeBackendHost = 'backend:8081'; beforeEach(() => { envSettingsOverride.QuixBackendInternalUrl = fakeBackendHost; }); beforeAndAfter(); it('should proxy requests to the backend', async () => { nock(`http://${fakeBackendHost}`) .get('/api/db/explore') .reply(200, ['mocked']); const returned = await driver.get('db/explore'); expect(returned).toEqual(['mocked']); }); }); describe('User list', () => { beforeAndAfter(); beforeEach(() => { driver.addUser('user1', user1profile).addUser('user2', user2profile); }); it('should add a user on first login', async () => { await driver.doLogin('user1'); let users = await driver.as('user1').get('users'); expect(users).toHaveLength(1); await driver.doLogin('user2'); users = await driver.as('user1').get('users'); expect(users).toMatchArrayAnyOrder([ { id: user1profile.email, name: user1profile.name, rootFolder: expect.any(String), dateCreated: expect.any(Number), dateUpdated: expect.any(Number), }, { id: user2profile.email, name: user2profile.name, rootFolder: expect.any(String), dateCreated: expect.any(Number), dateUpdated: expect.any(Number), }, ]); expect(users[0].dateCreated - Date.now()).toBeLessThan(2000); // Within 2 seconds }); it('should update details on login', async () => { await driver.doLogin('user1'); driver.addUser('user1', {...user1profile, name: 'new name'}); await driver.doLogin('user1'); const users = await driver.as('user1').get('users'); expect(users).toMatchArrayAnyOrder([ { id: user1profile.email, name: 'new name', rootFolder: expect.any(String), dateCreated: expect.any(Number), dateUpdated: expect.any(Number), }, ]); }); }); describe('Demo Mode', () => { beforeEach(() => { envSettingsOverride.DemoMode = true; }); beforeAndAfter(); beforeEach(() => { driver.addUser('user1', user1profile).addUser('user2', user2profile); }); const expectObject = (json: object) => ({ toNotLeakUserData(user: IExternalUser) { expect(JSON.stringify(json)).toEqual( expect.not.stringContaining(user2profile.email), ); expect(JSON.stringify(json)).toEqual( expect.not.stringContaining(user2profile.name!), ); expect(JSON.stringify(json)).toEqual( expect.not.stringContaining(user2profile.id!), ); expect(JSON.stringify(json)).toEqual( expect.not.stringContaining(user2profile.avatar!), ); }, }); it('user list should not contain private information', async () => { await driver.doLogin('user1'); let users = await driver.as('user1').get('users'); expect(users).toHaveLength(1); await driver.doLogin('user2'); users = await driver.as('user1').get('users'); expect(users).toMatchArrayAnyOrder( [ { id: expect.stringContaining('**'), name: 'Quix User', rootFolder: expect.any(String), }, { id: user1profile.email, name: user1profile.name, rootFolder: expect.any(String), }, ], 'name', ); expectObject(users).toNotLeakUserData(user2profile); }); it('when fetching other user notebook, user name should be hidden', async () => { await driver.doLogin('user1'); const [{id: rootFolder}] = await driver.as('user1').get('files'); const [notebookId, createAction] = builder.createNotebookAction([ {id: rootFolder}, ]); await driver.as('user1').postEvents(createAction); let notebookFromServer = await driver .as('user1') .get('notebook', notebookId); expect(notebookFromServer.owner).toBe(user1profile.email); notebookFromServer = await driver.as('user2').get('notebook', notebookId); expect(notebookFromServer.owner).toBe( sanitizeUserEmail(user1profile.email), ); expectObject(notebookFromServer).toNotLeakUserData(user1profile); }); it('when searching notebooks, sanitize user', async () => { await driver.doLogin('user1'); const [{id: rootFolder}] = await driver.as('user1').get('files'); const [notebookId, createAction] = builder.createNotebookAction([ {id: rootFolder}, ]); await driver.as('user1').postEvents([ createAction, builder.createNoteAction(notebookId, { content: 'some query goes here', }), ]); let searchResults = await driver .as('user1') .search('"some query goes here"'); expect(searchResults.notes[0].owner).toBe(user1profile.email); searchResults = await driver.as('user2').search('"some query goes here"'); expect(searchResults.notes[0].owner).toBe( sanitizeUserEmail(user1profile.email), ); expectObject(searchResults).toNotLeakUserData(user1profile); }); }); describe('Search', () => { beforeAndAfter(); beforeEach(() => { driver.addUser('user1', user1profile); }); it('when searching notebooks, should receive the search terms back', async () => { await driver.doLogin('user1'); const [{id: rootFolder}] = await driver.as('user1').get('files'); const [notebookId, createAction] = builder.createNotebookAction([ {id: rootFolder}, ]); await driver.as('user1').postEvents([ createAction, builder.createNoteAction(notebookId, { content: 'some query goes here', type: 'presto', }), builder.createNoteAction(notebookId, { content: 'diffrent query goes here', type: 'python', }), ]); let searchResults1 = await driver .as('user1') .search('type:python "query goes here"'); expect(searchResults1.notes).toHaveLength(1); expect(searchResults1.term.type).toBe('python'); expect(searchResults1.term.content[0].text).toBe('query goes here'); expect(searchResults1.term.fullText).toBe('type:python "query goes here"'); }); }); describe('Synchronize sessions', () => { const defaultCookie = testingDefaults.AuthCookieName; beforeAndAfter(); beforeEach(() => { driver.addUser('user1', user1profile).addUser('user2', user2profile); }); describe('websocket', () => { it(`should close connection if token is not passed in subscription`, async () => { await app.listenAsync(3000); const ws1 = new WebSocket('ws://localhost:3000/subscription', { headers: {Cookie: serializeCookie(defaultCookie, 'abc')}, }); await new Promise(resolve => ws1.on('open', resolve)); ws1.send(JSON.stringify({event: 'subscribe', data: {}})); await new Promise(resolve => ws1.on('close', resolve)); }); it(`should send actions only to a single connection`, async () => { await app.listenAsync(3000); await driver.doLogin('user1'); const token = driver.as('user1').getToken(); const {ws: ws1, sessionId: sessionId1} = await driver .as('user1') .wsConnect(); const {ws: ws2, sessionId: sessionId2} = await driver .as('user1') .wsConnect(); const [{id: rootFolder}] = await driver.as('user1').get('files'); const [notebookId, createAction] = builder.createNotebookAction([ {id: rootFolder}, ]); await driver.as('user1').postEvents(createAction, sessionId1); expect(driver.getMessages(ws1)).toHaveLength(0); expect(driver.getMessages(ws2)).toEqual([ { event: 'action', data: createAction, }, ]); }); }); }); }); function resolveIn(n: number = 1000) { return new Promise(resolve => setTimeout(resolve, n)); } ================================================ FILE: quix-frontend/service/test/builder.ts ================================================ import { IFilePathItem, FileActions, FileType, } from '@wix/quix-shared/entities/file'; import * as uuid from 'uuid'; import { INote, createNote, NoteActions, createNotebook, NotebookActions, DeletedNotebookActions, createDeletedNotebook, INotebook, createEmptyIUser, IDeletedNotebook, TrashBinActionTypes, TrashBinActions, } from '@wix/quix-shared'; import {string} from 'fp-ts'; class BaseMockDataBuilder { constructor(protected defaultUser: S) {} createNotebook = createNotebook.bind(this); createNotebookAction( path: Partial[] = [], user = this.defaultUser, ) { const id = uuid.v4(); const action = { ...NotebookActions.createNotebook( id, createNotebook(path as IFilePathItem[], {id}), ), user, }; return [id, action] as const; } createDeletedNotebookAction( path: Partial[] = [], user = this.defaultUser, ) { const id = uuid.v4(); const action = { ...DeletedNotebookActions.createDeletedNotebook( id, createDeletedNotebook(path as IFilePathItem[], {id}), ), user, }; return [id, action] as const; } permanentlyDeleteDeletedNotebookAction( user = this.defaultUser, notebookId?: string, ) { notebookId = notebookId || uuid.v4(); const action = { ...TrashBinActions.permanentlyDeleteNotebook(notebookId), user, }; return [notebookId, action] as const; } moveNotebookToTrashBinAction(user = this.defaultUser, notebookId?: string) { const id = notebookId || uuid.v4(); const action = { ...TrashBinActions.moveNotebookToTrashBin(id), user, ethereal: true, }; return [id, action] as const; } restoreNotebookFromTrashBinAction( user = this.defaultUser, restoreFolderId: string, notebookId?: string, ) { const id = notebookId || uuid.v4(); const action = { ...TrashBinActions.restoreDeletedNotebook(id, restoreFolderId), user, ethereal: true, }; return [id, action] as const; } createNoteAction( notebookId: string, note: Partial = {}, user = this.defaultUser, ) { note.id = note.id || uuid.v4(); const action = { ...NoteActions.addNote(note.id, createNote(notebookId, note)), user, }; return action; } createFolderAction( name: string, path: {id: string}[], user = this.defaultUser, ) { const id = uuid.v4(); const action = { ...FileActions.createFile(id, { id, type: FileType.folder, name, path: path as IFilePathItem[], isLiked: false, owner: user || '', ownerDetails: createEmptyIUser(user), dateCreated: 0, dateUpdated: 0, }), user, }; return [id, action] as const; } } export class E2EMockDataBuilder extends BaseMockDataBuilder { constructor() { super(undefined as never); } } export class MockDataBuilder extends BaseMockDataBuilder { constructor(defaultUser: string) { super(defaultUser); } } ================================================ FILE: quix-frontend/service/test/custom-matchers.ts ================================================ declare global { namespace jest { interface Matchers { toMatchArrayAnyOrder(expected: any, sortBy?: string): R; } } } expect.extend({ toMatchArrayAnyOrder(x: any[], y: any[], z = 'id') { const sortFn = (a: any, b: any) => (a[z] as string).localeCompare(b[z]); const arr1Sorted = x.sort(sortFn); const arr2Sorted = y.sort(sortFn); const diff: any = {}; const pass = arr1Sorted.every((item, index) => { const isEqual = this.equals( expect.objectContaining(arr2Sorted[index]), item, ); if (!isEqual) { diff.index = index; diff.a = item; diff.b = arr2Sorted[index]; } return isEqual; }); return { pass, message: () => { if (this.isNot) { return 'Arrays are equal.'; } else { return `Items don't match in index ${diff.index} Expected: ${this.utils.printExpected(diff.a)} Received: ${this.utils.printReceived(diff.b)} `; } }, }; }, }); export const dummyVar = 'just to make this a module'; ================================================ FILE: quix-frontend/service/test/driver.ts ================================================ /* tslint:disable:variable-name */ import {INestApplication} from '@nestjs/common'; import request from 'supertest'; import {IExternalUser} from '../src/modules/auth'; import {testingDefaults} from '../src/config/env/static-settings'; import {INotebook, INote, IFolder, IFile, IUser} from '@wix/quix-shared'; import WebSocket from 'ws'; import uuid from 'uuid'; import {serialize} from 'cookie'; const defaultCookie = testingDefaults.AuthCookieName; interface GetFunctionTypeHelper { (url: 'users'): Promise; (url: 'files'): Promise; (url: 'files', id: string): Promise; (url: 'note', id: string): Promise; (url: 'notebook', id: string): Promise; (...url: string[]): Promise; } const createUserCookie = (user: IExternalUser) => Buffer.from(JSON.stringify(user)).toString('base64'); const wsMessageLog: WeakMap = new WeakMap(); class HttpHelper { constructor( protected _supertest: request.SuperTest, protected user?: IExternalUser, ) {} public getToken() { return this.user ? createUserCookie(this.user) : ''; } public baseGet(url: string) { let chain = this._supertest.get('/api/' + url); if (this.user) { chain = chain.set( 'Cookie', `${defaultCookie}=${createUserCookie(this.user)}`, ); } return chain; } search = async (term: string, offset = 0, total = 5) => ( await this.baseGet(['search', encodeURIComponent(term)].join('/')).query({ offset, total, }) ).body; get: GetFunctionTypeHelper = async (...url: string[]) => (await this.baseGet(url.join('/')).expect(200)).body; getAndExpectFail = (url: string, errorCode: number) => this.baseGet(url).expect(errorCode); private basePost(url: string, data: any) { let chain = this._supertest.post('/api/' + url); if (this.user) { chain = chain.set('Cookie', [ `${defaultCookie}=${createUserCookie(this.user)}`, ]); } return chain.send(data); } post = (url: string, data: any) => this.basePost(url, data).expect(200); postAndExpectFail = (url: string, data: any, errorCode: number) => this.basePost(url, data).expect(errorCode); postEvents = (data: any, sessionId?: string) => { return this.basePost('events', data) .query({sessionId}) .send(data) .expect(200); }; async wsConnect() { const ws = new WebSocket('ws://localhost:3000/subscription', { headers: this.user ? {Cookie: serialize(defaultCookie, createUserCookie(this.user))} : {}, }); const sessionId = uuid.v4(); await new Promise(resolve => ws.on('open', resolve)); ws.send( JSON.stringify({ event: 'subscribe', data: {token: this.getToken(), sessionId}, }), ); ws.on('message', (data: any) => { const messages = [...(wsMessageLog.get(ws) || []), JSON.parse(data)]; wsMessageLog.set(ws, messages); }); return {ws, sessionId}; } getMessages(ws: WebSocket): any[] { return wsMessageLog.get(ws) || []; } } export class E2EDriver extends HttpHelper { private users: Map = new Map(); constructor(private app: INestApplication) { super(request(app.getHttpServer())); } addUser(nickname: string, up: IExternalUser) { this.users.set(nickname, up); return this; } setDefaultUser(nickname: string) { this.user = this.users.get(nickname); } as = (username: string) => { const user = this.users.get(username); return new HttpHelper(this._supertest, user); }; doLogin(nickname: string) { const user = this.users.get(nickname); if (!user) { throw new Error(); } return this.get( `authenticate?code=${encodeURIComponent(JSON.stringify(user))}`, ); } get supertest() { return this._supertest; } } ================================================ FILE: quix-frontend/service/test/jest-e2e.js ================================================ const path = require('path'); const pkgJsonPath = path.resolve(__dirname, '..', 'package.json'); const pkgJson = require(pkgJsonPath) module.exports = { "moduleFileExtensions": ["js", "json", "ts"], "rootDir": "../src", "roots": ["", "/../test"], "testEnvironment": "node", "testRegex": ".e2e-spec.ts$", "transform": { "^.+\\.ts$": "ts-jest" }, "transformIgnorePatterns": ["/node_modules/", "/quix-frontend\\shared/"], } ================================================ FILE: quix-frontend/service/tsconfig.build.json ================================================ { "extends": "./tsconfig.json", "references": [{ "path": "../shared" }], "include": ["src/main.ts", "src/types/**/*.ts", "src/migrations/*.ts"], "exclude": ["node_modules", "test", "**/*spec.ts"] } ================================================ FILE: quix-frontend/service/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "declaration": true, "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "noErrorTruncation": true, "target": "esnext", "sourceMap": true, "moduleResolution": "node", "esModuleInterop": true, "outDir": "./dist", "baseUrl": "./", "strict": true, "skipLibCheck": true, "importHelpers": true, "typeRoots": [ "./node_modules/@types", "./src/types/3rd-party" ] }, "references": [ { "path": "../shared" } ], "include": [ "src/**/*.ts", "test/**/*.ts" ], "exclude": [ "node_modules" ] } ================================================ FILE: quix-frontend/service/tslint.json ================================================ { "defaultSeverity": "error", "extends": [ "tslint:recommended", "tslint-config-prettier" ], "jsRules": { "no-unused-expression": true }, "rules": { "quotemark": [ true, "single" ], "member-access": [ false ], "ordered-imports": [ false ], "member-ordering": [ false ], "interface-name": [ false ], "array-type": false, "arrow-parens": false, "object-literal-sort-keys": false, "max-classes-per-file": false, "no-non-null-assertion": true, "prettier": true }, "rulesDirectory": [ "tslint-plugin-prettier" ] } ================================================ FILE: quix-frontend/shared/.gitignore ================================================ node_modules dist target coverage typings maven velocity.private.data.js test/e2e/screenshots *npm-debug.log .history .idea *.iml .yo-rc.json *.js *.js.map *.d.ts *.d.ts.map tsconfig.tsbuildinfo ================================================ FILE: quix-frontend/shared/config-helper/config-helper.ts ================================================ import { ModuleEngineType, ModuleComponentType } from './consts'; interface ComponentConfigurationTypes { [ModuleComponentType.Db]: {}; [ModuleComponentType.Note]: {}; } export type ComponentConfiguration = {[K in ModuleComponentType]?: ComponentConfigurationTypes[K]} interface ConfigModule { id: string; name: string; components: ComponentConfiguration; syntax: string; engine: ModuleEngineType; } const defaultConfigData = { modules: [] as ConfigModule[], auth: { googleClientId: '', }, clientTopology: { staticsBaseUrl: '', executeBaseUrl: '', apiBasePath: '', }, mode: { debug: false, demo: false, } } type ConfigData = typeof defaultConfigData; export class ClientConfigHelper { private readonly config: ConfigData; constructor(initialConfig: Partial = {}) { this.config = { ...defaultConfigData, ...initialConfig }; } serialize(): string { return JSON.stringify(this.config); } static load(input: string | object): ClientConfigHelper { if (typeof input === 'string') { return new ClientConfigHelper(JSON.parse(input)); } return new ClientConfigHelper(input); } getModule(id: string) { return this.getModules().find(m => m.id === id); } getModuleComponent(id: string, component: C) { const m = this.getModule(id); return m && m.components[component]; } getModules() { return this.config.modules; } addModule(p: ConfigModule) { this.config.modules.push(p); return this; } getModulesByComponent(component: ModuleComponentType) { return this.config.modules.filter(p => Object.keys(p.components).includes(component)); } addModuleComponent(moduleId: string, component: C, configuration: ComponentConfigurationTypes[C]) { const m = this.getModule(moduleId); if (m) { m.components[component] = configuration; } return this; } getAuth() { return this.config.auth; } getClientTopology() { return this.config.clientTopology; } getMode() { return this.config.mode; } setAuth(auth: ConfigData['auth']) { this.config.auth = {...auth} return this; } setClientTopology(clientTopology: ConfigData['clientTopology']) { this.config.clientTopology = {...clientTopology}; return this; } setMode(mode: ConfigData['mode']) { this.config.mode = {...mode}; return this; } } ================================================ FILE: quix-frontend/shared/config-helper/consts.ts ================================================ export type TModuleComponentType = 'note' | 'db'; export enum ModuleComponentType { Note = 'note', Db = 'db', } export enum ModuleEngineType { Presto = 'presto', Athena = 'athena', Jdbc = 'jdbc', BigQuery = 'bigquery', Python = 'python', } export const ModuleEngineToSyntaxMap = { presto: 'presto', athena: 'athena', bigquery: 'ansisql', python: 'python' } ================================================ FILE: quix-frontend/shared/entities/common/actions.ts ================================================ import {mapValues} from 'lodash'; export type ExtractActions any>> = {[K in keyof T]: ReturnType}[keyof T]; export type ExtractActionTypes any>> = {[K in keyof T]: ReturnType['type']}[keyof T]; export const ExtractActionTypes = any>>(actions: T) => { const result: {[K in keyof T]: ReturnType['type']} = mapValues(actions, ((actionCreator: Function) => actionCreator().type)) as any; return result; } ================================================ FILE: quix-frontend/shared/entities/common/common-types.ts ================================================ import {IUser} from '../user'; export interface IEntity { id: string; name: string; owner: string ownerDetails?: IUser dateCreated: number; dateUpdated: number; } export interface BaseAction { type: string; id: string; } export interface AnyAction extends BaseAction { type: string; [k: string]: any } export type Reducer = (state: S | undefined, action: A) => (S | undefined); ================================================ FILE: quix-frontend/shared/entities/common/create-reducer.spec.ts ================================================ import {createReducer, createListReducer} from './create-reducer'; interface SomeRandomEntity { id: string; name: string; description: string; someNestedObject: { foo: number; } } describe('createBaseReducer', () => { const entity: SomeRandomEntity = { id: '1', name: 'someName', description: 'words go here', someNestedObject: { foo: 10 } } it('should handle create actions', () => { const reducer = createReducer('someEntity') const action = { type: 'someEntity.create', someEntity: entity, id: '1' } const newState = reducer(undefined, action); expect(newState).toEqual(entity); expect(newState).not.toBe(entity); }); it('should handle delete actions', () => { const reducer = createReducer('someEntity') const action = { type: 'someEntity.delete', id: '1' } const newState = reducer(entity, action); expect(newState).toBe(entity); }); it('should handle update actions', () => { const reducer = createReducer('someEntity') const action = { type: 'someEntity.update.name', name: 'newName', id: '1' } const newState = reducer(entity, action); expect(newState).toBeDefined; expect(newState!.name).toEqual('newName'); }); it('should handle update actions of deep properties', () => { const reducer = createReducer('someEntity') const action = { type: 'someEntity.update.someNestedObject', id: '1', someNestedObject: { foo: 11 } } const newState = reducer(entity, action); expect(newState).toBeDefined; expect(newState!.someNestedObject).toEqual({foo: 11}); }); it('should do nothing on unsupported action', () => { const reducer = createReducer('someEntity') const action = { type: 'someEntity.someNestedObject.update.foo', foo: 11, id: '1' } const newState = reducer(entity, action); expect(newState).toBe(entity); }); }); describe('createListReducer', () => { const entity: SomeRandomEntity = { id: '1', name: 'someName', description: 'words go here', someNestedObject: { foo: 10 } } let state: SomeRandomEntity[] = []; const baseReducer = createReducer('someEntity') beforeEach(() => state = []); it('should add item to list', () => { const listReducer = createListReducer('someEntity', baseReducer); const action = { type: 'someEntity.create', someEntity: entity, id: entity.id }; const newState = listReducer(state, action); expect(newState).toEqual([entity]); }); it('should remove item from list', () => { const listReducer = createListReducer('someEntity', baseReducer); const action = { type: 'someEntity.delete', id: entity.id }; const newState = listReducer([entity], action); expect(newState).toEqual([]); }); it('should handle updates', () => { const listReducer = createListReducer('someEntity', baseReducer); const action = { type: 'someEntity.update.description', id: entity.id, description: 'newDescription' }; const newState = listReducer([entity], action); expect(newState).toMatchObject([{...entity, description: 'newDescription'}]) }); }); ================================================ FILE: quix-frontend/shared/entities/common/create-reducer.ts ================================================ import {Reducer, BaseAction, AnyAction} from './common-types'; import {replaceWith} from '../../utils/utils'; const creatingReducer = ( entityName: string, entityTransformer = (x: any) => x ): Reducer => (state, action_) => { const action = action_ as AnyAction; switch (action.type) { case `${entityName}.create`: { if (action[entityName]) { const owner = action.user ? {owner: action.user} : {}; return {...entityTransformer(action[entityName]), ...owner}; } break; } default: } return state; } const deletingReducer = ( entityName: string ): Reducer => (state, action_) => { const action = action_ as AnyAction; switch (action.type) { case `${entityName}.delete`: return state; default: } return state; } const updatingReducer = ( entityName: string ): Reducer => (state, action_) => { const action = action_ as AnyAction; if (action.type.startsWith(`${entityName}.update`) && state && state.id === action.id) { const prop = action.type.split('.')[2]; if (prop && typeof action[prop] !== 'undefined') { state.dateUpdated = action.dateCreated || Date.now(); return {...state as any, [prop]: action[prop]}; } } return state; } const listReducer = ( entityOrMap: string | Record>, reducer: Reducer = x => x, options: { createIfNull: boolean; delete: boolean; } ) => (s: T[], a: A) => { const entityMap = typeof entityOrMap === 'string' ? {[entityOrMap]: reducer} : entityOrMap; const fn = (state: T[], action: A) => { const [entityName, actionType] = action.type.split('.'); const entityReducer = entityMap[entityName]; if (!entityReducer) { return state; } switch (actionType) { case 'create': state = !state && options.createIfNull ? [] : state; return state && [...state, entityReducer(undefined, action) as T]; case 'delete': if (options.delete) { return state && state.filter(item => item.id !== action.id); } break; case 'update': return state && replaceWith(state, {id: action.id}, item => entityReducer(item, action)); default: } return state; }; return fn(s, a); } export const composeReducers = ( ...args: Reducer[] ): Reducer => (state, action) => args.reduce((s, reducer) => reducer(s, action), state); export const createReducer = ( entityName: string, entityTransformer = (x: any) => x ): Reducer => composeReducers( creatingReducer(entityName, entityTransformer), deletingReducer(entityName), updatingReducer(entityName), ); export const createClientReducer = ( entityName: string ): Reducer => composeReducers( updatingReducer(entityName), ); export const createListReducer = ( entityOrMap: string | Record>, reducer: Reducer = x => x ) => listReducer(entityOrMap, reducer, {createIfNull: true, delete: true}); export const createClientListReducer = ( entityOrMap: string | Record>, reducer: Reducer = x => x, options: { delete: boolean; } = {delete: true} ) => listReducer(entityOrMap, reducer, {createIfNull: false, delete: options.delete}); ================================================ FILE: quix-frontend/shared/entities/deleted-notebook/actions.ts ================================================ import { IDeletedNotebook } from './types'; import { ExtractActionTypes, ExtractActions } from '../common/actions'; export const DeletedNotebookActions = { createDeletedNotebook: (id: string, deletedNotebook: IDeletedNotebook) => ({ type: 'deletedNotebook.create' as const, deletedNotebook, id, }), deleteDeletedNotebook: (id: string) => ({ type: 'deletedNotebook.delete' as const, id, }), restoreDeletedNotebook: (id: string) => ({ type: 'deletedNotebook.restore' as const, id, }), }; export type DeletedNotebookActions = ExtractActions< typeof DeletedNotebookActions >; export type DeletedNotebookActionTypes = ExtractActionTypes< typeof DeletedNotebookActions >; export const DeletedNotebookActionTypes = ExtractActionTypes( DeletedNotebookActions ); ================================================ FILE: quix-frontend/shared/entities/deleted-notebook/deleted-notebook.ts ================================================ import uuid from 'uuid/v4'; import {IDeletedNotebook} from './types'; import {IFilePathItem} from '../file/types'; import {createEmptyIUser} from '../user/user'; import {IUser} from '../user'; export const createDeletedNotebook = (path: IFilePathItem[] = [], props: Partial = {}, user: IUser = createEmptyIUser('')): IDeletedNotebook => ({ id: uuid(), name: 'Deleted notebook', notes: [], isLiked: false, path, owner: user.id, ownerDetails: user, dateCreated: Date.now(), dateUpdated: Date.now(), dateDeleted: Date.now(), ...props }); ================================================ FILE: quix-frontend/shared/entities/deleted-notebook/index.ts ================================================ export { IDeletedNotebook } from './types'; export { clientDeletedNotebookListReducer as clientDeletedNotebookReducer, deletedNotebookReducer as deletedNotebookReducer } from './reducer'; export { DeletedNotebookActionTypes, DeletedNotebookActions } from './actions' export { createDeletedNotebook } from './deleted-notebook' ================================================ FILE: quix-frontend/shared/entities/deleted-notebook/reducer.ts ================================================ import { createClientListReducer, createReducer } from '../common/create-reducer'; import { IDeletedNotebook } from './types'; export const deletedNotebookReducer = createReducer('deletedNotebook'); export const clientDeletedNotebookListReducer = createClientListReducer('deletedNotebook'); ================================================ FILE: quix-frontend/shared/entities/deleted-notebook/types.ts ================================================ import { INotebook } from '../notebook'; export interface IDeletedNotebook extends INotebook { dateDeleted: number; } ================================================ FILE: quix-frontend/shared/entities/file/actions.ts ================================================ import {IFile, IFilePathItem} from './types'; import {ExtractActionTypes, ExtractActions} from '../common/actions'; export const FileActions = { createFile: (id: string, file: IFile) => ({ type: 'file.create' as const, id, file }), deleteFile: (id: string) => ({ type: 'file.delete' as const, id }), moveFile: (id: string, newPath: IFilePathItem[]) => ({ type: 'file.update.path' as const, id, path: newPath }), updateName: (id: string, name: string) => ({ type: 'file.update.name' as const, id, name }), toggleIsLiked: (id: string, isLiked: boolean) => ({ type: 'file.update.isLiked' as const, id, isLiked }), } export type FileActions = ExtractActions export type FileActionTypes = ExtractActionTypes export const FileActionTypes = ExtractActionTypes(FileActions); ================================================ FILE: quix-frontend/shared/entities/file/file.ts ================================================ import uuid from 'uuid/v4'; import {IFile, FileType, IFilePathItem} from './types'; import {IUser} from '../user'; import {createEmptyIUser} from '../user/user'; const file = (type: FileType, path: IFilePathItem[] = [], props: Partial = {}, user: IUser = createEmptyIUser('')): IFile => ({ id: uuid(), name: `New ${type}`, type, path, isLiked: false, owner: user.id, ownerDetails: user, dateCreated: Date.now(), dateUpdated: Date.now(), ...props }) export const createFolder = (path: IFilePathItem[] = [], props: Partial = {}): IFile => file(FileType.folder, path, props); export const createFile = (path: IFilePathItem[] = [], props: Partial = {}): IFile => file(FileType.notebook, path, props); ================================================ FILE: quix-frontend/shared/entities/file/index.ts ================================================ export {FileActions, FileActionTypes} from './actions'; export {FileType, IFile, IFilePathItem} from './types'; export {fileReducer, clientFileReducer, fileListReducer, clientFileListReducer} from './reducer' export {createFile, createFolder} from './file' ================================================ FILE: quix-frontend/shared/entities/file/reducer.ts ================================================ import {last, remove} from 'lodash'; import {createReducer, composeReducers, createListReducer, createClientReducer, createClientListReducer} from '../common/create-reducer'; import {INotebook, clientNotebookReducer} from '../notebook'; import {createFile} from './file'; import {IFilePathItem, IFile, FileType} from './types'; import {FileActionTypes} from './actions'; const moveFile = (files: IFile[], id: string, path: IFilePathItem[]) => { const file = files.find(f => f.id === id); if (file) { file.path = path; if (file.type === FileType.folder) { files.filter(f => // tslint:disable-next-line: no-non-null-assertion f.path.length && last(f.path)!.id === id).forEach(f => moveFile(files, f.id, [...path, {id: file.id, name: file.name}])); } } return files; } const deleteFile = (files: IFile[], id: string) => { const file = remove(files, {id})[0]; if (file && file.type === FileType.folder) { files.filter(f => // tslint:disable-next-line: no-non-null-assertion f.path.length && last(f.path)!.id === id).forEach(f => deleteFile(files, f.id)); } return files; } export const fileReducer = composeReducers( createReducer('file'), createReducer('notebook', (notebook: INotebook) => createFile(notebook.path, { id: notebook.id, name: notebook.name })) ); export const clientFileReducer = composeReducers( createClientReducer('file'), clientNotebookReducer ); export const fileListReducer = composeReducers( createListReducer('file', fileReducer) as any, createListReducer('notebook', fileReducer) as any ); export const clientFileListReducer = composeReducers( createClientListReducer('file', fileReducer, {delete: false}) as any, createClientListReducer('notebook', fileReducer) as any, ((state: IFile[], action: any) => { switch (action.type) { case FileActionTypes.moveFile: return state && [...moveFile(state, action.id, action.path)]; case FileActionTypes.deleteFile: return state && [...deleteFile(state, action.id)]; default: } return state; }) as any ); ================================================ FILE: quix-frontend/shared/entities/file/types.ts ================================================ import {IEntity} from '../common/common-types'; export enum FileType { folder = 'folder', notebook = 'notebook' } export interface IFile extends IEntity { type: FileType; path: IFilePathItem[]; isLiked: boolean; } export interface IFilePathItem { id: string; name: string; } ================================================ FILE: quix-frontend/shared/entities/folder/folder.ts ================================================ import uuid from 'uuid/v4'; import {IFolder} from './types'; import {IFilePathItem} from '../file'; import {IUser} from '../user'; import {createEmptyIUser} from '../user/user'; export const createFolderPayload = (path: IFilePathItem[] = [], props: Partial = {}, user: IUser = createEmptyIUser('')): IFolder => ({ id: uuid(), name: `New folder`, path, files: [], isLiked: false, owner: user.id, ownerDetails: user, dateCreated: Date.now(), dateUpdated: Date.now(), ...props }); ================================================ FILE: quix-frontend/shared/entities/folder/index.ts ================================================ export {IFolder} from './types'; export {createFolderPayload} from './folder'; ================================================ FILE: quix-frontend/shared/entities/folder/types.ts ================================================ import {IEntity} from '../common/common-types'; import {IFilePathItem} from '../file'; export interface IFolder extends IEntity { path: IFilePathItem[]; files: IFilePathItem[]; isLiked: boolean; } ================================================ FILE: quix-frontend/shared/entities/history/actions.ts ================================================ import { IHistory } from './types'; import { ExtractActionTypes, ExtractActions } from '../common/actions'; export const HistoryActions = { createHistory: (id: string, history: IHistory) => ({ type: 'history.create' as const, history, id }), }; export type HistoryActions = ExtractActions; export type HistoryActionTypes = ExtractActionTypes; export const HistoryActionTypes = ExtractActionTypes(HistoryActions); ================================================ FILE: quix-frontend/shared/entities/history/history.ts ================================================ import uuid from 'uuid/v4'; import { IHistory } from './types'; export const createHistory = (props: Partial = {}): IHistory => ({ id: uuid(), email: 'local@quix.com', query: [], moduleType: 'presto', startedAt: '', ...props }); ================================================ FILE: quix-frontend/shared/entities/history/index.ts ================================================ export { IHistory } from './types'; export { createHistory } from './history'; export { HistoryActionTypes, HistoryActions } from './actions'; ================================================ FILE: quix-frontend/shared/entities/history/types.ts ================================================ export interface IHistory { id: string; email: string; query: string[]; moduleType: string; startedAt: string; } ================================================ FILE: quix-frontend/shared/entities/note/actions.ts ================================================ import {ExtractActionTypes, ExtractActions} from '../common/actions'; import {INote} from './types'; export const NoteActions = { updateName: (id: string, name: string) => ({ type: 'note.update.name' as const, name, id }), updateContent: (id: string, content: any, richContent?: any) => ({ type: 'note.update.content' as const, id, content, richContent }), move: (id: string, newNotebookId: string) => ({ type: 'note.move' as const, id, newNotebookId }), addNote: (id: string, note: INote) => { return { type: 'note.create' as const, id, note }; }, deleteNote: (id: string) => ({ type: 'note.delete' as const, id }), reorderNote: (id: string, to: number) => ({ type: 'note.reorder' as const, id, to }), } export type NoteActions = ExtractActions; export type NoteActionT = NoteActions & {type: T}; export type NoteActionTypes = ExtractActionTypes; export const NoteActionTypes = ExtractActionTypes(NoteActions); ================================================ FILE: quix-frontend/shared/entities/note/index.ts ================================================ export {NoteActions, NoteActionTypes} from './actions'; export {INote, IBaseNote} from './types'; export {noteReducer, clientNoteReducer, noteListReducer, clientNoteListReducer} from './reducer' export {createNote} from './note' ================================================ FILE: quix-frontend/shared/entities/note/note.ts ================================================ import uuid from 'uuid/v4'; import {INote} from './types'; export const createNote = (notebookId: string, props: Partial = {}): INote => ({ id: uuid(), notebookId, name: 'New note', type: 'presto', content: '\n', owner: '', dateCreated: Date.now(), dateUpdated: Date.now(), ...props as any }); ================================================ FILE: quix-frontend/shared/entities/note/reducer.ts ================================================ import { INote } from './types'; import { createReducer, createClientReducer, composeReducers, createListReducer, createClientListReducer, } from '../common/create-reducer'; import { NoteActions, NoteActionTypes } from './actions'; import { AnyAction } from '../common/common-types'; const commonReducer = (state: INote | undefined, action: NoteActions) => { switch (action.type) { case NoteActionTypes.move: return state && { ...state, notebookId: action.newNotebookId }; case NoteActionTypes.updateContent: // update of "plain text" content happens in the default reducer if (state) { state.dateUpdated = (action as AnyAction).dateCreated || Date.now(); return { ...state, richContent: action.richContent }; } return state; default: return state; } }; export const noteReducer = composeReducers( commonReducer, createReducer('note') ); export const clientNoteReducer = composeReducers( commonReducer, createClientReducer('note') ); export const noteListReducer = composeReducers( createListReducer('note', createReducer('note')) as any ); export const clientNoteListReducer = composeReducers( createClientListReducer('note', createReducer('note')) as any ); ================================================ FILE: quix-frontend/shared/entities/note/types.ts ================================================ import {IEntity} from '../common/common-types'; type Omit = Pick>; export interface IBaseNote extends Omit { notebookId: string; type: string; content: string; richContent?: Record, owner: string; } export type INote = IBaseNote; ================================================ FILE: quix-frontend/shared/entities/notebook/actions.ts ================================================ import { INotebook } from './types'; import { ExtractActionTypes, ExtractActions } from '../common/actions'; import { IFilePathItem } from '../file'; export const NotebookActions = { createNotebook: (id: string, notebook: INotebook) => ({ type: 'notebook.create' as const, notebook, id, }), deleteNotebook: (id: string) => ({ type: 'notebook.delete' as const, id, }), deleteNotebookNotes: (id: string) => ({ type: 'notebook.deleteNotes' as const, id, }), moveNotebook: (id: string, newPath: IFilePathItem[]) => ({ type: 'notebook.update.path' as const, id, path: newPath, }), updateName: (id: string, name: string) => ({ type: 'notebook.update.name' as const, name, id, }), toggleIsLiked: (id: string, isLiked: boolean) => ({ type: 'notebook.update.isLiked' as const, id, isLiked, }), }; export type NotebookActions = ExtractActions; export type NotebookActionTypes = ExtractActionTypes; export const NotebookActionTypes = ExtractActionTypes(NotebookActions); ================================================ FILE: quix-frontend/shared/entities/notebook/index.ts ================================================ export {NotebookActions, NotebookActionTypes} from './actions'; export {INotebook} from './types'; export {notebookReducer, clientNotebookReducer} from './reducer' export {createNotebook, createNotebookWithNote} from './notebook' ================================================ FILE: quix-frontend/shared/entities/notebook/notebook.ts ================================================ import uuid from 'uuid/v4'; import {INotebook} from './types'; import {createNote} from '../note/note'; import {IFilePathItem} from '../file/types'; import {createEmptyIUser} from '../user/user'; import {IUser} from '../user'; export const createNotebook = (path: IFilePathItem[] = [], props: Partial = {}, user: IUser = createEmptyIUser('')): INotebook => ({ id: uuid(), name: 'New notebook', notes: [], isLiked: false, path, owner: user.id, ownerDetails: user, dateCreated: Date.now(), dateUpdated: Date.now(), ...props }); export const createNotebookWithNote = (path: IFilePathItem[] = [], props: Partial = {}) => ((notebook: INotebook): INotebook => ({ ...notebook, notes: [createNote(notebook.id)], }))(createNotebook(path, props)); ================================================ FILE: quix-frontend/shared/entities/notebook/reducer.ts ================================================ import {createReducer, createClientReducer} from '../common/create-reducer'; import {INotebook} from './types'; export const notebookReducer = createReducer('notebook'); export const clientNotebookReducer = createClientReducer('notebook'); ================================================ FILE: quix-frontend/shared/entities/notebook/types.ts ================================================ import {INote} from '../note/types'; import {IEntity} from '../common/common-types'; import {IFilePathItem} from '../file/types'; export interface INotebook extends IEntity { notes: INote[]; path: IFilePathItem[]; isLiked: boolean; } ================================================ FILE: quix-frontend/shared/entities/trash-bin/actions.ts ================================================ import { ExtractActionTypes, ExtractActions } from '../common/actions'; export const TrashBinActions = { moveNotebookToTrashBin: (id: string) => ({ type: 'trashBin.addNotebook' as const, id, }), moveFolderToTrashBin: (id: string) => ({ type: 'trashBin.addFolderContent' as const, id, }), permanentlyDeleteNotebook: (id: string) => ({ type: 'trashBin.deleteNotebook' as const, id, }), restoreDeletedNotebook: (id: string, folderId: string) => ({ type: 'trashBin.restoreNotebook' as const, folderId, id, }), }; export type TrashBinActions = ExtractActions; export type TrashBinActionTypes = ExtractActionTypes; export const TrashBinActionTypes = ExtractActionTypes(TrashBinActions); ================================================ FILE: quix-frontend/shared/entities/trash-bin/index.ts ================================================ export { TrashBinActions, TrashBinActionTypes } from './actions'; ================================================ FILE: quix-frontend/shared/entities/trash-bin/types.ts ================================================ ================================================ FILE: quix-frontend/shared/entities/user/actions.ts ================================================ import {IUser} from './types'; import {ExtractActionTypes, ExtractActions} from '../common/actions'; export const UserActions = { createNewUser: (id: string, user: IUser) => ({ type: 'user.create' as const, newUser: user, id, }), updateUser: (id: string, avatar: string, name: string, email: string, changeUserCreated?: Date) => ({ type: 'user.update' as const, name, email, avatar, id, changeUserCreated }), } export type UserActions = ExtractActions export type UserActionTypes = ExtractActionTypes export const UserActionTypes = ExtractActionTypes(UserActions); ================================================ FILE: quix-frontend/shared/entities/user/index.ts ================================================ export {IUser} from './types'; export {createUser, createEmptyIUser} from './user'; export {UserActionTypes, UserActions} from './actions'; ================================================ FILE: quix-frontend/shared/entities/user/types.ts ================================================ export interface IUser { email: string; id: string; name: string; avatar: string; rootFolder: string; dateUpdated: number; dateCreated: number; } ================================================ FILE: quix-frontend/shared/entities/user/user.ts ================================================ import uuid from 'uuid/v4'; import {IUser} from './types'; export const createUser = (props: Partial = {}): IUser => ({ id: uuid(), name: 'Local User', email: 'local@quix.com', avatar: '', rootFolder: '', dateCreated: 0, dateUpdated: 0, ...props }); export const createEmptyIUser = (userId: string = ''): IUser => ({ id: userId, name: '', email: userId, avatar: '', rootFolder: '', dateCreated: 0, dateUpdated: 0, }); ================================================ FILE: quix-frontend/shared/index.ts ================================================ export { IEntity } from './entities/common/common-types'; export { composeReducers } from './entities/common/create-reducer'; export { INotebook, NotebookActions, NotebookActionTypes, createNotebook, createNotebookWithNote, notebookReducer, clientNotebookReducer, } from './entities/notebook'; export { IDeletedNotebook, DeletedNotebookActions, DeletedNotebookActionTypes, deletedNotebookReducer, clientDeletedNotebookReducer, createDeletedNotebook, } from './entities/deleted-notebook'; export { TrashBinActionTypes, TrashBinActions } from './entities/trash-bin'; export { IFile, IFilePathItem, FileType, FileActions, FileActionTypes, createFile, createFolder, fileReducer, clientFileReducer, fileListReducer, clientFileListReducer, } from './entities/file'; export { IFolder, createFolderPayload } from './entities/folder'; export { INote, NoteActions, NoteActionTypes, createNote, noteReducer, clientNoteReducer, noteListReducer, clientNoteListReducer, } from './entities/note'; export { ClientConfigHelper, ComponentConfiguration, } from './config-helper/config-helper'; export { ModuleEngineToSyntaxMap, ModuleEngineType, ModuleComponentType, TModuleComponentType, } from './config-helper/consts'; export { IUser, createEmptyIUser, createUser, UserActionTypes, UserActions, } from './entities/user'; export { IHistory, createHistory, HistoryActionTypes, HistoryActions, } from './entities/history'; export { SearchTypes, SpecialSearchTypes, SearchTextType, ContentSearch, SearchQuery, SearchResult, } from './types/search-types'; ================================================ FILE: quix-frontend/shared/package.json ================================================ { "name": "@wix/quix-shared", "version": "1.0.16", "license": "MIT", "description": "Presto-based notebook manager", "author": { "name": "Anton Podolsky", "email": "antonp@wix.com" }, "contributors": [ { "name": "Aviad Hadad", "email": "aviadh@wix.com" } ], "scripts": { "test": "jest", "test:ci": "jest", "build": "tsc -b ." }, "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" }, "files": [ "*" ], "main": "dist/index.js", "types": "dist/index.d.ts", "devDependencies": { "@types/jest": "^24.0.11", "@types/lodash": "^4.14.123", "@types/uuid": "^8.3.0", "jest": "^26.0.0", "ts-jest": "^26.0.0", "typescript": "^4.0.0" }, "dependencies": { "lodash": "^4.17.11", "tslib": "^2.3.0", "uuid": "^3.3.2" }, "jest": { "moduleFileExtensions": [ "js", "json", "ts" ], "rootDir": "./", "testRegex": ".spec.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" }, "coverageDirectory": "./coverage", "testEnvironment": "node" } } ================================================ FILE: quix-frontend/shared/tsconfig.json ================================================ { "compilerOptions": { "sourceMap": true, "module": "commonjs", "moduleResolution": "node", "target": "es5", "noUnusedLocals": true, "lib": [ "es2016" ], "importHelpers": true, "esModuleInterop": true, "downlevelIteration": true, "composite": true, "declaration": true, "declarationMap": true, "strict": true } } ================================================ FILE: quix-frontend/shared/types/search-types.ts ================================================ import {INote} from '../entities/note/types'; export enum SearchTypes { user = "owner", type = "type", noteName = "name", content = "content", } export type SpecialSearchTypes = | SearchTypes.noteName | SearchTypes.type | SearchTypes.user; export enum SearchTextType { PHRASE, WORD, } export interface ContentSearch { type: SearchTextType; text: string; } export interface SearchQuery { fullText: string; [SearchTypes.content]: ContentSearch[]; [SearchTypes.user]?: string; [SearchTypes.noteName]?: string; [SearchTypes.type]?: string; } export interface SearchResult { notes: INote[]; count: number; term: SearchQuery; }; ================================================ FILE: quix-frontend/shared/utils/utils.ts ================================================ import {findIndex} from 'lodash'; export const replaceWith = (collection: any[], predicate: Record, value: (current: any) => any) => { const index = findIndex(collection, predicate); if (index === -1) { return collection; } collection.splice(index, 1, value(collection[index])); return [...collection]; } ================================================ FILE: terraform/README.md ================================================ # Terraform AWS for QUIX-environment This package allows you to easily create your own QUIX on Amazon Web Services with [Terraform][https://www.terraform.io/downloads.html] project that builds [VPC with Public and Private Subnets][https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html#VPC_Scenario2_Implementation] from the AWS documentation. ## Getting Started **Note: Master is the only supported branch. All other branches of this repo should not be considered stable, and is to be used at your own risk.** # Getting Started ## Pre Reqs We use Terraform to automate parts of the infrastructure for your CircleCI Server install, so you will need to install this first: * [Terraform](https://www.terraform.io/downloads.html) **Note: This script only supports terraform version 0.12 and higher. Please update to the most recent version before fetching from upstream.** ## Installation ### Basic 1. Clone or download this repository ```bash git clone git@github.com:wix/quix.git ``` 2. Run `terraform init` to install Terraform plugins 3. Run `terraform apply` 4. Visit ALB adress supplied at the end of the Terraform output 5. Follow instructions to setup and configure your installation ### Extra #### Prepare right [Shared Credentials file for Terraform](https://www.terraform.io/docs/providers/aws/index.html#shared-credentials-file) > You can use an AWS credentials file to specify your credentials. The default location is $HOME/.aws/credentials on Linux and OS X, or "%USERPROFILE%\.aws\credentials" for Windows > users. If we fail to detect credentials inline, or in the environment, Terraform will check this location. You can optionally specify a different location in the configuration by > providing the shared_credentials_file attribute, or in the environment with the AWS_SHARED_CREDENTIALS_FILE variable. This method also supports a profile configuration and matching > AWS_PROFILE environment variable: ~/.aws/credentials ``` [default] aws_access_key_id=AKEXAMPLEEXAMPLEEXAMPLE aws_secret_access_key=EXAMPLE/K7MDENG/bPxRfiCYEXAMPLEKEY ``` ~/.aws/config ``` [default] region=us-east-1 output=json ``` ### We are using [Terraform S3 BackEnd](https://www.terraform.io/docs/backends/types/s3.html) * bucket = "tf-state-backend-bucket" * key = "terraform.tfstate" * dynamodb_table = "terraform-lock" * region = "us-east-1" * key = "example.tfstate" ## 2. Usage ### 2.1 Import ``` terraform init ``` ### 2.2 Apply Plan ``` terraform plan -out vpc.plan && terraform apply "vpc.plan" ``` ### Plan ``` terraform plan -var-file terraform.tfvars ``` `terraform.tfvars` holds variables which should be overriden with valid ones. ### Apply ``` terraform apply -var-file terraform.tfvars ``` ### Destroy ``` terraform destroy -var-file terraform.tfvars ``` ## Links * [Terraform](http://terraform.io) * [Terraform VPC](https://nickcharlton.net/posts/terraform-aws-vpc.html) * [scenario_two](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html) * [AWS documentation](http://aws.amazon.com/documentation/) * [blog_post](https://nickcharlton.net/posts/terraform-aws-vpc.html) * [ECS Resources: The amount of memory used by the task.](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-memory) ## Author Copyright (c) 2019 Valeriy Soloviov . ================================================ FILE: terraform/acme_certificate.tf ================================================ # ---------------------------------------------------------------- # Inputs required to do an initial registration (aka create an # account) with the ACME provider (Let's Encrypt) # ---------------------------------------------------------------- # Create an on the fly private key for the registration # (not the certificate). Could simply be imported as well resource "tls_private_key" "acme_registration_private_key" { count = var.enable_acme_ssl ? 1 : 0 algorithm = "RSA" } # Set up a registration using the registration private key resource "acme_registration" "reg" { count = var.enable_acme_ssl ? 1 : 0 account_key_pem = tls_private_key.acme_registration_private_key[0].private_key_pem email_address = var.acme_registration_email lifecycle { create_before_destroy = true } } # ---------------------------------------------------------------- # Inputs required to request a new cert from ACME provider # ---------------------------------------------------------------- # Create a certificate resource "acme_certificate" "certificate" { count = var.enable_acme_ssl ? 1 : 0 account_key_pem = tls_private_key.acme_registration_private_key[0].private_key_pem common_name = var.acme_certificate_common_name subject_alternative_names = [var.dns_domain_name] min_days_remaining = var.min_days_remaining recursive_nameservers = ["8.8.8.8:53"] dns_challenge { provider = "route53" # Without this explicit config, the ACME provider (which uses lego # under the covers) will look for environment variables to use. # These environment variable names happen to overlap with the names # also required by the native Terraform AWS provider, however is not # guaranteed. You may want to explicitly configure them here if you # would like to use different credentials to those used by the main # Terraform provider config = { AWS_REGION = var.aws_region AWS_PROFILE = var.aws_acme_profile AWS_HOSTED_ZONE_ID = aws_route53_zone.quix.zone_id AWS_TTL = 60 AWS_PROPAGATION_TIMEOUT = 120 } } lifecycle { create_before_destroy = true } } resource "aws_acm_certificate" "cert" { count = var.enable_ssl ? 1 : 0 domain_name = var.dns_domain_name subject_alternative_names = ["*.${var.dns_domain_name}"] validation_method = "DNS" tags = merge( { "Name" = "quix-zone" }, var.tags, ) lifecycle { create_before_destroy = true } } resource "aws_acm_certificate_validation" "cert" { count = var.enable_ssl ? 1 : 0 certificate_arn = aws_acm_certificate.cert[0].arn validation_record_fqdns = ["${aws_route53_record.cert_validation[0].fqdn}"] } resource "aws_iam_server_certificate" "alb_cert" { count = var.enable_acme_ssl ? 1 : 0 name = "wild-quix-${formatdate("YY-MM-DD", timestamp())}" certificate_body = acme_certificate.certificate[0].certificate_pem certificate_chain = acme_certificate.certificate[0].issuer_pem private_key = acme_certificate.certificate[0].private_key_pem lifecycle { create_before_destroy = true ignore_changes = [ # Ignore changes to name, e.g. because it's calculating at execution name ] } } ================================================ FILE: terraform/aws-tf-backend.tf ================================================ data "aws_caller_identity" "current" {} resource "aws_s3_bucket" "terraform_state" { bucket = "terraform-state.quix-oss" acl = "private" versioning { enabled = true } lifecycle { prevent_destroy = true } tags = merge( { Name = "TerraformStateBucket", Description = "Terraform state locking bucket for account ${data.aws_caller_identity.current.account_id}." }, var.tags, ) } resource "aws_dynamodb_table" "tf_backend_state_lock_table" { # count = true name = var.tf_dynamodb_lock_table_name read_capacity = var.tf_lock_table_read_capacity write_capacity = var.tf_lock_table_write_capacity hash_key = "LockID" attribute { name = "LockID" type = "S" } tags = merge( { Description = "Terraform state locking table for account ${data.aws_caller_identity.current.account_id}." }, var.tags, ) lifecycle { prevent_destroy = true } } ================================================ FILE: terraform/ecs.tf ================================================ /* * ECS Cluster for Quix * */ resource "aws_ecs_cluster" "main" { name = "quix-ecs-cluster" tags = merge( { "Name" = "alb-tg-${var.vpc_name}" }, var.tags, ) } resource "aws_cloudwatch_log_group" "quix-logs" { name = "quix-logs" retention_in_days = "14" } # You can use # Presto ALB http://${aws_alb.presto.dns_name}:${var.presto_port}/v1 locals { backend_url = "http%{if var.enable_acme_ssl != false || var.enable_ssl != false}s%{endif}://${var.dns_domain_name}:${var.backend_public_port}" } resource "aws_ecs_task_definition" "quix" { family = "quix" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = var.fargate_cpu * 16 memory = var.fargate_memory * 32 execution_role_arn = aws_iam_role.ecs_task_role.arn container_definitions = <