[
  {
    "path": ".dockerignore",
    "content": "*/node_modules\n*.log\n"
  },
  {
    "path": ".github/workflows/quix-backend-build.yml",
    "content": "name: Quix Backend Build\non:\n  pull_request:\n    paths:\n    - 'quix-backend/**'  \n  push:\n    paths:\n    - 'quix-backend/**'\n  workflow_dispatch:\njobs:\n  scala_tests:\n    runs-on: ubuntu-20.04\n    strategy:\n      matrix:\n        scala_version: ['2.12.17', '2.13.9']\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v1\n    - name: Setup Scala\n      uses: olafurpg/setup-scala@v12\n      with:\n        java-version: \"adopt@1.8\"\n    - name: Coursier cache\n      uses: coursier/cache-action@v5\n    - name: Build and Test\n      working-directory: ./quix-backend\n      run: |\n        sbt ++${{matrix.scala_version}} -v -Dfile.encoding=UTF-8 test publishM2\n        if [[ ${{matrix.scala_version}} = '2.12.17' ]]\n        then\n          mvn --quiet -f quix-webapps/quix-web-spring/pom.xml test\n        fi\n        rm -rf \"$HOME/.ivy2/local\" || true\n        find $HOME/Library/Caches/Coursier/v1        -name \"ivydata-*.properties\" -delete || true\n        find $HOME/.ivy2/cache                       -name \"ivydata-*.properties\" -delete || true\n        find $HOME/.cache/coursier/v1                -name \"ivydata-*.properties\" -delete || true\n        find $HOME/.sbt                              -name \"*.lock\"               -delete || true\n"
  },
  {
    "path": ".github/workflows/quix-documentation-publish.yml",
    "content": "# This Workflow will publish Documentation on any push to master branch into \n# the documentation folder.\nname: Quix Documentation Publish\non:\n  workflow_dispatch:\n    inputs:\n      comment:\n        description: 'Comment'     \n        required: true\n        default: 'Publish'\n  push:\n    branches: ['master']\n    paths:\n    - 'documentation/**/*.*'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v2\n    - uses: actions/setup-node@v2\n      with:\n        node-version: '14.19.1'\n    - run: npm install\n      working-directory: 'documentation/website'\n    - run: npm run build\n      working-directory: 'documentation/website'\n    - name: Deploy\n      if: success()\n      uses: crazy-max/ghaction-github-pages@v2\n      with:\n        target_branch: gh-pages\n        build_dir: documentation/website/build/quix\n      env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}"
  },
  {
    "path": ".github/workflows/quix-frontend-publish.yml",
    "content": "# Build on each branch and Publish to NPM on master if version bumped\nname: Quix Frontend Build & Publish\non:\n  workflow_dispatch:\n    inputs:\n      comment:\n        description: 'Comment'     \n        required: true\n        default: 'Publish'\n  push:\n    paths:\n    - 'quix-frontend/**'\ndefaults:\n  run:\n    working-directory: quix-frontend\njobs:\n  build_and_test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '14.19.1'\n      - uses: samin/mysql-action@v1.3\n        with:\n          mysql database: 'quixtest'\n          mysql version: '5.7'\n      \n      - run: npm ci\n      - run: npm run build:ci\n      - run: npm test\n\n      - name: Prepare Publish To NPM\n        if: github.ref == 'refs/heads/master'\n        run: |\n          echo \"registry=http://registry.npmjs.org/\" >> .npmrc\n          echo \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> .npmrc\n        env: \n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n      \n      - name: Publish\n        if: github.ref == 'refs/heads/master'\n        run: npm run publish\n        env: \n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/quix-frontend-release.yml",
    "content": "name: Quix Frontend Release DockerHub\n\non:\n  workflow_dispatch:\n    inputs:\n      comment:\n        description: 'Comment'     \n        required: true\n        default: 'Release'\n      tags:\n        description: 'Tags'\n      labels:\n        description: 'Labels'\n        \n  release:\n    types: [published]\n\ndefaults:\n  run:\n    working-directory: quix-frontend\n\njobs:\n  push_to_registry:\n    name: Push Docker image to Docker Hub\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v2\n      \n      - name: Log in to Docker Hub\n        uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_PASSWORD }}\n      \n      - name: Extract metadata (tags, labels) for Docker\n        id: meta\n        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38\n        with:\n          images: wixquix/quix-frontend\n          \n      - name: Log\n        run: |\n          echo \"${{ steps.meta.outputs.tags }} ${{ steps.meta.outputs.labels }}\" \\\n          && echo \"${{github.event.inputs.tags}}\" \\\n          && echo \"${{github.event.inputs.labels}}\" \n      \n      - name: Build and push Docker image\n        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc\n        with:\n          context: ./quix-frontend/\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Created by https://www.gitignore.io/api/maven,scala,jetbrains\n\n### Maven ###\ntarget/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\npom.xml.next\nrelease.properties\ndependency-reduced-pom.xml\nbuildNumber.properties\n.mvn/timing.properties\n\n\n### Scala ###\n*.class\n*.log\n\n# sbt specific\n.cache\n.history\n.lib/\ndist/*\ntarget/\nlib_managed/\nsrc_managed/\nproject/boot/\nproject/plugins/project/\n\n# Scala-IDE specific\n.scala_dependencies\n.worksheet\n\n\n### JetBrains ###\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n# User-specific stuff:\n# .idea/workspace.xml\n# .idea/tasks.xml\n# .idea/dictionaries\n\n# Sensitive or high-churn files:\n# .idea/dataSources.ids\n# .idea/dataSources.xml\n# .idea/sqlDataSources.xml\n# .idea/dynamic.xml\n# .idea/uiDesigner.xml\n\n# Gradle:\n# .idea/gradle.xml\n# .idea/libraries\n\n# Mongo Explorer plugin:\n# .idea/mongoSettings.xml\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\n\n.DS_Store\n.vscode\nnode_modules\n\n.env\n\n\n## Terraform\n*.tfstate\n*.tfstate.backup\n.terraform\nvpc.plan\nterraform.tfvars\n\nquix-frontend/.npmrc\ndocumentation/website/build/"
  },
  {
    "path": ".travis.yml",
    "content": "jobs:\n  include:\n    - stage: test\n      name: \"Frontend\"\n      language: node_js\n      dist: bionic\n      node_js: 14\n      cache: npm\n      env: PROJECT=frontend\n      services:\n        - mysql\n      before_install:\n        - mysql -e 'CREATE DATABASE IF NOT EXISTS quixtest;'\n      install:\n        - $TRAVIS_BUILD_DIR/build-selector.sh $TRAVIS_COMMIT_RANGE $PROJECT || exit 0\n        - cd ./quix-frontend\n        - npm install\n      script:\n        - $TRAVIS_BUILD_DIR/build-selector.sh $TRAVIS_COMMIT_RANGE $PROJECT || exit 0\n        - npm run build:ci\n        - npm run test\n      deploy:\n        provider: script\n        script: bash npm-deploy.sh\n        edge: true\n        on:\n          branch: master\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Wix Incubator\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Quix\n![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)\n\n[![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)\n[![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)\n\nQuix 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.\n\n* [Installation](https://wix-incubator.github.io/quix/docs/installation)\n\n## Intro\nCheck out these blog posts introducing Quix on Wix Engineering Blog : \n* [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)\n* [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)\n\n## Quick start\nUsing `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. \n\n```bash\nmkdir quix && cd quix\ncurl https://raw.githubusercontent.com/wix/quix/master/docker-compose.prebuilt.yml -o docker-compose.yml\ncurl https://raw.githubusercontent.com/wix/quix/master/env-example -o .env\ndocker-compose up\n```\n\nBe 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.\n\nFor support please contact us via [oss@wix.com](mailto:oss@wix.com).\n\n## Main features\n- [Query management](#Management) - organize your notebooks in folders for easy access and sharing\n- [Visualizations](#Visualizations) - quickly plot time and bar series (more visualizations to follow)\n- [DB Explorer](#Explorer) - explore your data sources\n- Search - search notes of all users\n\n#### Management\n![](documentation/docs/assets/management.gif)\n\n#### Visualizations\n![](documentation/docs/assets/chart.gif)\n\n#### Explorer\n![](documentation/docs/assets/db.gif)\n\n## License\nMIT\n"
  },
  {
    "path": "build-selector.sh",
    "content": "#!/usr/bin/env bash\n\nif [ -z $2 ]; then\n  GIT_RANGE=\"HEAD^1\"\n  BUILD_TYPE=$1\nelse\n  GIT_RANGE=\"$1\"\n  BUILD_TYPE=\"$2\"\nfi\n\necho GIT RANGE=$GIT_RANGE\necho BUILD_TYPE=$BUILD_TYPE\n\ndeclare -A PATTERN_MAP\n\nPATTERN_MAP[frontend]='^((quix-frontend/)|\\.travis\\.yml)'\nPATTERN_MAP[backend]='^(quix-backend/|\\.travis\\.yml)'\n\n\ngit diff --name-only $GIT_RANGE | grep -qE ${PATTERN_MAP[$BUILD_TYPE]}"
  },
  {
    "path": "docker-compose.prebuilt.yml",
    "content": "version: '3'\nservices:\n  backend:\n    image: wixquix/quix-backend:latest\n    ports:\n      - \"8081:8081\"\n    depends_on:\n      - presto\n    env_file:\n      - .env\n    environment:\n      - MODULES\n      - AUTH_COOKIE\n      - AUTH_SECRET\n      - AUTH_TYPE\n  frontend:\n    image: wixquix/quix-frontend:latest\n    ports:\n      - \"3000:3000\"\n    depends_on:\n      - backend\n      - db\n    env_file:\n      - .env\n    environment:\n      - DB_NAME\n      - DB_USER\n      - DB_PASS\n      - DB_HOST\n      - DB_PORT\n      - BACKEND_INTERNAL_URL\n      - BACKEND_PUBLIC_URL\n      - GOOGLE_SSO_CLIENT_ID\n      - GOOGLE_SSO_SECRET\n      - AUTH_COOKIE\n      - AUTH_SECRET\n      - AUTH_TYPE\n      - APPMETRICS_PORT\n      - ENABLE_APPMETRICS\n      - MODULES\n  db:\n    image: \"mysql:5.7\"\n    restart: always\n    environment:\n      MYSQL_ALLOW_EMPTY_PASSWORD: \"yes\"\n      MYSQL_DATABASE: \"quix\"\n    volumes:\n      - \"db_volume:/var/lib/mysql\"\n  presto:\n    image: \"starburstdata/presto:340-e\"\n    ports:\n      - \"8181:8080\"\n\nvolumes:\n  db_volume:\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: \"3\"\nservices:\n  backend:\n    build: ./quix-backend/\n    ports:\n      - \"8081:8081\"\n    depends_on:\n      - presto\n      - postgres\n    env_file:\n      - .env\n    environment:\n      - MODULES\n      - AUTH_COOKIE\n      - AUTH_SECRET\n      - AUTH_TYPE\n  frontend:\n    build: ./quix-frontend/\n    ports:\n      - \"3000:3000\"\n    depends_on:\n      - backend\n      - db\n    env_file:\n      - .env\n    environment:\n      - DB_NAME\n      - DB_USER\n      - DB_PASS\n      - DB_HOST\n      - DB_PORT\n      - BACKEND_INTERNAL_URL\n      - BACKEND_PUBLIC_URL\n      - GOOGLE_SSO_CLIENT_ID\n      - GOOGLE_SSO_SECRET\n      - AUTH_COOKIE\n      - AUTH_SECRET\n      - AUTH_TYPE\n      - APPMETRICS_PORT\n      - ENABLE_APPMETRICS\n      - MODULES\n  db:\n    image: \"mysql:5.7\"\n    restart: always\n    environment:\n      MYSQL_ALLOW_EMPTY_PASSWORD: \"yes\"\n      MYSQL_DATABASE: \"quix\"\n    volumes:\n      - \"db_volume:/var/lib/mysql\"\n  presto:\n    image: \"starburstdata/presto:340-e\"\n    ports:\n      - \"8181:8080\"\n  postgres:\n    image: \"aa8y/postgres-dataset:dellstore\"\n    ports:\n      - \"5432:5432\"\n\nvolumes:\n  db_volume:\n"
  },
  {
    "path": "documentation/docs/about.md",
    "content": "---\nid: about\ntitle: About\nsidebar_label: About\n---\n\nQuix 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.\n\n* [Demo](https://quix-demo.io/)\n* [Installation](/quix/docs/installation)\n\n## Quick start\nUsing 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. \n\n```bash\nmkdir quix && cd quix\ncurl https://raw.githubusercontent.com/wix/quix/master/docker-compose.prebuilt.yml -o docker-compose.yml\ncurl https://raw.githubusercontent.com/wix/quix/master/env-example -o .env\ndocker-compose up\n```\n\nBe 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.\n\nFor support please conatct us via [oss@wix.com](mailto:oss@wix.com).\n\n## Main features\n- [Query management](#management) - organize your notebooks in folders for easy access and sharing\n- [Visualizations](#visualizations) - quickly plot time and bar series (more visualizations to follow)\n- [DB Explorer](#explorer) - explore your data sources\n- Search - search notes of all users\n\n#### Management\n![](assets/management.gif)\n\n#### Visualizations\n![](assets/chart.gif)\n\n#### Explorer\n![](assets/db.gif)\n\n"
  },
  {
    "path": "documentation/docs/architecture.md",
    "content": "---\nid: architecture\ntitle: Architecture\nsidebar_label: Architecture\n---\n\n![](assets/architecture.png)\n\nQuix consists of three main elements:\n\n* Frontend to serve UI and manage notebooks\n* Backend to communicate with Presto\n* DB for storing notebooks\n\nEach component is run in a separate Docker container, and all of them are managed by a single Docker Compose configuration.\n\nThere's also a fourth Docker container provided with this repository running Presto inside Docker Compose, but it's for demonstration purposes only."
  },
  {
    "path": "documentation/docs/athena.md",
    "content": "---\nid: athena\ntitle: Amazon Athena\nsidebar_label: Athena\n---\n## Features\nWork with Amazon Athena tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n## Setup\n\n### 1. Create a new IAM Policy\n\nCreate a new IAM policy to allow access to your bucket\n```json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:GetObject\",\n                \"s3:PutObject\"\n            ],\n            \"Resource\": [\n                \"arn:aws:s3:::your-bucket-name/*\"\n            ]\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:GetBucketLocation\",\n                \"s3:ListBucket\"\n            ],\n            \"Resource\": [\n                \"arn:aws:s3:::your-bucket-name\"\n            ]\n        }\n    ]\n}\n```\n\n### 2. Create a new IAM user\nCreate a new user with `Programmatic Access`. Attach security policy `AmazonAthenaFullAccess` along with policy created in step 1. \n\n\n### 3. Pick a new name for your athena note and update .env\n\nAdd/update following properties to .env file to configure your new note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo` |\n| `MODULES_FOO_ENGINE`      | note type | `athena` |\n| `MODULES_FOO_OUTPUT` | s3 bucket for results      |   `s3://some-bucket-id/` |\n| `MODULES_FOO_REGION` | aws region      |   `us-east-1` |\n| `MODULES_FOO_DATABASE` | default database      |   `default` |\n| `MODULES_FOO_AWS_ACCESS_KEY_ID` | aws access key      |    |\n| `MODULES_FOO_AWS_SECRET_KEY` | awe secret key      |   |\n\nExample of possible configuration that will create note type named foo : \n```properties\nMODULES_FOO_ENGINE=athena\nMODULES_FOO_OUTPUT=s3://some-bucket-id/\nMODULES_FOO_REGION=us-east-1\nMODULES_FOO_DATABASE=default\nMODULES_FOO_AWS_ACCESS_KEY_ID=123\nMODULES_FOO_AWS_SECRET_KEY=abc\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/bigquery.md",
    "content": "---\nid: bigquery\ntitle: Google BigQuery\nsidebar_label: BigQuery\n---\n## Features\nWork with Google bigquery tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n## Setup\n\n### 1. Create a new service account\nGo to `Api & Services` -> `Credentials` and click `Create credentials` with `Service Account key`.\nChoose new service account in the dropdown, enter quix-bigquery-user as username, \n`BigQuery Admin` as role, and `Json` as key type.\n\nStore resulting json in a secure location and use `base64` command line tool to calculate the base64 string of the file contents.\nAlternatively use some online tool like https://www.base64encode.org/ to process the contents of json with credentials.     \n\n### 2. Pick a new name for your bigquery note and update .env\n\nAdd/update following properties in .env file to configure your new note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo` |\n| `MODULES_FOO_ENGINE`      | note type | `bigquery` |\n| `MODULES_FOO_CREDENTIALS_BASE64` | base64 value of your credentials.json      |  `AABB111222` |\n\n\nExample of possible configuration that will create new bigquery note named foo : \n```properties\nMODULES_BQ_ENGINE=bigquery\nMODULES_BQ_SYNTAX=ansi_sql\nMODULES_BQ_CREDENTIALS_BASE64=AAABBBCCCDDDEEEFFFF\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/clickhouse.md",
    "content": "---\nid: clickhouse\ntitle: ClickHouse\nsidebar_label: ClickHouse\n---\n\n## Features\nUsing 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.\n\n\n## Setup\nTo setup [ClickHouse](https://clickhouse.tech/) note you have to perform the following :\n\n\n### 1. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `ru.yandex.clickhouse.ClickHouseDriver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:clickhouse://localhost:8123/test` |\n| `MODULES_FOO_USER` | db username      |   `user` |\n| `MODULES_FOO_PASS` | db password      |   `pass` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `ansi_sql` |\n\n\nexample of clickhouse jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=ru.yandex.clickhouse.ClickHouseDriver\nMODULES_FOO_URL=jdbc:clickhouse://localhost:8123/test\nMODULES_FOO_USER=your-user\nMODULES_FOO_PASS=your-password\nMODULES_FOO_SYNTAX=ansi_sql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/installation.md",
    "content": "---\nid: installation\ntitle: Installation\nsidebar_label: Installation\n---\n\n## Requirements\n* [Docker](https://www.docker.com/products)\n* [Docker Compose](https://docs.docker.com/compose/install/)\n\n## Running\nRun Docker Compose:\n\n```\ndocker-compose up\n```\n\nThe 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.\nYou will need an `.env` file to run it. We will configure it in the next step.\n\nTo access Quix, navigate to:  \n`http://localhost:3000`\n\n## Clone repository\n```\ngit clone https://github.com/wix-incubator/quix.git\n```\n## Configuration\nMost of the configuration you'll need is done through environment variables. docker-compose can load environment-variables easily through a `.env` file.\nYou 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. \n\n#### Presto\nBy default, Quix works with demo Presto instance that runs inside Docker Compose.  \nTo work with your real Presto DB, change `PRESTO_API` environment variable.\n\nNote that you need to specify full URL, including protocol, port and API version:\n* MODULES_PRESTO_API - `http://presto.my.domain:8181/v1`  \n\n  If you're running Presto locally, use the following instead of `localhost`:\n  * Your internal IP\n  * Or `host.docker.internal` (macOS only)\n\n#### DB\nQuix also uses MySQL to store notebooks and other application data. The default docker-compose uses a mysql container, so no further setup is needed. \nAs an alternative, you can also use an external MySQL database, by specifying some of the following variables:\n* DB_NAME - defaults to `quix`, must exist\n* DB_USER - defaults to `root`\n* DB_PASS - defaults to empty password\n* DB_HOST - defaults to `db`\n* DB_PORT - defaults to `3306`\n\n* 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.\n\n#### User authentication\nQuix 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:\n* AUTH_TYPE - can be `fake` or `google`. Defaults to `fake` (single-user mode).\n\nIf you use Google OAuth, you must supply the clientId and the secret:\n* GOOGLE_SSO_CLIENT_ID\n* GOOGLE_SSO_SECRET\n\nOther variables related to authentication:\n* AUTH_COOKIE - defaults to `__quix`. When using `google` auth, must be provided.\n* AUTH_SECRET - the encryption key for the cookie. Must be provided.\n* COOKIE_MAX_AGE - should be in seconds, default is 30 days.\n\n#### Configuration for custom deployment\nRunning quix with `docker-compose` should \"just work\", but when deploying quix, there are a couple more variables you might want to change:\n\n* BACKEND_INTERNAL_URL - An address + port number (no protocol) where you have the backend service deployed and accessible to the frontend service.\n* 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`.\n* ENABLE_APPMETRICS - Set this variable if you want to enable [appmetrics-dash](https://github.com/RuntimeTools/appmetrics-dash).\n* APPMETRICS_PORT - The port where appmetrics dashboard will be exposed.\n\n## Upgrading Quix\nThis takes into account a `docker-compose` setup. Extrapolate as needed if you have some other custom deployment. \n\n1. Backup your data, if possible.\n2. 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`.\n3. Stop the frontend and backend services - `docker-compose stop backend frontend`.\n4. Make sure all your environment variables are exported correctly in your current shell, specifically all the `DB_*` variables.\n5. Run DB migrations: `docker-compose run --no-deps --rm frontend scripts/run_migrations.sh`.\n6. Start services again `docker-compose up -d`.\n"
  },
  {
    "path": "documentation/docs/jdbc.md",
    "content": "---\nid: jdbc\ntitle: Jdbc\nsidebar_label: Jdbc\n---\n\n## Features\nUsing jdbc note you can use quix to query \n[MySQL](mysql.md), \n[ClickHouse](clickhouse.md), \n[PostgreSQL](postgresql.md), \nMicrosoft SQL Server, \n[MariaDB](mariadb.md), \n[Oracle](oracle.md), \nSQLite, \n[Redshift](redshift.md), \nFirebird, \nH2, \nHSQLDB, \nApache Derby, \nIBM DB2, \nTeradata and more. \n\nYou will be able to execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n## Setup\nTo setup jdbc note you have to perform the following two steps :\n\n### 1. Add new jdbc dependency to [Dockerfile](https://github.com/wix-incubator/quix/blob/master/quix-backend/Dockerfile)\nRight now quix is pre-bundled with several populat jdbc drivers. If your driver is missing from the list, \nyou should edit the [Dockerfile](https://github.com/wix-incubator/quix/blob/master/quix-backend/Dockerfile) and \nadd a line that will download the driver and another line to push it into `quix.jar` file \n\n\nExamples of pre-bundled jdbc drivers : \n```\nRUN wget -q -P BOOT-INF/lib/ \\\n    https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc/0.2.4/clickhouse-jdbc-0.2.4.jar \\\n    https://repo1.maven.org/maven2/org/postgresql/postgresql/42.2.10/postgresql-42.2.10.jar \\\n    https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.19/mysql-connector-java-8.0.19.jar \\\n    https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.30.1/sqlite-jdbc-3.30.1.jar \\\n    https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.5.4/mariadb-java-client-2.5.4.jar \\\n    https://repo1.maven.org/maven2/org/hsqldb/hsqldb/2.5.0/hsqldb-2.5.0.jar \\\n    https://maven.ceon.pl/artifactory/repo/com/oracle/ojdbc/ojdbc10/19.3.0.0/ojdbc10-19.3.0.0.jar \\\n    https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/8.2.1.jre11/mssql-jdbc-8.2.1.jre11.jar\n\nRUN jar uf0 quix.jar \\\n    BOOT-INF/lib/clickhouse-jdbc-0.2.4.jar \\\n    BOOT-INF/lib/postgresql-42.2.10.jar \\\n    BOOT-INF/lib/mysql-connector-java-8.0.19.jar \\\n    BOOT-INF/lib/sqlite-jdbc-3.30.1.jar \\\n    BOOT-INF/lib/mariadb-java-client-2.5.4.jar \\\n    BOOT-INF/lib/hsqldb-2.5.0.jar \\\n    BOOT-INF/lib/ojdbc10-19.3.0.0.jar \\\n    BOOT-INF/lib/mssql-jdbc-8.2.1.jre11.jar\n``` \n\n### 2. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `org.postgresql.Driver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:postgresql:postgres` |\n| `MODULES_FOO_USER` | db username      |   `user` |\n| `MODULES_FOO_PASS` | db password      |   `pass` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `mysql` or `ansi_sql` |\n\n\nexample of postgres jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=org.postgresql.Driver\nMODULES_FOO_URL=jdbc:postgresql:postgres\nMODULES_FOO_USER=your-user\nMODULES_FOO_PASS=your-password\nMODULES_FOO_SYNTAX=ansi_sql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/mariadb.md",
    "content": "---\nid: mariadb\ntitle: MariaDB\nsidebar_label: MariaDB\n---\n\n## Features\nWork with MariaDB tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n## Setup\nTo setup MariaDB note you have to perform the following two steps :\n\n### 1. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `org.mariadb.jdbc.Driver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:mariadb://localhost:3306/DB` |\n| `MODULES_FOO_USER` | db username      |   `user` |\n| `MODULES_FOO_PASS` | db password      |   `pass` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `mysql`|\n\n\nexample of mariadb jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=org.mariadb.jdbc.Driver\nMODULES_FOO_URL=jdbc:mariadb://localhost:3306/DB\nMODULES_FOO_USER=your-username\nMODULES_FOO_PASS=your-password\nMODULES_FOO_SYNTAX=mysql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/mysql.md",
    "content": "---\nid: mysql\ntitle: MySQL\nsidebar_label: MySQL\n---\n\n## Features\nWork with MySQL tables straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n\n## Setup\nTo setup MySQL note you have to perform the following two steps :\n\n### 1. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `com.mysql.jdbc.Driver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:mysql://localhost/test` |\n| `MODULES_FOO_USER` | db username      |   `user` |\n| `MODULES_FOO_PASS` | db password      |   `pass` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `mysql`|\n\n\nexample of mysql jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=com.mysql.jdbc.Driver\nMODULES_FOO_URL=jdbc:mysql://localhost/test\nMODULES_FOO_USER=your-username\nMODULES_FOO_PASS=your-password\nMODULES_FOO_SYNTAX=mysql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/oracle.md",
    "content": "---\nid: oracle\ntitle: Oracle\nsidebar_label: Oracle\n---\n\n## Features\nWork with Oracle straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n## Setup\nTo setup Oracle note you have to perform the following two steps :\n\n### 1. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new oracle note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `oracle.jdbc.driver.OracleDriver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:oracle:thin:@localhost:1521:db` |\n| `MODULES_FOO_USER` | db username      |   `user` |\n| `MODULES_FOO_PASS` | db password      |   `pass` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `ansi_sql` |\n\n\nexample of oracle jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=oracle.jdbc.driver.OracleDriver\nMODULES_FOO_URL=jdbc:oracle:thin:@localhost:1521:db\nMODULES_FOO_USER=your-user\nMODULES_FOO_PASS=your-password\nMODULES_FOO_SYNTAX=ansi_sql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/postgresql.md",
    "content": "---\nid: postgresql\ntitle: PostgreSQL\nsidebar_label: PostgreSQL\n---\n\n## Features\nWork with PostgreSQL straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n\n## Setup\nTo setup PostgreSQL note you have to perform the following two steps :\n\n### 1. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new postgresql note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `org.postgresql.Driver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:postgresql:postgres` |\n| `MODULES_FOO_USER` | db username      |   `user` |\n| `MODULES_FOO_PASS` | db password      |   `pass` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `ansi_sql` |\n\n\nexample of postgresql jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=org.postgresql.Driver\nMODULES_FOO_URL=jdbc:postgresql:postgres\nMODULES_FOO_USER=your-user\nMODULES_FOO_PASS=your-password\nMODULES_FOO_SYNTAX=ansi_sql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/docs/presto.md",
    "content": "---\nid: presto\ntitle: Presto\nsidebar_label: Presto\n---\n## Features\nQuix is a great tool for querying Presto. You can execute multiple queries in parallel, \nstream results straight to your browser, download them as csv, build visualizations, \nshare your notes with other people in your organization and more.\n\n## Setup\n\n### 1. Pick a new name for your presto note and update .env\n\nAdd the following properties to the .env file to configure your new presto note\n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo` |\n| `MODULES_FOO_ENGINE`      | note type | `presto` |\n| `MODULES_FOO_API` | presto url      |   `http://presto.your-domain.com:8080/v1` |\n| `MODULES_FOO_CATALOG` | default catalog      |   `system` |\n| `MODULES_FOO_SCHEMA` | default schema      |   `runtime` |\n| `MODULES_FOO_SOURCE` | default source      |   `quix` |\n\nExample of possible configuration that will create Presto note named foo : \n```properties\nMODULES_FOO_ENGINE=presto\nMODULES_FOO_API=http://presto:8080/v1\nMODULES_FOO_CATALOG=system\nMODULES_FOO_SCHEMA=runtime\nMODULES_FOO_SOURCE=quix\n```\n\n## Troubleshooting\n"
  },
  {
    "path": "documentation/docs/python.md",
    "content": "---\nid: python\ntitle: Python\nsidebar_label: Python\n---\n## Features\n* Execute lightweight Python scripts straight from Quix\n* Manage pip packages on user-level\n* Render and visualize results in Quix\n\n## Ideas for using python in Quix\n1) Python notes can be used to orchestrate more complex processes that are hard to\nachieve in simple sql note, so it's a perfect tool for simple prototyping and ETLS.  \n\n2) You can query much more data sources in addition to out-of-the-box Quix notes.\n For example, PyMongo can be used to query MongoDB, hbase-python for HBase, boto3 for s3, python-firebase for firebase and many more. \n\n## Setup\n\n### 1. Pick a new name for your python note and update .env\n\nAdd the following properties to the .env file to configure your new python note\n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo` |\n| `MODULES_FOO_ENGINE`      | note type | `python` |\n| `MODULES_FOO_SYNTAX`      | note syntax | `python` |\n| `MODULES_FOO_PIP_INDEX`      | custom pip index url | `https://your-own-pypi-mirror.org/simple` |\n| `MODULES_FOO_PIP_EXTRA_INDEX`      | extra pip index url | `https://pypi.python.org/simple` |\n| `MODULES_FOO_PIP_PACKAGES`      | list of mandatory pip packages | `ujson,pyhive` |\n| `MODULES_FOO_SCRIPTS_DIR`      | dir that will be used to store each user temp files | `/tmp/quix-python` |\n| `MODULES_FOO_ADDITIONAL_CODE_FILE`      | additional code that would be prepended to each python note | `/tmp/quix-python/init.py` |\n\nExample : \n```properties\nMODULES=foo\nMODULES_FOO_ENGINE=python\nMODULES_FOO_SYNTAX=python\nMODULES_FOO_PIP_INDEX=https://pypi.your-domain.com/simple\nMODULES_FOO_PIP_EXTRA_INDEX=https://pypi.python.org/simple\nMODULES_FOO_PIP_PACKAGES=ujson,requests\nMODULES_FOO_SCRIPTS_DIR=/tmp/quix-python\nMODULES_FOO_ADDITIONAL_CODE_FILE=/tmp/quix-python/init.py\n```\n\n## Troubleshooting\n"
  },
  {
    "path": "documentation/docs/redshift.md",
    "content": "---\nid: redshift\ntitle: Amazon Redshift\nsidebar_label: Redshift\n---\n\n## Features\nQuery Amazon Redshift data warehouse straight from Quix, execute multiple queries in parallel, explore the db tree, visualize and download the results into csv.\n\n\n## Setup\nTo setup Amazon Redshift note you have to perform the following steps :\n\n### 1. Obtain link to redshift jdbc driver \nGo to https://docs.aws.amazon.com/redshift/latest/mgmt/configure-jdbc-connection.html#download-jdbc-driver and choose the jar file that you need.\nFor example, \n```\nhttps://s3.amazonaws.com/redshift-downloads/drivers/jdbc/1.2.41.1065/RedshiftJDBC42-no-awssdk-1.2.41.1065.jar\n``` \n\n### 2. Update [Dockerfile](https://github.com/wix-incubator/quix/blob/master/quix-backend/Dockerfile) \nYou need to update the Dockerfile that prepares image of quix-backend to include the missing jar. \nEdit it and add a line that will download the driver and another line to push it into `quix.jar` file \n\n```\nRUN wget -q -P BOOT-INF/lib/ \\\n    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\n\nRUN jar uf0 quix.jar \\\n    BOOT-INF/lib/RedshiftJDBC42-no-awssdk-1.2.41.1065.jar\n```\n### 3. Build the quix-backend image\n\nExecute the following command to prepare a new docker image of quix-backend \n```\ndocker-compose build backend\n``` \n\n\n### 4. Pick new name and update .env\n\nAdd/update following properties to .env file to configure your new Amazon Redshift note    \n\n| Variables        | Meaning           | Example  |\n| ------------- |:-------------:| -----:|\n| `MODULES`      | list of registered notes | `foo,boo,prod,qa` |\n| `MODULES_FOO_ENGINE`      | note type | `jdbc` |\n| `MODULES_FOO_DRIVER` | jdbc driver class      |   `com.amazon.redshift.jdbc.Driver` |\n| `MODULES_FOO_URL` | jdbc url      |   `jdbc:redshift://examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com:5439/dev` |\n| `MODULES_FOO_SYNTAX` | syntax marker      |   `ansi_sql` |\n\n\nexample of redshift jdbc note that will be named `foo` in the UI\n\n```properties\nMODULES=<comma separated list of your modules>,foo\n\nMODULES_FOO_ENGINE=jdbc\nMODULES_FOO_DRIVER=com.amazon.redshift.jdbc.Driver\nMODULES_FOO_URL=jdbc:redshift://examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com:5439/dev\nMODULES_FOO_SYNTAX=ansi_sql\n```\n\n## Troubleshooting"
  },
  {
    "path": "documentation/website/README.md",
    "content": "This website was created with [Docusaurus](https://docusaurus.io/).\n\n# What's In This Document\n\n* [Get Started in 5 Minutes](#get-started-in-5-minutes)\n* [Directory Structure](#directory-structure)\n* [Editing Content](#editing-content)\n* [Adding Content](#adding-content)\n* [Full Documentation](#full-documentation)\n\n# Get Started in 5 Minutes\n\n1. Make sure all the dependencies for the website are installed:\n\n```sh\n# Install dependencies\n$ yarn\n```\n2. Run your dev server:\n\n```sh\n# Start the site\n$ yarn start\n```\n\n## Directory Structure\n\nYour project file structure should look something like this\n\n```\nmy-docusaurus/\n  docs/\n    doc-1.md\n    doc-2.md\n    doc-3.md\n  website/\n    blog/\n      2016-3-11-oldest-post.md\n      2017-10-24-newest-post.md\n    core/\n    node_modules/\n    pages/\n    static/\n      css/\n      img/\n    package.json\n    sidebar.json\n    siteConfig.js\n```\n\n# Editing Content\n\n## Editing an existing docs page\n\nEdit docs by navigating to `docs/` and editing the corresponding document:\n\n`docs/doc-to-be-edited.md`\n\n```markdown\n---\nid: page-needs-edit\ntitle: This Doc Needs To Be Edited\n---\n\nEdit me...\n```\n\nFor more information about docs, click [here](https://docusaurus.io/docs/en/navigation)\n\n## Editing an existing blog post\n\nEdit blog posts by navigating to `website/blog` and editing the corresponding post:\n\n`website/blog/post-to-be-edited.md`\n```markdown\n---\nid: post-needs-edit\ntitle: This Blog Post Needs To Be Edited\n---\n\nEdit me...\n```\n\nFor more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog)\n\n# Adding Content\n\n## Adding a new docs page to an existing sidebar\n\n1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`:\n\n```md\n---\nid: newly-created-doc\ntitle: This Doc Needs To Be Edited\n---\n\nMy new content here..\n```\n\n1. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`:\n\n```javascript\n// Add newly-created-doc to the Getting Started category of docs\n{\n  \"docs\": {\n    \"Getting Started\": [\n      \"quick-start\",\n      \"newly-created-doc\" // new doc here\n    ],\n    ...\n  },\n  ...\n}\n```\n\nFor more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation)\n\n## Adding a new blog post\n\n1. Make sure there is a header link to your blog in `website/siteConfig.js`:\n\n`website/siteConfig.js`\n```javascript\nheaderLinks: [\n    ...\n    { blog: true, label: 'Blog' },\n    ...\n]\n```\n\n2. Create the blog post with the format `YYYY-MM-DD-My-Blog-Post-Title.md` in `website/blog`:\n\n`website/blog/2018-05-21-New-Blog-Post.md`\n\n```markdown\n---\nauthor: Frank Li\nauthorURL: https://twitter.com/foobarbaz\nauthorFBID: 503283835\ntitle: New Blog Post\n---\n\nLorem Ipsum...\n```\n\nFor more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog)\n\n## Adding items to your site's top navigation bar\n\n1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`:\n\n`website/siteConfig.js`\n```javascript\n{\n  headerLinks: [\n    ...\n    /* you can add docs */\n    { doc: 'my-examples', label: 'Examples' },\n    /* you can add custom pages */\n    { page: 'help', label: 'Help' },\n    /* you can add external links */\n    { href: 'https://github.com/facebook/Docusaurus', label: 'GitHub' },\n    ...\n  ],\n  ...\n}\n```\n\nFor more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation)\n\n## Adding custom pages\n\n1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`:\n1. 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:\n\n`website/siteConfig.js`\n```javascript\n{\n  headerLinks: [\n    ...\n    { page: 'my-new-custom-page', label: 'My New Custom Page' },\n    ...\n  ],\n  ...\n}\n```\n\nFor more information about custom pages, click [here](https://docusaurus.io/docs/en/custom-pages).\n\n# Full Documentation\n\nFull documentation can be found on the [website](https://docusaurus.io/).\n\n"
  },
  {
    "path": "documentation/website/blog/2019-11-25-first-release.md",
    "content": "---\ntitle: First release\nauthor: Quix Team\n---\nQuix is a notebook manager that focuses on ease of use and shareability.  \nIt aims to be a shared space for your company's BI insights and know-how.\n\nSince 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.\n\nIf you're in the market for an intuitive and fast tool to query and share your data, give Quix a try:\n* [Online demo](https://quix-demo.io/)\n* Quick start\n```bash\nmkdir quix && cd quix\ncurl https://raw.githubusercontent.com/wix/quix/master/docker-compose.prebuilt.yml -o docker-compose.yml\ncurl https://raw.githubusercontent.com/wix/quix/master/env-example -o .env\ndocker-compose up\n```\n* [Full installation](https://wix.github.io/quix/docs/installation)\n\n### Here's what's available in our first release:\n\n#### Notebook/note management with multi-user support\n* Shareable folders/notebooks/notes\n* Favorite notebooks\n* Full-text note search across all users\n* Readonly access to the notebooks of all users\n\n#### Query editor\n* Multiple statements\n* Syntax highlighting\n* Live syntax validation and autocompletion (currently for Presto only)\n* Keyboard shortcuts\n* Typed parameters (String, Boolean, Number, Date, Option, List)\n* Export results as CSV\n\n#### One-click visualizations\n* Timeline chart\n* Bar chart\n* Pie chart\n\n#### DB types you can query\n* Presto (supports live syntax validation and basic autocompletion)\n* Amazon Athena\n* Google BigQuery\n* Generic JDBC (MySQL, PostgreSQL, SQL Server, ClickHouse, etc...)\n\n#### DB Explorer\n* Navigate, search and preview your catalogs and tables\n\n#### What's in the pipeline?\n* Python note\n* More SSO options (OpenID)\n* More visualizations\n* Note embedding\n* Scheduled queries\n* Public queries\n* SDK for extending the base functionality of Quix\n\n#### Contributors\n@frolovv, @sthuck, @antonpod, @ittaym, @yaarams, @stas-slu, @shl3vi, @amitmarx, @kgshv, @erezr\n"
  },
  {
    "path": "documentation/website/core/Footer.js",
    "content": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nconst React = require('react');\n\nclass Footer extends React.Component {\n  docUrl(doc, language) {\n    const baseUrl = this.props.config.baseUrl;\n    const docsUrl = this.props.config.docsUrl;\n    const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;\n    const langPart = `${language ? `${language}/` : ''}`;\n    return `${baseUrl}${docsPart}${langPart}${doc}`;\n  }\n\n  pageUrl(doc, language) {\n    const baseUrl = this.props.config.baseUrl;\n    return baseUrl + (language ? `${language}/` : '') + doc;\n  }\n\n  render() {\n    return (\n      <footer className=\"nav-footer\" id=\"footer\">\n        <section className=\"sitemap\">\n          <a href={this.props.config.baseUrl} className=\"nav-home\">\n            {this.props.config.footerIcon && (\n              <img\n                src={this.props.config.baseUrl + this.props.config.footerIcon}\n                alt={this.props.config.title}\n              />\n            )}\n          </a>\n          <div>\n            <h5>Docs</h5>\n            <a href={this.docUrl('about.html#quick-start')}>\n              Quick Start\n            </a>\n            <a href={this.docUrl('installation.html')}>\n              Installation\n            </a>\n          </div>\n\n          <div>\n            <h5>Social</h5>\n            <a href={`${this.props.config.baseUrl}blog`}>Blog</a>\n            <a\n              className=\"github-button\"\n              href={this.props.config.repoUrl}\n              data-icon=\"octicon-star\"\n              data-count-href=\"/wix/quix/stargazers\"\n              data-show-count=\"true\"\n              data-count-aria-label=\"# stargazers on GitHub\"\n              aria-label=\"Star this project on GitHub\">\n              Quix\n            </a>\n          </div>\n\n          <div>\n            <h5>Contact Us</h5>\n            <a href=\"mailto:oss@wix.com\">By Email</a>\n          </div>\n        </section>\n        <section className=\"copyright\">{this.props.config.copyright}</section>\n      </footer>\n    );\n  }\n}\n\nmodule.exports = Footer;\n"
  },
  {
    "path": "documentation/website/i18n/en.json",
    "content": "{\n  \"_comment\": \"This file is auto-generated by write-translations.js\",\n  \"localized-strings\": {\n    \"next\": \"Next\",\n    \"previous\": \"Previous\",\n    \"tagline\": \"An easy-to-use notebook manager\",\n    \"docs\": {\n      \"about\": {\n        \"title\": \"About\",\n        \"sidebar_label\": \"About\"\n      },\n      \"architecture\": {\n        \"title\": \"Architecture\",\n        \"sidebar_label\": \"Architecture\"\n      },\n      \"athena\": {\n        \"title\": \"Amazon Athena\",\n        \"sidebar_label\": \"Athena\"\n      },\n      \"bigquery\": {\n        \"title\": \"Google BigQuery\",\n        \"sidebar_label\": \"BigQuery\"\n      },\n      \"clickhouse\": {\n        \"title\": \"ClickHouse\",\n        \"sidebar_label\": \"ClickHouse\"\n      },\n      \"installation\": {\n        \"title\": \"Installation\",\n        \"sidebar_label\": \"Installation\"\n      },\n      \"jdbc\": {\n        \"title\": \"Jdbc\",\n        \"sidebar_label\": \"Jdbc\"\n      },\n      \"mariadb\": {\n        \"title\": \"MariaDB\",\n        \"sidebar_label\": \"MariaDB\"\n      },\n      \"mysql\": {\n        \"title\": \"MySQL\",\n        \"sidebar_label\": \"MySQL\"\n      },\n      \"oracle\": {\n        \"title\": \"Oracle\",\n        \"sidebar_label\": \"Oracle\"\n      },\n      \"postgresql\": {\n        \"title\": \"PostgreSQL\",\n        \"sidebar_label\": \"PostgreSQL\"\n      },\n      \"presto\": {\n        \"title\": \"Presto\",\n        \"sidebar_label\": \"Presto\"\n      },\n      \"python\": {\n        \"title\": \"Python\",\n        \"sidebar_label\": \"Python\"\n      },\n      \"redshift\": {\n        \"title\": \"Amazon Redshift\",\n        \"sidebar_label\": \"Redshift\"\n      }\n    },\n    \"links\": {\n      \"Docs\": \"Docs\",\n      \"Blog\": \"Blog\",\n      \"GitHub\": \"GitHub\"\n    },\n    \"categories\": {\n      \"Introduction\": \"Introduction\",\n      \"Getting Started\": \"Getting Started\",\n      \"Supported datasources\": \"Supported datasources\"\n    }\n  },\n  \"pages-strings\": {\n    \"Help Translate|recruit community translators for your project\": \"Help Translate\",\n    \"Edit this Doc|recruitment message asking to edit the doc source\": \"Edit\",\n    \"Translate this Doc|recruitment message asking to translate the docs\": \"Translate\"\n  }\n}\n"
  },
  {
    "path": "documentation/website/package.json",
    "content": "{\n  \"scripts\": {\n    \"examples\": \"docusaurus-examples\",\n    \"start\": \"docusaurus-start\",\n    \"build\": \"docusaurus-build\",\n    \"publish-gh-pages\": \"docusaurus-publish\",\n    \"write-translations\": \"docusaurus-write-translations\",\n    \"version\": \"docusaurus-version\",\n    \"rename-version\": \"docusaurus-rename-version\"\n  },\n  \"devDependencies\": {\n    \"docusaurus\": \"^1.14.6\"\n  }\n}\n"
  },
  {
    "path": "documentation/website/pages/en/help.js",
    "content": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nconst React = require('react');\n\nconst CompLibrary = require('../../core/CompLibrary.js');\n\nconst Container = CompLibrary.Container;\nconst GridBlock = CompLibrary.GridBlock;\n\nfunction Help(props) {\n  const {config: siteConfig, language = ''} = props;\n  const {baseUrl, docsUrl} = siteConfig;\n  const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;\n  const langPart = `${language ? `${language}/` : ''}`;\n  const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`;\n\n  const supportLinks = [\n    {\n      content: `Learn more using the [documentation on this site.](${docUrl(\n        'doc1.html',\n      )})`,\n      title: 'Browse Docs',\n    },\n    {\n      content: 'Ask questions about the documentation and project',\n      title: 'Join the community',\n    },\n    {\n      content: \"Find out what's new with this project\",\n      title: 'Stay up to date',\n    },\n  ];\n\n  return (\n    <div className=\"docMainWrapper wrapper\">\n      <Container className=\"mainContainer documentContainer postContainer\">\n        <div className=\"post\">\n          <header className=\"postHeader\">\n            <h1>Need help?</h1>\n          </header>\n          <p>This project is maintained by a dedicated group of people.</p>\n          <GridBlock contents={supportLinks} layout=\"threeColumn\" />\n        </div>\n      </Container>\n    </div>\n  );\n}\n\nmodule.exports = Help;\n"
  },
  {
    "path": "documentation/website/pages/en/index.js",
    "content": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nconst React = require('react');\n\nconst CompLibrary = require('../../core/CompLibrary.js');\n\nconst Container = CompLibrary.Container;\nconst GridBlock = CompLibrary.GridBlock;\n\nclass HomeSplash extends React.Component {\n  render() {\n    const {siteConfig, language = ''} = this.props;\n    const {baseUrl, docsUrl} = siteConfig;\n    const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;\n    const langPart = `${language ? `${language}/` : ''}`;\n    const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`;\n\n    const SplashContainer = props => (\n      <div className=\"homeContainer\">\n        <div className=\"homeSplashFade\">\n          <div className=\"wrapper homeWrapper\">{props.children}</div>\n        </div>\n      </div>\n    );\n\n    const Logo = props => (\n      <div className=\"projectLogo\">\n        <img src={props.img_src} alt=\"Project Logo\" />\n      </div>\n    );\n\n    const ProjectTitle = () => (\n      <h2 className=\"projectTitle\">\n        {siteConfig.title}\n        <small>{siteConfig.tagline}</small>\n      </h2>\n    );\n\n    const PromoSection = props => (\n      <div className=\"section promoSection\">\n        <div className=\"promoRow\">\n          <div className=\"pluginRowBlock\">{props.children}</div>\n        </div>\n      </div>\n    );\n\n    const Button = props => (\n      <div className=\"pluginWrapper buttonWrapper\">\n        <a className=\"button\" href={props.href} target={props.target}>\n          {props.children}\n        </a>\n      </div>\n    );\n\n    return (\n      <SplashContainer>\n        <Logo img_src={`${baseUrl}img/chart.gif`} />\n        <div className=\"inner\">\n          <ProjectTitle siteConfig={siteConfig} />\n          <PromoSection>\n            <Button href={docUrl('about')}>Quick start</Button>\n            <Button href={docUrl('installation')}>Installation</Button>\n            <Button href=\"mailto:oss@wix.com\">Contact us</Button>\n          </PromoSection>\n        </div>\n      </SplashContainer>\n    );\n  }\n}\n\nclass Index extends React.Component {\n  render() {\n    const {config: siteConfig, language = ''} = this.props;\n    const {baseUrl, docsUrl} = siteConfig;\n    const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;\n    const langPart = `${language ? `${language}/` : ''}`;\n    const docUrl = (doc, hash) => `${baseUrl}${docsPart}${langPart}${doc}${hash ? `#${hash}` : ''}`;\n\n    const Block = props => (\n      <Container\n        padding={['bottom', 'top']}\n        id={props.id}\n        background={props.background}>\n        <GridBlock\n          align=\"center\"\n          contents={props.children}\n          layout={props.layout}\n        />\n      </Container>\n    );\n\n    const MainFeatures = () => (\n      <Block layout=\"threeColumn\" background=\"light\">\n        {[\n          {\n            content: 'You can run Quix in single-user or <br> multi-user mode via Google OAuth',\n            title: 'Multi-user web-app',\n          },\n          {\n            content: 'Quix uses notes to edit and run queries. <br> Notes live inside notebooks, which  <br>  can be organized in folders.',\n            title: 'Notebook manager',\n          },\n          {\n            content: 'The DB explorer lets you navigate, <br> search and preview your tables',\n            title: 'DB explorer',\n          },\n        ]}\n      </Block>\n    );\n\n    const MoreFeatures = () => (\n      <React.Fragment>\n        <Block layout=\"threeColumn\">\n          {[\n            {\n              content: 'Quix features smart charts which help <br> you quickly visualize your data',\n              title: 'One-click visualizations',\n            },\n            {\n              content: 'Search queries across all users',\n              title: 'Search',\n            },\n            {\n              content: 'Easily share your folders, notebooks and notes',\n              title: 'Shareability',\n            },\n          ]}\n        </Block>\n        <Block layout=\"threeColumn\" background=\"light\">\n          {[\n            {\n              content: 'View the history of queries executed by you <br> or other users',\n              title: 'History',\n            },\n            {},\n            {},\n          ]}\n        </Block>\n      </React.Fragment>\n    );\n\n    const Showcase = () => {\n      if ((siteConfig.users || []).length === 0) {\n        return null;\n      }\n\n      const showcase = siteConfig.users\n        .filter(user => user.pinned)\n        .map(user => (\n          <a href={user.infoLink} key={user.infoLink}>\n            <img src={user.image} alt={user.caption} title={user.caption} />\n          </a>\n        ));\n\n      const pageUrl = page => baseUrl + (language ? `${language}/` : '') + page;\n\n      return (\n        <div className=\"productShowcaseSection paddingBottom\">\n          <h2>Who is Using This?</h2>\n          <p>This project is used by all these people</p>\n          <div className=\"logos\">{showcase}</div>\n          <div className=\"more-users\">\n            <a className=\"button\" href={pageUrl('users.html')}>\n              More {siteConfig.title} Users\n            </a>\n          </div>\n        </div>\n      );\n    };\n\n    return (\n      <div>\n        <HomeSplash siteConfig={siteConfig} language={language} />\n        <div className=\"mainContainer\">\n          <MainFeatures />\n          <MoreFeatures />\n        </div>\n      </div>\n    );\n  }\n}\n\nmodule.exports = Index;\n"
  },
  {
    "path": "documentation/website/pages/en/users.js",
    "content": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nconst React = require('react');\n\nconst CompLibrary = require('../../core/CompLibrary.js');\n\nconst Container = CompLibrary.Container;\n\nclass Users extends React.Component {\n  render() {\n    const {config: siteConfig} = this.props;\n    if ((siteConfig.users || []).length === 0) {\n      return null;\n    }\n\n    const editUrl = `${siteConfig.repoUrl}/edit/master/website/siteConfig.js`;\n    const showcase = siteConfig.users.map(user => (\n      <a href={user.infoLink} key={user.infoLink}>\n        <img src={user.image} alt={user.caption} title={user.caption} />\n      </a>\n    ));\n\n    return (\n      <div className=\"mainContainer\">\n        <Container padding={['bottom', 'top']}>\n          <div className=\"showcaseSection\">\n            <div className=\"prose\">\n              <h1>Who is Using This?</h1>\n              <p>This project is used by many folks</p>\n            </div>\n            <div className=\"logos\">{showcase}</div>\n            <p>Are you using this project?</p>\n            <a href={editUrl} className=\"button\">\n              Add your company\n            </a>\n          </div>\n        </Container>\n      </div>\n    );\n  }\n}\n\nmodule.exports = Users;\n"
  },
  {
    "path": "documentation/website/sidebars.json",
    "content": "{\n  \"docs\": {\n    \"Introduction\": [\"about\", \"architecture\"],\n    \"Getting Started\": [\"installation\"],\n    \"Supported datasources\": [\"athena\", \"bigquery\", \"clickhouse\", \"jdbc\", \"mariadb\", \"mysql\", \"oracle\", \"postgresql\", \"presto\", \"python\", \"redshift\"]\n  }\n}\n"
  },
  {
    "path": "documentation/website/siteConfig.js",
    "content": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n// See https://docusaurus.io/docs/site-config for all the possible\n// site configuration options.\n\n// List of projects/orgs using your project for the users page.\nconst users = [\n  {\n    caption: 'User1',\n    // You will need to prepend the image path with your baseUrl\n    // if it is not '/', like: '/test-site/img/image.jpg'.\n    image: '/img/undraw_open_source.svg',\n    infoLink: 'https://www.facebook.com',\n    pinned: true,\n  },\n];\n\nconst siteConfig = {\n  algolia: {\n    apiKey: '706ea6606dcf22ab4091945383d0cff9',\n    indexName: 'quix',\n  },\n  title: 'Quix', // Title for your website.\n  tagline: 'An easy-to-use notebook manager',\n  // url: 'https://your-docusaurus-test-site.com', // Your website URL\n  baseUrl: '/quix/', // Base URL for your project */\n  // For github.io type URLs, you would set the url and baseUrl like:\n  url: 'https://wix.github.io',\n  baseUrl: '/quix/',\n\n  // Used for publishing and more\n  projectName: 'quix',\n  organizationName: 'wix',\n  // For top-level user or org sites, the organization is still the same.\n  // e.g., for the https://JoelMarcey.github.io site, it would be set like...\n  //   organizationName: 'JoelMarcey'\n\n  // For no header links in the top nav bar -> headerLinks: [],\n  headerLinks: [\n    {doc: 'installation', label: 'Docs'},\n    {blog: true, label: 'Blog'},\n    {href: 'https://github.com/wix-incubator/quix', label: 'GitHub'},\n  ],\n\n  // If you have users set above, you add it here:\n  users,\n\n  /* path to images for header/footer */\n  headerIcon: 'img/favicon.ico',\n  footerIcon: 'img/favicon.ico',\n  favicon: 'img/favicon.ico',\n\n  /* Colors for website */\n  colors: {\n    primaryColor: '#fc4a6a',\n    secondaryColor: '#00a9f4',\n  },\n\n  /* Custom fonts for website */\n  /*\n  fonts: {\n    myFont: [\n      \"Times New Roman\",\n      \"Serif\"\n    ],\n    myOtherFont: [\n      \"-apple-system\",\n      \"system-ui\"\n    ]\n  },\n  */\n\n  // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds.\n  copyright: `© ${new Date().getFullYear()} Wix.com, Inc`,\n\n  highlight: {\n    // Highlight.js theme to use for syntax highlighting in code blocks.\n    theme: 'default',\n  },\n\n  // Add custom scripts here that would be placed in <script> tags.\n  scripts: ['https://buttons.github.io/buttons.js'],\n\n  // On page navigation for the current documentation page.\n  onPageNav: 'separate',\n  // No .html extensions for paths.\n  cleanUrl: true,\n\n  // Open Graph and Twitter card images.\n  ogImage: 'img/undraw_online.svg',\n  twitterImage: 'img/undraw_tweetstorm.svg',\n\n  // Show documentation's last contributor's name.\n  // enableUpdateBy: true,\n\n  // Show documentation's last update time.\n  // enableUpdateTime: true,\n\n  // You may provide arbitrary config keys to be used as needed by your\n  // template. For example, if you need your repo's URL...\n  repoUrl: 'https://github.com/wix-incubator/quix',\n};\n\nmodule.exports = siteConfig;\n"
  },
  {
    "path": "documentation/website/static/css/custom.css",
    "content": "/* your custom css */\n\n@media only screen and (min-device-width: 360px) and (max-device-width: 736px) {\n}\n\n@media only screen and (min-width: 1024px) {\n}\n\n@media only screen and (max-width: 1023px) {\n}\n\n@media only screen and (min-width: 1400px) {\n}\n\n@media only screen and (min-width: 1500px) {\n}\n\n.homeContainer {\n  text-align: unset;\n}\n\n.homeContainer .homeWrapper {\n  padding: 2em 100px;\n}\n\n.homeContainer .homeWrapper .projectLogo {\n  padding: 20px 100px 0;\n}\n\n.promoSection .promoRow .pluginRowBlock {\n  justify-content: unset;\n}\n\n.imageAlignTop .blockImage {\n  position: relative;\n  display: block;\n  max-width: 60%;\n}\n\n.imageAlignTop .blockImage:after {\n  content: '';\n  display: block;\n  padding-bottom: 100%;\n}\n\n.imageAlignTop .blockImage img {\n  transform: translate(0, -50%);\n  position: absolute;\n  top: 50%;\n  left: 0;\n}\n\n.fixedHeaderContainer header .logo {\n  height: 20px;\n  padding: 4px;\n  background-color: #ffffff;\n  border-radius: 100px;\n}"
  },
  {
    "path": "env-example",
    "content": "#MODULES=presto,athena,prod,bq\nMODULES=presto\n\n\nMODULES_PRESTO_ENGINE=presto\nMODULES_PRESTO_API=http://presto:8080/v1\nMODULES_PRESTO_CATALOG=system\nMODULES_PRESTO_SCHEMA=runtime\nMODULES_PRESTO_SOURCE=quix\nMODULES_PRESTO_DB_EMPTY_TIMEOUT=60000\nMODULES_PRESTO_DB_REQUEST_TIMEOUT=10000\nMODULES_PRESTO_HTTP_HEADERS_PREFIX=X-PRESTO-\n\n#MODULES_ATHENA_ENGINE=athena\n#MODULES_ATHENA_OUTPUT=s3://some-bucket-id/\n#MODULES_ATHENA_REGION=us-east-1\n#MODULES_ATHENA_DATABASE=default\n#MODULES_ATHENA_DB_EMPTY_TIMEOUT=60000\n#MODULES_ATHENA_DB_REQUEST_TIMEOUT=10000\n\n#MODULES_PROD_ENGINE=jdbc\n#MODULES_PROD_DRIVER=com.mysql.jdbc.Driver\n#MODULES_PROD_URL=jdbc:mysql://localhost:2222/aschema\n#MODULES_PROD_USER=prod-user\n#MODULES_PROD_PASS=prod-pass\n#MODULES_PROD_SYNTAX=mysql\n\n#MODULES_BQ_ENGINE=bigquery\n#MODULES_BQ_SYNTAX=ansi_sql\n#MODULES_BQ_CREDENTIALS_BASE64= BASE64 of credentials.json\n\n#fake or google\nAUTH_TYPE=fake\nAUTH_USER=dummy-user\nAUTH_COOKIE=\nAUTH_SECRET=\n#COOKIE_MAX_AGE=30\nDB_NAME=quix\nDB_USER=\nDB_PASS=\nDB_HOST=\nDB_PORT=\n#BACKEND_INTERNAL_URL=\n#BACKEND_PUBLIC_URL=\nGOOGLE_SSO_CLIENT_ID=\nGOOGLE_SSO_SECRET=\n"
  },
  {
    "path": "quix-backend/Dockerfile",
    "content": "FROM maven:alpine as maven\n\n# Install sbt\nRUN \\\n    curl -L --silent \"https://raw.githubusercontent.com/sbt/sbt/v1.5.1/sbt\" > $HOME/sbt && \\\n    chmod +x $HOME/sbt && \\\n    mv $HOME/sbt /usr/local/bin/sbt\n\nCOPY build.sbt .\nCOPY version.sbt .\nRUN sbt update -Dsbt.rootdir=true;\nCOPY /quix-webapps/quix-web-spring/pom.xml ./quix-webapps/quix-web-spring/pom.xml\nRUN mvn -B -f /quix-webapps/quix-web-spring/pom.xml dependency:resolve --fail-never\n\nCOPY quix-api/src ./quix-api/src\nCOPY quix-core/src ./quix-core/src\nCOPY /quix-modules/quix-presto-module/src ./quix-modules/quix-presto-module/src\nCOPY /quix-modules/quix-athena-module/src ./quix-modules/quix-athena-module/src\nCOPY /quix-modules/quix-bigquery-module/src ./quix-modules/quix-bigquery-module/src\nCOPY /quix-modules/quix-jdbc-module/src ./quix-modules/quix-jdbc-module/src\nCOPY /quix-modules/quix-python-module/src ./quix-modules/quix-python-module/src\nCOPY /quix-modules/quix-dummy-module/src ./quix-modules/quix-dummy-module/src\nCOPY /quix-webapps/quix-web-spring/src ./quix-webapps/quix-web-spring/src\n\nRUN sbt +publishM2 -Dsbt.rootdir=true;\nRUN mvn -f /quix-webapps/quix-web-spring/pom.xml install -DskipTests\n\nFROM ubuntu:20.04\n\n# Setup python and java and base system\nENV PYTHONUNBUFFERED=1\nENV DEBIAN_FRONTEND noninteractive\nENV LANG=en_US.UTF-8\n\nRUN apt-get update && \\\n  apt-get install -q -y --no-install-recommends \\\n  default-jdk \\\n  python3 \\\n  python-dev \\\n  python3-dev \\\n  python3-pip \\\n  libsnappy-dev \\\n  language-pack-en \\\n  build-essential \\\n  wget \\\n  && rm -rf /var/lib/apt/lists/*\n\nRUN pip3 install --no-cache --upgrade pip setuptools wheel py4j\n\nEXPOSE 8081\n\nWORKDIR /quix-webapps/quix-web-spring\n\nCOPY --from=maven /quix-webapps/quix-web-spring/target/quix-web-spring-*.jar ./quix.jar\n\nRUN wget -q -P BOOT-INF/lib/ \\\n    https://repo1.maven.org/maven2/ru/yandex/clickhouse/clickhouse-jdbc/0.2.4/clickhouse-jdbc-0.2.4.jar \\\n    https://repo1.maven.org/maven2/org/postgresql/postgresql/42.2.10/postgresql-42.2.10.jar \\\n    https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.19/mysql-connector-java-8.0.19.jar \\\n    https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.30.1/sqlite-jdbc-3.30.1.jar \\\n    https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.5.4/mariadb-java-client-2.5.4.jar \\\n    https://repo1.maven.org/maven2/org/hsqldb/hsqldb/2.5.0/hsqldb-2.5.0.jar \\\n    https://maven.ceon.pl/artifactory/repo/com/oracle/ojdbc/ojdbc10/19.3.0.0/ojdbc10-19.3.0.0.jar \\\n    https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/8.2.1.jre11/mssql-jdbc-8.2.1.jre11.jar\n\nRUN jar uf0 quix.jar \\\n    BOOT-INF/lib/clickhouse-jdbc-0.2.4.jar \\\n    BOOT-INF/lib/postgresql-42.2.10.jar \\\n    BOOT-INF/lib/mysql-connector-java-8.0.19.jar \\\n    BOOT-INF/lib/sqlite-jdbc-3.30.1.jar \\\n    BOOT-INF/lib/mariadb-java-client-2.5.4.jar \\\n    BOOT-INF/lib/hsqldb-2.5.0.jar \\\n    BOOT-INF/lib/ojdbc10-19.3.0.0.jar \\\n    BOOT-INF/lib/mssql-jdbc-8.2.1.jre11.jar\n\nCMD [\"java\", \"-jar\", \"quix.jar\"]\n"
  },
  {
    "path": "quix-backend/README.md",
    "content": "# Quix Backend\nQuix backend is based on SpringBoot and Scala, and is built with sbt and Maven.\n \n## Installation\n\n### Requirements\n* Presto\n* Docker\n* Maven 3.6\n* sbt 1.3.8\n\n### Building\nThe default build will download all dependencies inside the Docker container. This build is safer and doesn't require sbt/Maven to be installed locally, but takes longer.\n``` \ndocker build -t quix-backend .\n```\n\n### Running\nProvide a mandatory config values to docker\n```\ndocker run -p 8081:8081 --name quix-backend -t quix-backend \n```\n\nIn case you have local `application.properties` file, we can map it into Docker container and execute it\n```docker run -v /path-to-local/application.properties:/application.properties -p 8081:8081 -t quix-backend``` \n\n## Sample application.properties \n```\nserver.port=8081\n\n# logging levels of different classes\nlogging.level.org.springframework.web=DEBUG\nlogging.level.org.hibernate=ERROR\n\n# mandatory presto api url\npresto.api=<your-presto-master-hostname>:8181/v1\n\n# refresh policy of db tree, every 15 minutes with initial 1 minute delay\ndb.refresh.initialDelayInMinutes=1\ndb.refresh.delayInMinutes=15\n\n```\n\n### Stopping\n``` \ndocker stop quix-backend && docker rm quix-backend \n```\n\n## License\nMIT\n\n## Contributing\n"
  },
  {
    "path": "quix-backend/build.sbt",
    "content": "lazy val publishSettings = Seq(\n  publishTo := {\n    val nexus = \"https://oss.sonatype.org/\"\n    if (version.value.trim.endsWith(\"SNAPSHOT\"))\n      Some(\"snapshots\" at nexus + \"content/repositories/snapshots\")\n    else\n      Some(\"releases\" at nexus + \"service/local/staging/deploy/maven2\")\n  },\n  publishMavenStyle := true,\n  ThisBuild / pomExtra :=\n    <scm>\n      <url>https://github.com/wix-incubator/quix.git</url>\n      <connection>scm:git:https://github.com/wix-incubator/quix.git</connection>\n    </scm>\n      <developers>\n        <developer>\n          <id>frolovv</id>\n          <name>Valery Frolov</name>\n          <email>valeryf@wix.com</email>\n          <organization>Wix</organization>\n        </developer>\n      </developers>\n)\n\nlazy val compileOptions = Seq(\n  crossScalaVersions := Seq(\"2.12.17\", \"2.13.9\"),\n)\n\nlazy val noPublish = Seq(publish := {}, publishLocal := {}, publishArtifact := false)\n\nlazy val baseSettings =\n  publishSettings ++\n    compileOptions ++\n    Seq(\n      organization := \"com.wix\",\n      homepage := Some(url(\"https://github.com/wix-incubator/quix\")),\n      licenses := Seq(\"MIT\" -> url(\"https://opensource.org/licenses/MIT\"))\n    )\n\nval loggingDeps = Seq(\n  \"com.typesafe.scala-logging\" %% \"scala-logging\" % \"3.9.3\",\n  \"ch.qos.logback\" % \"logback-classic\" % \"1.2.3\"\n)\n\nval specs2Deps = Seq(\n  \"org.specs2\" %% \"specs2-core\" % \"4.10.6\" % \"test\",\n  \"org.specs2\" %% \"specs2-junit\" % \"4.10.6\" % \"test\",\n  \"org.specs2\" %% \"specs2-mock\" % \"4.10.6\" % \"test\",\n)\n\nlazy val quixApi = (project in file(\"quix-api\"))\n  .settings(Seq(\n    name := \"Quix Api\",\n    libraryDependencies += \"io.monix\" %% \"monix\" % \"3.3.0\"\n  ) ++ baseSettings)\n\nlazy val quixCore = (project in file(\"quix-core\"))\n  .dependsOn(quixApi)\n  .settings(Seq(\n    name := \"Quix Core\",\n\n    libraryDependencies += \"com.github.blemale\" %% \"scaffeine\" % \"3.1.0\",\n\n    // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core\n    libraryDependencies += \"com.fasterxml.jackson.core\" % \"jackson-core\" % \"2.10.4\",\n\n    // https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-scala\n    libraryDependencies += \"com.fasterxml.jackson.module\" %% \"jackson-module-scala\" % \"2.10.4\",\n\n    // https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jdk8\n    libraryDependencies += \"com.fasterxml.jackson.datatype\" % \"jackson-datatype-jdk8\" % \"2.10.4\",\n\n    // https://mvnrepository.com/artifact/io.prestosql/presto-parser\n    libraryDependencies += \"io.prestosql\" % \"presto-parser\" % \"329\",\n\n    // https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3\n    libraryDependencies += \"com.amazonaws\" % \"aws-java-sdk-s3\" % \"1.11.728\",\n\n    // https://mvnrepository.com/artifact/com.opencsv/opencsv\n    libraryDependencies += \"com.opencsv\" % \"opencsv\" % \"5.5.2\",\n\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n\n    // https://mvnrepository.com/artifact/com.wix/wix-embedded-mysql\n    libraryDependencies += \"com.wix\" % \"wix-embedded-mysql\" % \"4.6.1\" % Test,\n\n    // https://mvnrepository.com/artifact/mysql/mysql-connector-java\n    libraryDependencies += \"mysql\" % \"mysql-connector-java\" % \"8.0.19\" % Test,\n  ) ++ baseSettings)\n\nlazy val quixAthenaModule = (project in file(\"quix-modules/quix-athena-module\"))\n  .dependsOn(quixCore)\n  .settings(Seq(\n    name := \"Quix Athena Module\",\n\n    // https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-athena\n    libraryDependencies += \"com.amazonaws\" % \"aws-java-sdk-athena\" % \"1.11.715\",\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n  ) ++ baseSettings)\n\nlazy val quixBigqueryModule = (project in file(\"quix-modules/quix-bigquery-module\"))\n  .dependsOn(quixCore)\n  .settings(Seq(\n    name := \"Quix Bigquery Module\",\n\n    // https://mvnrepository.com/artifact/com.google.cloud/google-cloud-bigquery\n    libraryDependencies += \"com.google.cloud\" % \"google-cloud-bigquery\" % \"1.106.0\",\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n  ) ++ baseSettings)\n\nlazy val quixDummyModule = (project in file(\"quix-modules/quix-dummy-module\"))\n  .dependsOn(quixCore)\n  .settings(Seq(\n    name := \"Quix Dummy Module\",\n\n    libraryDependencies += \"io.monix\" %% \"monix\" % \"3.3.0\",\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n  ) ++ baseSettings ++ noPublish)\n\nlazy val quixJdbcModule = (project in file(\"quix-modules/quix-jdbc-module\"))\n  .dependsOn(quixCore)\n  .settings(Seq(\n    name := \"Quix Jdbc Module\",\n\n    libraryDependencies += \"io.monix\" %% \"monix\" % \"3.3.0\",\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n    // https://mvnrepository.com/artifact/com.wix/wix-embedded-mysql\n    libraryDependencies += \"com.wix\" % \"wix-embedded-mysql\" % \"4.6.1\" % Test,\n\n    // https://mvnrepository.com/artifact/mysql/mysql-connector-java\n    libraryDependencies += \"mysql\" % \"mysql-connector-java\" % \"8.0.19\" % Test,\n  ) ++ baseSettings)\n\nlazy val quixPrestoModule = (project in file(\"quix-modules/quix-presto-module\"))\n  .dependsOn(quixCore)\n  .settings(Seq(\n    name := \"Quix Presto Module\",\n\n    libraryDependencies += \"io.monix\" %% \"monix\" % \"3.3.0\",\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n    // https://mvnrepository.com/artifact/io.prestosql/presto-parser\n    libraryDependencies += \"io.prestosql\" % \"presto-parser\" % \"329\",\n    // https://mvnrepository.com/artifact/io.prestosql/presto-client\n    libraryDependencies += \"io.prestosql\" % \"presto-client\" % \"329\",\n    // https://mvnrepository.com/artifact/org.scalaj/scalaj-http\n    libraryDependencies += \"org.scalaj\" %% \"scalaj-http\" % \"2.4.2\",\n  ) ++ baseSettings)\n\nlazy val quixPythonModule = (project in file(\"quix-modules/quix-python-module\"))\n  .dependsOn(quixCore)\n  .settings(Seq(\n    name := \"Quix Python Module\",\n\n    libraryDependencies ++= loggingDeps,\n    libraryDependencies ++= specs2Deps,\n    // https://mvnrepository.com/artifact/com.zaxxer/nuprocess\n    libraryDependencies += \"com.zaxxer\" % \"nuprocess\" % \"2.0.1\",\n    // https://mvnrepository.com/artifact/net.sf.py4j/py4j\n    libraryDependencies += \"net.sf.py4j\" % \"py4j\" % \"0.10.9.2\",\n  ) ++ baseSettings)\n\nlazy val root = (project in file(\".\"))\n  .aggregate(quixApi, quixCore, quixAthenaModule, quixBigqueryModule, quixJdbcModule, quixPrestoModule, quixPythonModule)\n  .settings(\n    crossScalaVersions := Nil,\n    publish / skip := true,\n  )\n"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/db/Db.scala",
    "content": "package quix.api.v1.db\n\nimport monix.eval.Task\n\nsealed case class Catalog(name: String,\n                          children: List[Schema],\n                          `type`: String = \"catalog\")\n\nsealed case class Schema(name: String,\n                         children: List[Table],\n                         `type`: String = \"schema\")\n\nsealed case class Table(name: String,\n                        children: List[Kolumn],\n                        `type`: String = \"table\")\n\nsealed case class Kolumn(name: String,\n                         dataType: String,\n                         `type`: String = \"column\")\n\n/** Db exposes database tree, supports autocomplete in quix editor and powers the DB search. */\ntrait Db {\n\n  /** Supports up-to 4 levels of hierarchy : catalogs, schemas, tables and columns */\n  def getCatalogs: Task[List[Catalog]]\n\n  /** Returns list of all possible autocomplete items within different categories.\n   * For example, in case of presto-module : catalogs, schemas, tables and columns.\n   * */\n  def getAutocomplete: Task[Map[String, List[String]]]\n\n  /** Returns columns and types for a table identified by catalog, schema and table name */\n  def getTable(catalog: String, schema: String, table: String): Task[Table]\n\n  /** Returns list of catalogs filtered using a given substring */\n  def search(query: String): Task[List[Catalog]]\n}\n\n/** Catalogs expose list of catalogs present within a module */\ntrait Catalogs {\n\n  /** This method should return within under X milliseconds (configurable via .env) and will be called directly\n   * from quix-frontend if db tree is empty */\n  def fast: Task[List[Catalog]]\n\n  /** This method isn't exposed to quix-frontend and will be called in background to cache the full db tree */\n  def full: Task[List[Catalog]]\n}\n\n/** Autocomplete exposes list of categories and autocomplete items that belong to these categories.\n * For example, 'catalogs' might be a category and list of 'foo' and 'boo' might be catalogs\n * */\ntrait Autocomplete {\n  def fast: Task[Map[String, List[String]]]\n\n  def full: Task[Map[String, List[String]]]\n}\n\n/** Tables expose a way to get metadata of table */\ntrait Tables {\n\n  /** This method will be called when user tries to expand a table in quix-frontend db tree */\n  def get(catalog: String, schema: String, table: String): Task[Table]\n}"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/execute/Api.scala",
    "content": "package quix.api.v1.execute\n\nimport java.io.IOException\n\nimport monix.eval.Task\nimport quix.api.v1.users.User\n\n/** End consumer of quix backend messages.\n * In case of quix frontend, it is a websocket channel.\n *\n */\ntrait Consumer[Message] {\n  def id: String\n\n  def user: User\n\n  @throws[IOException]\n  def write(payload: Message): Task[Unit]\n\n  @throws[IOException]\n  def close(): Task[Unit]\n}"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/execute/Batch.scala",
    "content": "package quix.api.v1.execute\n\ncase class BatchColumn(name: String)\n\ncase class BatchError(message: String)\n\n/** Used in [[quix.api.v1.execute.Builder]] to send batched payloads from [[quix.api.v1.module.ExecutionModule]] to\n * [[quix.api.v1.execute.Consumer]]\n *\n * @param data list of rows\n * @param columns optional list of column names\n * @param error optional error\n * @param stats optional stats object for custom properties\n */\ncase class Batch(data: Seq[Seq[Any]] = Seq.empty,\n                 columns: Option[Seq[BatchColumn]] = None,\n                 error: Option[BatchError] = None,\n                 stats: Map[String, Any] = Map.empty)\n\n\nobject Batch {\n  val PERCENTAGE = \"percentage\"\n  val STATUS = \"status\"\n  val TYPE = \"type\"\n\n  implicit class BatchStatsOps(val batch: Batch) extends AnyVal {\n    def percentage = {\n      batch.stats.get(PERCENTAGE) match {\n        case Some(value: Int) => Some(value)\n        case _ => None\n      }\n    }\n\n    def queryType: Option[String] = {\n      batch.stats.get(TYPE) match {\n        case Some(value: String) => Some(value)\n        case _ => None\n      }\n    }\n\n    def withPercentage(percentage: Int): Batch = {\n      batch.copy(stats = batch.stats.updated(PERCENTAGE, percentage))\n    }\n\n    def withStatus(status: String) = {\n      batch.copy(stats = batch.stats.updated(STATUS, status))\n    }\n\n    def withType(queryType: String) = {\n      batch.copy(stats = batch.stats.updated(TYPE, queryType))\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/execute/ExecutionEngine.scala",
    "content": "package quix.api.v1.execute\n\nimport monix.eval.Task\nimport quix.api.v1.users.User\n\n\ncase class ActiveQuery[Code](id: String,\n                             statements: Seq[Code],\n                             user: User,\n                             var current: Int = 0,\n                             var isCancelled: Boolean = false,\n                             var session: Map[String, Any] = Map.empty,\n                             var catalog: Option[String] = None,\n                             var schema: Option[String] = None) {\n  def text = statements(current)\n}\n\n\n/**\n * Builder is used to propagate messages between AsyncQueryExecutor and quix frontend\n *\n * @tparam Code    designates type of incoming code, usually String\n * @tparam Results designates type of outgoing messages, usually [[quix.api.v1.execute.Batch]]\n */\n\ntrait Builder[Code, Results] {\n\n  /** Sent when query is started */\n  def start(query: ActiveQuery[Code]): Task[Unit]\n\n  /** Sent when query is ended */\n  def end(query: ActiveQuery[Code]): Task[Unit]\n\n  /** Sent when query fails with exception */\n  def error(queryId: String, e: Throwable): Task[Unit]\n\n  /** Total counter of all rows */\n  def rowCount: Long\n\n  def lastError: Option[Throwable]\n\n  /** Sent of every sub query start, each subquery will be shown in different tab in quix */\n  def startSubQuery(subQueryId: String, code: Code, results: Results): Task[Unit]\n\n  /** Used to stream results back to quix frontend */\n  def addSubQuery(subQueryId: String, results: Results): Task[Unit]\n\n  /** Sent of every sub query end, quix frontend will use it to stop populating currect tab */\n  def endSubQuery(subQueryId: String, statistics: Map[String, Any] = Map.empty): Task[Unit]\n\n  def errorSubQuery(subQueryId: String, e: Throwable): Task[Unit]\n\n  /** Used to send different log messages.\n   *\n   * @param line  message to log\n   * @param level supported levels are INFO and ERROR\n   * */\n  def log(queryId: String, line: String, level: String = \"INFO\"): Task[Unit]\n}\n\n/** Used to execute single query and stream the results back to Builder */\ntrait AsyncQueryExecutor[Code, Results] {\n  def runTask(query: ActiveQuery[Code], builder: Builder[Code, Results]): Task[Unit]\n}\n\n/** Used to show exceptions in the quix frontend\n *\n * @param message the message will be shown to client as is\n **/\ncase class ExceptionPropagatedToClient(message: String) extends Exception"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/execute/ExecutionProtocol.scala",
    "content": "package quix.api.v1.execute\n\nsealed trait EventData\n\n/**\n * Event used to communicate changes\n *\n * @param event event name, shared between quix backend and quix frontend\n * @param data  data that arrives with every event\n */\nsealed case class ExecutionEvent(event: String, data: EventData)\n\nsealed case class Start(id: String, numOfQueries: Int) extends EventData\n\nsealed case class Error(id: String, message: String) extends EventData\n\nsealed case class End(id: String) extends EventData\n\nsealed case class SubQueryStart(id: String) extends EventData\n\nsealed case class SubQueryFields(id: String, fields: Seq[String]) extends EventData\n\nsealed case class SubQueryDetails[Code](id: String, code: Code) extends EventData\n\nsealed case class SubQueryEnd(id: String, statistics: Map[String, Any]) extends EventData\n\nsealed case class SubQueryError(id: String, message: String) extends EventData\n\nsealed case class Progress(id: String, percentage: Int) extends EventData\n\nsealed case class Row(id: String, values: Seq[Any]) extends EventData\n\nsealed case class Download(id: String, url: String) extends EventData\n\nsealed case class StartCommand[Code](code: Code, session: Map[String, String]) extends EventData\n\nsealed case class Log(id: String, line: String, level: String) extends EventData\n\nobject Empty extends EventData\n\nobject Start {\n  def apply(id: String, numOfQueries: Int): ExecutionEvent = ExecutionEvent(\"start\", new Start(id, numOfQueries))\n}\n\nobject End {\n  def apply(id: String): ExecutionEvent = ExecutionEvent(\"end\", new End(id))\n}\n\n\nobject SubQueryStart {\n  def apply(id: String): ExecutionEvent = ExecutionEvent(\"query-start\", new SubQueryStart(id))\n}\n\nobject SubQueryDetails {\n  def apply[Code](id: String, code: Code): ExecutionEvent = ExecutionEvent(\"query-details\", new SubQueryDetails(id, code))\n}\n\nobject SubQueryEnd {\n  def apply(id: String, statistics: Map[String, Any] = Map.empty): ExecutionEvent = ExecutionEvent(\"query-end\", new SubQueryEnd(id, statistics))\n}\n\nobject SubQueryError {\n  def apply(id: String, message: String): ExecutionEvent = ExecutionEvent(\"error\", new SubQueryError(id, message))\n}\n\nobject SubQueryFields {\n  def apply(id: String, fields: Seq[String]): ExecutionEvent = ExecutionEvent(\"fields\", new SubQueryFields(id, fields))\n}\n\nobject Progress {\n  def apply(id: String, percentage: Int): ExecutionEvent = ExecutionEvent(\"percentage\", new Progress(id, percentage))\n}\n\nobject Error {\n  def apply(id: String, message: String): ExecutionEvent = ExecutionEvent(\"error\", new Error(id, message))\n}\n\nobject Row {\n  def apply(id: String, values: Seq[Any]): ExecutionEvent = ExecutionEvent(\"row\", new Row(id, values))\n}\n\nobject Pong {\n  def apply(id: String): ExecutionEvent = ExecutionEvent(\"pong\", Empty)\n}\n\nobject Download {\n  def apply(id: String, url: String): ExecutionEvent = ExecutionEvent(\"query-download\", new Download(id, url))\n}\n\nobject Log {\n  def apply(id: String, line: String, level: String): ExecutionEvent = ExecutionEvent(\"log\", new Log(id, line, level))\n}"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/module/ExecutionModule.scala",
    "content": "package quix.api.v1.module\n\nimport monix.eval.Task\nimport quix.api.v1.db.Db\nimport quix.api.v1.execute.{Builder, StartCommand}\nimport quix.api.v1.users.User\n\n/** Every quix note type must implement ExecutionModule to support query execution and db tree exploration\n *\n * @tparam Code\n * @tparam Results\n */\ntrait ExecutionModule[Code, Results] {\n\n  /** Describes execution of code passed via [[quix.api.v1.execute.StartCommand]] and invocations\n   * of [[quix.api.v1.execute.Builder]] methods.\n   *\n   * @param command includes the code that must be executed. Might contains multiple statements\n   * @param id      query id\n   * @param user    user that asked to execute command\n   * @param builder instance of [[quix.api.v1.execute.Builder]] that serves as communication channel to quix frontend\n   * @return description of execution by means of [[monix.eval.Task]]\n   */\n  def start(command: StartCommand[Code], id: String, user: User, builder: Builder[Code, Results]): Task[Unit]\n\n  /** Execution module might expose db tree that can be visualized and explored in quix frontend\n   *\n   * @return optional instance of db\n   */\n  def db: Option[Db]\n}"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v1/users/Users.scala",
    "content": "package quix.api.v1.users\n\nsealed case class User(email: String, id: String = \"\")\n\ntrait Users {\n  @throws[RequestNotAuthenticated]\n  def auth[T](headers: Map[String, String])(code: User => T): T\n}\n\nclass DummyUsers(val user: String) extends Users {\n  override def auth[T](headers: Map[String, String])(code: User => T): T = code(User(user))\n}\n\ncase class RequestNotAuthenticated(msg: String) extends RuntimeException(msg)"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v2/execute/Builder.scala",
    "content": "package quix.api.v2.execute\n\nimport monix.eval.Task\nimport quix.api.v1.execute.Batch\n\n/**\n * Builder is used to propagate messages between AsyncQueryExecutor and quix frontend\n *\n */\ntrait Builder {\n\n  /** Sent when query is started */\n  def start(query: Query): Task[Unit]\n\n  /** Sent when query is ended */\n  def end(query: Query): Task[Unit]\n\n  /** Sent when query fails with exception */\n  def error(queryId: String, e: Throwable): Task[Unit]\n\n  /** Total counter of all rows */\n  def rowCount: Long\n\n  def lastError: Option[Throwable]\n\n  /** Sent of every sub query start, each subquery will be shown in different tab in quix */\n  def startSubQuery(subQueryId: String, code: String): Task[Unit]\n\n  /** Used to stream results back to quix frontend */\n  def addSubQuery(subQueryId: String, results: Batch): Task[Unit]\n\n  /** Sent of every sub query end, quix frontend will use it to stop populating currect tab */\n  def endSubQuery(subQueryId: String, stats: Map[String, Any] = Map.empty): Task[Unit]\n\n  def errorSubQuery(subQueryId: String, e: Throwable): Task[Unit]\n\n  /** Used to send different log messages.\n   *\n   * @param line  message to log\n   * @param level supported levels are INFO and ERROR\n   **/\n  def log(subQueryId: String, line: String, level: String = \"INFO\"): Task[Unit]\n}\n"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v2/execute/ExecutionModule.scala",
    "content": "package quix.api.v2.execute\n\nimport monix.eval.Task\nimport quix.api.v1.db.Db\nimport quix.api.v1.execute.StartCommand\nimport quix.api.v1.users.User\n\n/** Every quix note type must implement ExecutionModule to support query execution and db tree exploration\n */\ntrait ExecutionModule {\n\n  /** Describes execution of code passed via [[quix.api.v1.execute.StartCommand]] and invocations\n   * of [[quix.api.v1.execute.Builder]] methods.\n   *\n   * @param command includes the code that must be executed. Might contains multiple statements\n   * @param id      query id\n   * @param user    user that asked to execute command\n   * @param builder instance of [[quix.api.v1.execute.Builder]] that serves as communication channel to quix frontend\n   * @return description of execution by means of [[monix.eval.Task]]\n   */\n  def start(command: StartCommand[String], id: String, user: User, builder: Builder): Task[Unit]\n\n  /** Execution module might expose db tree that can be visualized and explored in quix frontend\n   *\n   * @return optional instance of db\n   */\n  def db: Option[Db]\n}"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v2/execute/Executor.scala",
    "content": "package quix.api.v2.execute\n\nimport monix.eval.Task\n\n/** Used to execute single query and stream the results back to Builder */\ntrait Executor {\n  def execute(query: SubQuery, builder: Builder): Task[Unit]\n}\n"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v2/execute/Session.scala",
    "content": "package quix.api.v2.execute\n\ntrait Session {\n  def put(key: String, value: String)\n\n  def remove(key: String)\n\n  def get: Map[String, String]\n}\n\nclass MutableSession(val session: () => Map[String, String] = () => Map.empty,\n                     private var state: Map[String, String] = Map.empty) extends Session {\n  override def put(key: String, value: String): Unit = state = state.updated(key, value)\n\n  override def remove(key: String): Unit = state = state - key\n\n  override def get: Map[String, String] = state\n}\n\nobject MutableSession {\n  def apply(kv: (String, String)*): MutableSession = new MutableSession(state = kv.toMap)\n\n  def apply(session: () => Map[String, String]): MutableSession = new MutableSession(session = session)\n}"
  },
  {
    "path": "quix-backend/quix-api/src/main/scala/quix/api/v2/execute/SubQuery.scala",
    "content": "package quix.api.v2.execute\n\nimport java.util.UUID\n\nimport monix.execution.atomic.Atomic\nimport quix.api.v1.users.User\n\ntrait SubQuery {\n  def id: String\n\n  def text: String\n\n  def session: Session\n\n  def user: User\n\n  def canceled: Atomic[Boolean]\n}\n\ncase class ImmutableSubQuery(text: String, user: User,\n                             canceled: Atomic[Boolean] = Atomic(false),\n                             id: String = UUID.randomUUID().toString,\n                             session: Session = new MutableSession) extends SubQuery\n\ncase class Query(subQueries: Seq[SubQuery],\n                 id: String = UUID.randomUUID().toString,\n                 canceled: Atomic[Boolean] = Atomic(false),\n                 rawCode: String = \"\")"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/db/DbOps.scala",
    "content": "package quix.core.db\n\nimport com.typesafe.scalalogging.LazyLogging\nimport quix.api.v1.db.Catalog\n\nobject DbOps extends LazyLogging {\n  def mergeNewAndOldCatalogs(newCatalogs: List[Catalog], oldCatalogs: List[Catalog]): List[Catalog] = {\n    newCatalogs.map { newCatalog =>\n      val maybeOldCatalog = oldCatalogs.find(_.name == newCatalog.name)\n\n      (newCatalog, maybeOldCatalog) match {\n        case (_, None) =>\n          newCatalog\n\n        case (_, Some(oldCatalog)) if newCatalog.children.isEmpty =>\n          logger.warn(\"Catalog \" + newCatalog + \"is empty\")\n          oldCatalog\n\n        case _ =>\n          newCatalog\n      }\n    }\n  }\n\n  def search(catalogs: List[Catalog], query: String): List[Catalog] = search(catalogs, DbQuery(query))\n\n  def search(catalogs: List[Catalog], query: DbQuery): List[Catalog] = {\n    val filtered = catalogs.map {\n\n      case catalog if query.matches(catalog.name) =>\n        catalog\n\n      case catalog =>\n        val schemas = catalog.children\n\n        val filtered = schemas.map {\n          case schema if query.matches(schema.name) =>\n            schema\n\n          case schema =>\n            val tables = schema.children\n            val filtered = tables.filter(table => query.matches(table.name))\n\n            schema.copy(children = filtered)\n        }.filter(schema => schema.children.nonEmpty || query.matches(schema.name))\n\n        catalog.copy(children = filtered)\n    }.filter(catalog => catalog.children.nonEmpty || query.matches(catalog.name))\n\n    filtered\n  }\n}\n\ntrait DbQuery {\n  def matches(name: String): Boolean\n}\n\nobject DbQuery {\n  def apply(query: String): DbQuery = {\n    query match {\n\n      case null =>\n        DbQueryFalse\n\n      case query if isExactMatch(query) =>\n        new DbQueryExactMatch(query.substring(1, query.length - 1))\n\n      case _ =>\n        new DbQueryContains(query)\n    }\n  }\n\n  private def isExactMatch(query: String) = {\n    query.startsWith(\"\\\"\") & query.endsWith(\"\\\"\") || query.startsWith(\"'\") & query.endsWith(\"'\")\n  }\n}\n\nclass DbQueryContains(query: String) extends DbQuery {\n  override def matches(name: String): Boolean = name.contains(query)\n}\n\nclass DbQueryExactMatch(query: String) extends DbQuery {\n  override def matches(name: String): Boolean = query == name\n}\n\nobject DbQueryFalse extends DbQuery {\n  override def matches(name: String): Boolean = false\n}"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/db/RefreshableAutocomplete.scala",
    "content": "package quix.core.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.Autocomplete\n\nimport scala.concurrent.duration._\n\nclass RefreshableAutocomplete(autocomplete: Autocomplete,\n                              timeoutInMillis: Long,\n                              staleThreshold: Long,\n                              var state: State[Map[String, List[String]]] = State(Map.empty, 0L)) {\n  def get: Task[Map[String, List[String]]] = {\n    state match {\n      case State(data, _) if data.isEmpty =>\n        for {\n          _ <- startUpdate()\n\n          newCatalogs <-\n          autocomplete.fast\n            .flatMap(update)\n            .timeout(timeoutInMillis.millis)\n            .onErrorFallbackTo(Task.now(state.data))\n\n          _ <- autocomplete.full\n            .flatMap(update)\n            .attempt.start\n        } yield newCatalogs\n\n      case State(_, expirationDate) if expirationDate < System.currentTimeMillis() =>\n        for {\n          _ <- startUpdate()\n          _ <- autocomplete.full\n            .flatMap(update)\n            .attempt.start\n        } yield state.data\n\n      case _ => Task.now(state.data)\n    }\n  }\n\n  def startUpdate() = {\n    Task(this.state = this.state.copy(expirationDate = System.currentTimeMillis() + staleThreshold))\n  }\n\n  def update(newData: Map[String, List[String]]) = {\n    Task {\n      this.state = this.state.copy(data = newData)\n      newData\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/db/RefreshableCatalogs.scala",
    "content": "package quix.core.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Catalog, Catalogs}\n\nimport scala.concurrent.duration._\n\nclass RefreshableCatalogs(catalogs: Catalogs,\n                          timeoutInMillis: Long,\n                          staleThreshold: Long,\n                          var state: State[List[Catalog]] = State(Nil, 0L)) {\n\n  def get: Task[List[Catalog]] = {\n    state match {\n      case State(data, _) if data.isEmpty =>\n        for {\n          _ <- startUpdate()\n\n          newCatalogs <-\n          catalogs.fast\n            .flatMap(update)\n            .timeout(timeoutInMillis.millis)\n            .onErrorFallbackTo(Task.now(state.data))\n\n          _ <- catalogs.full\n            .flatMap(update)\n            .attempt.start\n        } yield newCatalogs\n\n      case State(_, expirationDate) if expirationDate < System.currentTimeMillis() =>\n        for {\n          _ <- startUpdate()\n          _ <- catalogs.full\n            .flatMap(update)\n            .attempt.start\n        } yield state.data\n\n      case _ => Task.now(state.data)\n    }\n  }\n\n  def startUpdate() = {\n    Task(this.state = this.state.copy(expirationDate = System.currentTimeMillis() + staleThreshold))\n  }\n\n  def update(newCatalogs: List[Catalog]) = {\n    Task {\n      this.state = this.state.copy(data = newCatalogs)\n      newCatalogs\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/db/RefreshableDb.scala",
    "content": "package quix.core.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Catalog, Db, Table, Tables}\n\nclass RefreshableDb(catalogs: RefreshableCatalogs, autocomplete: RefreshableAutocomplete, tables: Tables) extends Db {\n\n  override def getCatalogs: Task[List[Catalog]] =\n    catalogs.get\n\n  override def getAutocomplete: Task[Map[String, List[String]]] =\n    autocomplete.get\n\n  override def getTable(catalog: String, schema: String, table: String): Task[Table] =\n    tables.get(catalog, schema, table)\n\n  override def search(query: String): Task[List[Catalog]] =\n    catalogs.get.map(c => DbOps.search(c, query))\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/db/State.scala",
    "content": "package quix.core.db\n\ncase class State[T](data: T, expirationDate: Long)"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/download/DownloadConfig.scala",
    "content": "package quix.core.download\n\nimport java.io.InputStream\nimport java.nio.file.{Files, Path, Paths}\nimport java.util.zip.GZIPInputStream\n\nimport com.amazonaws.auth.{AWSStaticCredentialsProvider, BasicAWSCredentials}\nimport com.amazonaws.services.s3.{AmazonS3, AmazonS3ClientBuilder}\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\n\ncase class DownloadConfig(downloadDir: String, cloudConfig: Map[String, String] = Map.empty)\n\ntrait QueryResultsStorage {\n  def upload(queryId: String, file: Path): Task[Unit]\n\n  def exists(queryId: String): Task[Boolean]\n\n  def delete(queryId: String): Task[Unit]\n\n  def getInputStream(queryId: String): Task[InputStream]\n}\n\nobject QueryResultsStorage {\n  def apply(config: DownloadConfig): QueryResultsStorage = {\n    config.cloudConfig match {\n      case _ if hasS3Keys(config.cloudConfig) =>\n        initS3(config.cloudConfig)\n      case _ =>\n        initLocalFS(config)\n    }\n  }\n\n  def hasS3Keys(config: Map[String, String]) = {\n    config.keySet.contains(\"accessKey\") &&\n      config.keySet.contains(\"secretKey\") &&\n      config.keySet.contains(\"region\") &&\n      config.keySet.contains(\"bucket\")\n  }\n\n  def initS3(config: Map[String, String]): QueryResultsStorage = {\n    val accessKey = config(\"accessKey\")\n    val secretKey = config(\"secretKey\")\n    val region = config(\"region\")\n    val bucket = config(\"bucket\")\n\n    val credentials = new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey))\n\n    val amazonS3Client: AmazonS3 = AmazonS3ClientBuilder\n      .standard()\n      .withCredentials(credentials)\n      .withRegion(region)\n      .build()\n\n    new QueryResultsStorage with LazyLogging {\n      override def upload(queryId: String, file: Path): Task[Unit] = Task {\n        logger.info(s\"event=s3-upload-start query-id=$queryId file=$file size=${Files.size(file)}\")\n        amazonS3Client.putObject(bucket, queryId, file.toFile)\n        logger.info(s\"event=s3-upload-done query-id=$queryId file=$file size=${Files.size(file)}\")\n      }\n\n      override def getInputStream(queryId: String): Task[InputStream] = Task {\n        logger.info(s\"event=s3-get-inputstream-start query-id=$queryId\")\n        val is = new GZIPInputStream(amazonS3Client.getObject(bucket, queryId).getObjectContent)\n        logger.info(s\"event=s3-get-inputstream-done query-id=$queryId\")\n        is\n      }\n\n      override def exists(queryId: String): Task[Boolean] = Task {\n        logger.info(s\"event=s3-exists-start query-id=$queryId\")\n        val response = amazonS3Client.doesObjectExist(bucket, queryId)\n        logger.info(s\"event=s3-exists-done query-id=$queryId response=$response\")\n        response\n      }\n\n      override def delete(queryId: String): Task[Unit] = Task {\n        logger.info(s\"event=s3-delete-start query-id=$queryId\")\n        amazonS3Client.deleteObject(bucket, queryId)\n        logger.info(s\"event=s3-delete-done query-id=$queryId\")\n      }\n    }\n  }\n\n  def initLocalFS(config: DownloadConfig): QueryResultsStorage = {\n    new QueryResultsStorage {\n      override def upload(queryId: String, file: Path): Task[Unit] = Task.unit\n\n      override def getInputStream(queryId: String): Task[InputStream] = Task {\n        val path = Paths.get(config.downloadDir, queryId)\n        new GZIPInputStream(Files.newInputStream(path))\n      }\n\n      override def exists(queryId: String): Task[Boolean] = Task(Files.exists(Paths.get(config.downloadDir, queryId)))\n\n      override def delete(queryId: String): Task[Unit] = Task(Files.deleteIfExists(Paths.get(config.downloadDir, queryId)))\n    }\n  }\n}"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/download/DownloadableBuilder.scala",
    "content": "package quix.core.download\n\nimport com.opencsv.CSVWriter\nimport monix.eval.Task\nimport quix.api.v1.execute.{Builder => _, _}\nimport quix.api.v2.execute._\nimport quix.core.executions.DelegatingBuilder\n\nimport java.io.{BufferedWriter, OutputStream, OutputStreamWriter}\nimport java.nio.file.{Files, Paths}\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.zip.GZIPOutputStream\n\nclass DownloadableBuilder[Code](delegate: Builder,\n                                downloadConfig: DownloadConfig,\n                                queryResultsStorage: QueryResultsStorage,\n                                consumer: Consumer[ExecutionEvent])\n  extends DelegatingBuilder(delegate) {\n  val sentColumnsPerQuery = collection.mutable.Set.empty[String]\n  val openStreams = new ConcurrentHashMap[String, OutputStream]\n\n  override def startSubQuery(subQueryId: String, code: String): Task[Unit] = {\n    for {\n      _ <- delegate.startSubQuery(subQueryId, code)\n      _ <- createNewFile(subQueryId)\n    } yield ()\n  }\n\n  override def addSubQuery(subQueryId: String, results: Batch): Task[Unit] = {\n    sendColumns(subQueryId, results.columns) >>\n      use(subQueryId, results.data)\n  }\n\n  override def endSubQuery(subQueryId: String, stats: Map[String, Any]): Task[Unit] = {\n    for {\n      _ <- delegate.endSubQuery(subQueryId, stats).attempt\n      _ <- close(subQueryId)\n      _ <- consumer.write(Download(subQueryId, \"/api/download/\" + subQueryId))\n      _ <- Task(sentColumnsPerQuery.remove(subQueryId))\n    } yield ()\n  }\n\n  override def errorSubQuery(subQueryId: String, e: Throwable): Task[Unit] = {\n    for {\n      _ <- delegate.errorSubQuery(subQueryId, e).attempt\n      _ <- cancel(subQueryId)\n      _ <- Task(sentColumnsPerQuery.remove(subQueryId))\n    } yield ()\n  }\n\n  def sendColumns(subQueryId: String, columnsOpt: Option[Seq[BatchColumn]]) = {\n    columnsOpt match {\n      case Some(columns) if !sentColumnsPerQuery.contains(subQueryId) =>\n        use(subQueryId, Seq(columns.map(_.name))) >>\n          Task(sentColumnsPerQuery.add(subQueryId))\n\n      case _ => Task.unit\n\n    }\n  }\n\n  def createNewFile(subQueryId: String): Task[Unit] = {\n    val path = Paths.get(downloadConfig.downloadDir, subQueryId)\n\n    val writerTask = Task(Files.createDirectories(Paths.get(downloadConfig.downloadDir))) >>\n      Task(Files.deleteIfExists(path)) >>\n      Task(Files.createFile(path)) >>\n      Task(new GZIPOutputStream(Files.newOutputStream(path)))\n\n    for {\n      writer <- writerTask\n      _ <- Task(openStreams.put(subQueryId, writer))\n    } yield writer\n  }\n\n  def use(subQueryId: String, rows: Seq[Seq[Any]]): Task[Unit] = Task {\n    val stream = openStreams.get(subQueryId)\n    val writer = new CSVWriter(new BufferedWriter(new OutputStreamWriter(stream, \"UTF-8\")))\n\n    if (rows.nonEmpty && stream != null) {\n      rows.foreach(row => writer.writeNext(row.toArray.map(nullToEmpty), true))\n      writer.flush()\n    }\n  }\n\n  def nullToEmpty(any: Any): String = if (any == null) \"\" else any.toString\n\n  def close(subQueryId: String): Task[Unit] = {\n    val path = Paths.get(downloadConfig.downloadDir, subQueryId)\n\n    openStreams.get(subQueryId) match {\n      case null => Task.unit\n      case stream =>\n        Task(stream.flush()).attempt >>\n          Task(stream.close()).attempt >>\n          Task(openStreams.remove(subQueryId)) >>\n          queryResultsStorage.upload(subQueryId, path)\n    }\n  }\n\n  def cancel(subQueryId: String): Task[Unit] = {\n    val path = Paths.get(downloadConfig.downloadDir, subQueryId)\n\n    close(subQueryId) >> Task(Files.deleteIfExists(path))\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/executions/DelegatingBuilder.scala",
    "content": "package quix.core.executions\n\nimport quix.api.v1.execute.Batch\nimport quix.api.v2.execute._\n\nabstract class DelegatingBuilder(val delegate: Builder) extends Builder {\n\n  override def start(query: Query) =\n    delegate.start(query)\n\n  override def end(query: Query) =\n    delegate.end(query)\n\n  override def error(queryId: String, e: Throwable) =\n    delegate.error(queryId, e)\n\n  override def rowCount: Long =\n    delegate.rowCount\n\n  override def lastError: Option[Throwable] =\n    delegate.lastError\n\n  override def startSubQuery(subQueryId: String, code: String) =\n    delegate.startSubQuery(subQueryId, code)\n\n  override def addSubQuery(subQueryId: String, results: Batch) =\n    delegate.addSubQuery(subQueryId, results)\n\n  override def endSubQuery(subQueryId: String, stats: Map[String, Any]) =\n    delegate.endSubQuery(subQueryId, stats)\n\n  override def errorSubQuery(subQueryId: String, e: Throwable) =\n    delegate.errorSubQuery(subQueryId, e)\n\n  override def log(subQueryId: String, line: String, level: String) =\n    delegate.log(subQueryId, line, level)\n}"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/executions/SingleQueryExecutor.scala",
    "content": "package quix.core.executions\n\nimport monix.eval.Task\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{Executor, ImmutableSubQuery}\nimport quix.core.results.SingleBuilder\n\n/** SingleQueryExecutor exposes useful methods for executing single queries with small amount of rows */\ntrait SingleQueryExecutor {\n  val queryExecutor: Executor\n\n  val user = User(\"quix-db-tree\")\n\n  /** @param sql  sql that when executed will return small amount of results\n   * @param delim delimiter that will be used to concatenate each row produced by sql\n   * @return list of rows, if row is made of more than one column, they will be concatenated with delim\n   **/\n  def executeForSingleColumn(sql: String, delim: String = \"\"): Task[List[String]] = {\n    executeFor[String](sql, x => x.mkString(delim))\n  }\n\n  /** @param sql         Sql that when executed will return small amount of results\n   * @param resultMapper Function that will be applied to each row\n   * @return Returns list of T produced by applying resultMapper on each row\n   */\n  def executeFor[T](sql: String, resultMapper: List[String] => T): Task[List[T]] = {\n    val subQuery = ImmutableSubQuery(sql, user)\n    val resultBuilder = new SingleBuilder\n    for {\n      _ <- queryExecutor.execute(subQuery, resultBuilder)\n      results <- Task(\n        resultBuilder.build()\n          .map(row => resultMapper(row.map(_.toString).toList))\n      )\n      _ <- if (resultBuilder.isFailure) {\n        Task.raiseError(new Exception(\"query failed\"))\n      } else {\n        Task.unit\n      }\n\n    } yield results\n  }\n}"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/executions/SqlModule.scala",
    "content": "package quix.core.executions\n\nimport monix.eval.Task\nimport quix.api.v1.db.Db\nimport quix.api.v1.execute.StartCommand\nimport quix.api.v1.users.User\nimport quix.api.v2.execute._\nimport quix.core.sql.{PrestoLikeSplitter, SqlSplitter}\n\nclass SqlModule(val executor: Executor,\n                val db: Option[Db],\n                val splitter: SqlSplitter = PrestoLikeSplitter) extends ExecutionModule {\n\n  override def start(command: StartCommand[String], id: String, user: User, builder: Builder): Task[Unit] = {\n    val query = splitter.split(command, id, user)\n\n    for {\n      _ <- builder.start(query)\n      _ <- Task.traverse(query.subQueries) { q =>\n        Task(builder.lastError).flatMap {\n          case None =>\n            executor.execute(q, builder)\n          case Some(e) =>\n            Task.raiseError(e)\n        }\n      }.attempt\n      _ <- builder.end(query)\n    } yield ()\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/history/Execution.scala",
    "content": "package quix.core.history\n\nimport java.time.Instant\n\nimport quix.api.v1.users.User\n\ncase class Execution(id: String,\n                     queryType: String,\n                     statements: Seq[String],\n                     code: String,\n                     user: User,\n                     startedAt: Instant,\n                     status: ExecutionStatus)\n\nsealed trait ExecutionStatus\n\nobject ExecutionStatus {\n  case object Running extends ExecutionStatus\n  case object Finished extends ExecutionStatus\n  case object Failed extends ExecutionStatus\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/history/HistoryBuilder.scala",
    "content": "package quix.core.history\n\nimport monix.eval.Task\nimport quix.api.v1.execute.Batch\nimport quix.api.v2.execute.{Builder, Query}\nimport quix.core.history.dao.HistoryWriteDao\n\nclass HistoryBuilder[Results](delegate: Builder,\n                              historyWriteDao: HistoryWriteDao,\n                              queryType: String)\n  extends Builder {\n\n  override def start(query: Query): Task[Unit] =\n    delegate.start(query).flatMap(_ => historyWriteDao.executionStarted(query, queryType))\n\n  override def end(query: Query): Task[Unit] =\n    delegate.end(query).flatMap(_ => historyWriteDao.executionSucceeded(query.id))\n\n  override def error(queryId: String, e: Throwable): Task[Unit] =\n    delegate.error(queryId, e).flatMap(_ => historyWriteDao.executionFailed(queryId, e))\n\n  override def rowCount: Long =\n    delegate.rowCount\n\n  override def lastError: Option[Throwable] =\n    delegate.lastError\n\n  override def startSubQuery(subQueryId: String, code: String): Task[Unit] =\n    delegate.startSubQuery(subQueryId, code)\n\n  override def addSubQuery(subQueryId: String, results: Batch): Task[Unit] =\n    delegate.addSubQuery(subQueryId, results)\n\n  override def endSubQuery(subQueryId: String, stats: Map[String, Any]): Task[Unit] =\n    delegate.endSubQuery(subQueryId, stats)\n\n  override def errorSubQuery(subQueryId: String, e: Throwable): Task[Unit] =\n    delegate.errorSubQuery(subQueryId, e)\n\n  override def log(subQueryId: String, line: String, level: String): Task[Unit] =\n    delegate.log(subQueryId, line, level)\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/history/dao/HistoryReadDao.scala",
    "content": "package quix.core.history.dao\n\nimport monix.eval.Task\nimport quix.core.history.{Execution, ExecutionStatus}\n\nimport scala.collection.mutable.ListBuffer\n\ntrait HistoryReadDao {\n  def executions(filter: Filter = Filter.None,\n                 sort: Sort = Sort.Default,\n                 page: Page = Page.First): Task[List[Execution]]\n}\n\nsealed trait Filter\n\nobject Filter {\n\n  case object None extends Filter\n\n  case class Status(status: ExecutionStatus) extends Filter\n\n  case class User(email: String) extends Filter\n\n  case class Query(query: String) extends Filter\n\n  case class QueryType(queryType: String) extends Filter\n\n  case class CompoundFilter(filters: List[Filter]) extends Filter\n\n  def apply(userEmail: String, query: String): Filter = apply(userEmail, query, \"\")\n\n  def apply(userEmail: String, query: String, queryType: String): Filter = {\n    var filters = ListBuffer.empty[Filter]\n\n    if (userEmail.nonEmpty) filters += User(userEmail)\n    if (query.nonEmpty) filters += Query(query)\n    if (queryType.nonEmpty) filters += QueryType(queryType)\n\n    filters.toList match {\n      case Nil => None\n      case List(single) => single\n      case many => CompoundFilter(many)\n    }\n  }\n\n}\n\ncase class Sort(by: SortField, order: SortOrder)\n\nobject Sort {\n  val Default = Sort(SortField.StartTime, SortOrder.Descending)\n}\n\nsealed trait SortField\n\nobject SortField {\n\n  case object StartTime extends SortField\n\n}\n\nsealed trait SortOrder\n\nobject SortOrder {\n\n  case object Ascending extends SortOrder\n\n  case object Descending extends SortOrder\n\n}\n\ntrait Page {\n  def offset: Int\n\n  def limit: Int\n\n  def endOffset: Int = offset + limit\n}\n\nobject Page {\n  val DefaultLimit = 20\n  val MaxLimit = 1000\n  val First = Page(0, DefaultLimit)\n\n  def apply(offset: Int, limit: Int): Page = {\n    val offset1 = offset max 0\n    val limit1 = limit min MaxLimit\n    new Page {\n      override val offset: Int = offset1\n      override val limit: Int = limit1\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/history/dao/HistoryWriteDao.scala",
    "content": "package quix.core.history.dao\n\nimport monix.eval.Task\nimport quix.api.v2.execute.Query\n\ntrait HistoryWriteDao {\n  def executionStarted(query: Query, queryType: String): Task[Unit]\n\n  def executionSucceeded(queryId: String): Task[Unit]\n\n  def executionFailed(queryId: String, error: Throwable): Task[Unit]\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/history/dao/InMemoryHistoryDao.scala",
    "content": "package quix.core.history.dao\n\nimport java.time.Clock\n\nimport cats.effect.concurrent.Ref\nimport monix.eval.Task\nimport quix.api.v2.execute.Query\nimport quix.core.history.dao.InMemoryHistoryDao.{comparator, predicate}\nimport quix.core.history.{Execution, ExecutionStatus}\n\ncase class InMemoryHistoryDao(state: Ref[Task, Map[String, Execution]], clock: Clock)\n  extends HistoryWriteDao with HistoryReadDao {\n\n  private val instant = Task(clock.instant)\n\n  override def executionStarted(query: Query, queryType: String): Task[Unit] =\n    instant.flatMap { now =>\n      val execution = Execution(\n        id = query.id,\n        queryType = queryType,\n        statements = query.subQueries.map(_.text),\n        code = query.rawCode,\n        user = query.subQueries.map(_.user).head,\n        startedAt = now,\n        status = ExecutionStatus.Running)\n\n      state.update(_ + (query.id -> execution))\n    }\n\n  override def executionSucceeded(queryId: String): Task[Unit] =\n    update(queryId, _.copy(status = ExecutionStatus.Finished))\n\n  override def executionFailed(queryId: String, error: Throwable): Task[Unit] =\n    update(queryId, _.copy(status = ExecutionStatus.Failed))\n\n  override def executions(filter: Filter, sort: Sort, page: Page): Task[List[Execution]] =\n    state.get.map { map =>\n      map.values.toList\n        .filter(predicate(filter))\n        .sortWith(comparator(sort))\n        .slice(page.offset, page.endOffset)\n    }\n\n  private def update(queryId: String, f: Execution => Execution): Task[Unit] =\n    state.update { map =>\n      map.get(queryId).fold(map) { execution =>\n        map + (queryId -> f(execution))\n      }\n    }\n\n}\n\nobject InMemoryHistoryDao {\n  def make(clock: Clock): Task[InMemoryHistoryDao] =\n    Ref.of[Task, Map[String, Execution]](Map.empty).map(InMemoryHistoryDao(_, clock))\n\n  def predicate(filter: Filter)(execution: Execution): Boolean = filter match {\n    case Filter.None => true\n\n    case Filter.Status(status) =>\n      execution.status == status\n\n    case Filter.User(email) =>\n      execution.user.email == email\n\n    case Filter.QueryType(queryType) =>\n      execution.queryType == queryType\n\n    case Filter.Query(text) =>\n      execution.code.toLowerCase.contains(text.toLowerCase())\n\n    case Filter.CompoundFilter(filters) =>\n      filters.forall(filter => predicate(filter)(execution))\n  }\n\n  def comparator(sort: Sort)(e1: Execution, e2: Execution): Boolean = sort match {\n    case Sort(SortField.StartTime, SortOrder.Ascending) =>\n      e1.startedAt isBefore e2.startedAt\n\n    case Sort(SortField.StartTime, SortOrder.Descending) =>\n      e1.startedAt isAfter e2.startedAt\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/history/dao/MySqlHistoryDao.scala",
    "content": "package quix.core.history.dao\n\nimport java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}\nimport java.time.{Clock, Instant}\n\nimport cats.effect.Resource\nimport monix.eval.Task\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{Query => ActiveQuery}\nimport quix.core.history.dao.MySqlHistoryDao._\nimport quix.core.history.{Execution, ExecutionStatus}\n\nclass MySqlHistoryReadDao(connection: Connection) extends HistoryReadDao {\n\n  override def executions(filter: Filter, sort: Sort, page: Page): Task[List[Execution]] = {\n    val insertStatement = prepare(connection) {\n      s\"\"\"\n        SELECT id, query_type, statements, code, user_id, user_email, created_at, status\n        FROM executions_history\n        WHERE ${where(filter)}\n        ${orderBy(sort)}\n        LIMIT ?, ?\n      \"\"\"\n    }\n\n    insertStatement.use { statement =>\n      for {\n        _ <- Task(statement.setInt(1, page.offset))\n        _ <- Task(statement.setInt(2, page.limit))\n        rows <- Task(statement.executeQuery()).bracket(getRows(getExecution))(rs => Task(rs.close()))\n      } yield rows.reverse\n    }\n  }\n\n  private def where(filter: Filter): String = filter match {\n    case Filter.Status(status) => s\"status = '${status.toString.toUpperCase}'\"\n    case Filter.User(userEmail) => s\"user_email = '$userEmail'\"\n    case Filter.Query(query) => s\"code like '%$query%'\"\n    case Filter.QueryType(queryType) => s\"query_type = '$queryType'\"\n    case Filter.CompoundFilter(filters) => filters.map(where).mkString(\" and \")\n    case Filter.None => \"1 = 1\"\n  }\n\n  private def orderBy(sort: Sort): String =\n    s\"ORDER BY ${field(sort.by)} ${order(sort.order)}\"\n\n  private def field(sortField: SortField): String = sortField match {\n    case SortField.StartTime => \"created_at\"\n  }\n\n  private def order(sortOrder: SortOrder): String = sortOrder match {\n    case SortOrder.Descending => \"DESC\"\n    case SortOrder.Ascending => \"ASC\"\n  }\n\n  private def getRows[A](getRow: ResultSet => Task[A])(resultSet: ResultSet): Task[List[A]] = {\n    Task(resultSet.next()).flatMapLoop(List.empty[A]) { (hasRow, rows, continue) =>\n      if (hasRow) getRow(resultSet).flatMap(row => continue(row :: rows))\n      else Task.now(rows)\n    }\n  }\n\n  private def getExecution(resultSet: ResultSet): Task[Execution] = for {\n    id <- Task(resultSet.getString(\"id\"))\n    queryType <- Task(resultSet.getString(\"query_type\"))\n    statements <- Task(resultSet.getString(\"statements\"))\n    code <- Task(resultSet.getString(\"code\"))\n    userEmail <- Task(resultSet.getString(\"user_email\"))\n    userId <- Task(resultSet.getString(\"user_id\"))\n    createdAt <- Task(resultSet.getLong(\"created_at\"))\n    status <- Task(resultSet.getString(\"status\"))\n  } yield Execution(\n    id = id,\n    queryType = queryType,\n    statements = statements.split(separator),\n    code = code,\n    user = User(userEmail, userId),\n    startedAt = Instant.ofEpochMilli(createdAt),\n    status = statusFrom(status))\n\n  private def statusFrom(status: String): ExecutionStatus = status match {\n    case \"RUNNING\" => ExecutionStatus.Running\n    case \"FINISHED\" => ExecutionStatus.Finished\n    case _ => ExecutionStatus.Failed\n  }\n\n}\n\nclass MySqlHistoryWriteDao(connection: Connection, clock: Clock) extends HistoryWriteDao {\n\n  private val instant = Task(clock.instant())\n\n  private val startStatement = prepare(connection) {\n    \"\"\"\n      INSERT INTO executions_history (id, query_type, statements, code, user_id, user_email, created_at)\n      VALUES (?, ?, ?, ?, ?, ?, ?)\n    \"\"\"\n  }\n\n  private val succeedStatement = prepare(connection) {\n    \"UPDATE executions_history SET status = 'FINISHED' WHERE id = ? LIMIT 1\"\n  }\n\n  private val failStatement = prepare(connection) {\n    \"UPDATE executions_history SET status = 'FAILED' WHERE id = ? LIMIT 1\"\n  }\n\n  override def executionStarted(query: ActiveQuery, queryType: String): Task[Unit] =\n    startStatement.use { statement =>\n      for {\n        now <- instant\n        _ <- Task(statement.setString(1, query.id))\n        _ <- Task(statement.setString(2, queryType))\n        _ <- Task(statement.setString(3, query.subQueries.map(_.text).mkString(separator)))\n        _ <- Task(statement.setString(4, query.rawCode))\n        _ <- Task(statement.setString(5, query.subQueries.map(_.user).head.id))\n        _ <- Task(statement.setString(6, query.subQueries.map(_.user).head.email))\n        _ <- Task(statement.setLong(7, now.toEpochMilli))\n        _ <- Task(statement.executeUpdate())\n      } yield ()\n    }\n\n  override def executionSucceeded(queryId: String): Task[Unit] =\n    succeedStatement.use { statement =>\n      Task(statement.setString(1, queryId)) *>\n        Task(statement.executeUpdate())\n    }\n\n  override def executionFailed(queryId: String, error: Throwable): Task[Unit] =\n    failStatement.use { statement =>\n      Task(statement.setString(1, queryId)) *>\n        Task(statement.executeUpdate())\n    }\n\n}\n\ncase class JdbcConfig(url: String, user: String, pass: String)\n\nobject MySqlHistoryDao {\n  val separator = \";\"\n\n  def connect(config: JdbcConfig): Resource[Task, Connection] = {\n    val acquire = Task(DriverManager.getConnection(config.url, config.user, config.pass))\n    Resource.make(acquire)(connection => Task(connection.close()))\n  }\n\n  def prepare(connection: Connection)(sql: String): Resource[Task, PreparedStatement] =\n    Resource.make(Task(connection.prepareStatement(sql)))(statement => Task(statement.close()))\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/results/MultiBuilder.scala",
    "content": "package quix.core.results\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v1.execute.Batch._\nimport quix.api.v1.execute.{Batch, BatchColumn, BatchError, Consumer, End, Error, ExceptionPropagatedToClient, ExecutionEvent, Log, Progress, Row, Start, SubQueryDetails, SubQueryEnd, SubQueryError, SubQueryFields, SubQueryStart}\nimport quix.api.v2.execute._\n\n/** MultiBuilder accepts Consumer[ExecutionEvent] and propagates to it different events from lifecycle of Builder.\n * For example, {{{start(query: Execution)}}} will produce {{{Start(query.id, query.statements.size)}}}\n * */\nclass MultiBuilder(val consumer: Consumer[ExecutionEvent])\n  extends Builder with LazyLogging {\n\n  var rows = 0L\n  val sentColumnsPerQuery = collection.mutable.Set.empty[String]\n  var lastError: Option[Throwable] = None\n\n  override def start(query: Query) = {\n    consumer.write(Start(query.id, query.subQueries.size))\n  }\n\n  override def end(query: Query) = {\n    consumer.write(End(query.id))\n  }\n\n  override def startSubQuery(subQueryId: String, code : String) = {\n    val resetCount = Task(this.rows = 0L)\n    val startTask = consumer.write(SubQueryStart(subQueryId))\n    val detailsTask = consumer.write(SubQueryDetails(subQueryId, code))\n\n    Task.sequence(List(resetCount, startTask, detailsTask)).map(_ => ())\n  }\n\n  override def endSubQuery(subQueryId : String, stats : Map[String, Any]) = {\n    consumer.write(SubQueryEnd(subQueryId, stats))\n  }\n\n  override def addSubQuery(subQueryId : String, results: Batch) = {\n    val columnTask: Task[Unit] = results.columns.map(columns => sendColumns(subQueryId, columns)).getOrElse(Task.unit)\n    val progressTask: Task[Unit] = results.percentage.map(percentage => sendProgress(subQueryId, percentage)).getOrElse(Task.unit)\n    val errorTask: Task[Unit] = results.error.map(error => sendErrors(subQueryId, error)).getOrElse(Task.unit)\n\n    rows += results.data.size\n\n    val rowTask = Task.traverse(results.data) { row =>\n      consumer.write(Row(subQueryId, row))\n    }\n\n    Task.sequence(Seq(columnTask, progressTask, errorTask, rowTask)).map(_ => ())\n  }\n\n  def sendErrors(queryId: String, prestoError: BatchError) = {\n    lastError = Some(new RuntimeException(prestoError.message))\n    consumer.write(Error(queryId, prestoError.message))\n  }\n\n  def sendProgress(queryId: String, percentage: Int) = {\n    consumer.write(Progress(queryId, percentage))\n  }\n\n  override def errorSubQuery(subQueryId: String, e: Throwable) = {\n    lastError = Some(e)\n    val errorMessage = makeErrorMessage(e)\n    consumer.write(SubQueryError(subQueryId, errorMessage))\n  }\n\n  private def makeErrorMessage(e: Throwable) = {\n    e match {\n      case ExceptionPropagatedToClient(message) => message\n      case _ => s\"${e.getClass.getSimpleName}(${e.getMessage})\"\n    }\n  }\n\n  /** Sends to consumer SubQueryFields on every unique queryId.\n   * Every query can have only single list of columns, so no duplications are allowed.\n   *  */\n  def sendColumns(queryId: String, names: Seq[BatchColumn]) = {\n    val sentColumns = sentColumnsPerQuery.contains(queryId)\n    if (!sentColumns && names.nonEmpty) {\n      sentColumnsPerQuery += queryId\n      consumer.write(SubQueryFields(queryId, names.map(_.name)))\n    } else Task.unit\n  }\n\n  override def rowCount: Long = rows\n\n  override def error(queryId: String, e: Throwable) = {\n    lastError = Some(e)\n    val errorMessage = makeErrorMessage(e)\n    consumer.write(Error(queryId, errorMessage))\n  }\n\n  override def log(subQueryId: String, line: String, level: String): Task[Unit] = {\n    consumer.write(Log(subQueryId, line, level))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/results/SingleBuilder.scala",
    "content": "package quix.core.results\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v1.execute.{Batch, BatchColumn}\nimport quix.api.v2.execute.{Builder, Query}\n\nimport scala.collection.mutable.ListBuffer\n\n/** SingleBuilder accepts rows and stores them in memory in order of their arrival.\n * SingleBuilder is used by internal quix-backend processes such as db-tree traversal\n * or E2E tests. To receive the rows collected so far, one must call builder.build() */\nclass SingleBuilder extends Builder with LazyLogging {\n\n  private val rows = ListBuffer.empty[Seq[Any]]\n  private val headers = ListBuffer.empty[BatchColumn]\n  private var failureCause: Option[Throwable] = None\n  private var logMessages = ListBuffer.empty[String]\n  private var statistics = Map.empty[String, Any]\n  private val queriesStatuses = ListBuffer.empty[QueryStatus]\n\n  /**\n   * @returns the rows collected so far */\n  def build(): List[Seq[Any]] = rows.toList\n\n  override def errorSubQuery(subQueryId: String, e: Throwable) = Task {\n    queriesStatuses += QueryFailed(subQueryId, e.getMessage)\n    failureCause = Option(e)\n  }\n\n  override def startSubQuery(subQueryId: String, code: String) = Task {\n    queriesStatuses += QueryStarted(subQueryId, code)\n  }\n\n  override def addSubQuery(subQueryId: String, results: Batch) = handleBatch(results)\n\n  def handleBatch(batch: Batch): Task[Unit] = Task {\n    batch.error foreach { error =>\n      failureCause = Option(new RuntimeException(error.message))\n    }\n\n    for {\n      newHeaders <- batch.columns if headers.isEmpty\n    } headers ++= newHeaders\n\n    rows ++= batch.data\n  }\n\n  override def endSubQuery(subQueryId: String, stats: Map[String, Any]) = Task {\n    queriesStatuses += QueryFinished(subQueryId)\n    this.statistics = stats\n  }\n\n  override def start(query: Query) = Task.unit\n\n  override def end(query: Query) = Task.unit\n\n  def isFailure = failureCause.isDefined\n\n  override def rowCount: Long = rows.size\n\n  override def lastError: Option[Throwable] = failureCause\n\n  override def error(queryId: String, e: Throwable) = Task {\n    failureCause = Option(e)\n  }\n\n  def columns = headers.toList\n\n  override def log(subQueryId: String, line: String, level: String): Task[Unit] = Task {\n    logMessages += line\n  }\n\n  def logs = logMessages.toList\n\n  def queries = queriesStatuses.toList\n}\n\nsealed trait QueryStatus\n\nsealed case class QueryStarted(queryId: String, code: String) extends QueryStatus\n\nsealed case class QueryFinished(queryId: String) extends QueryStatus\n\nsealed case class QueryFailed(queryId: String, error: String) extends QueryStatus"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/sql/PrestoSqlOps.scala",
    "content": "package quix.core.sql\n\nimport io.prestosql.sql.parser.StatementSplitter\n\nimport scala.collection.JavaConverters._\n\nobject PrestoSqlOps {\n\n  def splitToStatements(multipleStatements: String): List[String] = {\n    val splitter = new StatementSplitter(multipleStatements, Set(\";\").asJava)\n\n    val completeStatements = splitter.getCompleteStatements.asScala.map(_.statement()).toList\n    val partialStatements = splitter.getPartialStatement\n\n    val restIsEmptyOrMadeofComments = partialStatements.trim.isEmpty || partialStatements.split(\"\\n\").filterNot(_.isEmpty).forall(_.trim.startsWith(\"--\"))\n\n    (completeStatements.isEmpty, restIsEmptyOrMadeofComments) match {\n      case (true, true) =>\n        List.empty\n\n      case (true, _) =>\n        List(multipleStatements)\n\n      case (false, true) =>\n        recoverLeadingSpaces(multipleStatements, completeStatements.head) +: completeStatements.tail\n\n      case (false, false) =>\n        recoverLeadingSpaces(multipleStatements, completeStatements.head) +: completeStatements.tail :+ partialStatements\n    }\n  }\n\n  /*\n    StatementSplitter trims all leading whitespaces, which makes it hard\n    to mark correct line in case of presto error\n\n    see https://github.com/wix-incubator/quix/issues/58 for more details\n   */\n  def recoverLeadingSpaces(original: String, trimmed: String): String = {\n    val index = original.indexOf(trimmed)\n    original.substring(0, index) ++ trimmed\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/sql/SqlSplitter.scala",
    "content": "package quix.core.sql\n\nimport monix.execution.atomic.Atomic\nimport quix.api.v1.execute.StartCommand\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{ImmutableSubQuery, MutableSession, Query, Session}\n\ntrait SqlSplitter {\n  def split(sql: String): List[String]\n\n  def newSession(command: StartCommand[String], user: User): Session = new MutableSession\n\n  def split(command: StartCommand[String], id: String, user: User): Query = {\n    val canceled = Atomic(false)\n    val session = newSession(command, user)\n\n    val subQueries = split(command.code).map { sql =>\n      ImmutableSubQuery(sql, user, canceled = canceled, session = session)\n    }\n\n    Query(subQueries, id, canceled, rawCode = command.code)\n  }\n}\n\nobject PrestoLikeSplitter extends SqlSplitter {\n  def split(sql: String): List[String] = {\n    PrestoSqlOps.splitToStatements(sql)\n  }\n}\n\nclass StopWordSqlSplitter(val stopWords: String*) extends SqlSplitter {\n  def split(sql: String): List[String] = {\n    val statements = PrestoSqlOps.splitToStatements(sql)\n\n    val noStopWords = statements.dropWhile(containsStopWords)\n\n    val maybeSplitByStopWords = noStopWords.headOption.map { statement =>\n      val newHead = sql.substring(0, sql.indexOf(statement) + statement.length)\n      newHead :: noStopWords.tail\n    }\n\n    maybeSplitByStopWords.getOrElse(statements)\n  }\n\n  def containsStopWords(sql: String): Boolean = {\n    stopWords.exists(sql.contains)\n  }\n}"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/utils/Chores.scala",
    "content": "package quix.core.utils\n\nimport java.util.concurrent.{Executors, ScheduledExecutorService, ThreadFactory}\n\nimport com.typesafe.scalalogging.LazyLogging\n\nimport scala.concurrent.duration.TimeUnit\nimport scala.util.control.NonFatal\n\ntrait Chores extends LazyLogging {\n  private val className = this.getClass.toString\n  private val poolName = \"chore-\" + className\n  private val executor = scheduledSingleThreadPoolNamed(poolName)\n\n  def chore(): Unit\n\n  def scheduleChore(initialDelay: Long, delay: Long, unit: TimeUnit) = {\n    val runnable = new Runnable {\n      override def run(): Unit = try {\n        logger.info(\"event=chore-start class-name=\" + className)\n        chore()\n        logger.info(\"event=chore-finish class-name=\" + className)\n      } catch {\n        case NonFatal(t) =>\n          logger.warn(\"event=chore-failure class-name=\" + className, t)\n      }\n    }\n\n    logger.warn(s\"schedule $className.chore() at fixed rate every ${unit.toMinutes(delay)} minutes\")\n    executor.scheduleAtFixedRate(runnable, initialDelay, delay, unit)\n  }\n\n  // helpers\n  private def daemonThreadsNamed(format: String): ThreadFactory = {\n    r: Runnable => {\n      val t = Executors.defaultThreadFactory.newThread(r)\n      t.setDaemon(true)\n      t.setName(format)\n      t\n    }\n  }\n\n  private def scheduledSingleThreadPoolNamed(format: String): ScheduledExecutorService = {\n    Executors.newSingleThreadScheduledExecutor(daemonThreadsNamed(format))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/utils/JsonOps.scala",
    "content": "package quix.core.utils\n\nimport java.lang.reflect.{ParameterizedType, Type}\nimport java.util.TimeZone\n\nimport com.fasterxml.jackson.core.`type`.TypeReference\nimport com.fasterxml.jackson.databind.SerializationFeature._\nimport com.fasterxml.jackson.databind.{DeserializationFeature, JsonNode, ObjectMapper}\nimport com.fasterxml.jackson.datatype.jdk8.Jdk8Module\nimport com.fasterxml.jackson.module.scala.DefaultScalaModule\nimport quix.core.utils.JacksonSupport._\n\nimport scala.util.control.NonFatal\n\ntrait StringJsonHelpersSupport {\n\n  implicit class String2jsonNode(s: String) {\n    def asJson(implicit mapper: ObjectMapper): JsonNode = mapper.readTree(s)\n\n    def as[T](implicit mn: Manifest[T], mapper: ObjectMapper): T = deserialize[T](s)\n\n    def get(key: String, default: String = \"\")(implicit mapper: ObjectMapper) = {\n      try {\n        s.asJson.get(key) match {\n          case null => default\n          case node if node.isTextual => node.asText(default)\n          case node if node.isObject && node.toString.nonEmpty => node.toString\n          case _ => default\n        }\n      } catch {\n        case NonFatal(_) => default\n      }\n    }\n  }\n\n  implicit class AnyObject2JsonNode(o: Any) {\n    def asJsonStr(implicit mapper: ObjectMapper): String = mapper.writeValueAsString(o)\n  }\n\n}\n\nobject JacksonSupport {\n  def deserialize[T](value: String)(implicit mn: Manifest[T], mapper: ObjectMapper): T =\n    mapper.readValue(value, typeReference[T])\n\n  private def typeReference[T: Manifest] = new TypeReference[T] {\n    override def getType = typeFromManifest(manifest[T])\n  }\n\n  private def typeFromManifest(m: Manifest[_]): Type = {\n    if (m.typeArguments.isEmpty) {\n      m.runtimeClass\n    }\n    else new ParameterizedType {\n      def getRawType = m.runtimeClass\n\n      def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray\n\n      def getOwnerType = null\n    }\n  }\n}\n\nobject JsonOps {\n\n  private val defaultModules = Seq(new DefaultScalaModule, new Jdk8Module)\n\n  def global: ObjectMapper = Implicits.global\n\n  def objectMapperFromTemplate: ObjectMapper =\n    new ObjectMapper().registerModules(defaultModules: _*)\n      .disable(WRITE_DATES_AS_TIMESTAMPS)\n      .setTimeZone(TimeZone.getTimeZone(\"UTC\"))\n\n  object Implicits {\n    implicit lazy val global: ObjectMapper = objectMapperFromTemplate\n      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)\n  }\n\n}"
  },
  {
    "path": "quix-backend/quix-core/src/main/scala/quix/core/utils/TaskOps.scala",
    "content": "package quix.core.utils\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\n\nimport scala.concurrent.duration.FiniteDuration\n\nobject TaskOps extends LazyLogging {\n\n  implicit class Ops[A](val task: Task[A]) extends AnyVal {\n    def retry(maxRetries: Int, firstDelay: FiniteDuration): Task[A] = {\n      task.onErrorHandleWith {\n        case ex: Exception =>\n          if (maxRetries > 0) {\n            logger.warn(s\"method=retry error=${ex.getClass.getSimpleName} retries=$maxRetries delay=${firstDelay.toMillis / 1000.0}\")\n            retry(maxRetries - 1, firstDelay * 2).delayExecution(firstDelay)\n          }\n          else\n            Task.raiseError(ex)\n      }\n    }\n\n    def logOnError(msg: String = \"\"): Task[A] = {\n      task.onErrorHandleWith {\n        case e: Exception =>\n          logger.error(msg, e)\n          Task.raiseError(e)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/resources/db/001_init.sql",
    "content": "CREATE TABLE executions_history (\n    id CHAR(36) NOT NULL PRIMARY KEY,\n    query_type VARCHAR(64) NOT NULL,\n    statements MEDIUMTEXT NOT NULL,\n    code MEDIUMTEXT NOT NULL,\n    user_id VARCHAR(64) NOT NULL,\n    user_email VARCHAR(64) NOT NULL,\n    status ENUM('RUNNING', 'FINISHED', 'FAILED') NOT NULL DEFAULT 'RUNNING',\n    created_at BIGINT UNSIGNED NOT NULL,\n    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP(),\n    INDEX published_forms (created_at)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/db/DbOpsTest.scala",
    "content": "package quix.core.db\n\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport quix.api.v1.db.{Catalog, Kolumn, Schema, Table}\n\nclass DbOpsTest extends SpecWithJUnit with MustMatchers  {\n\n  \"DbOps.mergeNewAndOldCatalogs\" should {\n\n    \"pass sanity if no change was detected\" in {\n      val columns: List[Kolumn] = List(Kolumn(\"uuid\", \"guid\"))\n      val tables: List[Table] = List(Table(\"users\", columns))\n      val schemas: List[Schema] = List(Schema(\"dbo\", tables))\n      val newCatalogs = List(Catalog(\"bi\", schemas))\n      val oldCatalogs = List(Catalog(\"bi\", schemas))\n\n      val mergedResult = DbOps.mergeNewAndOldCatalogs(newCatalogs, oldCatalogs)\n\n      mergedResult must_=== newCatalogs\n    }\n\n    \"swap old catalogs with new catalogs if tables were added\" in {\n      val columns: List[Kolumn] = List(Kolumn(\"uuid\", \"guid\"))\n      val nonEmptyTables: List[Table] = List(Table(\"users\", columns))\n      val emptyTables: List[Table] = List.empty[Table]\n      val newCatalogs = List(Catalog(\"bi\", List(Schema(\"dbo\", nonEmptyTables))))\n      val oldCatalogs = List(Catalog(\"bi\", List(Schema(\"dbo\", emptyTables))))\n\n      val mergedResult = DbOps.mergeNewAndOldCatalogs(newCatalogs, oldCatalogs)\n\n      mergedResult must_=== newCatalogs\n    }\n\n    \"swap old catalogs with new catalogs if tables were removed\" in {\n      val columns: List[Kolumn] = List(Kolumn(\"uuid\", \"guid\"))\n      val nonEmptyTables: List[Table] = List(Table(\"users\", columns))\n      val emptyTables: List[Table] = List.empty[Table]\n      val newCatalogs = List(Catalog(\"bi\", List(Schema(\"dbo\", emptyTables))))\n      val oldCatalogs = List(Catalog(\"bi\", List(Schema(\"dbo\", nonEmptyTables))))\n\n      val mergedResult = DbOps.mergeNewAndOldCatalogs(newCatalogs, oldCatalogs)\n\n      mergedResult must_=== newCatalogs\n    }\n\n    \"not swap old catalogs with new catalogs if schemas were removed\" in {\n      val columns: List[Kolumn] = List(Kolumn(\"uuid\", \"guid\"))\n      val nonEmptyTables: List[Table] = List(Table(\"users\", columns))\n      val newCatalogs = List(Catalog(\"bi\", List.empty[Schema]))\n      val oldCatalogs = List(Catalog(\"bi\", List(Schema(\"dbo\", nonEmptyTables))))\n\n      val mergedResult = DbOps.mergeNewAndOldCatalogs(newCatalogs, oldCatalogs)\n\n      mergedResult must_=== oldCatalogs\n    }\n\n  }\n\n  \"DbOps.search\" should {\n    \"pass sanity\" in {\n      DbOps.search(List.empty, \"foo\") must beEmpty\n    }\n\n    \"search by catalog name\" in {\n      val first = Catalog(\"this-is-foo-catalog\", Nil)\n      val second = Catalog(\"this-is-boo-catalog\", Nil)\n\n      val expected = List(first)\n\n      DbOps.search(List(first, second), \"foo\") must_=== expected\n    }\n\n    \"search by schema name\" in {\n      val first = Schema(\"this-is-foo-schema\", Nil)\n      val second = Schema(\"this-is-boo-schema\", Nil)\n\n      val catalog = Catalog(\"catalog\", List(first, second))\n      val expected = Catalog(\"catalog\", List(first))\n\n      DbOps.search(List(catalog), \"foo\") must contain(expected)\n    }\n\n    \"search by table name\" in {\n      val first = Table(\"this-is-foo-table\", Nil)\n      val second = Table(\"this-is-boo-table\", Nil)\n\n      val catalog = Catalog(\"catalog\", List(Schema(\"schema\", List(first, second))))\n      val expected = Catalog(\"catalog\", List(Schema(\"schema\", List(first))))\n\n      DbOps.search(List(catalog), \"foo\") must contain(expected)\n    }\n\n    \"return complete catalog tree on top-level match\" in {\n      val catalog = Catalog(\"c1\", List(Schema(\"s1\", List(Table(\"t1\", Nil), Table(\"t2\", Nil)))))\n\n      DbOps.search(List(catalog), \"c1\") must contain(catalog)\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/db/DbQueryTest.scala",
    "content": "package quix.core.db\n\nimport org.specs2.mutable.SpecWithJUnit\n\nclass DbQueryTest extends SpecWithJUnit {\n\n  \"DbQuery.apply\" should {\n    \"return exact match query for quoted strings\" in {\n      DbQuery(\"\"\"\"foo\"\"\"\").matches(\"foo\") must beTrue\n      DbQuery(\"\"\"'foo'\"\"\").matches(\"foo\") must beTrue\n    }\n\n    \"return contains query regular strings\" in {\n      DbQuery(\"foo\").matches(\"foo\") must beTrue\n      DbQuery(\"\").matches(\"foo\") must beTrue\n    }\n\n    \"handle nulls\" in {\n      DbQuery(null).matches(\"foo\") must beFalse\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/executions/SqlModuleTest.scala",
    "content": "package quix.core.executions\n\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.execute.{End, ExecutionEvent, Start, StartCommand}\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{Builder, Executor, SubQuery}\nimport quix.core.results.{MultiBuilder, TestConsumer}\n\nclass SqlModuleTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    val consumer = new TestConsumer[ExecutionEvent]\n    val builder = new MultiBuilder(consumer)\n    val user = User(\"user@quix\", \"user-id\")\n    val module = new SqlModule(TestExecutor, None)\n\n    val emptyCommand = StartCommand[String](\"\", Map.empty)\n  }\n\n  \"SqlModule.start\" should {\n    \"invoke builder.start & builder.end methods on every command\" in new ctx {\n      module.start(emptyCommand, \"id\", user, builder).runSyncUnsafe()\n\n      eventually {\n        consumer.payloads must contain(Start(\"id\", 0))\n        consumer.payloads must contain(End(\"id\"))\n      }\n    }\n  }\n\n  object TestExecutor extends Executor {\n    override def execute(query: SubQuery, builder: Builder): Task[Unit] = Task.unit\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/ExecutionMatchers.scala",
    "content": "package quix.core.history\n\nimport org.specs2.matcher.Matcher\nimport org.specs2.matcher.Matchers._\n\nobject ExecutionMatchers {\n  def executionWithId(id: String): Matcher[Execution] =\n    equalTo(id) ^^ ((_: Execution).id)\n\n  def executionWithStatus(status: ExecutionStatus): Matcher[Execution] =\n    equalTo(status) ^^ ((_: Execution).status)\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/FakeBuilder.scala",
    "content": "package quix.core.history\n\nimport cats.effect.concurrent.Ref\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport quix.api.v1.execute.Batch\nimport quix.api.v2.execute.{Builder, Query}\n\ncase class FakeBuilder(state: Ref[Task, State]) extends Builder {\n\n  override def start(query: Query): Task[Unit] =\n    state.update(_.start(query))\n\n  override def end(query: Query): Task[Unit] =\n    state.update(_.end(query))\n\n  override def error(subQueryId: String, e: Throwable): Task[Unit] =\n    state.update(_.error(subQueryId, e))\n\n  override def rowCount: Long = get(_.rows)\n\n  override def lastError: Option[Throwable] = get(_.lastError)\n\n  override def startSubQuery(queryId: String, code: String): Task[Unit] =\n    state.update(_.startSubQuery(queryId, code))\n\n  override def addSubQuery(subQueryId: String, results: Batch): Task[Unit] =\n    state.update(_.addSubQuery(subQueryId, results))\n\n  override def endSubQuery(subQueryId: String, statistics: Map[String, Any]): Task[Unit] =\n    state.update(_.endSubQuery(subQueryId))\n\n  override def errorSubQuery(subQueryId: String, e: Throwable): Task[Unit] =\n    state.update(_.error(subQueryId, e))\n\n  override def log(subQueryId: String, line: String, level: String): Task[Unit] =\n    state.update(_.addLogLine(subQueryId, line, level))\n\n  private def get[A](f: State => A): A =\n    state.get.map(f).runSyncUnsafe()\n\n}\n\nobject FakeBuilder {\n  def make: Task[FakeBuilder] =\n    Ref.of[Task, State](State.Empty).map(FakeBuilder(_))\n}\n\ncase class State(queries: Map[String, HistoricalQuery],\n                 subQueries: Map[String, HistoricalSubQuery],\n                 errors: List[Error],\n                 log: List[LogLine]) {\n\n  def rows: Long = subQueries.values.foldLeft(0L)(_ + _.rows)\n\n  def start(execution: Query): State =\n    copy(queries = queries + (execution.id -> HistoricalQuery(execution, QueryStatus.Started)))\n\n  def end(query: Query): State =\n    copy(queries = queries + (query.id -> HistoricalQuery(query, QueryStatus.Ended)))\n\n  def error(queryId: String, e: Throwable): State =\n    copy(errors = Error(queryId, e) :: errors)\n\n  def lastError: Option[Throwable] =\n    errors.headOption.map(_.error)\n\n  def startSubQuery(queryId: String, code: String): State =\n    copy(subQueries = subQueries + (queryId -> SubQuery(code)))\n\n  def addSubQuery(queryId: String, results: Batch): State =\n    copy(subQueries = updateSubQuery(queryId, _.addResults(results)))\n\n  def endSubQuery(queryId: String): State =\n    copy(subQueries = updateSubQuery(queryId, _.ended))\n\n  def addLogLine(queryId: String, line: String, level: String): State =\n    copy(log = LogLine(queryId, line, level) :: log)\n\n  private def updateSubQuery(queryId: String, f: HistoricalSubQuery => HistoricalSubQuery): Map[String, HistoricalSubQuery] =\n    subQueries.get(queryId).fold(subQueries)(query => subQueries + (queryId -> f(query)))\n}\n\nobject State {\n  val Empty = State(Map.empty, Map.empty, Nil, Nil)\n}\n\nsealed trait QueryStatus\n\nobject QueryStatus {\n\n  case object Started extends QueryStatus\n\n  case object Ended extends QueryStatus\n\n}\n\ncase class HistoricalQuery(query: Query, status: QueryStatus)\n\ncase class HistoricalSubQuery(code: String,\n                              results: List[Batch],\n                              status: QueryStatus) {\n\n  def rows: Long = results.foldLeft(0L)(_ + _.data.size)\n\n  def addResults(moreResults: Batch): HistoricalSubQuery =\n    copy(results = moreResults :: results)\n\n  def ended: HistoricalSubQuery =\n    copy(status = QueryStatus.Ended)\n\n}\n\nobject SubQuery {\n  def apply(code: String): HistoricalSubQuery =\n    HistoricalSubQuery(code, List.empty, QueryStatus.Started)\n}\n\ncase class Error(queryId: String, error: Throwable)\n\ncase class LogLine(queryId: String, line: String, level: String)\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/FakeClock.scala",
    "content": "package quix.core.history\n\nimport java.time.{Clock, Instant, ZoneId, ZoneOffset}\nimport java.util.concurrent.atomic.AtomicReference\n\nimport scala.concurrent.duration.FiniteDuration\n\ncase class FakeClock(now: AtomicReference[Instant],\n                     getZone: ZoneId) extends Clock {\n\n  override def withZone(zone: ZoneId): Clock = copy(getZone = zone)\n\n  override def instant: Instant = now.get\n\n  def sleep(duration: FiniteDuration): Unit =\n    now.updateAndGet(_.plusMillis(duration.toMillis))\n\n}\n\nobject FakeClock {\n  def apply(now: Instant, zone: ZoneId = ZoneOffset.UTC): FakeClock =\n    FakeClock(new AtomicReference(now), zone)\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/HistoryBuilderTest.scala",
    "content": "package quix.core.history\n\nimport java.time.{Clock, Instant, ZoneOffset}\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.mutable.SpecificationWithJUnit\nimport quix.api.v1.execute.Batch\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{ImmutableSubQuery, Query}\nimport quix.core.history.ExecutionMatchers._\nimport quix.core.history.HistoryBuilderTest._\nimport quix.core.history.dao.InMemoryHistoryDao\n\nclass HistoryBuilderTest extends SpecificationWithJUnit {\n\n  val subQuery = \"query3\"\n  val now = Instant.ofEpochMilli(0)\n  val clock = Clock.fixed(now, ZoneOffset.UTC)\n  val makeDao = InMemoryHistoryDao.make(clock)\n\n  \"delegate calls to internal builder\" in {\n    val result = for {\n      delegate <- FakeBuilder.make\n      dao <- makeDao\n      builder = new HistoryBuilder(delegate, dao, queryType)\n      _ <- builder.start(query1)\n      _ <- builder.startSubQuery(subQuery, code1.text)\n      _ <- builder.addSubQuery(subQuery, batch1)\n      _ <- builder.addSubQuery(subQuery, batch2)\n      _ <- builder.endSubQuery(subQuery)\n      _ <- builder.end(query1)\n      _ <- builder.start(query2)\n      _ <- builder.log(query2.id, \"some-log\")\n      _ <- builder.error(query2.id, error1)\n      _ <- builder.errorSubQuery(subQuery, error2)\n      state <- delegate.state.get\n    } yield state\n\n    result.runSyncUnsafe() must\n      equalTo(\n        State(\n          queries = Map(\n            query1.id -> HistoricalQuery(query1, QueryStatus.Ended),\n            query2.id -> HistoricalQuery(query2, QueryStatus.Started)),\n          subQueries = Map(subQuery -> HistoricalSubQuery(code1.text, List(batch2, batch1), QueryStatus.Ended)),\n          errors = List(Error(subQuery, error2), Error(query2.id, error1)),\n          log = List(LogLine(query2.id, \"some-log\", \"INFO\"))))\n  }\n\n  \"persist execution history\" in {\n    val result = for {\n      delegate <- FakeBuilder.make\n      dao <- makeDao\n      builder = new HistoryBuilder(delegate, dao, queryType)\n      _ <- builder.start(query1)\n      _ <- builder.end(query1)\n      executions <- dao.executions()\n    } yield executions\n\n    result.runSyncUnsafe() must\n      contain(executionWithStatus(ExecutionStatus.Finished))\n  }\n\n  \"persist failed execution\" in {\n    val error = new RuntimeException(\"oops\")\n    val result = for {\n      delegate <- FakeBuilder.make\n      dao <- makeDao\n      builder = new HistoryBuilder(delegate, dao, queryType)\n      _ <- builder.start(query1)\n      _ <- builder.error(query1.id, error)\n      executions <- dao.executions()\n    } yield executions\n\n    result.runSyncUnsafe() must\n      contain(executionWithStatus(ExecutionStatus.Failed))\n  }\n\n}\n\nobject HistoryBuilderTest {\n  val user = User(\"foo@bar.com\", \"some-user\")\n  val code1 = ImmutableSubQuery(\"code1\", user)\n  val code2 = ImmutableSubQuery(\"code2\", user)\n  val code3 = ImmutableSubQuery(\"code3\", user)\n  val queryType = \"query-type\"\n  val query1 = Query(List(code1, code2), id = \"query1\")\n  val query2 = Query(List(code3), id = \"query2\")\n  val batch1 = Batch(List(List(1), List(2)))\n  val batch2 = Batch(List(List(3)))\n  val error1 = new RuntimeException(\"foo\")\n  val error2 = new RuntimeException(\"bar\")\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/dao/HistoryDaoContractTest.scala",
    "content": "package quix.core.history.dao\n\nimport java.time.{Clock, Instant, ZoneOffset}\n\nimport cats.effect.Resource\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.mutable.SpecificationWithJUnit\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{ImmutableSubQuery, Query}\nimport quix.core.history.ExecutionMatchers._\nimport quix.core.history.dao.HistoryDaoContractTest._\nimport quix.core.history.{Execution, ExecutionStatus, FakeClock}\n\nimport scala.concurrent.duration._\n\ntrait HistoryDaoContractTest extends SpecificationWithJUnit {\n\n  def createDao(clock: Clock = defaultClock): Resource[Task, HistoryWriteDao with HistoryReadDao]\n\n  \"return empty list of executions if none was saved\" in {\n    val result = createDao().use(_.executions())\n\n    result.runSyncUnsafe() must beEmpty\n  }\n\n  \"return running execution\" in {\n    val result = createDao().use { dao =>\n      dao.executionStarted(query, queryType) *>\n        dao.executions()\n    }\n\n    result.runSyncUnsafe() must contain(\n      Execution(\n        id = \"query-id\",\n        queryType = queryType,\n        statements = statements,\n        code = query.rawCode,\n        user = user,\n        startedAt = now,\n        status = ExecutionStatus.Running))\n  }\n\n  \"return succeeded execution\" in {\n    val result = createDao().use { dao =>\n      dao.executionStarted(query, queryType) *>\n        dao.executionSucceeded(queryId) *>\n        dao.executions()\n    }\n\n    result.runSyncUnsafe() must\n      contain(executionWithStatus(ExecutionStatus.Finished))\n  }\n\n  \"return failed execution\" in {\n    val error = new RuntimeException(\"oops\")\n    val result = createDao().use { dao =>\n      dao.executionStarted(query, queryType) *>\n        dao.executionFailed(queryId, error) *>\n        dao.executions()\n    }\n\n    result.runSyncUnsafe() must\n      contain(executionWithStatus(ExecutionStatus.Failed))\n  }\n\n  \"support paging\" in {\n    val query1 = query.copy(id = \"query-1\")\n    val query2 = query.copy(id = \"query-2\")\n    val query3 = query.copy(id = \"query-3\")\n    val query4 = query.copy(id = \"query-4\")\n    val query5 = query.copy(id = \"query-5\")\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- dao.executionStarted(query2, queryType)\n        _ <- dao.executionStarted(query3, queryType)\n        _ <- dao.executionStarted(query4, queryType)\n        _ <- dao.executionStarted(query5, queryType)\n        page1 <- dao.executions(page = Page(0, 3))\n        page2 <- dao.executions(page = Page(3, 3))\n      } yield (page1, page2)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (page1, page2) =>\n        (page1 must contain(exactly(executionWithId(query1.id), executionWithId(query2.id), executionWithId(query3.id)))) and\n          (page2 must contain(exactly(executionWithId(query4.id), executionWithId(query5.id))))\n    }\n  }\n\n  \"support filtering by queryType\" in {\n    val query1 = query.copy(id = \"query-1\")\n    val query2 = query.copy(id = \"query-2\")\n    val query3 = query.copy(id = \"query-3\")\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, \"query-type-1\")\n        _ <- dao.executionStarted(query2, \"query-type-1\")\n        _ <- dao.executionStarted(query3, \"query-type-2\")\n        _ <- dao.executionSucceeded(query2.id)\n        _ <- dao.executionFailed(query3.id, new RuntimeException)\n        firstType <- dao.executions(filter = Filter.QueryType(\"query-type-1\"))\n        secondType <- dao.executions(filter = Filter.QueryType(\"query-type-2\"))\n      } yield (firstType, secondType)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (firstType, secondType) =>\n        (firstType must contain(exactly(executionWithId(query1.id), executionWithId(query2.id)))) and\n          (secondType must contain(exactly(executionWithId(query3.id))))\n    }\n  }\n\n  \"support filtering by status\" in {\n    val query1 = query.copy(id = \"query-1\")\n    val query2 = query.copy(id = \"query-2\")\n    val query3 = query.copy(id = \"query-3\")\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- dao.executionStarted(query2, queryType)\n        _ <- dao.executionStarted(query3, queryType)\n        _ <- dao.executionSucceeded(query2.id)\n        _ <- dao.executionFailed(query3.id, new RuntimeException)\n        running <- dao.executions(filter = Filter.Status(ExecutionStatus.Running))\n        finished <- dao.executions(filter = Filter.Status(ExecutionStatus.Finished))\n        failed <- dao.executions(filter = Filter.Status(ExecutionStatus.Failed))\n      } yield (running, finished, failed)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (running, finished, failed) =>\n        (running must contain(exactly(executionWithId(query1.id)))) and\n          (finished must contain(exactly(executionWithId(query2.id)))) and\n          (failed must contain(exactly(executionWithId(query3.id))))\n    }\n  }\n\n  \"support filtering by user email\" in {\n    def makeSubQueries(userEmail: String) =\n      List(ImmutableSubQuery(\"select 1\", User(email = userEmail)))\n\n    val query1 = query.copy(id = \"query-1\", subQueries = makeSubQueries(\"foo@quix.com\"))\n    val query2 = query.copy(id = \"query-2\", subQueries = makeSubQueries(\"boo@quix.com\"))\n    val query3 = query.copy(id = \"query-3\", subQueries = makeSubQueries(\"bar@quix.com\"))\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- dao.executionStarted(query2, queryType)\n        _ <- dao.executionStarted(query3, queryType)\n        foo <- dao.executions(filter = Filter.User(\"foo@quix.com\"))\n        boo <- dao.executions(filter = Filter.User(\"boo@quix.com\"))\n        bar <- dao.executions(filter = Filter.User(\"bar@quix.com\"))\n      } yield (foo, boo, bar)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (running, finished, failed) =>\n        (running must contain(exactly(executionWithId(query1.id)))) and\n          (finished must contain(exactly(executionWithId(query2.id)))) and\n          (failed must contain(exactly(executionWithId(query3.id))))\n    }\n  }\n\n  \"support filtering by query text\" in {\n    def newQuery(queryId: String, userEmail: String) = query.copy(id = queryId,\n      subQueries = List(ImmutableSubQuery(s\"select $userEmail as email\", User(email = userEmail))),\n      rawCode = s\"select $userEmail as email\"\n    )\n\n    val query1 = newQuery(\"query-1\", \"foo@quix.com\")\n    val query2 = newQuery(\"query-2\", \"boo@quix.com\")\n    val query3 = newQuery(\"query-3\", \"bar@quix.com\")\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- dao.executionStarted(query2, queryType)\n        _ <- dao.executionStarted(query3, queryType)\n        foo <- dao.executions(filter = Filter.Query(\"foo@quix.com\"))\n        boo <- dao.executions(filter = Filter.Query(\"boo@quix.com\"))\n        bar <- dao.executions(filter = Filter.Query(\"bar@quix.com\"))\n      } yield (foo, boo, bar)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (running, finished, failed) =>\n        (running must contain(exactly(executionWithId(query1.id)))) and\n          (finished must contain(exactly(executionWithId(query2.id)))) and\n          (failed must contain(exactly(executionWithId(query3.id))))\n    }\n  }\n\n  \"support filtering by query and user email\" in {\n    def newQuery(queryId: String, sql: String, userEmail: String) = query.copy(id = queryId,\n      subQueries = List(ImmutableSubQuery(sql, User(email = userEmail))),\n      rawCode = sql\n    )\n\n    val query1 = newQuery(\"query-1\", \"select 1\", \"foo@quix.com\")\n    val query2 = newQuery(\"query-2\", \"select 2\", \"foo@quix.com\")\n    val query3 = newQuery(\"query-3\", \"select 3\", \"foo@quix.com\")\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- dao.executionStarted(query2, queryType)\n        _ <- dao.executionStarted(query3, queryType)\n        first <- dao.executions(filter = Filter.CompoundFilter(List(Filter.Query(\"select 1\"), Filter.User(\"foo@quix.com\"))))\n        second <- dao.executions(filter = Filter.CompoundFilter(List(Filter.Query(\"select 2\"), Filter.User(\"foo@quix.com\"))))\n        third <- dao.executions(filter = Filter.CompoundFilter(List(Filter.Query(\"select 3\"), Filter.User(\"foo@quix.com\"))))\n      } yield (first, second, third)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (running, finished, failed) =>\n        (running must contain(exactly(executionWithId(query1.id)))) and\n          (finished must contain(exactly(executionWithId(query2.id)))) and\n          (failed must contain(exactly(executionWithId(query3.id))))\n    }\n  }\n\n  \"support sorting by start time\" in {\n    val clock = FakeClock(now)\n    val query1 = query.copy(id = \"query-1\")\n    val query2 = query.copy(id = \"query-2\")\n\n    val result = createDao(clock).use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- Task(clock.sleep(1.second))\n        _ <- dao.executionStarted(query2, queryType)\n        ascending <- dao.executions(sort = Sort(SortField.StartTime, SortOrder.Ascending))\n        descending <- dao.executions(sort = Sort(SortField.StartTime, SortOrder.Descending))\n      } yield (ascending, descending)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (ascending, descending) =>\n        (ascending must contain(exactly(executionWithId(query1.id), executionWithId(query2.id)).inOrder)) and\n          (descending must contain(exactly(executionWithId(query2.id), executionWithId(query1.id)).inOrder))\n    }\n  }\n\n  \"support case-insentitive filtering by query text\" in {\n    def newQuery(queryId: String, userEmail: String) = query.copy(id = queryId,\n      subQueries = List(ImmutableSubQuery(s\"select $userEmail as email\", User(email = userEmail))),\n      rawCode = s\"select $userEmail as email\"\n    )\n\n    val query1 = newQuery(\"query-1\", \"foo@quix.com\")\n    val query2 = newQuery(\"query-2\", \"boo@quix.com\")\n    val query3 = newQuery(\"query-3\", \"bar@quix.com\")\n\n    val result = createDao().use { dao =>\n      for {\n        _ <- dao.executionStarted(query1, queryType)\n        _ <- dao.executionStarted(query2, queryType)\n        _ <- dao.executionStarted(query3, queryType)\n        lower <- dao.executions(filter = Filter.Query(\"select\"))\n        upper <- dao.executions(filter = Filter.Query(\"SELECT\"))\n      } yield (lower, upper)\n    }\n\n    result.runSyncUnsafe() must beLike {\n      case (lower, upper) =>\n        (lower must haveSize(3)) and\n          (upper must haveSize(3))\n    }\n  }\n\n}\n\nobject HistoryDaoContractTest {\n  val now = Instant.ofEpochMilli(0)\n  val defaultClock = Clock.fixed(now, ZoneOffset.UTC)\n  val queryType = \"query-type\"\n  val user = User(\"foo@bar.com\", \"some-user\")\n  val queryId = \"query-id\"\n\n  val query1 = ImmutableSubQuery(\"code1\", user)\n  val query2 = ImmutableSubQuery(\"code2\", user)\n  val query = Query(Seq(query1, query2), id = queryId, rawCode = \"code1\\ncode2\")\n  val statements = query.subQueries.map(_.text)\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/dao/InMemoryHistoryDaoTest.scala",
    "content": "package quix.core.history.dao\n\nimport java.time.Clock\n\nimport cats.effect.Resource\nimport monix.eval.Task\n\nclass InMemoryHistoryDaoTest extends HistoryDaoContractTest {\n\n  override def createDao(clock: Clock): Resource[Task, HistoryWriteDao with HistoryReadDao] =\n    Resource.liftF(InMemoryHistoryDao.make(clock))\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/history/dao/MySqlHistoryDaoTest.scala",
    "content": "package quix.core.history.dao\n\nimport java.time.Clock\n\nimport cats.effect.Resource\nimport com.typesafe.scalalogging.LazyLogging\nimport com.wix.mysql.EmbeddedMysql\nimport com.wix.mysql.EmbeddedMysql.anEmbeddedMysql\nimport com.wix.mysql.ScriptResolver.classPathScript\nimport com.wix.mysql.config.Charset.UTF8\nimport com.wix.mysql.config.MysqldConfig.aMysqldConfig\nimport com.wix.mysql.distribution.Version.v5_6_23\nimport monix.eval.Task\nimport org.specs2.specification.{AfterAll, BeforeAll, BeforeEach}\nimport quix.api.v2.execute.{Query => ActiveQuery}\nimport quix.core.history.Execution\n\nclass MySqlHistoryDaoTest\n  extends HistoryDaoContractTest\n    with BeforeAll\n    with BeforeEach\n    with AfterAll {\n\n  sequential\n\n  def beforeAll(): Unit = EmbeddedMysqlDb.start()\n\n  def before(): Unit = EmbeddedMysqlDb.reloadSchema()\n\n  def afterAll(): Unit = EmbeddedMysqlDb.stop()\n\n  override def createDao(clock: Clock): Resource[Task, HistoryWriteDao with HistoryReadDao] =\n    MySqlHistoryDao.connect(EmbeddedMysqlDb.Config).map { connection =>\n      val reader = new MySqlHistoryReadDao(connection)\n      val writer = new MySqlHistoryWriteDao(connection, clock)\n      new HistoryWriteDao with HistoryReadDao {\n        override def executionStarted(query: ActiveQuery, queryType: String): Task[Unit] =\n          writer.executionStarted(query, queryType)\n\n        override def executionSucceeded(queryId: String): Task[Unit] =\n          writer.executionSucceeded(queryId)\n\n        override def executionFailed(queryId: String, error: Throwable): Task[Unit] =\n          writer.executionFailed(queryId, error)\n\n        override def executions(filter: Filter, sort: Sort, page: Page): Task[List[Execution]] =\n          reader.executions(filter, sort, page)\n      }\n    }\n\n}\n\nobject EmbeddedMysqlDb extends LazyLogging {\n  Class.forName(\"com.mysql.cj.jdbc.Driver\")\n\n  private val port = 2215\n\n  private val user = \"wix\"\n\n  private val pass = \"wix\"\n\n  private val schema = \"aschema\"\n\n  private var db: EmbeddedMysql = _\n\n  val Config = JdbcConfig(s\"jdbc:mysql://localhost:$port/$schema\", user, pass)\n\n  def reloadSchema(): Unit = {\n    logger.info(\"method=reloadSchema\")\n    db.reloadSchema(schema, classPathScript(\"db/001_init.sql\"))\n  }\n\n  def stop(): Unit = {\n    logger.info(\"method=stop\")\n    db.stop()\n  }\n\n  def start(): Unit = {\n    logger.info(\"method=start\")\n    db = anEmbeddedMysql(\n      aMysqldConfig(v5_6_23)\n        .withCharset(UTF8)\n        .withPort(port)\n        .withUser(user, pass)\n        .build())\n      .addSchema(schema, classPathScript(\"db/001_init.sql\"))\n      .start()\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/results/MultiBuilderTest.scala",
    "content": "package quix.core.results\n\nimport java.util.UUID\n\nimport monix.eval.Task\nimport monix.execution.Scheduler\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.execute.Batch._\nimport quix.api.v1.execute._\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{Query, ImmutableSubQuery}\n\nimport scala.collection.mutable.ListBuffer\n\nclass MultiBuilderTest extends SpecWithJUnit {\n\n  class ctx extends Scope {\n    val consumer = new TestConsumer[ExecutionEvent]\n    val builder = new MultiBuilder(consumer)\n    val query = ImmutableSubQuery(\"text\", User(\"test\"))\n    val execution = Query(Seq(query), canceled = query.canceled)\n  }\n\n  \"MultiBuilder.start\" should {\n    \"send Start event on start(query)\" in new ctx {\n      builder.start(execution).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Start(execution.id, execution.subQueries.size))\n      }\n    }\n  }\n\n  \"MultiBuilder.end\" should {\n\n    \"send End event on end(query)\" in new ctx {\n      builder.end(execution).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(End(execution.id))\n      }\n    }\n  }\n\n  \"MultiBuilder.startSubQuery\" should {\n\n    \"send StartQuery & SubQueryDetails event on every startSubQuery(queryId, code, results)\" in new ctx {\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(SubQueryStart(\"query-id\"))\n        consumer.payloads must contain(SubQueryDetails(\"query-id\", \"code\"))\n      }\n    }\n\n    \"send SubQueryFields if columns are present in results during startSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List.empty, Option(List(BatchColumn(\"column\"))))\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(SubQueryFields(\"query-id\", List(\"column\")))\n      }\n    }\n\n    \"send SubQueryFields only once if columns are present in results during startSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List.empty, Option(List(BatchColumn(\"column\"))))\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads.filter(_ == SubQueryFields(\"query-id\", List(\"column\"))) must haveSize(1)\n      }\n    }\n\n    \"send Progress if present in results during startSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List.empty).withPercentage(100)\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Progress(\"query-id\", 100))\n      }\n    }\n\n    \"send Progress on every batch during startSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List.empty).withPercentage(100)\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads.filter(_ == Progress(\"query-id\", 100)) must haveSize(2)\n      }\n    }\n\n    \"send Error if present in results during startSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List.empty, error = Option(BatchError(\"boom!\")))\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Error(\"query-id\", \"boom!\"))\n      }\n    }\n\n    \"send Row events if data is present in results during startSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List(List(\"a\", \"b\", \"c\"), List(\"d\", \"e\", \"f\")))\n      builder.startSubQuery(\"query-id\", \"code\").runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Row(\"query-id\", List(\"a\", \"b\", \"c\")))\n        consumer.payloads must contain(Row(\"query-id\", List(\"d\", \"e\", \"f\")))\n      }\n    }\n  }\n\n  \"MultiBuilder.endSubQuery\" should {\n\n    \"send SubQueryEnd event on endSubQuery(query)\" in new ctx {\n      builder.endSubQuery(query.id).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(SubQueryEnd(query.id))\n      }\n    }\n  }\n\n  \"MultiBuilder.errorSubQuery\" should {\n\n    \"send SubQueryError event on errorSubQuery(query)\" in new ctx {\n      builder.errorSubQuery(query.id, new Exception(\"boom!\")).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(SubQueryError(query.id, \"Exception(boom!)\"))\n      }\n    }\n\n    \"omit exception class on ExceptionPropagatedToClient\" in new ctx {\n      builder.errorSubQuery(query.id, ExceptionPropagatedToClient(\"boom!\")).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(SubQueryError(query.id, \"boom!\"))\n      }\n    }\n  }\n\n  \"MultiBuilder.error\" should {\n\n    \"send Error event on error(query)\" in new ctx {\n      builder.error(query.id, new Exception(\"boom!\")).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Error(query.id, \"Exception(boom!)\"))\n      }\n    }\n\n    \"omit exception class on ExceptionPropagatedToClient\" in new ctx {\n      builder.error(query.id, ExceptionPropagatedToClient(\"boom!\")).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Error(query.id, \"boom!\"))\n      }\n    }\n  }\n\n  \"MultiBuilder.addSubQuery\" should {\n\n    \"send SubQueryFields if columns are present in results during addSubQuery(queryId, results)\" in new ctx {\n      val batch = Batch(List.empty, Option(List(BatchColumn(\"column\"))))\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(SubQueryFields(\"query-id\", List(\"column\")))\n      }\n    }\n\n    \"send SubQueryFields only once if columns are present in results during addSubQuery(queryId, results)\" in new ctx {\n      val batch = Batch(List.empty, Option(List(BatchColumn(\"column\"))))\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads.filter(_ == SubQueryFields(\"query-id\", List(\"column\"))) must haveSize(1)\n      }\n    }\n\n    \"send Progress if present in results during addSubQuery(queryId, results)\" in new ctx {\n      val batch = Batch(List.empty).withPercentage(100)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Progress(\"query-id\", 100))\n      }\n    }\n\n    \"send Progress on every batch during addSubQuery(queryId, results)\" in new ctx {\n      val batch = Batch(List.empty).withPercentage(100)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads.filter(_ == Progress(\"query-id\", 100)) must haveSize(2)\n      }\n    }\n\n    \"send Error if present in results during addSubQuery(queryId, results)\" in new ctx {\n      val batch = Batch(List.empty, error = Option(BatchError(\"boom!\")))\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Error(\"query-id\", \"boom!\"))\n      }\n    }\n\n    \"send Row events if data is present in results during addSubQuery(queryId, code, results)\" in new ctx {\n      val batch = Batch(List(List(\"a\", \"b\", \"c\"), List(\"d\", \"e\", \"f\")))\n      builder.addSubQuery(\"query-id\", batch).runToFuture(Scheduler.global)\n\n      eventually {\n        consumer.payloads must contain(Row(\"query-id\", List(\"a\", \"b\", \"c\")))\n        consumer.payloads must contain(Row(\"query-id\", List(\"d\", \"e\", \"f\")))\n      }\n    }\n  }\n\n}\n\nclass TestConsumer[T] extends Consumer[T] {\n  val payloads = ListBuffer.empty[T]\n\n  override def id: String = \"id\"\n\n  override def user: User = User(\"test\")\n\n  override def write(payload: T): Task[Unit] = Task(payloads += payload)\n\n  override def close(): Task[Unit] = Task.unit\n}"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/sql/PrestoSqlOpsTest.scala",
    "content": "package quix.core.sql\n\nimport org.specs2.mutable.SpecWithJUnit\nimport quix.core.sql.PrestoSqlOps.{splitToStatements => split}\n\nclass PrestoSqlOpsTest extends SpecWithJUnit {\n\n  \"PlainPrestoSqlSupport.splitToStatements\" should {\n    \"handle single line statements\" in {\n      split(\"select 1\") must contain(\"select 1\")\n    }\n\n    \"handle delimited statements\" in {\n      split(\"select 1;select 2\") must_=== List(\"select 1\", \"select 2\")\n    }\n\n    \"handle delimited statements with empty partial statement\" in {\n      split(\"select 1;select 2;\") must contain(\"select 1\", \"select 2\")\n    }\n\n    \"handle delimited statements with many empty lines between them\" in {\n      val newlines = List.fill(10)(\"\\n\").mkString\n      val sql = \"select 1;\" + newlines + \"select 2\"\n      split(sql) must contain(\"select 1\", \"select 2\")\n    }\n\n    \"handle empty strings\" in {\n      split(\"       \\n\\n\\n\\n\\n\") must beEmpty\n    }\n\n    \"handle trailing comments\" in {\n      val sqls = split(\"select 1;\\n--comment1\\n--comment2\")\n\n      sqls must_=== List(\"select 1\")\n    }\n\n    \"do not strip leading newlines in case of single statement\" in {\n      val sqls = split(\"\\nselect 1\")\n\n      sqls must_=== List(\"\\nselect 1\")\n    }\n\n    \"do not strip leading newlines in case of multiple statements\" in {\n      val sqls = split(\"\\nselect 1;\\nselect 2;\")\n\n      sqls must_=== List(\"\\nselect 1\", \"select 2\")\n    }\n\n    \"do not strip leading newlines in case of multiple statements\" in {\n      val sqls = split(\"\\n--comment\\nselect 1;\\nselect 2;\")\n\n      sqls must_=== List(\"\\n--comment\\nselect 1\", \"select 2\")\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-core/src/test/scala/quix/core/sql/StopWordsSplitterTest.scala",
    "content": "package quix.core.sql\n\nimport org.specs2.mutable.SpecWithJUnit\n\nclass StopWordsSplitterTest extends SpecWithJUnit {\n\n  \"StopWordSqlSplitter.split\" should {\n    \"do not split on stop word\" in {\n      val splitter = new StopWordSqlSplitter(\"FUNCTION\")\n\n      splitter.split(\n        \"\"\"\n          |CREATE TEMP FUNCTION FOO;\n          |SELECT 1;\n          |\"\"\".stripMargin) must contain(\n        \"\"\"\n          |CREATE TEMP FUNCTION FOO;\n          |SELECT 1\"\"\".stripMargin)\n    }\n\n    \"split on non stop word\" in {\n      val splitter = new StopWordSqlSplitter(\"FUNCTION\")\n\n      val splits = splitter.split(\n        \"\"\"\n          |CREATE TEMP FUNCTION FOO;\n          |SELECT 1;\n          |SELECT 2;\n          |\"\"\".stripMargin)\n\n      splits must contain(\n        \"\"\"\n          |CREATE TEMP FUNCTION FOO;\n          |SELECT 1\"\"\".stripMargin)\n\n      splits must contain(\"SELECT 2\")\n\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AthenaAutocomplete.scala",
    "content": "package quix.athena\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Autocomplete, Catalog, Catalogs}\n\nclass AthenaAutocomplete(val catalogs: Catalogs) extends Autocomplete {\n\n  override def fast: Task[Map[String, List[String]]] = catalogs.fast.map(extractAutoCompleteItems)\n\n  override def full: Task[Map[String, List[String]]] = catalogs.full.map(extractAutoCompleteItems)\n\n  def extractAutoCompleteItems(catalogList: List[Catalog]): Map[String, List[String]] = {\n    Map(\"schemas\" -> catalogList.flatMap(_.children.map(_.name)),\n      \"tables\" -> catalogList.flatMap(_.children.flatMap(_.children.map(_.name))))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AthenaCatalogs.scala",
    "content": "package quix.athena\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Catalog, Catalogs, Schema, Table}\nimport quix.api.v2.execute.Executor\nimport quix.core.executions.SingleQueryExecutor\n\nclass AthenaCatalogs(val queryExecutor: Executor) extends Catalogs with SingleQueryExecutor {\n\n  override def fast: Task[List[Catalog]] = {\n    for {schemas <- executeForSingleColumn(\"show databases\")}\n      yield List(Catalog(\"__root\", schemas.map(schema => Schema(schema, Nil))))\n  }\n\n  override def full: Task[List[Catalog]] = {\n    for {\n      schemaNames <- executeForSingleColumn(\"show databases\")\n      schemas <- Task.traverse(schemaNames)(inferSchemaInOneQuery)\n    } yield List(Catalog(\"__root\", schemas))\n  }\n\n  def inferSchemaInOneQuery(schemaName: String): Task[Schema] = {\n    val sql = s\"show tables in `$schemaName`\"\n\n    for {\n      tablesNames <- executeForSingleColumn(sql)\n    } yield {\n      val tables = tablesNames.map(table => Table(table, List()))\n      Schema(schemaName, tables.sortBy(_.name))\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AthenaClient.scala",
    "content": "package quix.athena\n\nimport com.amazonaws.services.athena.model.{GetQueryExecutionResult, GetQueryResultsResult, StartQueryExecutionResult}\nimport monix.eval.Task\nimport quix.api.v2.execute.SubQuery\n\ntrait AthenaClient {\n  def init(query: SubQuery): Task[StartQueryExecutionResult]\n\n  def get(queryId: String): Task[GetQueryExecutionResult]\n\n  def advance(queryId: String, tokenOpt: Option[String] = None): Task[GetQueryResultsResult]\n\n  def close(queryId: String): Task[Unit]\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AthenaConfig.scala",
    "content": "package quix.athena\n\ncase class AthenaConfig(output: String,\n                        region: String,\n                        database: String,\n                        firstEmptyStateDelay : Long,\n                        requestTimeout : Long,\n                        accessKey : String = \"\",\n                        secretKey : String = \"\") {\n  override def toString: String = s\"AthenaConfig($output,$region,$database,$firstEmptyStateDelay,$requestTimeout,****,***)\"\n}\n\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AthenaQueryExecutor.scala",
    "content": "package quix.athena\n\nimport java.net.{ConnectException, SocketException, SocketTimeoutException}\n\nimport com.amazonaws.SdkClientException\nimport com.amazonaws.auth._\nimport com.amazonaws.services.athena.AmazonAthenaClient\nimport com.amazonaws.services.athena.model.{AmazonAthenaException, GetQueryResultsResult, QueryExecutionState, StartQueryExecutionResult, Row => AthenaRow}\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v1.execute.{Batch, BatchColumn}\nimport quix.api.v2.execute._\nimport quix.core.utils.TaskOps._\n\nimport scala.concurrent.duration.{FiniteDuration, _}\n\nclass AthenaQueryExecutor(val client: AthenaClient,\n                          val initialAdvanceDelay: FiniteDuration = 100.millis,\n                          val maxAdvanceDelay: FiniteDuration = 15.seconds)\n  extends Executor with LazyLogging {\n\n  def waitLoop(queryId: String, activeQuery: SubQuery, builder: Builder, delay: FiniteDuration = initialAdvanceDelay): Task[QueryExecutionState] = {\n    val runningStatuses = Set(QueryExecutionState.RUNNING, QueryExecutionState.QUEUED).map(_.toString)\n    val failed = Set(QueryExecutionState.FAILED, QueryExecutionState.CANCELLED).map(_.toString)\n\n    client.get(queryId).map(_.getQueryExecution).flatMap {\n      case query if runningStatuses.contains(query.getStatus.getState) && !activeQuery.canceled.get =>\n        for {\n          _ <- Task(logger.info(s\"method=waitLoop event=not-finished query-id=$queryId user=${activeQuery.user.email} status=${query.getStatus.getState} delay=$delay\"))\n          _ <- builder.addSubQuery(queryId, Batch(data = List.empty))\n          status <- waitLoop(queryId, activeQuery, builder, maxAdvanceDelay.min(delay * 2)).delayExecution(delay)\n        } yield status\n\n      case query if failed.contains(query.getStatus.getState) =>\n        for {\n          _ <- Task(logger.info(s\"method=waitLoop event=failed query-id=$queryId user=${activeQuery.user.email} delay=$delay status=${query.getStatus.getState} canceled=${activeQuery.canceled.get}\"))\n          _ <- builder.errorSubQuery(queryId, new IllegalStateException(s\"Query failed with status ${query.getStatus.getState} with reason = ${query.getStatus.getStateChangeReason}\"))\n        } yield QueryExecutionState.fromValue(query.getStatus.getState)\n\n      case query if query.getStatus.getState == QueryExecutionState.SUCCEEDED.toString || activeQuery.canceled.get =>\n        Task.eval(logger.info(s\"method=waitLoop event=finished query-id=$queryId user=${activeQuery.user.email} delay=$delay status=${query.getStatus.getState} canceled=${activeQuery.canceled.get}\"))\n          .map(_ => QueryExecutionState.fromValue(query.getStatus.getState))\n    }\n  }\n\n  def drainResults(queryId: String, nextToken: Option[String], builder: Builder, query: SubQuery): Task[Option[String]] = {\n    val log = Task(logger.info(s\"method=drainResults event=start query-id=$queryId user=${query.user.email} tokenOpt=$nextToken\"))\n\n    val tokenTask = nextToken match {\n      case Some(_) if !query.canceled.get =>\n        for {\n          nextState <- advance(builder, queryId, query, nextToken)\n\n          _ <- builder.addSubQuery(queryId, makeBatch(nextState))\n\n          futureState <- drainResults(queryId, Option(nextState.getNextToken), builder, query)\n        } yield futureState\n\n      case _ =>\n        Task.now(nextToken)\n    }\n\n    log.flatMap(_ => tokenTask)\n  }\n\n  def fetchFirstBatch(queryId: String, builder: Builder, query: SubQuery): Task[Option[String]] = {\n    val log = Task(logger.info(s\"method=fetchFirstBatch event=start query-id=$queryId user=${query.user.email} cancelled=${query.canceled.get()}\"))\n\n    val batch = if (query.canceled.get) Task.now(None)\n    else for {\n      state <- advance(builder, queryId, query)\n      _ <- builder.addSubQuery(queryId, makeBatch(state, isFirst = true))\n      _ <- Task(logger.info(s\"method=fetchFirstBatch event=done query-id=$queryId user=${query.user.email} cancelled=${query.canceled.get()} tokenOpt=${state.getNextToken}\"))\n    } yield Option(state.getNextToken)\n\n    log.flatMap(_ => batch)\n  }\n\n  def makeBatch(result: GetQueryResultsResult, isFirst: Boolean = false): Batch = {\n    logger.info(s\"method=makeBatch event=start isFirst=$isFirst rows=${result.getResultSet.getRows.size()}\")\n\n    import scala.collection.JavaConverters._\n    // first batch contains columns as first row\n\n    val columns = if (isFirst) {\n      val rs = result.getResultSet\n      Option(rs.getResultSetMetadata.getColumnInfo.asScala.map(col => BatchColumn(col.getName)).toList)\n    } else None\n\n    val types = result.getResultSet.getResultSetMetadata.getColumnInfo.asScala.map(_.getType)\n\n    val res = result.getResultSet\n\n    val rows = res.getRows.asScala.toList\n\n    val data = for ((row, index) <- rows.zipWithIndex if !columnsRow(row, index, columns))\n      yield {\n        for ((datatype, datum) <- types.zip(row.getData.asScala.map(_.getVarCharValue)).toList)\n          yield convert(datatype, datum)\n      }\n\n    Batch(data = data, columns = columns)\n  }\n\n  /*\n    athena docs states that first row contains column names, we need to skip that row\n   */\n  def columnsRow(row: AthenaRow, index: Int, maybeColumns: Option[List[BatchColumn]]) = {\n    import scala.collection.JavaConverters._\n\n    if (index == 0) {\n      val values = row.getData.asScala.map(_.getVarCharValue).toList\n      val types = maybeColumns.map(_.map(_.name)).getOrElse(Nil)\n\n      values == types\n    } else false\n  }\n\n  def convert(datatype: String, datum: String): AnyRef = {\n    datatype match {\n      case \"varchar\" => String.valueOf(datum)\n      case \"tinyint\" => new Integer(datum)\n      case \"smallint\" => new Integer(datum)\n      case \"integer\" => new Integer(datum)\n      case \"bigint\" => new java.lang.Long(datum)\n      case \"double\" => new java.lang.Double(datum)\n      case \"boolean\" => new java.lang.Boolean(datum)\n      case \"date\" => String.valueOf(datum)\n      case \"timestamp\" => String.valueOf(datum)\n      case _ => String.valueOf(datum.toString)\n    }\n  }\n\n  def advance(builder: Builder, queryId: String, query: SubQuery, token: Option[String] = None): Task[GetQueryResultsResult] = {\n\n    client.advance(queryId, token)\n      .onErrorHandleWith {\n        case e@(_: ConnectException | _: SocketTimeoutException | _: SocketException) =>\n          val ex = new IllegalStateException(s\"Athena can't be reached, please try later. Underlying exception name is ${e.getClass.getSimpleName}\", e)\n          builder.errorSubQuery(queryId, ex)\n            .flatMap(_ => Task.raiseError(ex))\n\n        case ex: Exception =>\n          val log = Task(logger.warn(s\"method=advance event=error query-id=$queryId user=${query.user.email} cancelled=${query.canceled.get()}\", ex))\n\n          builder.errorSubQuery(queryId, ex)\n            .flatMap(_ => log)\n            .flatMap(_ => Task.raiseError(ex))\n      }\n  }\n\n  def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    val close = (startExecution: StartQueryExecutionResult) => client.close(startExecution.getQueryExecutionId)\n\n    initClient(query, builder).bracket { startExecution =>\n      val queryLoop = for {\n        queryState <- waitLoop(startExecution.getQueryExecutionId, query, builder, initialAdvanceDelay)\n        _ <- if (queryState == QueryExecutionState.SUCCEEDED) {\n          for {\n            token <- fetchFirstBatch(startExecution.getQueryExecutionId, builder, query)\n            _ <- drainResults(startExecution.getQueryExecutionId, token, builder, query)\n          } yield ()\n        } else Task.unit\n      } yield ()\n\n      for {\n        _ <- Task.eval(logger.info(s\"method=runAsync event=start query-id=${query.id} user=${query.user.email} \" +\n          s\"sql=${query.text.replace(\"\\n\", \"-newline-\").replace(\"\\\\s\", \"-space-\")}\"))\n\n        _ <- builder.startSubQuery(startExecution.getQueryExecutionId, query.text)\n        _ <- queryLoop.onErrorFallbackTo(Task.unit)\n        _ <- builder.endSubQuery(startExecution.getQueryExecutionId)\n\n        _ <- Task.eval(logger.info(s\"method=runAsync event=end query-id=${query.id} user=${query.user.email} rows=${builder.rowCount}\"))\n      } yield ()\n    }(close)\n  }\n\n  def initClient(query: SubQuery, builder: Builder): Task[StartQueryExecutionResult] = {\n    val log = Task(logger.info(s\"method=initClient event=start query-id=${query.id} user=${query.user.email} sql=${query.text}\"))\n\n    val clientTask = client\n      .init(query)\n      .logOnError(s\"method=initClient event=error query-id=${query.id} user=${query.user.email} sql=${query.text}\")\n      .onErrorHandleWith {\n        case e: Exception =>\n          builder.error(query.id, rewriteException(e))\n            .flatMap(_ => Task.raiseError(rewriteException(e)))\n      }\n\n    log.flatMap(_ => clientTask)\n  }\n\n  def rewriteException(e: Exception): Exception = {\n    def badCredentials(e: Exception) = {\n      new IllegalStateException(\n        s\"\"\"\n           |Athena can't be reached, make sure you configured aws credentials correctly.\n           |Refer to https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html for details.\n           |Quix is using DefaultAWSCredentialsProviderChain from aws-java-sdk to discover the aws credentials.\n           |\n           |Underlying exception name is ${e.getClass.getSimpleName} with message [${e.getMessage}]\n           |\n           |\"\"\".stripMargin, e)\n    }\n\n    e match {\n      case e: SdkClientException\n        if e.getMessage.contains(\"Unable to load AWS credentials\") ||\n          e.getMessage.contains(\"Unable to load credentials\") => badCredentials(e)\n\n      case e: AmazonAthenaException if e.getMessage.contains(\"Check your AWS Secret Access Key\") =>\n        badCredentials(e)\n\n      case e: AmazonAthenaException if e.getMessage.contains(\"The security token included in the request is invalid\") =>\n        badCredentials(e)\n\n      case e@(_: ConnectException | _: SocketTimeoutException | _: SocketException) =>\n        new IllegalStateException(s\"Athena can't be reached, please try later. Underlying exception name is ${e.getClass.getSimpleName}\", e)\n      case _ => e\n    }\n  }\n}\n\nobject AthenaQueryExecutor {\n  def apply(config: AthenaConfig) = {\n    val credentials = {\n      if (config.accessKey != null && config.secretKey != null && config.accessKey.nonEmpty && config.secretKey.nonEmpty) {\n        new AWSCredentialsProvider {\n          override def getCredentials: AWSCredentials = new BasicAWSCredentials(config.accessKey, config.secretKey)\n\n          override def refresh(): Unit = {}\n        }\n      } else new DefaultAWSCredentialsProviderChain\n    }\n\n    val athena = AmazonAthenaClient.builder\n      .withRegion(config.region)\n      .withCredentials(credentials)\n      .build()\n\n    val client = new AwsAthenaClient(athena, config)\n    new AthenaQueryExecutor(client)\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AthenaTables.scala",
    "content": "package quix.athena\n\nimport monix.eval.Task\nimport quix.api.v1.db._\nimport quix.api.v2.execute.Executor\nimport quix.core.executions.SingleQueryExecutor\n\nclass AthenaTables(val queryExecutor: Executor) extends Tables with SingleQueryExecutor {\n  override def get(catalog: String, schema: String, table: String): Task[Table] = {\n    val sql = s\"describe `$schema`.`$table`\"\n\n    val mapper: List[String] => Kolumn = {\n      case List(nameAndType) =>\n        nameAndType.split(\"\\\\s+\") match {\n          case Array(name, kind) => Kolumn(name, kind)\n          case _ => Kolumn(nameAndType, \"unknown\")\n        }\n    }\n\n    for {columns <- executeFor(sql, mapper)}\n      yield Table(table, columns.filter(_.name.trim.nonEmpty).filterNot(_.name.startsWith(\"# \")).distinct)\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/AwsAthenaClient.scala",
    "content": "package quix.athena\n\nimport com.amazonaws.services.athena.AmazonAthena\nimport com.amazonaws.services.athena.model._\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v2.execute.SubQuery\n\nclass AwsAthenaClient(athena: AmazonAthena, config: AthenaConfig) extends AthenaClient with LazyLogging {\n\n  override def init(query: SubQuery): Task[StartQueryExecutionResult] = Task {\n    logger.info(s\"method=init query-id=${query.id} query-sql=[${query.text.replace(\"\\n\", \"-newline-\")}] config=$config\")\n\n    val request =\n      new StartQueryExecutionRequest()\n        .withQueryString(query.text)\n        .withResultConfiguration(new ResultConfiguration().withOutputLocation(config.output))\n\n    athena.startQueryExecution(request)\n  }\n\n  override def get(queryId: String): Task[GetQueryExecutionResult] = Task {\n    logger.info(s\"\"\"method=get query-id=$queryId config=$config\"\"\")\n\n    val request = new GetQueryExecutionRequest()\n      .withQueryExecutionId(queryId)\n\n    athena.getQueryExecution(request)\n  }\n\n  override def advance(queryId: String, tokenOpt: Option[String] = None): Task[GetQueryResultsResult] = Task {\n    logger.info(s\"method=advance query-id=$queryId tokenOpt=$tokenOpt\")\n\n    val request = new GetQueryResultsRequest()\n      .withQueryExecutionId(queryId)\n\n    tokenOpt.foreach(request.withNextToken)\n\n    athena.getQueryResults(request)\n  }\n\n  override def close(queryId: String): Task[Unit] = Task {\n    logger.info(s\"method=close query-id=$queryId config=$config\")\n\n    val request = new StopQueryExecutionRequest()\n      .withQueryExecutionId(queryId)\n\n    athena.stopQueryExecution(request)\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/main/scala/quix/athena/TryAthena.scala",
    "content": "package quix.athena\n\nimport com.amazonaws.auth.DefaultAWSCredentialsProviderChain\nimport com.amazonaws.regions.Regions\nimport com.amazonaws.services.athena.AmazonAthenaClient\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.execution.Scheduler.Implicits.global\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\n\nobject TryAthena extends LazyLogging {\n  def main(args: Array[String]): Unit = {\n    val config = AthenaConfig(\"s3://valery-athena-test/\", Regions.US_EAST_1.getName, \"default\", 10000L, 10000L)\n\n    val athena = AmazonAthenaClient.builder\n      .withRegion(config.region)\n      .withCredentials(new DefaultAWSCredentialsProviderChain)\n      .build()\n\n    val client = new AwsAthenaClient(athena, config)\n    val queryExecutor = new AthenaQueryExecutor(client)\n\n    val results = new SingleBuilder\n\n    val task = queryExecutor.execute(ImmutableSubQuery(\"SELECT *\\nFROM default.elb_logs\\nLIMIT 1000\", User(\"valeryf\")), results)\n\n    task.runSyncUnsafe()\n\n    logger.info(\"results = \" + results.build())\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-athena-module/src/test/scala/quix/athena/AthenaQueryExecutorTest.scala",
    "content": "package quix.athena\n\nimport com.amazonaws.services.athena.model._\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport monix.execution.atomic.Atomic\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mock.Mockito\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.execute.BatchColumn\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\n\nclass AthenaQueryExecutorTest extends SpecWithJUnit with MustMatchers with Mockito {\n\n  class ctx extends Scope {\n    val athena = mock[AthenaClient]\n    val executor = new AthenaQueryExecutor(athena)\n    val query = ImmutableSubQuery(id = \"query-id\", text = \"select 1\", user = User(\"athena-test\"))\n    val builder = spy(new SingleBuilder)\n  }\n\n  \"AthenaQueryExecutor\" should {\n    \"notify builder on exceptions in client.init\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      athena.init(query) returns Task.raiseError(exception)\n\n      // call\n      executor.initClient(query, builder).runToFuture\n\n      // verify\n      eventually {\n        there was one(builder).error(query.id, exception)\n      }\n    }\n\n    \"notify builder on exceptions in client.advance\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      athena.advance(any(), any()) returns Task.raiseError(exception)\n\n      // call\n      executor.advance(builder, query.id, query).runToFuture\n\n\n      // verify\n      eventually {\n        there was one(builder).errorSubQuery(query.id, exception)\n      }\n    }\n\n\n  }\n\n  \"AthenaQueryExecutor.waitLoop\" should {\n    \"stop if query is canceled but still running\" in new ctx {\n      // query that is still running\n      athena.get(anyString) returns Task.now(\n        new GetQueryExecutionResult()\n          .withQueryExecution(new QueryExecution()\n            .withStatus(new QueryExecutionStatus()\n              .withState(QueryExecutionState.RUNNING))))\n\n      // call\n      val queryExecution = executor.waitLoop(\"query-id\", query.copy(canceled = Atomic(true)), builder).runSyncUnsafe()\n\n      // verify\n      queryExecution must_=== QueryExecutionState.RUNNING\n    }\n\n    \"stop if query is canceled but still queued\" in new ctx {\n      // query that is still running\n      athena.get(anyString) returns Task.now(\n        new GetQueryExecutionResult()\n          .withQueryExecution(new QueryExecution()\n            .withStatus(new QueryExecutionStatus()\n              .withState(QueryExecutionState.QUEUED))))\n\n      // call\n      val queryExecution = executor.waitLoop(\"query-id\", query.copy(canceled = Atomic(true)), builder).runSyncUnsafe()\n\n      // verify\n      queryExecution must_=== QueryExecutionState.QUEUED\n    }\n\n    \"stop if query is finished\" in new ctx {\n      // query that is still running\n      val running = {\n        Task.now(\n          new GetQueryExecutionResult()\n            .withQueryExecution(new QueryExecution()\n              .withStatus(new QueryExecutionStatus()\n                .withState(QueryExecutionState.RUNNING))))\n      }\n\n      val finished = {\n        Task.now(\n          new GetQueryExecutionResult()\n            .withQueryExecution(new QueryExecution()\n              .withStatus(new QueryExecutionStatus()\n                .withState(QueryExecutionState.SUCCEEDED))))\n      }\n\n      athena.get(anyString) returns(running, finished)\n\n      // call\n      val queryExecution = executor.waitLoop(\"query-id\", query, builder).runSyncUnsafe()\n\n      // verify\n      queryExecution must_=== QueryExecutionState.SUCCEEDED\n    }\n\n    \"stop if query is FAILED and notify builder\" in new ctx {\n      // query that is still running\n      val running = {\n        Task.now(\n          new GetQueryExecutionResult()\n            .withQueryExecution(new QueryExecution()\n              .withStatus(new QueryExecutionStatus()\n                .withState(QueryExecutionState.RUNNING))))\n      }\n\n      val failed = {\n        Task.now(\n          new GetQueryExecutionResult()\n            .withQueryExecution(new QueryExecution()\n              .withStatus(new QueryExecutionStatus()\n                .withState(QueryExecutionState.FAILED)\n                .withStateChangeReason(\"boom!\"))))\n      }\n\n      athena.get(anyString) returns(running, failed)\n\n      // call\n      val queryExecution = executor.waitLoop(\"query-id\", query, builder).runSyncUnsafe()\n\n      // verify\n      queryExecution must_=== QueryExecutionState.FAILED\n      builder.lastError.map(_.getMessage) must beSome(\"Query failed with status FAILED with reason = boom!\")\n    }\n  }\n\n  \"AthenaQueryExecutor.makeBatch\" should {\n\n    \"pass sanity\" in new ctx {\n      val emptyResult = new GetQueryResultsResult()\n        .withResultSet(new ResultSet()\n          .withRows()\n          .withResultSetMetadata(new ResultSetMetadata().withColumnInfo()))\n\n      val batch = executor.makeBatch(emptyResult)\n\n      batch.columns must beEmpty\n      batch.data must beEmpty\n    }\n\n    \"skip first row for first batch\" in new ctx {\n      val firstResult = new GetQueryResultsResult()\n        .withResultSet(new ResultSet()\n          .withRows(new Row().withData(new Datum().withVarCharValue(\"foo\")))\n          .withResultSetMetadata(new ResultSetMetadata().withColumnInfo(new ColumnInfo().withName(\"foo\"))))\n\n      val batch = executor.makeBatch(firstResult, isFirst = true)\n\n      batch.columns must beSome(List(BatchColumn(\"foo\")))\n      batch.data must beEmpty\n    }\n\n    \"convert data and skip columns on non first batches\" in new ctx {\n      val result = new GetQueryResultsResult()\n        .withResultSet(new ResultSet()\n          .withRows(new Row().withData(new Datum().withVarCharValue(\"123\")))\n          .withResultSetMetadata(new ResultSetMetadata().withColumnInfo(new ColumnInfo().withName(\"foo\").withType(\"bigint\"))))\n\n      val batch = executor.makeBatch(result)\n\n      batch.columns must beEmpty\n      batch.data must_=== List(List(123))\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/BigQueryClient.scala",
    "content": "package quix.bigquery\n\nimport com.google.cloud.bigquery.Job\nimport monix.eval.Task\nimport quix.api.v2.execute.SubQuery\n\ntrait BigQueryClient {\n\n  def init(query: SubQuery): Task[Job]\n\n  def close(jobId: String): Task[Unit]\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/BigQueryConfig.scala",
    "content": "package quix.bigquery\n\ncase class BigQueryConfig(credentialBytes: Array[Byte],\n                          firstEmptyStateDelay: Long,\n                          requestTimeout: Long)\n\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/BigQueryQueryExecutor.scala",
    "content": "package quix.bigquery\n\nimport java.io.ByteArrayInputStream\n\nimport com.google.api.client.googleapis.json.GoogleJsonResponseException\nimport com.google.auth.oauth2.ServiceAccountCredentials\nimport com.google.cloud.bigquery.{BigQueryOptions, FieldValue, Job, JobStatistics, TableResult}\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v1.execute.{Batch, BatchColumn, BatchError}\nimport quix.api.v2.execute.{Executor, SubQuery, _}\nimport quix.core.utils.TaskOps._\n\nimport scala.collection.JavaConverters._\n\nclass BigQueryQueryExecutor(val client: BigQueryClient, val advanceTimeout: Long)\n  extends Executor with LazyLogging {\n\n  def toBatch(job: Job, result: TableResult, rowsSoFar: Long): Batch = {\n    val rows = for {\n      row <- result.getValues.asScala.toSeq\n    } yield row.asScala.map(getValue).toList\n\n    val percentage = if (result.getTotalRows > 0) {\n      ((rowsSoFar + rows.size).toDouble / result.getTotalRows * 100).toInt\n    } else 0\n\n\n    Batch(rows, toColumns(result), error = getError(job))\n      .withPercentage(percentage)\n  }\n\n  def toColumns(result: TableResult) = {\n    Option(result.getSchema).map { schema =>\n      schema.getFields.asScala.map(f => BatchColumn(f.getName)).toList\n    }\n  }\n\n  def getValue(value: FieldValue): Any = {\n    value.getAttribute match {\n      case FieldValue.Attribute.PRIMITIVE if !value.isNull =>\n        value.getStringValue\n\n      case FieldValue.Attribute.REPEATED =>\n        \"[\" + value.getRepeatedValue.asScala.map(getValue).mkString(\", \") + \"]\"\n\n      case FieldValue.Attribute.RECORD =>\n        \"{\" + value.getRecordValue.asScala.map(getValue).mkString(\", \") + \"}\"\n\n      case _ => null\n    }\n  }\n\n  def getError(job: Job): Option[BatchError] = {\n    for (error <- Option(job.getStatus.getError))\n      yield BatchError(error.getMessage)\n  }\n\n  def loop(query: SubQuery, builder: Builder, job: Job, result: TableResult): Task[Unit] = {\n    if (result != null && !query.canceled.get) {\n      for {\n        _ <- builder.addSubQuery(job.getGeneratedId, toBatch(job, result, builder.rowCount))\n        nextPage <- Task(result.getNextPage)\n        _ <- loop(query, builder, job, nextPage)\n      } yield ()\n    } else Task.unit\n  }\n\n  def waitForFinish(job: Job, activeQuery: SubQuery): Task[Job] = Task {\n    job.waitFor()\n  }\n\n  override def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    def close(job: Job) = client.close(job.getJobId.getJob)\n\n    initClient(query, builder).bracket { job =>\n      for {\n        _ <- builder.startSubQuery(job.getGeneratedId, query.text)\n        completedJob <- waitForFinish(job, query)\n        _ <- loop(query, builder, completedJob, completedJob.getQueryResults()).onErrorHandleWith { e =>\n          builder.errorSubQuery(job.getGeneratedId, e)\n        }\n        _ <- builder.endSubQuery(job.getGeneratedId, fetchStatistics(completedJob))\n      } yield ()\n    }(close)\n  }\n\n  def fetchStatistics(job: Job) = {\n    val jobStatistics = job.getStatistics[JobStatistics.QueryStatistics]\n\n    Map(\n      \"cacheHit\" -> jobStatistics.getCacheHit,\n      \"bytesProcessed\" -> jobStatistics.getTotalBytesProcessed,\n      \"bytesBilled\" -> jobStatistics.getTotalBytesBilled,\n      \"type\" -> jobStatistics.getStatementType.name(),\n    )\n  }\n\n  def initClient(query: SubQuery, builder: Builder): Task[Job] = {\n    val log = Task(logger.info(s\"method=initClient event=start query-id=${query.id} user=${query.user.email} sql=${query.text}\"))\n\n    val clientTask = client\n      .init(query)\n      .logOnError(s\"method=initClient event=error query-id=${query.id} user=${query.user.email} sql=${query.text}\")\n      .onErrorHandleWith {\n        case e: Exception =>\n          builder.error(query.id, rewriteException(e))\n            .flatMap(_ => Task.raiseError(rewriteException(e)))\n      }\n\n    log.flatMap(_ => clientTask)\n  }\n\n  def rewriteException(e: Exception): Exception = {\n    def badCredentials(e: Exception) = {\n      new IllegalStateException(\n        s\"\"\"\n           |BigQuery can't be reached, make sure you configured credentials correctly from the JSON file.\n           |Refer to https://cloud.google.com/iam/docs/creating-managing-service-account-keys for details.\n           |\n           |Underlying exception name is ${e.getClass.getSimpleName} with message [${e.getMessage}]\n           |\n           |\"\"\".stripMargin, e)\n    }\n\n    e match {\n      case e: GoogleJsonResponseException if e.getMessage.contains(\"401 Unauthorized\") =>\n        badCredentials(e)\n      case _ => e\n    }\n  }\n}\n\nobject BigQueryQueryExecutor {\n\n  def apply(config: BigQueryConfig) = {\n    val credentials = ServiceAccountCredentials.fromStream(new ByteArrayInputStream(config.credentialBytes))\n\n    val bigQuery = BigQueryOptions\n      .newBuilder()\n      .setCredentials(credentials)\n      .build()\n      .getService\n\n    val client = new GoogleBigQueryClient(bigQuery, config)\n    new BigQueryQueryExecutor(client, 1000L)\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/BigQueryTestQueryExecutor.scala",
    "content": "package quix.bigquery\n\nimport monix.eval.Task\nimport quix.api.v2.execute.{Builder, Executor, SubQuery}\n\nimport scala.collection.mutable\nimport scala.concurrent.duration.{Duration, FiniteDuration}\n\nclass SingleBigQueryExecution(exception: Option[Exception] = Option.empty[Exception],\n                              results: List[List[AnyRef]] = Nil,\n                              queryId: String = \"test-query-id\",\n                              columns: List[String] = Nil,\n                              delay: FiniteDuration = Duration.Zero) {\n\n  def act(query: SubQuery, builder: Builder): Task[Unit] = Task.unit\n}\n\nclass BigQueryTestQueryExecutor extends Executor {\n\n  val executions: mutable.Queue[SingleBigQueryExecution] = mutable.Queue.empty\n  var resultBuilder: Builder = _\n\n  def withException(e: Exception) = {\n    executions.enqueue(new SingleBigQueryExecution(exception = Some(e)))\n    this\n  }\n\n  def withExceptions(e: Exception, n: Int) = {\n    for (e <- List.fill(n)(e))\n      executions.enqueue(new SingleBigQueryExecution(exception = Some(e)))\n    this\n  }\n\n  def withResults(results: List[List[AnyRef]], queryId: String = \"query-id\", columns: List[String] = Nil, delay: FiniteDuration = Duration.Zero) = {\n    executions.enqueue(new SingleBigQueryExecution(results = results, queryId = queryId, columns = columns, delay = delay))\n    this\n  }\n\n  override def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    for {\n      _ <- Task.eval(this.resultBuilder = builder)\n      execution <- Task.eval(executions.dequeue())\n      _ <- execution.act(query, builder)\n    } yield ()\n  }\n\n  def clear = {\n    executions.clear()\n    this\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/GoogleBigQueryClient.scala",
    "content": "package quix.bigquery\n\nimport com.google.cloud.bigquery._\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v2.execute.SubQuery\n\nclass GoogleBigQueryClient(bigQuery: BigQuery, config: BigQueryConfig) extends BigQueryClient with LazyLogging {\n\n  override def init(query: SubQuery): Task[Job] = {\n    for {\n      jobInfo <- Task.now(JobInfo.of(QueryJobConfiguration.newBuilder(query.text).build))\n      _ <- Task(logger.info(s\"method=init query-id=${query.id} query-sql=[${query.text.replace(\"\\n\", \"-newline-\")}] config=$config\"))\n    } yield bigQuery.create(jobInfo)\n  }\n\n  override def close(jobId: String): Task[Unit] = {\n    for {\n      _ <- Task(logger.info(s\"method=close job-id=$jobId config=$config\"))\n      _ <- Task(bigQuery.cancel(jobId)).attempt\n    } yield ()\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/TryBigQuery.scala",
    "content": "package quix.bigquery\n\nimport java.nio.file.{Files, Paths}\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.execution.Scheduler.Implicits.global\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\n\nobject TryBigQuery extends LazyLogging {\n  val credentials = Files.readAllBytes(Paths.get(\"credentials.json\"))\n  val config = BigQueryConfig(credentials, 1000 * 60, 1000 * 10)\n\n  def main(args: Array[String]): Unit = {\n    val client = BigQueryQueryExecutor(config)\n\n    val text = \"SELECT * FROM `bigquery-public-data.samples.github_nested` LIMIT 20000\"\n\n    val builder = new SingleBuilder\n\n    val query = ImmutableSubQuery(text, User(\"valeryf@wix.com\", \"valeryf\"))\n\n    client.execute(query, builder).runSyncUnsafe()\n\n    logger.info(s\"rows=${builder.build().size}\")\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/db/BigQueryAutocomplete.scala",
    "content": "package quix.bigquery.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Autocomplete, Catalog, Catalogs}\nimport quix.api.v2.execute.Executor\n\nclass BigQueryAutocomplete(val catalogs: Catalogs,\n                           val queryExecutor: Executor) extends Autocomplete {\n\n  override def fast: Task[Map[String, List[String]]] = catalogs.fast.map(extractAutoCompleteItems)\n\n  override def full: Task[Map[String, List[String]]] = catalogs.full.map(extractAutoCompleteItems)\n\n  def extractAutoCompleteItems(catalogList: List[Catalog]): Map[String, List[String]] = {\n    Map(\n      \"schemas\" -> catalogList.flatMap(_.children.map(_.name)),\n      \"tables\" -> catalogList.flatMap(_.children.flatMap(_.children.map(_.name)))\n    )\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/db/BigQueryCatalogs.scala",
    "content": "package quix.bigquery.db\n\nimport com.google.cloud.bigquery.{BigQuery, DatasetId}\nimport monix.eval.Task\nimport quix.api.v1.db.{Catalog, Catalogs, Schema, Table}\nimport quix.bigquery.BigQueryConfig\n\nimport scala.collection.JavaConverters._\n\nclass BigQueryCatalogs(config: BigQueryConfig, val bigquery: BigQuery) extends Catalogs {\n\n  override def fast: Task[List[Catalog]] = {\n    for {\n      datasets <- Task(bigquery.listDatasets()).map(_.iterateAll().asScala.toList)\n    } yield List(Catalog(\"__root\", datasets.map(ds => Schema(ds.getDatasetId.getDataset, Nil))))\n  }\n\n  override def full: Task[List[Catalog]] = {\n    for {\n      datasets <- Task(bigquery.listDatasets()).map(_.iterateAll().asScala.toList)\n      schemas <- Task.traverse(datasets.map(_.getDatasetId))(inferSchemaInOneQuery)\n    } yield List(Catalog(\"__root\", schemas))\n  }\n\n  def inferSchemaInOneQuery(datasetId: DatasetId): Task[Schema] = {\n    for {\n      dataset <- Task(bigquery.getDataset(datasetId))\n      tables <- Task(dataset.list().iterateAll().asScala.toList)\n    } yield {\n      val tablesNames = tables.map(table => Table(table.getTableId.getTable, List()))\n      Schema(datasetId.getDataset, tablesNames.sortBy(_.name))\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/main/scala/quix/bigquery/db/BigQueryTables.scala",
    "content": "package quix.bigquery.db\n\nimport monix.eval.Task\nimport quix.api.v1.db._\nimport quix.api.v2.execute.Executor\nimport quix.core.executions.SingleQueryExecutor\n\nimport scala.concurrent.duration._\n\nclass BigQueryTables(val queryExecutor: Executor,\n                     val timeout: Long) extends Tables with SingleQueryExecutor {\n\n  override def get(catalog: String, schema: String, table: String): Task[Table] = {\n    val sql =\n      s\"\"\"SELECT column_name, data_type\n         |FROM `$schema.INFORMATION_SCHEMA.COLUMNS` WHERE table_name='$table'\n       \"\"\".stripMargin\n\n    val mapper: List[String] => Kolumn = {\n      case List(name, kind) => Kolumn(name, kind)\n      case row => Kolumn(row.mkString, \"unknown\")\n    }\n\n    for {\n      columns <- executeFor(sql, mapper)\n        .timeout(timeout.millis)\n        .onErrorFallbackTo(Task(Nil))\n    } yield Table(table, columns.filter(_.name.trim.nonEmpty).filterNot(_.name.startsWith(\"# \")).distinct)\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-bigquery-module/src/test/scala/quix/bigquery/BigQueryQueryExecutorTest.scala",
    "content": "package quix.bigquery\n\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mock.Mockito\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\n\nclass BigQueryQueryExecutorTest extends SpecWithJUnit with MustMatchers with Mockito {\n\n  class ctx extends Scope {\n\n    val client = mock[BigQueryClient]\n    val executor = new BigQueryQueryExecutor(client, 1000L)\n    val query = ImmutableSubQuery(id = \"query-id\", text = \"select 1\", user = User(\"bigquery-test\"))\n    val builder = spy(new SingleBuilder)\n  }\n\n  \"BigQueryQueryExecutor\" should {\n    \"notify builder on exceptions in client.init\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      client.init(query) returns Task.raiseError(exception)\n\n      // call\n      executor.initClient(query, builder).runToFuture\n\n      // verify\n      eventually {\n        there was one(builder).error(query.id, exception)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-dummy-module/src/main/scala/quix/dummy/DummyQueryExecutor.scala",
    "content": "package quix.dummy\n\nimport monix.eval.Task\nimport quix.api.v1.execute.{Batch, BatchColumn, BatchError}\nimport quix.api.v2.execute.{Builder, Executor, SubQuery}\n\nimport scala.util.Random\n\nclass DummyQueryExecutor extends Executor {\n\n  override def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    // all resources that are allocated per query can be allocated via Task\n    val allocateResource = Task(\"Resource\")\n\n    // code that accepts resource and releases it\n    val releaseResource = (_: String) => Task()\n\n    // code that accepts resource and uses it to execute the query\n    val useResource = (_: String) => generateExecution(query, builder)\n\n    // similar to try-with-resources of Java 8 or try/catch/finally for older Java versions to release resources\n    allocateResource.bracket(useResource)(releaseResource)\n  }\n\n  /** generates execution that consist of 2 subqueries with random results and failing last subquery */\n  def generateExecution(query: SubQuery, builder: Builder): Task[Unit] = {\n    for {\n      // each sub query will be rendered as different tab in quix-frontend\n      _ <- generateBatches(\"first-sub-query\", builder)\n      _ <- generateBatches(\"second-sub-query\", builder)\n\n      // third query will fail\n      _ <- builder.startSubQuery(\"third-sub-query\", \"failing sub query\")\n      _ <- builder.addSubQuery(\"third-sub-query\", Batch(\n        error = Option(BatchError(\"failing sub query\"))\n      ))\n    } yield ()\n  }\n\n\n  /** generates random data set and creates a list of monix Tasks that send it to builder when executed */\n  def generateBatches(subQueryId: String, builder: Builder): Task[Unit] = {\n    val columnsCount = Random.nextInt(10) + 5\n    val columns = for (i <- 0 to columnsCount) yield BatchColumn(s\"column_$i\")\n    val firstBatch = Batch(columns = Option(columns))\n\n    val batchCount = Random.nextInt(10) + 5\n    val rowCount = Random.nextInt(100) + 5\n\n    val batches = for (batch <- 1 to batchCount) yield {\n      val rows = for (i <- 0 to rowCount) yield Seq.fill(columns.size)(batch * i)\n\n      Batch(data = rows)\n    }\n\n    for {\n      _ <- builder.startSubQuery(subQueryId, s\"random results made of $columnsCount columns, $batchCount batches with $rowCount each\")\n      _ <- builder.addSubQuery(subQueryId, firstBatch)\n      _ <- Task.traverse(batches) { batch =>\n        builder.addSubQuery(subQueryId, batch)\n      }\n    } yield ()\n\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-dummy-module/src/test/scala/quix/dummy/DummyQueryExecutorTest.scala",
    "content": "package quix.dummy\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\n\nclass DummyQueryExecutorTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    val executor = new DummyQueryExecutor\n\n    def makeQuery(text: String) = {\n      ImmutableSubQuery(text, User(\"dummy-test-user\"), id = \"query-id\")\n    }\n\n    val query = makeQuery(\"select 1\")\n    val builder = new SingleBuilder\n  }\n\n  \"DummyQueryExecutor\" should {\n    \"pass sanity\" in new ctx {\n      executor.execute(\n        query, builder).runSyncUnsafe()\n\n      builder.build() must not be empty\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/it/resources/db/001_init.sql",
    "content": "create table empty_table\n(\n    col1 INTEGER NOT NULL\n);\n\ncreate table small_table\n(\n    col1 INTEGER NOT NULL\n);\n\nINSERT INTO small_table\nvalues (1);\n\ncreate table large_table\n(\n    col1 INTEGER NOT NULL\n);\n\nINSERT INTO large_table\nvalues (1),\n       (2),\n       (3),\n       (4),\n       (5),\n       (6),\n       (7),\n       (8),\n       (9),\n       (10);\n\ncreate table wide_table\n(\n    col1  INTEGER NOT NULL,\n    col2  INTEGER NOT NULL,\n    col3  INTEGER NOT NULL,\n    col4  INTEGER NOT NULL,\n    col5  INTEGER NOT NULL,\n    col6  INTEGER NOT NULL,\n    col7  INTEGER NOT NULL,\n    col8  INTEGER NOT NULL,\n    col9  INTEGER NOT NULL,\n    col10 INTEGER NOT NULL\n);"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/it/scala/quix/jdbc/EmbeddedMysqlDb.scala",
    "content": "package quix.jdbc\n\nimport com.typesafe.scalalogging.LazyLogging\nimport com.wix.mysql.EmbeddedMysql\nimport com.wix.mysql.EmbeddedMysql.anEmbeddedMysql\nimport com.wix.mysql.ScriptResolver.classPathScript\nimport com.wix.mysql.config.Charset.UTF8\nimport com.wix.mysql.config.MysqldConfig\nimport com.wix.mysql.config.MysqldConfig.aMysqldConfig\nimport com.wix.mysql.distribution.Version.v5_6_23\n\nobject EmbeddedMysqlDb extends LazyLogging {\n  val config: MysqldConfig = aMysqldConfig(v5_6_23)\n    .withCharset(UTF8)\n    .withPort(2215)\n    .withUser(\"wix\", \"wix\")\n    .build()\n\n  var db: EmbeddedMysql = _\n\n  def reloadSchema = {\n    logger.info(\"method=reloadSchema\")\n    db.reloadSchema(\"aschema\", classPathScript(\"db/001_init.sql\"))\n  }\n\n  def stop = {\n    logger.info(\"method=stop\")\n    db.stop()\n  }\n\n  def start = {\n    logger.info(\"method=start\")\n    db = anEmbeddedMysql(config)\n      .addSchema(\"aschema\", classPathScript(\"db/001_init.sql\"))\n      .start()\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/it/scala/quix/jdbc/MysqlJdbcIntegrationTest.scala",
    "content": "package quix.jdbc\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.{AfterAll, BeforeAll, BeforeEach, Scope}\n\nclass MysqlJdbcIntegrationTest extends SpecWithJUnit with BeforeAll with BeforeEach with AfterAll {\n  sequential\n\n  class ctx extends Scope {\n    val config = JdbcConfig(\"jdbc:mysql://localhost:2215/aschema\", \"wix\", \"wix\", \"com.mysql.cj.jdbc.Driver\")\n    Class.forName(config.driver)\n\n    val catalogs = new JdbcCatalogs(config)\n    val tables = new JdbcTables(config)\n  }\n\n  def before = EmbeddedMysqlDb.reloadSchema\n\n  def afterAll() = EmbeddedMysqlDb.stop\n\n  def beforeAll() = EmbeddedMysqlDb.start\n\n  \"JdbcCatalogs.fast\" should {\n    \"return only schema names\" in new ctx {\n      val db = catalogs.fast.runSyncUnsafe()\n      val catalogNames = db.map(_.name)\n      val schemaNames = db.flatMap(_.children.map(_.name))\n\n      catalogNames must contain(\"__root\")\n      schemaNames must contain(\"aschema\")\n    }\n  }\n\n  \"JdbcCatalogs.full\" should {\n    \"return complete db tree\" in new ctx {\n      val fullTree = catalogs.full.runSyncUnsafe()\n      val catalogNames = fullTree.map(_.name)\n      val schemaNames = fullTree.flatMap(_.children.map(_.name))\n      val tableNames = fullTree.flatMap(_.children.flatMap(_.children.map(_.name)))\n\n      catalogNames must contain(\"__root\")\n      schemaNames must contain(\"aschema\")\n      tableNames must contain(\"empty_table\", \"large_table\", \"small_table\")\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/it/scala/quix/jdbc/MysqlJdbcQueryExecutorIntegrationTest.scala",
    "content": "package quix.jdbc\n\nimport monix.execution.Scheduler.Implicits.global\nimport monix.execution.atomic.Atomic\nimport org.specs2.mock.Mockito\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.{AfterAll, BeforeAll, BeforeEach, Scope}\nimport quix.api.v1.execute.Batch\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\n\nclass MysqlJdbcQueryExecutorIntegrationTest extends SpecWithJUnit with BeforeAll with BeforeEach with AfterAll with Mockito {\n  sequential\n\n  class ctx extends Scope {\n    val config =\n      JdbcConfig(\"jdbc:mysql://localhost:2215/aschema\", \"wix\", \"wix\", \"com.mysql.cj.jdbc.Driver\", batchSize = 1)\n    val executor = new JdbcQueryExecutor(config)\n    Class.forName(config.driver)\n\n    val builder = spy(new SingleBuilder)\n\n    def query(sql: String) = ImmutableSubQuery(sql, User(\"user@quix\"))\n  }\n\n  def before = EmbeddedMysqlDb.reloadSchema\n\n  def afterAll() = EmbeddedMysqlDb.stop\n\n  def beforeAll() = EmbeddedMysqlDb.start\n\n  \"JdbcQueryExecutor\" should {\n\n    \"call builder.startSubQuery & builder.endSubQuery on valid\" in new ctx {\n      val sql = query(\"select * from small_table\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was one(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n    }\n\n    \"do not call builder.addSubQuery on zero results\" in new ctx {\n      val sql = query(\"select * from empty_table\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was no(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n    }\n\n    \"stop query if query.isCancelled is true\" in new ctx {\n      val sql = query(\"select * from large_table\").copy(canceled = Atomic(true))\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was no(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n    }\n\n    \"support create statements\" in new ctx {\n      val sql = query(\"create table new_table (col1 INTEGER NOT NULL)\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was no(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n\n      there was no(builder).errorSubQuery(anyString, any[Throwable]())\n    }\n\n    \"support insert statements\" in new ctx {\n      val sql = query(\"INSERT INTO small_table values (123);\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was no(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n\n      there was no(builder).errorSubQuery(anyString, any[Throwable]())\n    }\n\n    \"support update statements\" in new ctx {\n      val sql = query(\"update small_table set col1 = 123 where col1 = 1\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was no(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n\n      there was no(builder).errorSubQuery(anyString, any[Throwable]())\n    }\n\n    \"support delete statements\" in new ctx {\n      val sql = query(\"delete from small_table where col1 = 1\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).startSubQuery(anyString, anyString)\n\n      there was no(builder).addSubQuery(anyString, any[Batch]())\n\n      there was one(builder).endSubQuery(anyString, any())\n\n      there was no(builder).errorSubQuery(anyString, any[Throwable]())\n    }\n\n    \"call builder.error on connection errors\" in new ctx {\n      EmbeddedMysqlDb.stop\n      val sql = query(\"select * from empty_table\")\n      executor.execute(sql, builder).runSyncUnsafe()\n\n      // verify\n      there was one(builder).errorSubQuery(anyString, any[Throwable]())\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/it/scala/quix/jdbc/MysqlJdbcTablesIntegrationTest.scala",
    "content": "package quix.jdbc\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.{AfterAll, BeforeAll, BeforeEach, Scope}\n\nclass MysqlJdbcTablesIntegrationTest extends SpecWithJUnit with BeforeAll with BeforeEach with AfterAll {\n  sequential\n\n  class ctx extends Scope {\n    val config = JdbcConfig(\"jdbc:mysql://localhost:2215/aschema\", \"wix\", \"wix\", \"com.mysql.cj.jdbc.Driver\")\n    Class.forName(config.driver)\n\n    val catalogs = new JdbcCatalogs(config)\n    val tables = new JdbcTables(config)\n  }\n\n  def before = EmbeddedMysqlDb.reloadSchema\n\n  def afterAll() = EmbeddedMysqlDb.stop\n\n  def beforeAll() = EmbeddedMysqlDb.start\n\n  \"JdbcTables.fast\" should {\n    \"return table on valid request of single column table\" in new ctx {\n      val table = tables.get(\"__root\", \"aschema\", \"small_table\").runSyncUnsafe()\n      val columns = table.children.map(_.name)\n\n      table.name must_=== \"small_table\"\n      columns must contain(\"col1\")\n    }\n\n    \"return table with empty columns on bad request\" in new ctx {\n      val table = tables.get(\"foo\", \"bar\", \"baz\").runSyncUnsafe()\n\n      table.name must_=== \"baz\"\n      table.children must beEmpty\n    }\n\n    \"return all columns on valid request of wide table\" in new ctx {\n      val table = tables.get(\"__root\", \"aschema\", \"wide_table\").runSyncUnsafe()\n      val columns = table.children.map(_.name)\n\n      val expected = (1 to 10).map(i => \"col\" + i).toList\n\n      columns must_=== expected\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/main/scala/quix/jdbc/JdbcAutocomplete.scala",
    "content": "package quix.jdbc\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Autocomplete, Catalog}\n\nclass JdbcAutocomplete(val catalogs: JdbcCatalogs) extends Autocomplete {\n  override def fast: Task[Map[String, List[String]]] = {\n    catalogs.fast.map(toAutocompleteItems)\n  }\n\n  override def full: Task[Map[String, List[String]]] =\n    catalogs.full.map(toAutocompleteItems)\n\n  def toAutocompleteItems(catalogList: List[Catalog]) = {\n    Map(\n      \"catalogs\" -> catalogList.map(_.name),\n      \"schemas\" -> catalogList.flatMap(_.children.map(_.name)),\n      \"tables\" -> catalogList.flatMap(_.children.flatMap(_.children.map(_.name))))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/main/scala/quix/jdbc/JdbcCatalogs.scala",
    "content": "package quix.jdbc\n\nimport java.sql.{Connection, DriverManager, ResultSet}\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Catalog, Catalogs, Schema, Table}\n\nimport scala.collection.mutable.ListBuffer\nimport scala.concurrent.duration._\n\nclass JdbcCatalogs(val config: JdbcConfig)\n  extends Catalogs {\n\n  override def fast: Task[List[Catalog]] = full\n\n  def drainFullResultSet(rs: ResultSet) = Task {\n    case class RichTable(catalog: String, schema: String, name: String)\n\n    val tables = {\n      val result = ListBuffer.empty[RichTable]\n\n      while (rs.next()) {\n        val catalog = rs.getString(\"TABLE_CAT\")\n        val schema = rs.getString(\"TABLE_SCHEM\")\n        val table = rs.getString(\"TABLE_NAME\")\n\n        config.url match {\n          case url if url.startsWith(\"jdbc:mysql\") =>\n            result += RichTable(\"__root\", catalog, table)\n\n          case url if url.startsWith(\"jdbc:clickhouse\") =>\n            result += RichTable(\"__root\", schema, table)\n\n          case _ if catalog == null =>\n            result += RichTable(\"__root\", schema, table)\n\n          case _ =>\n            result += RichTable(catalog, schema, table)\n        }\n      }\n\n      result.toList.distinct\n    }\n\n    val catalogs = for ((catalogName, catalogTables) <- tables.groupBy(_.catalog).toList)\n      yield {\n        val schemas = for ((schemaName, schemaTables) <- catalogTables.groupBy(_.schema).toList)\n          yield Schema(schemaName, schemaTables.map(tbl => Table(tbl.name, Nil)))\n\n        Catalog(catalogName, schemas)\n      }\n\n    catalogs\n  }\n\n  override def full: Task[List[Catalog]] = {\n    val connect: Task[Connection] = {\n      for {\n        connection <- Task(\n          DriverManager.getConnection(config.url, config.user, config.pass)\n        ).timeout(config.connectTimeout.millis)\n      } yield connection\n    }\n\n    val close = (connection: Connection) =>\n      for (_ <- Task(connection.close()).attempt) yield ()\n\n\n    val use = (con: Connection) => {\n      for {\n        metadata <- Task(con.getMetaData)\n        resultSet <- Task(metadata.getTables(null, null, \"%\", null))\n        catalogs <- drainFullResultSet(resultSet)\n      } yield catalogs\n    }\n\n    connect\n      .bracket(use)(close)\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/main/scala/quix/jdbc/JdbcQueryExecutor.scala",
    "content": "package quix.jdbc\n\nimport java.sql.{Connection, DriverManager, ResultSet}\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v1.execute._\nimport quix.api.v2.execute.{Builder, Executor, SubQuery}\nimport quix.core.utils.TaskOps._\n\nimport scala.collection.mutable.ListBuffer\nimport scala.concurrent.duration._\n\ncase class JdbcConfig(url: String,\n                      user: String,\n                      pass: String,\n                      driver: String,\n                      connectTimeout: Long = 1000 * 10,\n                      batchSize: Int = 2000)\n\nclass JdbcQueryExecutor(config: JdbcConfig)\n  extends Executor with LazyLogging {\n\n  def prepareBatch(rs: ResultSet): Task[Batch] =\n    Task {\n      val rows = ListBuffer.empty[Seq[Any]]\n      val columnCount = rs.getMetaData.getColumnCount\n\n      val columns = for (i <- 1 to columnCount)\n        yield BatchColumn(rs.getMetaData.getColumnName(i))\n\n      do {\n        val row = for (i <- 1 to columnCount)\n          yield {\n            rs.getMetaData.getColumnType(i) match {\n              case java.sql.Types.ARRAY if rs.getArray(i) != null =>\n                rs.getArray(i).getArray\n\n              case _ => rs.getObject(i)\n            }\n          }\n\n        rows += row\n      } while (rows.size < config.batchSize && rs.next())\n\n      Batch(rows.toList, Some(columns))\n    }\n\n  def drainResultSet(query: SubQuery,\n                     rb: Builder,\n                     rs: ResultSet): Task[Unit] = {\n    if (!query.canceled.get && rs != null && rs.next()) {\n      for {\n        batch <- prepareBatch(rs)\n        _ <- rb.addSubQuery(query.id, batch)\n        _ <- drainResultSet(query, rb, rs)\n      } yield ()\n    } else Task.unit\n  }\n\n  def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n\n    val connect: Task[Connection] = {\n      for {\n        connection <- Task(\n          DriverManager.getConnection(config.url, config.user, config.pass)\n        ).timeout(config.connectTimeout.millis)\n      } yield connection\n    }\n\n    val close = (connection: Connection) =>\n      for (_ <- Task(connection.close()).attempt) yield ()\n\n    val use = (con: Connection) => {\n      for {\n        _ <- builder.startSubQuery(query.id, query.text)\n        statement <- Task(con.createStatement())\n        _ <- Task(statement.execute(query.text))\n        _ <- drainResultSet(query, builder, statement.getResultSet)\n        _ <- builder.endSubQuery(query.id, Map.empty)\n      } yield ()\n    }\n\n    connect\n      .bracket(use)(close)\n      .logOnError(s\"method=runTask event=error query-id=${query.id}\")\n      .onErrorHandleWith { e =>\n        builder.errorSubQuery(query.id, e)\n      }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-jdbc-module/src/main/scala/quix/jdbc/JdbcTables.scala",
    "content": "package quix.jdbc\n\nimport java.sql.{Connection, DatabaseMetaData, DriverManager, ResultSet}\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Kolumn, Table, Tables}\n\nimport scala.collection.mutable.ListBuffer\nimport scala.concurrent.duration._\n\nclass JdbcTables(val config: JdbcConfig) extends Tables {\n\n  override def get(catalog: String, schema: String, table: String): Task[Table] = {\n    val connect: Task[Connection] = {\n      for {\n        connection <- Task(\n          DriverManager.getConnection(config.url, config.user, config.pass)\n        ).timeout(config.connectTimeout.millis)\n      } yield connection\n    }\n\n    val close = (connection: Connection) =>\n      for (_ <- Task(connection.close()).attempt) yield ()\n\n    val use = (con: Connection) => {\n      for {\n        metadata <- Task(con.getMetaData)\n        resultSet <- fetchColumns(catalog, schema, table, metadata)\n        columns <- drainResultSet(resultSet)\n      } yield Table(table, columns)\n    }\n\n    connect\n      .bracket(use)(close)\n  }\n\n  private def fetchColumns(catalog: String, schema: String, table: String, metadata: DatabaseMetaData) = {\n    // https://bugs.mysql.com/bug.php?id=23304\n    // due to mysql jdbc/odbc driver legacy implementation .getCatalogs returns list of schemas\n    // and .getSchemas returns empty list\n\n    if (config.url.startsWith(\"jdbc:mysql\"))\n      Task(metadata.getColumns(schema, null, table, null))\n    else Task(metadata.getColumns(catalog, schema, table, null))\n  }\n\n  def drainResultSet(rs: ResultSet): Task[List[Kolumn]] = Task {\n    val columns = ListBuffer.empty[Kolumn]\n\n    while (rs.next()) {\n      val name = rs.getString(\"COLUMN_NAME\")\n      val datatype = rs.getString(\"TYPE_NAME\")\n      columns += Kolumn(name, datatype)\n    }\n\n    columns.toList\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/PrestoConfig.scala",
    "content": "package quix.presto\n\ncase class PrestoConfig(statementsApi: String,\n                        healthApi: String,\n                        queryInfoApi: String,\n                        schema: String,\n                        catalog: String,\n                        source: String,\n                        httpHeadersPrefix: String)"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/QueryExecutor.scala",
    "content": "package quix.presto\n\nimport java.net.{ConnectException, SocketException, SocketTimeoutException}\n\nimport monix.eval.Task\nimport quix.api.v1.execute.ExceptionPropagatedToClient\nimport quix.api.v2.execute._\nimport quix.presto.rest.{PrestoState, PrestoStateClient, PrestoStateToResults}\n\nimport scala.concurrent.duration._\n\nclass QueryExecutor(val client: PrestoStateClient,\n                    val initialAdvanceDelay: FiniteDuration = 100.millis,\n                    val maxAdvanceDelay: FiniteDuration = 33.seconds)\n  extends Executor {\n\n  // if got no results from presto, wait twice longer for next page\n  def nextDelay(delay: FiniteDuration, state: PrestoState): FiniteDuration = {\n    if (state.data.map(_.size).getOrElse(0) == 0)\n      delay.mul(2).min(maxAdvanceDelay) else initialAdvanceDelay\n  }\n\n  def loop(prestoId: String, nextUri: Option[String], builder: Builder, query: SubQuery, delay: FiniteDuration): Task[Option[String]] = {\n    Task(query.canceled.get()).flatMap {\n      case true =>\n        Task(Option.empty[String])\n\n      case false =>\n        nextUri.map { uri =>\n          for {\n            nextState <- advance(uri, builder, query, delay)\n            _ <- builder.addSubQuery(prestoId, PrestoStateToResults(nextState))\n            futureState <- loop(prestoId, nextState.nextUri, builder, query, nextDelay(delay, nextState))\n          } yield futureState\n        }.getOrElse(Task(Option.empty[String]))\n    }\n  }\n\n  def advance(uri: String, builder: Builder, query: SubQuery, delay: FiniteDuration): Task[PrestoState] = {\n    client.advance(uri, query)\n      .delayExecution(delay)\n      .onErrorHandleWith { originalException =>\n        val exception = rewriteException(originalException)\n        builder.errorSubQuery(query.id, exception)\n          .flatMap(_ => Task.raiseError(exception))\n      }\n  }\n\n  override def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    val executionTask = initClient(query, builder).bracket { firstState =>\n      for {\n        _ <- builder.startSubQuery(firstState.id, query.text)\n        _ <- builder.addSubQuery(firstState.id, PrestoStateToResults(firstState))\n\n        _ <- loop(firstState.id, firstState.nextUri, builder, query, initialAdvanceDelay)\n\n        _ <- builder.endSubQuery(firstState.id)\n        info <- client.info(firstState, query)\n      } yield info\n    }(state => client.close(state, query))\n\n    val task = for {\n      info <- executionTask\n      _ <- Task {\n        info.setCatalog.foreach(catalog => query.session.put(\"X-Presto-Catalog\", catalog))\n        info.setSchema.foreach(schema => query.session.put(\"X-Presto-Schema\", schema))\n        info.setSessionProperties.foreach { case (k, v) => query.session.put(k, v) }\n        info.resetSessionProperties.foreach(key => query.session.remove(key))\n      }\n    } yield ()\n\n    task\n\n  }\n\n  def initClient(query: SubQuery, builder: Builder): Task[PrestoState] = {\n    client.init(query).onErrorHandleWith { originalException =>\n      val exception = rewriteException(originalException)\n      builder.error(query.id, exception)\n        .flatMap(_ => Task.raiseError(exception))\n    }\n  }\n\n  def rewriteException(e: Throwable): Throwable = e match {\n    case e@(_: ConnectException | _: SocketTimeoutException | _: SocketException) =>\n      val message = s\"Presto can't be reached, please try later. Underlying exception name is ${e.getClass.getSimpleName}\"\n      ExceptionPropagatedToClient(message)\n    case _ => e\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/TestQueryExecutor.scala",
    "content": "package quix.presto\n\nimport monix.eval.Task\nimport quix.api.v2.execute.{Builder, Executor, SubQuery}\nimport quix.presto.rest._\n\nimport scala.collection.mutable\nimport scala.concurrent.duration.{Duration, FiniteDuration}\n\nclass SingleExecution(exception: Option[Exception] = Option.empty[Exception],\n                      error: Option[PrestoError] = Option.empty[PrestoError],\n                      results: List[List[AnyRef]] = Nil,\n                      queryId: String = \"test-query-id\",\n                      columns: List[String] = Nil,\n                      delay: FiniteDuration = Duration.Zero) {\n\n  def prestoColumns = {\n    if (columns.nonEmpty) {\n      Option(columns.map { name => PrestoColumn(name, \"string\") })\n    } else None\n  }\n\n  def act(query: SubQuery, builder: Builder): Task[Unit] = {\n    val client = new PrestoStateClient {\n      var index = 0\n\n      override def init(query: SubQuery): Task[PrestoState] = {\n        exception match {\n          case Some(e) =>\n            Task.raiseError(e)\n          case None =>\n            Task.eval {\n              val nextUri = error.map(_ => None).getOrElse(Some(\"next-uri\"))\n\n              val stats = PrestoStats(\"QUEUED\", true, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\n              PrestoState(queryId, \"info-uri\", None, nextUri, prestoColumns, None, stats, error, None)\n            }\n        }\n      }\n\n\n      override def advance(uri: String, query: SubQuery): Task[PrestoState] = Task.eval {\n        if (index + 1 <= results.size) {\n          val stats = PrestoStats(\"RUNNING\", true, 0, results.size, 0, 0, index, 0, 0, 0, 0, 0)\n          val state = PrestoState(queryId, \"info-uri\", None, Some(\"next-uri\"), prestoColumns, Option(List(results(index))), stats, None, None)\n          index = index + 1\n          state\n        } else {\n          val stats = PrestoStats(\"FINISHED\", true, 0, results.size, 0, 0, results.size, 0, 0, 0, 0, 0)\n          val restOfItems = results.drop(index)\n          val state = PrestoState(queryId, \"info-uri\", None, None, prestoColumns, Option(restOfItems), stats, None, None)\n          state\n        }\n      }\n\n      override def close(state: PrestoState, query: SubQuery): Task[Unit] = Task.unit\n\n      override def info(state: PrestoState, query: SubQuery): Task[PrestoQueryInfo] = Task.eval {\n        val queryStats = PrestoQueryStats(\"0\", \"0\", 0, \"\", \"\", \"\", 0)\n        PrestoQueryInfo(queryId, \"FINISHED\", queryStats, None, None, Map.empty, List.empty)\n      }\n\n      override def health(): Task[PrestoHealth] = Task.eval {\n        PrestoHealth(0, 0, 0, 0, 0, 0, 0, 0, 0)\n      }\n    }\n    new QueryExecutor(client).execute(query, builder).delayExecution(delay)\n  }\n}\n\nclass TestQueryExecutor extends Executor {\n\n  val executions: mutable.Queue[SingleExecution] = mutable.Queue.empty\n  var resultBuilder: Builder = _\n\n  def withException(e: Exception) = {\n    executions.enqueue(new SingleExecution(exception = Some(e)))\n    this\n  }\n\n  def withExceptions(e: Exception, n: Int) = {\n    for (e <- List.fill(n)(e))\n      executions.enqueue(new SingleExecution(exception = Some(e)))\n    this\n  }\n\n  def withPrestoError(e: PrestoError): TestQueryExecutor = {\n    executions.enqueue(new SingleExecution(error = Some(e)))\n    this\n  }\n\n  def withResults(results: List[List[AnyRef]], queryId: String = \"query-id\", columns: List[String] = Nil, delay: FiniteDuration = Duration.Zero) = {\n    executions.enqueue(new SingleExecution(results = results, queryId = queryId, columns = columns, delay = delay))\n    this\n  }\n\n  override def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    for {\n      _ <- Task.eval(this.resultBuilder = builder)\n      execution <- Task.eval(executions.dequeue())\n      _ <- execution.act(query, builder)\n    } yield ()\n  }\n\n  def clear = {\n    executions.clear()\n    this\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/TryPresto.scala",
    "content": "package quix.presto\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.SingleBuilder\nimport quix.presto.rest.ScalaJPrestoStateClient\n\nobject TryPresto extends LazyLogging {\n\n  def main(args: Array[String]): Unit = {\n    val statementApi = \"http://<.....enter your presto coordinator hostname.....>:8181/v1/statement/\"\n    val healthApi = \"http://<.....enter your presto coordinator hostname.....>:8181/v1/cluster\"\n    val infoQueryApi = \"http://<.....enter your presto coordinator hostname.....>:8181/v1/query/\"\n    val httpHeadersPrefix = \"X-Presto-\"\n    val config = PrestoConfig(statementApi, healthApi, infoQueryApi, \"events\", \"dbo\", \"quix\", httpHeadersPrefix)\n    val client = new ScalaJPrestoStateClient(config)\n\n    val executor = new QueryExecutor(client)\n\n    val results = for {\n      i <- 1 to 5\n      query = activeQuery(s\"-- query $i\\n select 1\")\n      builder = new SingleBuilder\n    } yield executor.execute(query, builder).map(_ => builder)\n\n    val builders = Task.sequence(results).runSyncUnsafe()\n\n    for {\n      (builder, index) <- builders.zipWithIndex\n    } logger.info(s\"builder $index got ${builder.build().length} rows\")\n  }\n\n  def activeQuery(text: String) = {\n    ImmutableSubQuery(text, User(id = \"user\", email = \"user@quix\"))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/db/PrestoAutocomplete.scala",
    "content": "package quix.presto.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Autocomplete, Catalog, Catalogs}\nimport quix.api.v2.execute.Executor\nimport quix.core.executions.SingleQueryExecutor\n\nclass PrestoAutocomplete(val catalogs: Catalogs,\n                         val queryExecutor: Executor)\n  extends Autocomplete with SingleQueryExecutor {\n\n  override def fast: Task[Map[String, List[String]]] = {\n    catalogs.fast.flatMap(singleQueryAutocomplete)\n  }\n\n  override def full: Task[Map[String, List[String]]] = {\n    catalogs.full.flatMap(singleQueryAutocomplete)\n  }\n\n  def singleQueryAutocomplete(catalogList: List[Catalog]) = {\n    for {\n      catalogs <- Task.now(catalogList.map(_.name))\n      schemas <- Task.now(catalogList.flatMap(_.children.map(_.name)))\n      tables <- Task.now(catalogList.flatMap(_.children.flatMap(_.children.map(_.name))))\n      columns <- executeForSingleColumn(\"select distinct column_name from system.jdbc.columns\")\n        .onErrorFallbackTo(Task(List.empty[String]))\n    } yield Map(\"catalogs\" -> catalogs, \"schemas\" -> schemas, \"tables\" -> tables, \"columns\" -> columns)\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/db/PrestoCatalogs.scala",
    "content": "package quix.presto.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Catalog, Catalogs, Schema, Table}\nimport quix.api.v2.execute.Executor\nimport quix.core.executions.SingleQueryExecutor\n\nclass PrestoCatalogs(val queryExecutor: Executor,\n                     val hiddenCatalogs: Set[String] = Set.empty)\n  extends Catalogs with SingleQueryExecutor {\n\n  override def fast: Task[List[Catalog]] = getCatalogNamesOnly\n\n  override def full: Task[List[Catalog]] =\n    inferCatalogsOneByOne\n      .onErrorFallbackTo(getCatalogNamesOnly)\n      .onErrorFallbackTo(Task.now(Nil))\n\n  case class RichTable(catalog: String, schema: String, name: String)\n\n  private def inferCatalogsOneByOne = {\n    for {\n      catalogNames <- getCatalogNames\n      catalogs <- Task.traverse(catalogNames)(inferSchemaOfCatalog)\n    } yield catalogs\n  }\n\n  private def getCatalogNames = {\n    for {\n      catalogNames <- executeForSingleColumn(\"show catalogs\")\n    } yield catalogNames.filterNot(hiddenCatalogs)\n  }\n\n  def getCatalogNamesOnly = {\n    for {\n      catalogNames <- getCatalogNames\n        .onErrorFallbackTo(Task.now(Nil))\n    } yield catalogNames.map(name => Catalog(name, Nil))\n  }\n\n  private def inferSchemaOfCatalog(catalogName: String) = {\n    val fastQueryInference = inferSchemaInOneQuery(catalogName)\n    val slowFallbackOne = inferSchemaOneByOne(catalogName)\n    val slowFallbackTwo = inferSchemaViaShowSchemas(catalogName)\n    val emptyCatalog = Task.now(Catalog(catalogName, List.empty))\n\n    fastQueryInference\n      .onErrorFallbackTo(slowFallbackOne)\n      .onErrorFallbackTo(slowFallbackTwo)\n      .onErrorFallbackTo(emptyCatalog)\n  }\n\n  def inferSchemaInOneQuery(catalogName: String): Task[Catalog] = {\n    val sql =\n      s\"\"\"select distinct catalog, schema, tbl from (\n         |    select distinct table_cat as catalog, table_schem as schema, table_name as tbl\n         |    from system.jdbc.tables\n         |    where table_cat = '$catalogName'\n         |    and table_schem != 'information_schema'\n         |\n         |    union all\n         |\n         |    select distinct table_catalog as catalog, table_schema as schema, table_name as tbl\n         |    from $catalogName.information_schema.tables\n         |    where table_schema not in ('information_schema')\n         |)\n         |\"\"\".stripMargin\n\n    val mapper: List[String] => RichTable = {\n      case List(catalog, schema, name) => RichTable(catalog, schema, name)\n    }\n\n    for {\n      tables <- executeFor(sql, mapper)\n    } yield {\n      val schemas = tables.groupBy(_.schema).map {\n        case (schema, schemaTables) =>\n          val tables = schemaTables.map(table => Table(table.name, List()))\n          Schema(schema, tables.sortBy(_.name))\n      }\n\n      Catalog(catalogName, schemas.toList.sortBy(_.name))\n    }\n  }\n\n  def inferSchemaOneByOne(catalogName: String): Task[Catalog] = {\n    val sql =\n      s\"\"\"\n         |select distinct table_schema from (\n         |    select distinct table_schem as table_schema\n         |    from system.jdbc.tables\n         |    where table_cat = '$catalogName'\n         |    and table_schem != 'information_schema'\n         |\n         |    union all\n         |\n         |    select distinct table_schema as table_schema\n         |    from $catalogName.information_schema.tables\n         |    where table_schema not in ('information_schema')\n         |\n         |    union all\n         |\n         |    select distinct table_schem as table_schema\n         |    from system.jdbc.schemas\n         |    where table_catalog = '$catalogName' and table_schem not in ('information_schema')\n         |) order by 1;\n         |\n         |\"\"\".stripMargin\n\n    for {\n      schemaNames <- executeForSingleColumn(sql)\n      schemas <- Task.traverse(schemaNames)(schema => inferTablesViaShowTables(catalogName, schema).map(tables => Schema(schema, tables)))\n    } yield Catalog(catalogName, schemas)\n  }\n\n  def inferSchemaViaShowSchemas(catalogName: String): Task[Catalog] = {\n    val sql = s\"show schemas from $catalogName\"\n\n    for {\n      schemaNames <- executeForSingleColumn(sql)\n      schemas <- Task.traverse(schemaNames)(schema => inferTablesViaShowTables(catalogName, schema).map(tables => Schema(schema, tables)))\n    } yield Catalog(catalogName, schemas)\n  }\n\n  def inferTablesViaShowTables(catalogName: String, schemaName: String): Task[List[Table]] = {\n    val sql = s\"show tables from $catalogName.$schemaName\"\n\n    for {\n      tables <- executeForSingleColumn(sql)\n    } yield {\n      tables.sorted.map(name => Table(name, List.empty))\n    }\n  }\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/db/PrestoTables.scala",
    "content": "package quix.presto.db\n\nimport monix.eval.Task\nimport quix.api.v1.db.{Kolumn, Table, Tables}\nimport quix.api.v2.execute.Executor\nimport quix.core.executions.SingleQueryExecutor\n\nimport scala.concurrent.duration._\n\nclass PrestoTables(val queryExecutor: Executor, val timeout: Long)\n  extends Tables with SingleQueryExecutor {\n\n  override def get(catalog: String, schema: String, table: String): Task[Table] = {\n    val sql =\n      s\"\"\"select column_name, type_name\n         |from system.jdbc.columns\n         |where table_cat = '$catalog'\n         |and table_schem = '$schema'\n         |and table_name = '$table'\"\"\".stripMargin\n\n    val mapper: List[String] => Kolumn = {\n      case List(name, kind) => Kolumn(name, kind)\n    }\n\n    for {\n      columns <- executeFor(sql, mapper)\n        .timeout(timeout.millis)\n        .onErrorFallbackTo(Task(Nil))\n\n    } yield Table(table, columns)\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/rest/PrestoRestApi.scala",
    "content": "package quix.presto.rest\n\nimport com.fasterxml.jackson.annotation.{JsonIgnoreProperties, JsonProperty}\nimport quix.api.v1.execute.{Batch, BatchColumn, BatchError}\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoState(id: String,\n                       infoUri: String,\n                       partialCancelUri: Option[String],\n                       nextUri: Option[String],\n                       columns: Option[List[PrestoColumn]],\n                       data: Option[List[List[AnyRef]]],\n                       stats: PrestoStats,\n                       error: Option[PrestoError],\n                       updateType: Option[String])\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoColumn(@JsonProperty(\"name\") name: String,\n                        @JsonProperty(\"type\") dataType: String)\n\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoError(message: String,\n                       errorCode: Int,\n                       errorName: String,\n                       errorType: String,\n                       errorLocation: Option[PrestoErrorLocation],\n                       failureInfo: PrestoErrorFailureInfo)\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoErrorLocation(lineNumber: Int, columnNumber: Int)\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoErrorFailureInfo(`type`: String, stack: Seq[String])\n\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoStats(state: String,\n                       scheduled: Boolean,\n                       nodes: Long,\n                       totalSplits: Long,\n                       queuedSplits: Long,\n                       runningSplits: Long,\n                       completedSplits: Long,\n                       userTimeMillis: Long,\n                       cpuTimeMillis: Long,\n                       wallTimeMillis: Long,\n                       processedRows: Long,\n                       processedBytes: Long)\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoHealth(runningQueries: Int,\n                        blockedQueries: Int,\n                        queuedQueries: Int,\n                        activeWorkers: Int,\n                        runningDrivers: Int,\n                        reservedMemory: Int,\n                        rowInputRate: Int,\n                        byteInputRate: Int,\n                        cpuTimeRate: Int)\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoQueryInfo(queryId: String,\n                           state: String,\n                           queryStats: PrestoQueryStats,\n                           setCatalog: Option[String],\n                           setSchema: Option[String],\n                           setSessionProperties: Map[String, String],\n                           resetSessionProperties: List[String])\n\n@JsonIgnoreProperties(ignoreUnknown = true)\ncase class PrestoQueryStats(outputDataSize: String,\n                            processedInputDataSize: String,\n                            processedInputPositions: Long,\n                            queuedTime: String,\n                            analysisTime: String,\n                            totalPlanningTime: String,\n                            outputPositions: Long)\n\n\nobject PrestoStateToResults {\n\n  def apply(state: PrestoState): Batch = {\n    val stats = state.stats\n    val completed = {\n      val total = stats.totalSplits\n      val done = stats.completedSplits\n      if (total > 0)\n        Math.round((done.toFloat / total.toFloat) * 100)\n      else 0\n    }\n\n    val columns = state.columns.map(_.map(pc => BatchColumn(pc.name)))\n    val error = state.error.map(pe => BatchError(pe.message))\n\n    val batch = Batch(state.data.getOrElse(Nil), columns, error = error)\n      .withPercentage(completed)\n      .withStatus(state.stats.state)\n\n    state.updateType.map { queryType =>\n      batch.withType(queryType)\n    }.getOrElse(batch)\n  }\n}\n\nclass ActiveQueryNotFound(id: String) extends RuntimeException(s\"query with id $id wasn't not found\")"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/rest/PrestoStateClient.scala",
    "content": "package quix.presto.rest\n\nimport monix.eval.Task\nimport quix.api.v2.execute.SubQuery\n\ntrait PrestoStateClient {\n\n  def init(query: SubQuery): Task[PrestoState]\n\n  def advance(uri: String, query: SubQuery): Task[PrestoState]\n\n  def close(state: PrestoState, query: SubQuery): Task[Unit]\n\n  def info(state: PrestoState, query: SubQuery): Task[PrestoQueryInfo]\n\n  def health(): Task[PrestoHealth]\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/rest/ScalaJPrestoOps.scala",
    "content": "package quix.presto.rest\n\nimport java.net.URLEncoder\n\nimport quix.api.v2.execute.SubQuery\nimport quix.presto.PrestoConfig\nimport scalaj.http.{Http, HttpRequest}\n\nobject ScalaJPrestoOps {\n  def makeHeaders(query: SubQuery, config: PrestoConfig): Map[String, String] = {\n    val session = query.session.get\n\n    val extraValues = for ((key, value) <- session if !key.startsWith(config.httpHeadersPrefix))\n      yield key + \"=\" + URLEncoder.encode(value, \"UTF-8\")\n\n    val prestoHeaders = session.filter { case (key, _) => key.startsWith(config.httpHeadersPrefix) }\n\n    Map(\n      config.httpHeadersPrefix + \"User\" -> query.user.email,\n      config.httpHeadersPrefix + \"Catalog\" -> config.catalog,\n      config.httpHeadersPrefix + \"Schema\" -> config.schema,\n      config.httpHeadersPrefix + \"Source\" -> config.source,\n      \"Content-Type\" -> \"text/plain\",\n      \"Accept\" -> \"application/json\",\n      config.httpHeadersPrefix + \"Session\" -> extraValues.mkString(\", \")) ++ prestoHeaders\n  }\n\n  def buildInitRequest(query: SubQuery, config: PrestoConfig): HttpRequest = {\n    Http(config.statementsApi)\n      .headers(makeHeaders(query, config))\n      .postData(query.text.getBytes(\"UTF-8\"))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/main/scala/quix/presto/rest/ScalaJPrestoStateClient.scala",
    "content": "package quix.presto.rest\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport quix.api.v1.execute.ExceptionPropagatedToClient\nimport quix.api.v2.execute.SubQuery\nimport quix.core.utils.JsonOps.Implicits.global\nimport quix.core.utils.StringJsonHelpersSupport\nimport quix.core.utils.TaskOps._\nimport quix.presto.PrestoConfig\nimport quix.presto.rest.ScalaJPrestoOps.makeHeaders\nimport scalaj.http.{Http, HttpResponse}\n\nimport scala.concurrent.duration._\n\nclass ScalaJPrestoStateClient(config: PrestoConfig)\n  extends PrestoStateClient with StringJsonHelpersSupport with LazyLogging {\n\n  override def init(query: SubQuery): Task[PrestoState] = {\n    for {\n      _ <- Task(logger.info(s\"method=init query-id=${query.id} query-sql=[${query.text.replace(\"\\n\", \" \")}\"))\n      state <- Task\n        .eval(ScalaJPrestoOps.buildInitRequest(query, config).asString)\n        .retry(2, 1.second)\n        .logOnError(s\"event=init-presto-client-error query-id=${query.id} query-sql=[${query.text.replace(\"\\n\", \" \")}]\")\n        .flatMap(response => readPrestoState[PrestoState](response))\n    } yield state\n  }\n\n  def readPrestoState[T: Manifest](response: HttpResponse[String]): Task[T] = {\n    val responseTask = if (response.isSuccess) {\n      Task.eval(response.body.as[T])\n    } else {\n      Task.raiseError(ExceptionPropagatedToClient(s\"Request to presto failed with code=${response.code} and body=${response.body}\"))\n    }\n\n    responseTask.logOnError(s\"event=read-presto-state-error response.code=${response.code} response.body=${response.body}\")\n  }\n\n  override def advance(uri: String, query: SubQuery): Task[PrestoState] = {\n    for {\n      _ <- Task.eval(logger.info(s\"method=advance uri=$uri\"))\n\n      response <- Task\n        .eval(Http(uri).headers(makeHeaders(query, config)).asString)\n        .retry(2, 1.second)\n        .logOnError(s\"event=advance-presto-client-error uri=$uri\")\n\n      state <- readPrestoState[PrestoState](response)\n    } yield state\n  }\n\n  override def close(state: PrestoState, query: SubQuery): Task[Unit] = {\n    val infoTask = for {\n      queryInfo <- info(state, query)\n      _ <- Task.eval(logger.info(s\"method=close \" +\n        s\"event=info \" +\n        s\"state=${queryInfo.state} \" +\n        s\"presto-id=${queryInfo.queryId} \" +\n\n        s\"output-data-size=${queryInfo.queryStats.outputDataSize} \" +\n        s\"input-data-size=${queryInfo.queryStats.processedInputDataSize} \" +\n\n        s\"input-rows=${queryInfo.queryStats.processedInputPositions} \" +\n        s\"output-rows=${queryInfo.queryStats.outputPositions} \" +\n\n        s\"planning-time=${queryInfo.queryStats.totalPlanningTime} \" +\n        \"\"))\n    } yield ()\n\n    for {\n      _ <- infoTask.attempt\n      _ <- Task.eval(logger.info(s\"method=close event=start next-uri=${state.nextUri} presto-id=${state.id}\"))\n      _ <- if (state.nextUri.isDefined) Task.eval(Http(state.nextUri.get).method(\"DELETE\").asString) else Task.unit\n    } yield ()\n  }\n\n  override def info(state: PrestoState, query: SubQuery): Task[PrestoQueryInfo] = {\n    for {\n      _ <- Task.eval(logger.info(s\"method=info state=${state.stats.state} presto-id=${state.id}\"))\n\n      response <- Task.eval(Http(config.queryInfoApi + state.id).headers(makeHeaders(query, config)).asString)\n\n      queryInfo <- readPrestoState[PrestoQueryInfo](response)\n    } yield queryInfo\n  }\n\n  override def health(): Task[PrestoHealth] = {\n    for {\n      _ <- Task.eval(logger.info(s\"method=health\"))\n\n      response <- Task.eval(Http(config.healthApi).asString)\n\n      health <- readPrestoState[PrestoHealth](response)\n    } yield health\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/test/scala/quix/presto/QueryExecutorTest.scala",
    "content": "package quix.presto\n\n\nimport java.util.UUID\n\nimport monix.eval.Task\nimport monix.execution.Scheduler\nimport monix.execution.atomic.Atomic\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mock.Mockito\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{ImmutableSubQuery, MutableSession}\nimport quix.core.results.SingleBuilder\nimport quix.core.utils.JsonOps.Implicits.global\nimport quix.core.utils.StringJsonHelpersSupport\nimport quix.presto.rest.{PrestoQueryInfo, PrestoState, PrestoStateClient, PrestoStateToResults}\nimport org.mockito.ArgumentMatchers.{eq => eqTo}\nimport scala.concurrent.duration._\n\nclass QueryExecutorTest extends SpecWithJUnit with MustMatchers with Mockito with StringJsonHelpersSupport {\n\n  class ctx extends Scope {\n    val client = mock[PrestoStateClient]\n    val builder = spy(new SingleBuilder)\n    val queryId = UUID.randomUUID().toString\n    val query = ImmutableSubQuery(\"select 1\", User(\"user@quix\"), id = queryId)\n    val stateWithoutNext = {\n      s\"\"\"{\"id\":\"presto-id\",\"infoUri\":\"info-uri\",\"stats\":{\"state\":\"PLANNING\",\"scheduled\":false,\"totalSplits\":0,\"queuedSplits\":0,\"runningSplits\":0,\"completedSplits\":456}}\"\"\"\n    }.as[PrestoState]\n\n    val stateWithNextUri = {\n      \"\"\"{\"id\":\"presto-id\",\"infoUri\":\"info-uri\",\"nextUri\":\"next-uri\",\"stats\":{\"state\":\"RUNNING\",\"scheduled\":false,\"totalSplits\":0,\"queuedSplits\":0,\"runningSplits\":0,\"completedSplits\":123}}\"\"\"\n    }.as[PrestoState]\n\n    val stateWithDataRows = {\n      \"\"\"{\"id\":\"20150720_141132_01041_k74p7\",\"infoUri\":\"http://presto:8181/v1/query/20150720_141132_01041_k74p7\",\"partialCancelUri\":\"http://172.16.210.140:8181/v1/stage/20150720_141132_01041_k74p7.0\",\"nextUri\":\"http://presto:8181/v1/statement/20150720_141132_01041_k74p7/2\",\"columns\":[{\"name\":\"Catalog\",\"type\":\"varchar\",\"typeSignature\":{\"rawType\":\"varchar\",\"typeArguments\":[],\"literalArguments\":[]}}],\"data\":[[\"raptor\"],[\"system\"],[\"jmx\"],[\"apollo\"],[\"events\"],[\"sunduk\"]],\"stats\":{\"state\":\"RUNNING\",\"scheduled\":true,\"nodes\":1,\"totalSplits\":1,\"queuedSplits\":0,\"runningSplits\":0,\"completedSplits\":1,\"userTimeMillis\":0,\"cpuTimeMillis\":0,\"wallTimeMillis\":1,\"processedRows\":0,\"processedBytes\":0,\"rootStage\":{\"stageId\":\"0\",\"state\":\"RUNNING\",\"done\":false,\"nodes\":1,\"totalSplits\":1,\"queuedSplits\":0,\"runningSplits\":0,\"completedSplits\":1,\"userTimeMillis\":0,\"cpuTimeMillis\":0,\"wallTimeMillis\":1,\"processedRows\":6,\"processedBytes\":67,\"subStages\":[]}}}\"\"\"\n    }.as[PrestoState]\n\n    val prestoQueryInfoWithCatalogAndSetSession = {\n      \"\"\"{\"queryId\":\"presto-id\", \"state\":\"FINISHED\", \"setSessionProperties\" : {\"some.session.key\": \"true\"}, \"resetSessionProperties\" : [\"first.session.key\"], \"setCatalog\":\"some-catalog\", \"setSchema\":\"some-schema\", \"queryStats\" : {\"outputDataSize\":\"0B\",\"processedInputDataSize\":\"0B\", \"processedInputPositions\":0, \"queuedTime\":\"91.14us\", \"totalPlanningTime\":\"304.00ns\", \"outputPositions\":0}}\"\"\".stripMargin\n    }.as[PrestoQueryInfo]\n\n    val scheduler = Scheduler.global\n    val testDelay = 0.seconds\n    val executor = new QueryExecutor(client, testDelay)\n\n  }\n\n  \"QueryExecutor\" should {\n\n    \"notify builder on exceptions in client.init\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      client.init(query) returns Task.raiseError(exception)\n\n      // call\n      executor.initClient(query, builder).runToFuture(scheduler)\n\n      // verify\n      eventually {\n        there was one(builder).error(queryId, exception)\n      }\n    }\n\n    \"notify builder on exceptions in client.advance\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      client.advance(anyString, any()) returns Task.raiseError(exception)\n\n      // call\n      executor.advance(\"some-uri\", builder, query, testDelay).runToFuture(scheduler)\n\n      // verify\n      eventually {\n        there was one(builder).errorSubQuery(query.id, exception)\n      }\n    }\n\n    \"notify builder on success of client.init\" in new ctx {\n      // mock\n      client.init(query) returns Task.now(stateWithoutNext)\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n\n      // verify\n      eventually {\n        there was one(builder).startSubQuery(stateWithoutNext.id, query.text)\n        there was one(builder).endSubQuery(stateWithoutNext.id)\n      }\n    }\n\n    \"notify builder on success of client.init / client.advance\" in new ctx {\n      // mock\n      client.init(query) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithoutNext)\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n\n      // verify\n      eventually {\n        there was one(builder).startSubQuery(stateWithNextUri.id, query.text)\n\n        there was one(builder).addSubQuery(stateWithNextUri.id, PrestoStateToResults(stateWithoutNext))\n\n        there was one(builder).endSubQuery(stateWithNextUri.id)\n      }\n    }\n\n    \"notify builder on success of client.init / multiple client.advances\" in new ctx {\n      // mock\n      client.init(query) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithNextUri) thenReturns Task.now(stateWithoutNext)\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n      // verify\n      eventually {\n        there was one(builder).startSubQuery(stateWithNextUri.id, query.text)\n\n        there was one(builder).addSubQuery(stateWithNextUri.id, PrestoStateToResults(stateWithoutNext))\n\n        there was one(builder).endSubQuery(stateWithNextUri.id)\n      }\n    }\n\n    \"cancel execution if query.isCanceled == true\" in new ctx {\n      // mock\n      client.init(any()) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithNextUri) thenReturns Task.now(stateWithoutNext)\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n      // verify\n      eventually {\n        there was one(builder).startSubQuery(stateWithNextUri.id, query.text)\n\n        there was one(builder).addSubQuery(stateWithNextUri.id, PrestoStateToResults(stateWithoutNext))\n\n        there was one(builder).endSubQuery(anyString, any[Map[String, String]]())\n      }\n    }\n\n    \"close presto client if query.isCanceled == true\" in new ctx {\n      // mock\n      client.init(any()) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithNextUri)\n\n      // call\n      executor.execute(query.copy(canceled = Atomic(true)), builder).runToFuture(scheduler)\n\n      // verify\n      eventually {\n        there was one(client).close(eqTo(stateWithNextUri), any())\n      }\n    }\n\n    \"close presto client in case of exceptions during client.advance\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      client.init(any()) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.raiseError(exception)\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n\n      // verify\n      eventually {\n        there was one(client).close(eqTo(stateWithNextUri), any())\n      }\n    }\n\n    \"close presto client in case of exceptions during builder.startSubQuery\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      client.init(any()) returns Task.now(stateWithNextUri)\n      builder.startSubQuery(any(), any()) throws exception\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n\n      // verify\n      eventually {\n        there was one(client).close(eqTo(stateWithNextUri), any())\n      }\n    }\n\n    \"close presto client in case of exceptions during builder.addSubQuery\" in new ctx {\n      // mock\n      val exception = new RuntimeException(\"boom!\")\n      client.init(any()) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithNextUri) thenReturns Task.now(stateWithoutNext)\n      builder.addSubQuery(any(), any()) throws exception\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n\n      // verify\n      eventually {\n        there was one(client).close(eqTo(stateWithNextUri), any())\n      }\n    }\n\n    \"increase delay if last state didn't had any rows\" in new ctx {\n      val delay = 10.seconds\n      executor.nextDelay(delay, stateWithNextUri) must_=== 20.seconds\n    }\n\n    \"delay should not exceed max delay\" in new ctx {\n      val delay = 1000.seconds\n      executor.nextDelay(delay, stateWithNextUri) must_=== executor.maxAdvanceDelay\n    }\n\n    \"delay should be reset in case of rows in result\" in new ctx {\n      val delay = 10.seconds\n      executor.nextDelay(delay, stateWithDataRows) must_=== executor.initialAdvanceDelay\n    }\n\n    \"update active query with catalog/schema if query info has setCatalog / setSchema commands\" in new ctx {\n      // mock\n      client.init(query) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithoutNext)\n      client.info(any(), any()) returns Task.now(prestoQueryInfoWithCatalogAndSetSession)\n      client.close(any(), any()) returns Task.unit\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n      eventually {\n        query.session.get must havePair(\"X-Presto-Catalog\", \"some-catalog\")\n        query.session.get must havePair(\"X-Presto-Schema\", \"some-schema\")\n      }\n    }\n\n    \"update active query with session params if query info has setSessionProperties\" in new ctx {\n      // mock\n      client.init(query) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithoutNext)\n      client.info(any(), any()) returns Task.now(prestoQueryInfoWithCatalogAndSetSession)\n      client.close(any(), any()) returns Task.unit\n\n      // call\n      executor.execute(query, builder).runToFuture(scheduler)\n\n      eventually {\n        query.session.get must havePair(\"some.session.key\", \"true\")\n      }\n    }\n\n    \"unset session properties of active if query info has resetSessionProperties\" in new ctx {\n      // mock\n      val queryWithSession = query.copy(session = MutableSession(\"first.session.key\" -> \"false\", \"second.session.key\" -> \"true\"))\n      client.init(queryWithSession) returns Task.now(stateWithNextUri)\n      client.advance(anyString, any()) returns Task.now(stateWithoutNext)\n      client.info(any(), any()) returns Task.now(prestoQueryInfoWithCatalogAndSetSession)\n      client.close(any(), any()) returns Task.unit\n\n      // call\n      executor.execute(queryWithSession, builder).runToFuture(scheduler)\n\n      eventually {\n        // existed before execution\n        queryWithSession.session.get must havePair(\"second.session.key\", \"true\")\n\n        // was added during execution\n        queryWithSession.session.get must havePair(\"some.session.key\", \"true\")\n\n        // was removed during execution\n        queryWithSession.session.get must not haveKey \"first.session.key\"\n      }\n    }\n  }\n}\n\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/test/scala/quix/presto/db/PrestoAutocompleteTest.scala",
    "content": "package quix.presto.db\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.presto.TestQueryExecutor\n\nclass PrestoAutocompleteTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    val executor = new TestQueryExecutor\n\n    val catalogs = new PrestoCatalogs(executor)\n    val autocomplete = new PrestoAutocomplete(catalogs, executor)\n\n    def fastAutocomplete = autocomplete.fast.runSyncUnsafe()\n\n    def fullAutocomplete = autocomplete.full.runSyncUnsafe()\n  }\n\n  \"PrestoAutocomplete.fast\" should {\n\n    \"use catalogs.fast as a baseline for calculating of autocomplete.fast items \" in new ctx {\n      executor\n        .withResults(List(List(\"catalog\")))\n        .withResults(List(List(\"column\")))\n\n      val items = fastAutocomplete\n\n      items must havePair(\"catalogs\" -> List(\"catalog\"))\n      items must havePair(\"columns\" -> List(\"column\"))\n    }\n  }\n\n  \"PrestoAutocomplete.full\" should {\n\n    \"use catalogs.full as a baseline for calculating of autocomplete.full items \" in new ctx {\n      executor\n        .withResults(List(List(\"catalog\")))\n        .withResults(List(List(\"catalog\", \"schema\", \"table\")))\n        .withResults(List(List(\"column\")))\n\n      val items = fullAutocomplete\n\n      items must havePair(\"catalogs\" -> List(\"catalog\"))\n      items must havePair(\"schemas\" -> List(\"schema\"))\n      items must havePair(\"tables\" -> List(\"table\"))\n      items must havePair(\"columns\" -> List(\"column\"))\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/test/scala/quix/presto/db/PrestoCatalogsTest.scala",
    "content": "package quix.presto.db\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.db.{Catalog, Schema, Table}\nimport quix.presto.TestQueryExecutor\n\nclass PrestoCatalogsTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    val executor = new TestQueryExecutor\n\n    val catalogs = new PrestoCatalogs(executor, Set(\"hidden-catalog\"))\n\n    def fastCatalogs = {\n      catalogs.fast.runSyncUnsafe()\n    }\n\n    def fullCatalogs = {\n      catalogs.full.runSyncUnsafe()\n    }\n  }\n\n  \"PrestoCatalogs.fast\" should {\n    \"return only catalog names\" in new ctx {\n      executor.withResults(List(List(\"test-catalog\")))\n\n      fastCatalogs must contain(Catalog(\"test-catalog\", Nil))\n    }\n\n    \"fallback to empty list if presto is down\" in new ctx {\n      executor\n        .withExceptions(new Exception(\"boom!\"), 100)\n\n      fastCatalogs must beEmpty\n    }\n\n    \"skip hidden catalogs\" in new ctx {\n      executor.withResults(List(List(\"test-catalog\"), List(\"hidden-catalog\")))\n\n      fastCatalogs must contain(Catalog(\"test-catalog\", Nil))\n      fastCatalogs must not contain (Catalog(\"hidden-catalog\", Nil))\n    }\n  }\n\n  \"PrestoCatalogs.full\" should {\n    \"return full catalogs tree if presto is live\" in new ctx {\n      executor\n        .withResults(List(List(\"test-catalog\")))\n        .withResults(List(List(\"test-catalog\", \"test-schema\", \"test-table\")))\n\n      fullCatalogs must contain(Catalog(\"test-catalog\", List(Schema(\"test-schema\", List(Table(\"test-table\", List.empty))))))\n    }\n\n    \"fallback to empty list if presto is down\" in new ctx {\n      executor.withExceptions(new Exception(\"boom!\"), 100)\n\n      fullCatalogs must beEmpty\n    }\n\n    \"skip hidden catalogs\" in new ctx {\n      executor\n        .withResults(List(List(\"test-catalog\"), List(\"hidden-catalog\")))\n        .withResults(List(List(\"test-catalog\", \"test-schema\", \"test-table\")))\n\n      fullCatalogs must contain(Catalog(\"test-catalog\", List(Schema(\"test-schema\", List(Table(\"test-table\", List.empty))))))\n      fullCatalogs must not contain(Catalog(\"hidden-catalog\", Nil))\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/test/scala/quix/presto/db/PrestoTablesTest.scala",
    "content": "package quix.presto.db\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.db.Kolumn\nimport quix.presto.TestQueryExecutor\n\nclass PrestoTablesTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    val executor = new TestQueryExecutor\n\n    val tables = new PrestoTables(executor, 1000)\n  }\n\n  \"PrestoTables\" should {\n    \"return table and columns\" in new ctx {\n      executor.withResults(List(List(\"uuid\", \"varchar\")))\n\n      val table = tables.get(\"sunduk\", \"tbl\", \"reg_users\").runSyncUnsafe()\n\n      table.name must_=== \"reg_users\"\n      table.children must contain(Kolumn(\"uuid\", \"varchar\"))\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/test/scala/quix/presto/rest/ScalaJPrestoOpsTest.scala",
    "content": "package quix.presto.rest\n\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{ImmutableSubQuery, MutableSession}\nimport quix.presto.PrestoConfig\n\nimport scala.collection.mutable\n\nclass ScalaJPrestoOpsTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    var factory = ScalaJPrestoOps\n    val query = ImmutableSubQuery(\"select 1\", User(\"user@quix\"))\n    val config = PrestoConfig(\"statements\", \"health\", \"queryInfo\", \"default-schema\", \"default-catalog\", \"default-source\", \"X-Presto-\")\n  }\n\n  \"ScalaJPrestoOps.buildPrestoRequest\" should {\n    \"construct the correct POST request for presto\" in new ctx {\n      val request = factory.buildInitRequest(query, config)\n\n      request.method must_=== \"POST\"\n      request.headers must contain(\"X-Presto-User\" -> query.user.email)\n    }\n\n    // https://github.com/prestodb/presto/wiki/HTTP-Protocol\n    \"add custom query session params as single comma-separated x-presto-session http header\" in new ctx {\n      val queryWithSession = query.copy(session = MutableSession(\"foo\" -> \"1\", \"bar\" -> \"2\"))\n      val request = factory.buildInitRequest(queryWithSession, config)\n\n      request.method must_=== \"POST\"\n      request.headers must contain(\"X-Presto-Session\" -> \"foo=1, bar=2\")\n    }\n\n    \"use catalog/schema from active query\" in new ctx {\n      val queryWithCatalogs = query.copy(session = MutableSession(\"X-Presto-Catalog\" -> \"catalog\", \"X-Presto-Schema\" -> \"schema\"))\n      val request = factory.buildInitRequest(queryWithCatalogs, config)\n\n      request.headers must contain(\"X-Presto-Catalog\" -> \"catalog\")\n      request.headers must contain(\"X-Presto-Schema\" -> \"schema\")\n    }\n\n    \"fallback to default catalog/schema values from config if missing in active query\" in new ctx {\n      val request = factory.buildInitRequest(query, config)\n\n      request.headers must contain(\"X-Presto-Catalog\" -> \"default-catalog\")\n      request.headers must contain(\"X-Presto-Schema\" -> \"default-schema\")\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-presto-module/src/test/scala/quix/presto/rest/ScalaJPrestoStateClientTest.scala",
    "content": "package quix.presto.rest\n\n\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.traced\nimport org.specs2.matcher.{MustMatchers, Scope}\nimport org.specs2.mutable.SpecWithJUnit\nimport quix.api.v1.execute.ExceptionPropagatedToClient\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.utils.JsonOps.Implicits.global\nimport quix.core.utils.StringJsonHelpersSupport\nimport quix.presto.PrestoConfig\nimport scalaj.http.HttpResponse\n\nclass ScalaJPrestoStateClientTest extends SpecWithJUnit with MustMatchers with StringJsonHelpersSupport {\n\n  class ctx extends Scope {\n    val config = PrestoConfig(\"statements\", \"health\", \"queryInfo\", \"default-schema\", \"default-catalog\", \"default-source\", \"X-Presto-\")\n    val client = new ScalaJPrestoStateClient(config)\n    val query = ImmutableSubQuery(\"select 1\", User(\"user@quix\"))\n    val advanceUri = \"localhost/1\"\n\n    val stateJson = s\"\"\"{\"id\":\"presto-id\",\"infoUri\":\"info-uri\",\"nextUri\":\"next-uri\",\"stats\":{\"state\":\"RUNNING\",\"scheduled\":false,\"totalSplits\":0,\"queuedSplits\":0,\"runningSplits\":0,\"completedSplits\":123}}\"\"\"\n\n    val state = stateJson.as[PrestoState]\n  }\n\n  \"ScalaJPrestoStateClient\" should {\n    \"pass sanity\" in new ctx {\n      client.init(query) must beAnInstanceOf[Task[PrestoState]]\n      client.advance(advanceUri, query) must beAnInstanceOf[Task[PrestoState]]\n      client.close(state, query) must beAnInstanceOf[Task[PrestoState]]\n    }\n\n    \"handle 200 responses and convert them into valid presto state objects\" in new ctx {\n      val goodResponse = HttpResponse(stateJson, 200, Map(\"Status\" -> IndexedSeq(\"bla\")))\n\n      client.readPrestoState[PrestoState](goodResponse)\n        .runSyncUnsafe() must_=== state\n    }\n\n    \"handle not 200 responses and fail them\" in new ctx {\n      val response = HttpResponse[String](\"bad response\", 500, Map.empty)\n\n      client.readPrestoState[PrestoState](response)\n        .runSyncUnsafe() must throwAn[ExceptionPropagatedToClient]\n    }\n  }\n\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/resources/activator.py",
    "content": "\"\"\"\ntaken from https://raw.githubusercontent.com/pypa/virtualenv/master/virtualenv_embedded/activate_this.py\n\nActivate virtualenv for current interpreter:\n\nUse exec(open(this_file).read(), {'__file__': this_file}).\n\nThis can be used when you must use an existing Python interpreter, not the virtualenv bin/python.\n\"\"\"\nimport os\nimport site\nimport sys\n\ntry:\n    __file__\nexcept NameError:\n    raise AssertionError(\"You must use exec(open(this_file).read(), {'__file__': this_file}))\")\n\n# prepend bin to PATH (this file is inside the bin directory)\nbin_dir = os.path.dirname(os.path.abspath(__file__))\nos.environ[\"PATH\"] = os.pathsep.join([bin_dir] + os.environ.get(\"PATH\", \"\").split(os.pathsep))\n\nbase = os.path.dirname(bin_dir)\n\n# virtual env is right above bin directory\nos.environ[\"VIRTUAL_ENV\"] = base\n\n# add the virtual environments site-package to the host python import mechanism\nIS_PYPY = hasattr(sys, \"pypy_version_info\")\nIS_JYTHON = sys.platform.startswith(\"java\")\nif IS_JYTHON:\n    site_packages = os.path.join(base, \"Lib\", \"site-packages\")\nelif IS_PYPY:\n    site_packages = os.path.join(base, \"site-packages\")\nelse:\n    IS_WIN = sys.platform == \"win32\"\n    if IS_WIN:\n        site_packages = os.path.join(base, \"Lib\", \"site-packages\")\n    else:\n        site_packages = os.path.join(base, \"lib\", \"python{}.{}\".format(*sys.version_info), \"site-packages\")\n\nprev = set(sys.path)\nsite.addsitedir(site_packages)\nsys.real_prefix = sys.prefix\nsys.prefix = base\n\n# Move the added items to the front of the path, in place\nnew = list(sys.path)\nsys.path[:] = [i for i in new if i not in prev] + [i for i in new if i in prev]\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/resources/packages.py",
    "content": "class Packages:\n\n    def __init__(self, dir, index_url, extra_url):\n        self.dir = dir\n        self.index_url = index_url\n        self.extra_url = extra_url\n\n    def __get_installed_packages(self):\n        try:\n            with open(self.dir + '/packages') as f:\n                return f.read().split(' ')\n        except IOError:\n            return []\n\n    def __create_environment(self):\n        import os.path\n        ready_env = os.path.isfile(self.dir + '/env')\n\n        if not ready_env:\n            import venv\n            # inherit system site packages for fast installation times\n            # in `init` function pip will be used with '--upgrade' option to allow using different versions\n            venv.create(self.dir, system_site_packages=True)\n\n            open(self.dir + '/env', 'a').close()\n\n    def __clean(self, packages):\n        for package in packages:\n            index = len(package)\n\n            if '==' in package:\n                index = package.find('==')\n            elif '>' in package and '<' in package:\n                greater = package.find('>')\n                less = package.find('<')\n                index = min(greater, less)\n            elif '>' in package:\n                index = package.find('>')\n            elif '<' in package:\n                index = package.find('<')\n            yield package[0: index]\n\n    def list(self):\n        import subprocess\n        from quix import Quix\n        quix = Quix()\n\n        process = subprocess.Popen(self.dir + '/bin/python3 -m pip list --format=freeze', shell=True, stdout=subprocess.PIPE)\n        stdout = process.communicate()[0]\n\n        reqs = sorted(stdout.decode('utf-8').strip().split('\\n'))\n        splitted = [req.split('==') for req in reqs]\n\n        quix.fields('package', 'version')\n        for (package, version) in splitted:\n            quix.row(package, version)\n\n    def install(self, *required_packages):\n        installed_packages = self.__get_installed_packages()\n        self.__create_environment()\n\n        if not set(required_packages).issubset(installed_packages):\n            exec (open(self.dir + '/bin/activator.py').read(), {'__file__': self.dir + '/bin/activator.py'})\n\n            index_url_args = []\n            extra_index_url_args = []\n\n            if self.index_url:\n                index_url_args = ['--index-url', self.index_url]\n            if self.extra_url:\n                extra_index_url_args = ['--extra-index-url', self.extra_url]\n\n            pipargs = ['install'] + list(required_packages) + ['--prefix', self.dir, '--ignore-installed',\n                                                               '--no-warn-script-location',\n                                                               '--disable-pip-version-check',\n                                                               '--no-warn-conflicts'] + index_url_args + extra_index_url_args\n\n            import subprocess\n            import sys\n            subprocess.check_call([sys.executable, '-m', 'pip'] + pipargs)\n\n            packages_file = open(self.dir + '/packages', 'w+')\n            packages = self.__clean(required_packages)\n            packages_file.write(' '.join(list(packages) + installed_packages))\n            packages_file.close()\n        else:\n            exec (open(self.dir + '/bin/activator.py').read(), {'__file__': self.dir + '/bin/activator.py'})\n\n    def uninstall(self, *packages):\n        self.__create_environment()\n        installed_packages = self.__get_installed_packages()\n\n        if set(packages).issubset(installed_packages):\n            import subprocess\n            import sys\n\n            process = subprocess.Popen(self.dir + '/bin/python3 -m pip uninstall --yes ' + ' '.join(list(packages)),\n                                       shell=True)\n            process.wait()\n\n            packages_file = open(self.dir + '/packages', 'w+')\n\n            for package in packages:\n                installed_packages.remove(package)\n            packages_file.write(' '.join(installed_packages))\n            packages_file.close()\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/resources/quix.py",
    "content": "class Quix:\n\n    def __init__(self):\n        import sys\n        from py4j.java_gateway import JavaGateway\n        from py4j.java_gateway import GatewayParameters\n        self.gateway = JavaGateway(gateway_parameters=GatewayParameters(auto_convert=True, port=int(sys.argv[1])))\n        self.bridge = self.gateway.entry_point\n        self.query_id = sys.argv[2]\n        self.user = sys.argv[3]\n\n    def fields(self, *fields):\n        self.bridge.tab_columns(self.query_id, list(fields))\n\n    def row(self, *row):\n        self.bridge.tab_row(self.query_id, list(row))\n\n    def error(self, message):\n        self.bridge.error(message)\n\n    def info(self, message):\n        self.bridge.info(message)\n\n    def tab(self, name):\n        return Tab(self.bridge, name)\n\n\nclass Tab:\n    def __init__(self, bridge, name):\n        self.bridge = bridge\n        self.name = name\n\n    def columns(self, *columns):\n        self.bridge.tab_columns(self.name, list(columns))\n\n    def row(self, *row):\n        self.bridge.tab_row(self.name, list(row))\n\n    def end(self):\n        self.bridge.tab_end(self.name)\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonApi.scala",
    "content": "package quix.python\n\nsealed trait PythonMessage\n\ncase class ProcessStartSuccess(jobId: String) extends PythonMessage\n\ncase class ProcessStartFailure(t: Throwable) extends PythonMessage\n\ncase class ProcessEndSuccess(jobId: String) extends PythonMessage\n\ncase class TabFields(tabId: String, fields: Seq[String]) extends PythonMessage\n\ncase class TabRow(tabId: String, row: Seq[Any]) extends PythonMessage\n\ncase class TabEnd(tabId: String) extends PythonMessage\n\ncase class ProcessStdout(jobId: String, line: String) extends PythonMessage\n\ncase class ProcessStderr(jobId: String, line: String) extends PythonMessage\n\ncase class Line(str: String, isPartial: Boolean = false)\n\ncase class PythonCode(code: String, modules: Seq[String] = Nil)"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonBridge.scala",
    "content": "package quix.python\n\nimport monix.reactive.observers.Subscriber\n\n/** Python Bridge is py4j bridge to connect between methods defined in quix.py and Quix execution model\n *\n * @param queryId the queryId that started the execution, it will be used to generate events in context of singe query\n */\nclass PythonBridge(val queryId: String) {\n\n  import scala.collection.JavaConverters._\n\n  var subscriberOpt: Option[Subscriber[PythonMessage]] = None\n\n  /** Python bridge will produce a stream of [[PythonMessage]] messages to communicate with quix.\n   * Each message would trigger some update of [[quix.api.v1.execute.Builder]]\n   *\n   * @param subscriber monix Subscriber that will receive every update from python\n   */\n  def register(subscriber: Subscriber[PythonMessage]): Unit = {\n    subscriberOpt = Option(subscriber)\n  }\n\n  def error(message: String): Unit = {\n    for (subscriber <- subscriberOpt) {\n      subscriber.onNext(ProcessStderr(queryId, message))\n    }\n  }\n\n  def info(message: String): Unit = {\n    for (subscriber <- subscriberOpt) {\n      subscriber.onNext(ProcessStdout(queryId, message))\n    }\n  }\n\n  def tab_columns(tabId: String, columns: java.util.ArrayList[Any]): Unit = {\n    for (subscriber <- subscriberOpt)\n      subscriber.onNext(TabFields(tabId, stringify(columns)))\n  }\n\n  def tab_row(tabId: String, row: java.util.ArrayList[Any]): Unit = {\n    for (subscriber <- subscriberOpt)\n      subscriber.onNext(TabRow(tabId, stringify(row)))\n  }\n\n  def tab_end(tabId: String): Unit = {\n    for (subscriber <- subscriberOpt)\n      subscriber.onNext(TabEnd(tabId))\n  }\n\n  def nullToEmpty(javaList: java.util.ArrayList[Any]): List[Any] = {\n    Option(javaList).map(_.asScala.toList).getOrElse(Nil)\n  }\n\n  def stringify(javaList: java.util.ArrayList[Any]): List[String] = {\n    nullToEmpty(javaList).map(v => String.valueOf(v))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonConfig.scala",
    "content": "package quix.python\n\n\n/** Python configuration populated via .env or applications.properties of spring\n *\n * @param indexUrl       will be used by pip to search for packages, use your hosted repository for internal packages\n * @param extraIndexUrl  will be used by pip as fallback for indexUrl\n * @param packages       list of packages that should be installed for every user\n * @param userScriptsDir directory that will be used to store user's scripts and virtualenv environments\n * @param additionalCode any additional code that will be prepended to every python script\n */\ncase class PythonConfig(indexUrl: String = \"https://pypi.org/simple\",\n                        extraIndexUrl: String = \"\",\n                        packages: Seq[String] = Nil,\n                        userScriptsDir: String = \"/tmp/quix-python\",\n                        additionalCode: String = \"\")\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonExecutor.scala",
    "content": "package quix.python\n\nimport java.nio.file.{Files, Path, Paths}\n\nimport com.google.common.io.Resources\nimport com.typesafe.scalalogging.LazyLogging\nimport com.zaxxer.nuprocess.NuProcessBuilder\nimport monix.eval.Task\nimport monix.execution.atomic.AtomicInt\nimport monix.reactive.{Observable, OverflowStrategy}\nimport py4j.GatewayServer\nimport quix.api.v1.execute._\nimport quix.api.v2.execute.{Builder, Executor, SubQuery}\n\nclass PythonExecutor(config: PythonConfig = PythonConfig()) extends Executor with LazyLogging {\n\n  var port = AtomicInt(25333)\n\n  def copy(dir: Path, filename: String): Task[Unit] = {\n    for {\n      bytes <- Task(Resources.toByteArray(Resources.getResource(filename)))\n      _ <- Task(Files.write(Paths.get(dir.toString, filename), bytes))\n    } yield ()\n  }\n\n  def execute(query: SubQuery, builder: Builder): Task[Unit] = {\n    makeProcess(query)\n      .bracket(process => run(process, query, builder))(_.close)\n  }\n\n  def makeProcess(query: SubQuery): Task[PythonRunningProcess] = {\n    val process = PythonRunningProcess(query.id)\n\n    for {\n      _ <- prepareFiles(process, query)\n      _ <- prepareGateway(process, query)\n    } yield process\n  }\n\n  def prepareFiles(process: PythonRunningProcess, query: SubQuery): Task[Path] = {\n    val user = query.user.email\n    val dir = Paths.get(config.userScriptsDir, user)\n    val bin = Paths.get(dir.toString, \"bin\")\n    val script = generateUserScript(dir, query).getBytes(\"UTF-8\")\n\n    for {\n      _ <- Task(if (Files.notExists(dir)) Files.createDirectories(dir))\n      _ <- Task(if (Files.notExists(bin)) Files.createDirectories(bin))\n\n      file <- Task(Files.createTempFile(dir, \"script-\", \".py\"))\n\n      _ <- Task(Files.write(file, script))\n\n      _ <- copy(dir, \"quix.py\")\n      _ <- copy(dir, \"packages.py\")\n      _ <- copy(bin, \"activator.py\")\n\n      _ <- Task(process.file = Some(file))\n    } yield file\n  }\n\n  private def generateUserScript(dir: Path, query: SubQuery) = {\n    val envSetup =\n      s\"\"\"\n         |from packages import Packages\n         |packages = Packages('$dir', '${config.indexUrl}', '${config.extraIndexUrl}')\n         |packages.install(${config.packages.map(lib => '\\'' + lib + '\\'').mkString(\", \")})\n         |\n         |\"\"\".stripMargin\n\n    val quixSetup =\n      s\"\"\"\n         |try:\n         |  from py4j.java_gateway import JavaGateway\n         |except ImportError:\n         |  import sys\n         |  print(\"mandatory py4j package is missing, installing\", file = sys.stderr)\n         |  packages.install('py4j')\n         |\n         |from quix import Quix\n         |\n         |quix = Quix()\n         |\n         |\"\"\".stripMargin\n\n    def get_current_user =\n      s\"\"\"\n         |def _get_user():\n         |    user = '${query.user.email}'\n         |    if (user):\n         |        return user\n         |    else:\n         |        return 'quix-python-executor'\n         |\n         |\"\"\".stripMargin\n\n    envSetup + quixSetup + get_current_user +  config.additionalCode + query.text\n  }\n\n  def prepareGateway(process: PythonRunningProcess, query: SubQuery): Task[GatewayServer] = {\n    for {\n      bridge <- Task(new PythonBridge(query.id))\n      _ <- Task(process.bridge = Some(bridge))\n\n      gatewayServer <- Task(new GatewayServer(bridge, port.incrementAndGet()))\n      _ <- Task(process.gatewayServer = Some(gatewayServer))\n    } yield gatewayServer\n  }\n\n  def run(process: PythonRunningProcess, query: SubQuery, builder: Builder): Task[Unit] = {\n\n    val pythonProcessMessages: Observable[PythonMessage] = Observable.create(OverflowStrategy.Unbounded) { sub =>\n      val task = for {\n        pb <- Task(new NuProcessBuilder(\"python3\", \"-W\", \"ignore\",\n          process.file.getOrElse(throw new IllegalStateException(\"No file to execute\")).toString,\n          process.gatewayServer.getOrElse(throw new IllegalStateException(\"No running gateway\")).getPort.toString,\n          query.id,\n          query.user.email\n        ))\n\n        handler <- Task(new PythonProcessHandler(query.id, sub))\n        _ <- Task(pb.setProcessListener(handler))\n        _ <- Task(process.gatewayServer.foreach(_.start()))\n        _ <- Task(process.process = Some(pb.start()))\n      } yield ()\n\n      task.runToFuture(sub.scheduler)\n    }\n\n    val quixInteropMessages: Observable[PythonMessage] = Observable.create(OverflowStrategy.Unbounded) { sub =>\n      Task(process.bridge.foreach(_.register(sub))).runToFuture(sub.scheduler)\n    }\n\n    Observable(quixInteropMessages, pythonProcessMessages).merge\n      .takeWhileInclusive {\n        case ProcessEndSuccess(_) =>\n          false\n\n        case _ if query.canceled.get => false\n\n        case _ => true\n      }\n      .mapEval {\n        case ProcessStartFailure(exception) =>\n          builder.error(query.id, exception)\n\n        case ProcessStdout(jobId, line) =>\n          builder.log(jobId, line, \"INFO\")\n\n        case ProcessStderr(jobId, line) =>\n          builder.log(jobId, line, \"ERROR\")\n\n        case TabFields(tabId, fields) =>\n          for {\n            _ <- builder.startSubQuery(tabId, query.text)\n            _ <- builder.addSubQuery(tabId, Batch(columns = Option(fields.map(BatchColumn))))\n          } yield ()\n\n        case TabRow(tabId, row) =>\n          builder.addSubQuery(tabId, Batch(Seq(row)))\n\n        case TabEnd(tabId) =>\n          builder.endSubQuery(tabId, Map.empty)\n        case event =>\n          Task(logger.info(s\"method=run event=unknown-event query-id=${query.id} user=${query.user.email} event=$event\"))\n      }.lastL\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonModule.scala",
    "content": "package quix.python\n\nimport monix.eval.Task\nimport quix.api.v1.db.Db\nimport quix.api.v1.execute.StartCommand\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{Builder, ExecutionModule, ImmutableSubQuery, Query}\n\nimport scala.collection.mutable\n\nclass PythonModule(val executor: PythonExecutor) extends ExecutionModule {\n\n  def start(command: StartCommand[String], id: String, user: User, builder: Builder): Task[Unit] = {\n    val subQuery = ImmutableSubQuery(command.code, user)\n    val query = Query(List(subQuery), canceled = subQuery.canceled)\n\n    for {\n      _ <- builder.start(query)\n      _ <- executor.execute(subQuery, builder)\n      _ <- builder.end(query)\n    } yield ()\n  }\n\n  override def db: Option[Db] = None\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonProcessHandler.scala",
    "content": "package quix.python\n\nimport java.nio.ByteBuffer\n\nimport com.google.common.base.Charsets\nimport com.typesafe.scalalogging.LazyLogging\nimport com.zaxxer.nuprocess.{NuAbstractProcessHandler, NuProcess}\nimport monix.reactive.observers.Subscriber\n\nclass PythonProcessHandler(queryId: String, subscriber: Subscriber[PythonMessage])\n  extends NuAbstractProcessHandler with LazyLogging {\n\n  import ByteBufferUtils._\n  var pid = 0L\n\n  override def onStart(nuProcess: NuProcess): Unit = {\n    pid = nuProcess.getPID\n    logger.info(s\"method=onStart query-id=$queryId pid=$pid\")\n    subscriber.onNext(ProcessStartSuccess(queryId))\n  }\n\n  override def onExit(statusCode: Int): Unit = {\n    logger.info(s\"method=onExit query-id=$queryId pid=$pid\")\n    subscriber.onNext(ProcessEndSuccess(queryId))\n  }\n\n  override def onStdout(buffer: ByteBuffer, closed: Boolean): Unit = {\n    if (!closed) {\n      for (line <- buffer.asLines()) {\n        logger.info(s\"method=onStdout query-id=$queryId pid=$pid line=${line.str}\")\n        subscriber.onNext(ProcessStdout(queryId, line.str))\n      }\n    }\n  }\n\n  override def onStderr(buffer: ByteBuffer, closed: Boolean): Unit = {\n    if (!closed) {\n      for (line <- buffer.asLines()) {\n        logger.info(s\"method=onStdErr pid=$pid line=${line.str}\")\n        subscriber.onNext(ProcessStderr(queryId, line.str))\n      }\n    }\n  }\n}\n\nobject ByteBufferUtils {\n\n  implicit class ExtractLinesFromByteBuffer(val buf: ByteBuffer) extends AnyVal {\n    def asLines(): Seq[Line] = {\n      val arr = new Array[Byte](buf.limit())\n      buf.get(arr)\n      val str = new String(arr, Charsets.UTF_8)\n\n      val lines = str\n        .split('\\n')\n        .filter(_.trim.nonEmpty)\n\n      lines match {\n        case Array(single) if str.endsWith(\"\\n\") =>\n          Array(Line(single))\n\n        case Array(single) =>\n          Array(Line(single, isPartial = true))\n\n        case many if many.nonEmpty =>\n          many.init.map(Line(_)) :+ Line(many.last, isPartial = true)\n\n        case _ =>\n          Seq.empty\n      }\n    }\n  }\n\n}"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/PythonRunningProcess.scala",
    "content": "package quix.python\n\nimport java.nio.file.{Files, Path, Paths}\n\nimport com.typesafe.scalalogging.LazyLogging\nimport com.zaxxer.nuprocess.NuProcess\nimport monix.eval.Task\nimport py4j.GatewayServer\nimport quix.core.utils.TaskOps._\n\n/** Python Bridge is py4j bridge to connect between methods defined in quix.py and Quix execution model\n *\n * @param queryId       the queryId that started the execution\n * @param gatewayServer py4j instance for communication between python note and quix\n * @param bridge        py4j bridge that maps functions exposed in python to quix implementations\n * @param process       nuprocess instance that executes the python process\n * @param file          python code that contains all init quix code and actual python note content\n */\ncase class PythonRunningProcess(queryId: String, var gatewayServer: Option[GatewayServer] = None,\n                                var bridge: Option[PythonBridge] = None,\n                                var process: Option[NuProcess] = None,\n                                var file: Option[Path] = None) extends LazyLogging {\n\n  /**\n   * Close all open resources and delete all temporary files\n   *\n   * @return\n   */\n  def close: Task[Unit] = {\n    val task = for {\n      _ <- Task(logger.info(s\"method=close event=cleanup-start query-id=$queryId\"))\n\n      _ <- Task(gatewayServer.map(_.shutdown())).attempt\n        .flatMap(_ => Task(this.gatewayServer = None))\n\n      _ <- Task(process.map(_.destroy(true))).attempt\n        .flatMap(_ => Task(this.process = None))\n\n      _ <- Task(file.map(f => Files.deleteIfExists(Paths.get(f.getParent.toString, \"quix.py\")))).attempt\n\n      _ <- Task(file.map(Files.deleteIfExists)).attempt\n\n      _ <- Task(file.map(_.getParent).map(Files.deleteIfExists)).attempt\n        .flatMap(_ => Task(this.file = None))\n      _ <- Task(logger.info(s\"method=close event=cleanup-done query-id=$queryId\"))\n    } yield ()\n\n    task.logOnError(s\"method=close event-cleanup-failure query-id=$queryId\")\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/main/scala/quix/python/TryPython.scala",
    "content": "package quix.python\n\nimport java.util.UUID\n\nimport quix.api.v1.execute.ActiveQuery\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.{Query, ImmutableSubQuery}\nimport quix.core.results.SingleBuilder\n\nobject TryPython {\n\n  import monix.execution.Scheduler.Implicits.global\n\n  def main(args: Array[String]): Unit = {\n    val executor = new PythonExecutor()\n    val query = ImmutableSubQuery(importQuix, User(\"default\"))\n    val builder = new SingleBuilder\n    val task = executor.execute(query, builder)\n\n    task.runSyncUnsafe()\n\n    for (row <- builder.build())\n      println(row)\n\n    for (log <- builder.logs)\n      println(log)\n  }\n\n  def samplePyBridge = {\n    \"\"\"\n      |from py4j.java_gateway import JavaGateway\n      |from py4j.java_gateway import GatewayParameters\n      |gateway = JavaGateway(gateway_parameters=GatewayParameters(auto_convert=True))\n      |bridge = gateway.entry_point\n      |bridge.fields([\"abc\", \"def\"])\n      |bridge.row([\"abc\", 123])\n      |\"\"\".stripMargin\n  }\n\n  def pyBridgeClass = {\n    \"\"\"\n      |class Bridge:\n      |\n      |    def __init__(self):\n      |        import sys\n      |        from py4j.java_gateway import JavaGateway\n      |        from py4j.java_gateway import GatewayParameters\n      |        self.gateway = JavaGateway(gateway_parameters=GatewayParameters(auto_convert=True, port=int(sys.argv[1])))\n      |        self.bridge = self.gateway.entry_point\n      |\n      |    def fields(self, fields):\n      |        self.bridge.fields(fields)\n      |\n      |    def row(self, row):\n      |        self.bridge.row(row)\n      |\n      |\n      |quix = Bridge()\n      |\n      |quix.fields(['abc', 'def'])\n      |quix.row([123, 456])\n      |\n      |\"\"\".stripMargin\n  }\n\n  def importQuix = {\n    \"\"\"\n      |from quix import Quix\n      |\n      |quix = Quix()\n      |\n      |quix.fields(['abc', 'def'])\n      |quix.row([123, 456])\n      |\n      |quix.error('error!!!!')\n      |quix.info('message bla bla bla')\n      |\n      |\"\"\".stripMargin\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/test/scala/quix/python/PythonBridgeTest.scala",
    "content": "package quix.python\n\nimport java.util\n\nimport com.google.common.collect.Lists\nimport org.specs2.matcher.MustMatchers\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\n\nclass PythonBridgeTest extends SpecWithJUnit with MustMatchers {\n\n  class ctx extends Scope {\n    val bridge = new PythonBridge(\"query-id\")\n  }\n\n  \"transform java list to scala list in nullToEmpty\" in new ctx {\n    val javaList: util.ArrayList[Any] = Lists.newArrayList(\"abc\", null, \"def\")\n    val scalaList: List[Any] = List(\"abc\", null, \"def\")\n\n    bridge.nullToEmpty(javaList) must_=== scalaList\n  }\n\n  \"handle null lists in nullToEmpty\" in new ctx {\n    val javaList: util.ArrayList[Any] = null\n    val scalaList: List[Any] = List()\n\n    bridge.nullToEmpty(javaList) must_=== scalaList\n  }\n\n  \"handle null values in stringify\" in new ctx {\n    val javaList: util.ArrayList[Any] = Lists.newArrayList(\"abc\", null, \"def\")\n    val scalaList: List[String] = List(\"abc\", \"null\", \"def\")\n\n    bridge.stringify(javaList) must_=== scalaList\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-modules/quix-python-module/src/test/scala/quix/python/PythonExecutorTest.scala",
    "content": "package quix.python\n\nimport java.util.UUID\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.specs2.matcher.{Matcher, MustMatchers}\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport quix.api.v1.users.User\nimport quix.api.v2.execute.ImmutableSubQuery\nimport quix.core.results.{QueryStarted, SingleBuilder}\n\nclass PythonExecutorTest extends SpecWithJUnit with MustMatchers {\n  sequential\n\n  class ctx extends Scope {\n    val executor = new PythonExecutor\n    lazy val user = User(\"user-\" + UUID.randomUUID().getLeastSignificantBits + \"@quix.com\", \"user-id\")\n\n    val builder = new SingleBuilder\n\n    def have(item: String): Matcher[SingleBuilder] = {\n      be_==(item) ^^ ((resultBuilder: SingleBuilder) =>\n        resultBuilder.build().map(_.toString()).mkString)\n    }\n\n    def script(code: String, modules: List[String] = Nil) =\n      ImmutableSubQuery(code, user, id = \"query-id\")\n  }\n\n  \"pass sanity\" in new ctx {\n    executor.execute(script(\n      \"\"\"import sys\n        |\n        |sys.exit()\n        |\"\"\".stripMargin), builder).runSyncUnsafe()\n\n    builder.build() must beEmpty\n  }\n\n  \"pass stdout to logs\" in new ctx {\n    executor.execute(script(\"\"\"print('hello from python')\"\"\"), builder).runSyncUnsafe()\n\n    builder.logs must contain(\"hello from python\")\n  }\n\n  \"pass stderr to logs\" in new ctx {\n    executor.execute(script(\"\"\"import foo\"\"\"), builder).runSyncUnsafe()\n\n    builder.logs.mkString(\"\\n\") must contain(\"ModuleNotFoundError: No module named 'foo'\")\n  }\n\n  \"support q.fields and q.row methods\" in new ctx {\n    val code =\n      \"\"\"from quix import Quix\n        |q = Quix()\n        |\n        |q.fields('foo', 'boo')\n        |q.row(1, 2)\n        |\"\"\".stripMargin\n\n    executor.execute(script(code), builder).runSyncUnsafe()\n\n    builder.columns.map(_.name) must_=== List(\"foo\", \"boo\")\n\n    builder.queries must contain(QueryStarted(\"query-id\", code))\n    builder.build().head.map(_.toString.toInt) must_=== List(1, 2)\n  }\n\n  \"use packages for installing new packages \" in new ctx {\n    executor.execute(script(\n      code =\n        \"\"\"packages.install('pipdate')\n          |packages.install('ujson')\n          |packages.install('packaging')\n          |\n          |import pipdate\n          |import ujson\n          |\n          |from quix import Quix\n          |q = Quix()\n          |\n          |q.fields('foo', 'boo')\n          |q.row(1, 2)\n          |\"\"\".stripMargin), builder).runSyncUnsafe()\n\n    builder.columns.map(_.name) must_=== List(\"foo\", \"boo\")\n    builder.build().head.map(_.toString.toInt) must_=== List(1, 2)\n  }\n\n  \"support requirements syntax for packages.install \" in new ctx {\n    executor.execute(script(\n      code =\n        \"\"\"packages.install('ujson==1.35')\n          |packages.install('ujson>1.0')\n          |packages.install('ujson>1.0,<1.30')\n          |\n          |import ujson\n          |print(123)\n          |\"\"\".stripMargin), builder).runSyncUnsafe()\n\n    builder.logs must contain(\"123\")\n  }\n\n  \"_get_user() should return current user \" in new ctx {\n    executor.execute(script(\n      code =\n        \"\"\"print(_get_user())\n          |\"\"\".stripMargin), builder).runSyncUnsafe()\n\n    builder.logs must contain(user.email)\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.wix</groupId>\n    <artifactId>quix-web-spring</artifactId>\n    <version>1.0.12-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n    </parent>\n\n    <properties>\n        <scala.library.version>2.12.15</scala.library.version>\n        <scala.dependencies.version>2.12</scala.dependencies.version>\n        <nuprocess.version>1.2.5</nuprocess.version>\n        <py4j.version>0.10.8.1</py4j.version>\n        <scala.logging.version>3.9.2</scala.logging.version>\n        <logback.version>1.2.3</logback.version>\n        <specs.version>4.8.1</specs.version>\n        <scala.maven.plugin.version>4.3.0</scala.maven.plugin.version>\n        <jwt.version>2.1.0</jwt.version>\n        <typesafe.config.version>1.4.0</typesafe.config.version>\n        <wix.embedded.mysql.version>4.6.1</wix.embedded.mysql.version>\n        <async.http.version>2.10.4</async.http.version>\n        <mysql.version>8.0.28</mysql.version>\n        <spring.jdbc.version>5.2.2.RELEASE</spring.jdbc.version>\n        <scalatest.version>3.1.0</scalatest.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>quix-presto-module_${scala.dependencies.version}</artifactId>\n            <version>1.0.12-SNAPSHOT</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>quix-athena-module_${scala.dependencies.version}</artifactId>\n            <version>1.0.12-SNAPSHOT</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>quix-bigquery-module_${scala.dependencies.version}</artifactId>\n            <version>1.0.12-SNAPSHOT</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>quix-python-module_${scala.dependencies.version}</artifactId>\n            <version>1.0.12-SNAPSHOT</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>quix-core_${scala.dependencies.version}</artifactId>\n            <version>1.0.12-SNAPSHOT</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/com.pauldijou/jwt-core -->\n        <dependency>\n            <groupId>com.pauldijou</groupId>\n            <artifactId>jwt-core_${scala.dependencies.version}</artifactId>\n            <version>${jwt.version}</version>\n        </dependency>\n\n        <!-- logging -->\n\n        <!-- https://mvnrepository.com/artifact/com.typesafe.scala-logging/scala-logging -->\n        <dependency>\n            <groupId>com.typesafe.scala-logging</groupId>\n            <artifactId>scala-logging_${scala.dependencies.version}</artifactId>\n            <version>${scala.logging.version}</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>${logback.version}</version>\n        </dependency>\n\n        <!-- websockets -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-websocket</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.eclipse.jetty.websocket</groupId>\n            <artifactId>websocket-common</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.eclipse.jetty.websocket</groupId>\n            <artifactId>websocket-api</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.eclipse.jetty.websocket</groupId>\n            <artifactId>websocket-server</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.specs2</groupId>\n            <artifactId>specs2-core_${scala.dependencies.version}</artifactId>\n            <version>${specs.version}</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>RELEASE</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/com.typesafe/config -->\n        <dependency>\n            <groupId>com.typesafe</groupId>\n            <artifactId>config</artifactId>\n            <version>${typesafe.config.version}</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-scala -->\n        <dependency>\n            <groupId>com.fasterxml.jackson.module</groupId>\n            <artifactId>jackson-module-scala_${scala.dependencies.version}</artifactId>\n            <version>${jackson.version}</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n            <version>${spring.jdbc.version}</version>\n        </dependency>\n\n        <!-- tests -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.scalatest</groupId>\n            <artifactId>scalatest_${scala.dependencies.version}</artifactId>\n            <version>${scalatest.version}</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>quix-jdbc-module_${scala.dependencies.version}</artifactId>\n            <version>1.0.12-SNAPSHOT</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.specs2</groupId>\n            <artifactId>specs2-junit_${scala.dependencies.version}</artifactId>\n            <version>${specs.version}</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.wix</groupId>\n            <artifactId>wix-embedded-mysql</artifactId>\n            <version>${wix.embedded.mysql.version}</version>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/org.hamcrest/java-hamcrest -->\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>java-hamcrest</artifactId>\n            <version>2.0.0.0</version>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/org.asynchttpclient/async-http-client -->\n        <dependency>\n            <groupId>org.asynchttpclient</groupId>\n            <artifactId>async-http-client</artifactId>\n            <version>${async.http.version}</version>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <sourceDirectory>src/main/scala</sourceDirectory>\n        <testSourceDirectory>src/test/scala</testSourceDirectory>\n\n        <plugins>\n            <plugin>\n                <groupId>net.alchim31.maven</groupId>\n                <artifactId>scala-maven-plugin</artifactId>\n                <version>${scala.maven.plugin.version}</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>compile</goal>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <scalaVersion>${scala.library.version}</scalaVersion>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <mainClass>quix.web.Server</mainClass>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/resources/application.properties",
    "content": "server.port=8081\n\nlogging.level.org.springframework.web=ERROR\nlogging.level.org.hibernate=ERROR\npresto.api=http://presto:8080/v1\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\n    <property name=\"LOGS\" value=\"./logs\"/>\n\n    <appender name=\"Console\"\n              class=\"ch.qos.logback.core.ConsoleAppender\">\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <Pattern>%date{ISO8601} %-5level [%thread] %40.40logger{40} : %m%n%ex{full}</Pattern>\n        </layout>\n    </appender>\n\n    <appender name=\"RollingFile\"\n              class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${LOGS}/quix.log</file>\n        <encoder\n                class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <Pattern>%date{ISO8601} %-5level [%thread] %40.40logger{40} : %m%n%ex{full}</Pattern>\n        </encoder>\n\n        <rollingPolicy\n                class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!-- rollover daily and when the file reaches 100 MegaBytes -->\n            <fileNamePattern>${LOGS}/archived/quix-%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <maxHistory>30</maxHistory>\n            <timeBasedFileNamingAndTriggeringPolicy\n                    class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>100MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n        </rollingPolicy>\n    </appender>\n\n    <!-- LOG everything at INFO level -->\n    <root level=\"info\">\n        <appender-ref ref=\"RollingFile\"/>\n        <appender-ref ref=\"Console\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/Server.scala",
    "content": "package quix.web\n\nimport com.typesafe.scalalogging.LazyLogging\nimport org.springframework.boot._\nimport quix.web.spring.SpringConfig\n\nobject Server extends LazyLogging {\n  def main(args: Array[String]): Unit = {\n    logger.info(\"Starting Server\")\n    SpringApplication.run(classOf[SpringConfig], args: _*)\n    \n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/auth/DemoUsers.scala",
    "content": "package quix.web.auth\n\nimport quix.api.v1.users.{User, Users}\n\nclass DemoUsers(users : Users) extends Users  {\n  override def auth[T](headers: Map[String, String])(code: User => T): T = {\n    users.auth(headers) { user =>\n      val domain = user.email.split(\"@\").lastOption.getOrElse(\"***\")\n      code(user.copy(email = \"*******@\" + domain))\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/auth/JwtUsers.scala",
    "content": "package quix.web.auth\n\nimport pdi.jwt.{Jwt, JwtAlgorithm}\nimport quix.api.v1.users.{RequestNotAuthenticated, User, Users}\nimport quix.core.utils.JsonOps.Implicits.global\nimport quix.core.utils.StringJsonHelpersSupport\n\nimport scala.util.Try\n\nclass JwtUsers(val headerName: String, val secret: String)\n  extends Users with StringJsonHelpersSupport {\n\n  override def auth[T](headers: Map[String, String])(code: User => T): T = {\n    val result = for {\n      header <- headers.get(headerName)\n      userJson <- Jwt.decodeRaw(header, secret, Seq(JwtAlgorithm.HS256)).toOption\n      user <- Try(userJson.as[User]).toOption\n    } yield code(user)\n\n    result.getOrElse(throw RequestNotAuthenticated(\"Request not authenticated\"))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/controllers/DbController.scala",
    "content": "package quix.web.controllers\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.springframework.stereotype.Controller\nimport org.springframework.web.bind.annotation._\nimport quix.api.v1.db.{Catalog, Schema, Table}\nimport quix.api.v2.execute.ExecutionModule\n\n@Controller\n@RequestMapping(Array(\"/api\"))\nclass DbController(modules: Map[String, ExecutionModule]) {\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/config\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def getDbConfig = {\n    Map(\"trees\" -> modules.keySet)\n  }\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/{moduleId}/explore\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def getCatalogsOf(@PathVariable moduleId: String): List[Catalog] = {\n    getDb(moduleId).map {\n      _.getCatalogs.runSyncUnsafe()\n    }.getOrElse(Nil)\n  }\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/{moduleId}/explore/{catalogId}\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def getSchemasOf(@PathVariable moduleId: String, @PathVariable catalogId: String): List[Schema] = {\n    getCatalogsOf(moduleId)\n      .find(_.name == catalogId)\n      .map(_.children)\n      .getOrElse(Nil)\n  }\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/{moduleId}/explore/{catalogId}/{schemaId}\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def getTablesOf(@PathVariable moduleId: String, @PathVariable catalogId: String, @PathVariable schemaId: String): List[Table] = {\n    getSchemasOf(moduleId, catalogId)\n      .find(_.name == schemaId)\n      .map(_.children)\n      .getOrElse(Nil)\n  }\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/{moduleId}/explore/{catalog}/{schema}/{table}\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def getTable(@PathVariable moduleId: String, @PathVariable catalog: String, @PathVariable schema: String, @PathVariable table: String) = {\n    getDb(moduleId).map {\n      _.getTable(catalog, schema, table).runSyncUnsafe()\n    }.getOrElse(Table(table, Nil))\n  }\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/{moduleId}/autocomplete\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def autocomplete(@PathVariable moduleId: String) = {\n    getDb(moduleId).map {\n      _.getAutocomplete.runSyncUnsafe()\n    }.getOrElse(Map.empty)\n  }\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/db/{moduleId}/search\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def search(@PathVariable moduleId: String, @RequestParam(\"q\") query: String) = {\n    getDb(moduleId).map {\n      _.search(query).runSyncUnsafe()\n    }.getOrElse(Map.empty)\n  }\n\n  def getDb(moduleId: String) = {\n    for {\n      module <- modules.get(moduleId)\n      db <- module.db\n    } yield db\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/controllers/DownloadController.scala",
    "content": "package quix.web.controllers\n\nimport java.io.{Closeable, OutputStream}\n\nimport com.google.common.io.ByteStreams\nimport com.typesafe.scalalogging.LazyLogging\nimport javax.servlet.http.HttpServletResponse\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport org.springframework.stereotype.Controller\nimport org.springframework.web.bind.annotation._\nimport quix.core.download.QueryResultsStorage\n\n@Controller\n@RequestMapping(Array(\"/api\"))\nclass DownloadController(val results: QueryResultsStorage) extends LazyLogging {\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/download/{queryId}\"), method = Array(RequestMethod.GET))\n  def startDownload(@PathVariable queryId: String, response: HttpServletResponse): Unit = {\n    logger.info(s\"event=download-start query-id=$queryId\")\n\n    val task = results.exists(queryId).flatMap {\n      case false =>\n        Task(response.setStatus(404))\n      case true =>\n        val responseUpdateTask = Task {\n          response.setContentType(\"text/csv\")\n          response.setHeader(\"Vary\", \"Accept-Encoding\")\n          response.addHeader(\"Connection\", \"Keep-Alive\")\n          response.addHeader(\"Keep-Alive\", \"timeout=900\")\n        }\n\n        val openOutput = Task(response.getOutputStream)\n        val openInput = results.getInputStream(queryId)\n        val closeStream = (stream: Closeable) => Task(stream.close())\n\n        val useOutput = (stream: OutputStream) => {\n          openInput\n            .bracket(data => Task(ByteStreams.copy(data, stream)))(closeStream)\n        }\n\n        val deleteFile = results.delete(queryId)\n\n        responseUpdateTask >> openOutput.bracket(useOutput)(closeStream) >> deleteFile\n    }\n\n    task.runSyncUnsafe()\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/controllers/HealthController.scala",
    "content": "package quix.web.controllers\n\nimport org.springframework.stereotype.Controller\nimport org.springframework.web.bind.annotation.{RequestMapping, RequestMethod, ResponseBody}\n\n@Controller\n@RequestMapping(Array(\"/health\"))\nclass HealthController {\n\n  @RequestMapping(value = Array(\"/is_alive\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def isAlive = {}\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/controllers/HistoryController.scala",
    "content": "package quix.web.controllers\n\nimport monix.execution.Scheduler.Implicits.global\nimport org.springframework.stereotype.Controller\nimport org.springframework.web.bind.annotation._\nimport quix.core.history.Execution\nimport quix.core.history.dao.{Filter, HistoryReadDao, Page}\n\n@Controller\n@RequestMapping(Array(\"/api/history\"))\nclass HistoryController(historyReadDao: HistoryReadDao) {\n\n  @CrossOrigin(origins = Array(\"*\"), allowedHeaders = Array(\"*\"))\n  @RequestMapping(value = Array(\"/executions\"), method = Array(RequestMethod.GET))\n  @ResponseBody\n  def executions(@RequestParam(defaultValue = \"0\") offset: String,\n                 @RequestParam(defaultValue = \"20\") limit: String,\n                 @RequestParam(defaultValue = \"\") user : String,\n                 @RequestParam(defaultValue = \"\") query : String\n                ): List[ExecutionDto] =\n    historyReadDao\n      .executions(page = Page(offset.toInt, limit.toInt), filter = Filter(user, query))\n      .runSyncUnsafe()\n      .map(ExecutionDto(_))\n\n}\n\ncase class ExecutionDto(id: String,\n                        email: String,\n                        query: Seq[String],\n                        code: String,\n                        moduleType: String,\n                        startedAt: String)\n\nobject ExecutionDto {\n  def apply(execution: Execution): ExecutionDto =\n    ExecutionDto(\n      id = execution.id,\n      email = execution.user.email,\n      query = execution.statements,\n      code = execution.code,\n      moduleType = execution.queryType,\n      startedAt = execution.startedAt.toString)\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/controllers/SqlStreamingController.scala",
    "content": "package quix.web.controllers\n\nimport java.util.concurrent.ConcurrentHashMap\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Task\nimport monix.execution.{CancelableFuture, Scheduler}\nimport org.springframework.web.socket.handler.{ConcurrentWebSocketSessionDecorator, TextWebSocketHandler}\nimport org.springframework.web.socket.{CloseStatus, TextMessage, WebSocketSession}\nimport quix.api.v1.execute.{Consumer, Empty, Error, EventData, ExecutionEvent, Pong, StartCommand}\nimport quix.api.v1.users.{User, Users}\nimport quix.api.v2.execute.{Builder, ExecutionModule}\nimport quix.core.download.{DownloadConfig, DownloadableBuilder, QueryResultsStorage}\nimport quix.core.history.HistoryBuilder\nimport quix.core.history.dao.HistoryWriteDao\nimport quix.core.results.MultiBuilder\nimport quix.core.utils.JsonOps.Implicits.global\nimport quix.core.utils.StringJsonHelpersSupport\nimport quix.core.utils.TaskOps._\n\nimport scala.util.Try\n\nclass SqlStreamingController(val modules: Map[String, ExecutionModule],\n                             val users: Users,\n                             val downloadConfig: DownloadConfig,\n                             val queryResultsStorage: QueryResultsStorage,\n                             val historyWriteDao: HistoryWriteDao,\n                             val io: Scheduler)\n  extends TextWebSocketHandler with LazyLogging with StringJsonHelpersSupport {\n\n  val executions = new ConcurrentHashMap[String, CancelableFuture[Unit]]\n\n  def handleUnknownMessage(socket: WebSocketSession, payload: String, user: User) = {\n    val task = Task {\n      logger.info(s\"event=unknown-message socket-id=${socket.getId} payload=$payload\")\n      socket.sendMessage(new TextMessage(Error(socket.getId, s\"Failed to handle unknown message : [$payload]\").asJsonStr))\n      socket.close(CloseStatus.BAD_DATA)\n    }\n\n    task.executeOn(io).runAsyncAndForget(io)\n  }\n\n  override def handleTextMessage(socket: WebSocketSession, message: TextMessage): Unit = users.auth(getHeaders(socket)) { user =>\n    logger.info(s\"event=handle-text-message socket-id=${socket.getId} message=${message.getPayload} user=${user.email}\")\n\n    message.getPayload match {\n      case ExecutionEvent(\"ping\", _) =>\n        handlePingMessage(socket)\n\n      case ExecutionEvent(\"execute\", command: StartCommand[String]) =>\n        val threadSafeSocket = new ConcurrentWebSocketSessionDecorator(socket, 1000, 1024 * 1024)\n        handleExecutionMessage(threadSafeSocket, command, user)\n\n      case _ =>\n        handleUnknownMessage(socket, message.getPayload, user)\n    }\n  }\n\n  private def handleExecutionMessage(socket: WebSocketSession, payload: StartCommand[String], user: User) = {\n    val queryType = socket.getUri.toString.split(\"/\").last\n\n    val initConsumer = Task.eval(new WebsocketConsumer[ExecutionEvent](socket.getId, user, socket))\n    val useConsumer = (consumer: WebsocketConsumer[ExecutionEvent]) => {\n      modules.get(queryType) match {\n        case Some(module) =>\n          logger.info(s\"event=start-execution socket-id=${socket.getId} sql=${payload.code} uri=${socket.getUri} queryType=$queryType\")\n          module.start(payload, consumer.id, consumer.user, makeResultBuilder(consumer, payload.session, queryType))\n        case None =>\n          logger.warn(s\"event=start-execution-failure message=unknown-query-type socket-id=${socket.getId} sql=${payload.code} uri=${socket.getUri} queryType=$queryType\")\n          Task.unit\n      }\n    }\n\n    val closeConsumer = (consumer: WebsocketConsumer[ExecutionEvent]) => consumer.close()\n\n    val task = initConsumer.bracket(useConsumer)(closeConsumer)\n\n    val future = task\n      .logOnError(s\"event=execution-failure socket-id=${socket.getId} sql=[${payload.code.replace(\"\\n\", \"-newline-\")}]\")\n      .executeOn(io).runToFuture(io)\n    executions.put(socket.getId, future)\n  }\n\n  private def handlePingMessage(socket: WebSocketSession) = {\n    val task = Task {\n      logger.info(s\"event=ping socket-id=${socket.getId}\")\n      socket.sendMessage(new TextMessage(Pong(socket.getId).asJsonStr))\n    }\n\n    task.runAsyncAndForget(io)\n  }\n\n  override def afterConnectionClosed(socket: WebSocketSession, status: CloseStatus): Unit = users.auth(getHeaders(socket)) { user =>\n    logger.info(s\"event=connection-closed status=$status socket-id=${socket.getId} user=${user.email}\")\n\n    for (execution <- Option(executions.remove(socket.getId)))\n      execution.cancel()\n  }\n\n  def getHeaders(socket: WebSocketSession): Map[String, String] = {\n    import scala.collection.JavaConverters._\n    socket.getAttributes.asScala.mapValues(String.valueOf).toMap\n  }\n\n  def makeResultBuilder(consumer: Consumer[ExecutionEvent],\n                        session: Map[String, String],\n                        queryType: String): Builder = {\n    val multiBuilder = new MultiBuilder(consumer)\n    val builder = if (session.get(\"mode\").contains(\"download\")) {\n      new DownloadableBuilder(multiBuilder, downloadConfig, queryResultsStorage, consumer)\n    } else {\n      multiBuilder\n    }\n    new HistoryBuilder(builder, historyWriteDao, queryType)\n  }\n}\n\nclass WebsocketConsumer[Results](val id: String, val user: User, socket: WebSocketSession)\n  extends Consumer[Results] with StringJsonHelpersSupport with LazyLogging {\n\n  override def write(payload: Results) = Task {\n    logger.trace(s\"event=write-payload socket-id=${socket.getId} user=${user.email} payload=[$payload]\")\n    socket.sendMessage(new TextMessage(payload.asJsonStr))\n  }\n\n  override def close() = Task {\n    logger.info(s\"event=socket-close socket-id=${socket.getId} user=${user.email}\")\n\n    if (socket.isOpen)\n      socket.close()\n  }\n}\n\nobject Start extends StringJsonHelpersSupport {\n  def unapply(payload: String): Option[StartCommand[String]] = {\n    Try {\n      val command = payload.as[StartCommand[String]]\n\n      assert(command.code != null)\n\n      command.copy(session = Option(command.session).getOrElse(Map.empty))\n    }.toOption\n  }\n}\n\nobject ExecutionEvent extends StringJsonHelpersSupport {\n  def unapply(event: String): Option[(String, EventData)] = {\n    val name = event.get(\"event\")\n    val data = event.get(\"data\")\n\n    (name, data) match {\n      case (\"ping\", _) =>\n        Some(name, Empty)\n\n      case (\"execute\", Start(command)) =>\n        Some(name, command)\n\n      case (_, _) =>\n        Some(name, Empty)\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/spring/HistoryDaoConfig.scala",
    "content": "package quix.web.spring\n\nimport java.time.Clock\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.execution.Scheduler.Implicits.global\nimport org.springframework.context.annotation.{Bean, Configuration}\nimport quix.core.history.dao.InMemoryHistoryDao\n\n@Configuration\nclass HistoryDaoConfig extends LazyLogging {\n\n  @Bean def historyDao: InMemoryHistoryDao = {\n    logger.info(\"event=[spring-config] bean=[InMemoryHistoryDao]\")\n    InMemoryHistoryDao.make(Clock.systemUTC()).runSyncUnsafe()\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/spring/SpringConfig.scala",
    "content": "package quix.web.spring\n\nimport java.io.ByteArrayInputStream\nimport java.nio.file.{Files, Paths}\nimport java.util.Base64\n\nimport com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper}\nimport com.google.auth.oauth2.ServiceAccountCredentials\nimport com.google.cloud.bigquery.BigQueryOptions\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.eval.Coeval\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.context.annotation.{Bean, Configuration, DependsOn}\nimport org.springframework.core.env.Environment\nimport quix.api.v1.execute.Batch\nimport quix.api.v2.execute.ExecutionModule\nimport quix.api.v1.users.DummyUsers\nimport quix.athena._\nimport quix.bigquery._\nimport quix.bigquery.db.{BigQueryAutocomplete, BigQueryCatalogs, BigQueryTables}\nimport quix.core.db.{RefreshableAutocomplete, RefreshableCatalogs, RefreshableDb}\nimport quix.core.download.{DownloadConfig, QueryResultsStorage}\nimport quix.core.executions.{SqlModule}\nimport quix.core.history.dao.HistoryReadDao\nimport quix.core.sql.StopWordSqlSplitter\nimport quix.core.utils.JsonOps\nimport quix.jdbc._\nimport quix.presto._\nimport quix.presto.db.{PrestoAutocomplete, PrestoCatalogs, PrestoTables}\nimport quix.presto.rest.ScalaJPrestoStateClient\nimport quix.python.{PythonConfig, PythonExecutor, PythonModule}\nimport quix.web.auth.{DemoUsers, JwtUsers}\nimport quix.web.controllers.{DbController, DownloadController, HealthController, HistoryController}\n\nimport scala.util.control.NonFatal\n\n@SpringBootApplication\n@Configuration\nclass SpringConfig {\n\n}\n\nobject Registry {\n  val modules = scala.collection.mutable.Map.empty[String, ExecutionModule]\n}\n\n@Configuration\nclass AuthConfig extends LazyLogging {\n\n  @Bean def initUsers(env: Environment) = {\n    logger.info(\"event=[spring-config] bean=[Users]\")\n\n    val authType = Coeval(env.getRequiredProperty(\"auth.type\"))\n    val dummyUsers = new DummyUsers(env.getProperty(\"auth.user\", \"dummy-user\"))\n\n    val auth = authType.map {\n      case \"fake\" =>\n        logger.info(s\"event=init-users-fake\")\n        dummyUsers\n\n      case \"google\" =>\n        logger.info(s\"event=init-users-google\")\n        val cookie = env.getRequiredProperty(\"auth.cookie\")\n        val secret = env.getRequiredProperty(\"auth.secret\")\n\n        require(cookie.nonEmpty, \"auth.cookie can't be an empty string\")\n        require(secret.nonEmpty, \"auth.secret can't be an empty string\")\n\n        new JwtUsers(cookie, secret)\n\n      case unknown =>\n        logger.warn(s\"event=init-users-failure reason=unknown-auth-type auth-type=$unknown\")\n        dummyUsers\n    }.onErrorRecoverWith { case NonFatal(e) =>\n      logger.warn(s\"event=init-users-failure reason=exception exception=[${e.getMessage}]\")\n      Coeval(dummyUsers)\n    }\n\n    env.getProperty(\"demo.mode\", \"false\").toLowerCase match {\n      case \"true\" => new DemoUsers(auth.value)\n      case _ => auth.value\n    }\n  }\n}\n\n@Configuration\nclass ModulesConfiguration extends LazyLogging {\n\n  def getModules(env: Environment, moduleName: String) = {\n    val modules = env.getProperty(\"modules\", \"\").split(\",\")\n\n    modules.filter { module =>\n      env.getProperty(s\"modules.$module.engine\", \"\") == moduleName || module == moduleName\n    }\n  }\n\n  @Bean def initPresto(env: Environment) = {\n\n    def getPrestoModule(presto: String) = {\n      val config = {\n        def addMissingSlashIfNeeded(endpoint: String) = {\n          if (endpoint.endsWith(\"/\")) endpoint\n          else endpoint + \"/\"\n        }\n\n        val prestoBaseApi = addMissingSlashIfNeeded {\n          env.getProperty(s\"modules.$presto.api\", env.getProperty(\"presto.api\"))\n        }\n\n        val statementsApi = prestoBaseApi + \"statement\"\n        val healthApi = prestoBaseApi + \"cluster\"\n        val queryInfoApi = prestoBaseApi + \"query/\"\n\n        val defaultCatalog = {\n          env.getProperty(s\"modules.$presto.catalog\", env.getProperty(\"presto.catalog\", \"system\"))\n        }\n\n        val defaultSchema = {\n          env.getProperty(s\"modules.$presto.schema\", env.getProperty(\"presto.schema\", \"runtime\"))\n        }\n\n        val defaultSource = {\n          env.getProperty(s\"modules.$presto.source\", env.getProperty(\"presto.source\", \"quix\"))\n        }\n\n        val httpHeadersPrefix = {\n          env.getProperty(s\"modules.$presto.http.headers.prefix\", \"X-Presto-\")\n        }\n\n        PrestoConfig(statementsApi, healthApi, queryInfoApi, defaultSchema, defaultCatalog, defaultSource, httpHeadersPrefix)\n      }\n\n      val client = new ScalaJPrestoStateClient(config)\n      val executor = new QueryExecutor(client)\n\n      val emptyDbTimeout = {\n        env.getProperty(s\"modules.$presto.db.empty.timeout\", classOf[Long],\n          env.getProperty(\"presto.db.empty.timeout\", classOf[Long], 1000L * 10))\n      }\n\n      val requestTimeout = {\n        env.getProperty(s\"modules.$presto.db.request.timeout\", classOf[Long],\n          env.getProperty(\"presto.db.request.timeout\", classOf[Long], 5000L))\n      }\n\n      logger.info(s\"event=[spring-config] bean=[RefreshableDbConfig] firstEmptyStateDelay=$emptyDbTimeout requestTimeout=$requestTimeout\")\n\n      val prestoCatalogs = new PrestoCatalogs(executor)\n      val catalogs = new RefreshableCatalogs(prestoCatalogs, emptyDbTimeout, 1000L * 60 * 5)\n      val autocomplete = new RefreshableAutocomplete(new PrestoAutocomplete(prestoCatalogs, executor), emptyDbTimeout, 1000L * 60 * 5)\n      val tables = new PrestoTables(executor, requestTimeout)\n\n      val db = new RefreshableDb(catalogs, autocomplete, tables)\n\n      new SqlModule(executor, Some(db))\n    }\n\n    for (module <- getModules(env, \"presto\"))\n      Registry.modules.update(module, getPrestoModule(module))\n\n    \"OK\"\n  }\n\n  @Bean def initAthena(env: Environment) = {\n    def getAthenaModule(athena: String) = {\n      val config = {\n        val output = env.getProperty(s\"modules.$athena.output\",\n          env.getProperty(\"athena.output\", \"\"))\n\n        val region = env.getProperty(s\"modules.$athena.region\",\n          env.getProperty(\"athena.region\", \"\"))\n\n        val database = env.getProperty(s\"modules.$athena.database\",\n          env.getProperty(\"athena.database\", \"\"))\n\n        val firstEmptyStateDelay = env.getProperty(s\"modules.$athena.db.empty.timeout\", classOf[Long], 1000L * 10)\n        val requestTimeout = env.getProperty(s\"modules.$athena.db.request.timeout\", classOf[Long], 5000L)\n\n        val awsAccessKeyId = env.getProperty(s\"modules.$athena.aws.access.key.id\",\n          env.getProperty(\"aws.access.key.id\"))\n        val awsSecretKey = env.getProperty(s\"modules.$athena.aws.secret.key\",\n          env.getProperty(\"aws.secret.key\"))\n\n        AthenaConfig(output, region, database, firstEmptyStateDelay, requestTimeout, awsAccessKeyId, awsSecretKey)\n      }\n\n      logger.warn(s\"event=[spring-config] bean=[AthenaConfig] config=$config\")\n\n      val executor = AthenaQueryExecutor(config)\n\n      val athenaCatalogs = new AthenaCatalogs(executor)\n      val catalogs = new RefreshableCatalogs(athenaCatalogs, config.firstEmptyStateDelay, 1000L * 60 * 5)\n      val autocomplete = new RefreshableAutocomplete(new AthenaAutocomplete(athenaCatalogs), config.firstEmptyStateDelay, 1000L * 60 * 5)\n      val tables = new AthenaTables(executor)\n\n      val db = new RefreshableDb(catalogs, autocomplete, tables)\n\n      new SqlModule(executor, Some(db))\n    }\n\n    for (module <- getModules(env, \"athena\"))\n      Registry.modules.update(module, getAthenaModule(module))\n\n    \"OK\"\n  }\n\n  @Bean def initBigQuery(env: Environment) = {\n    def getBigQueryModule(bigquery: String) = {\n      val config = {\n        val credentialsBase64 = env.getProperty(s\"modules.$bigquery.credentials.base64\")\n        val credentialsFile = env.getProperty(s\"modules.$bigquery.credentials.file\")\n\n        val credentials = if (credentialsBase64 != null && credentialsBase64.nonEmpty) {\n          Base64.getDecoder.decode(credentialsBase64.getBytes(\"UTF-8\"))\n        } else if (credentialsFile != null && credentialsFile.nonEmpty && Files.exists(Paths.get(credentialsFile))) {\n          Files.readAllBytes(Paths.get(credentialsFile))\n        } else throw new IllegalArgumentException(\"Missing BigQuery credentials data\")\n\n        BigQueryConfig(\n          credentials,\n          firstEmptyStateDelay = env.getProperty(s\"modules.$bigquery.db.empty.timeout\", classOf[Long], 1000L * 10),\n          requestTimeout = env.getProperty(s\"modules.$bigquery.db.request.timeout\", classOf[Long], 5000L)\n        )\n      }\n\n      logger.warn(s\"event=[spring-config] bean=[BigQueryConfig] config=$config\")\n\n      val executor = BigQueryQueryExecutor(config)\n\n      val credentials = ServiceAccountCredentials.fromStream(new ByteArrayInputStream(config.credentialBytes))\n\n      val bigQuery = BigQueryOptions\n        .newBuilder()\n        .setCredentials(credentials)\n        .build()\n        .getService\n\n      val bigQueryCatalogs = new BigQueryCatalogs(config, bigQuery)\n      val catalogs = new RefreshableCatalogs(bigQueryCatalogs, config.requestTimeout, config.firstEmptyStateDelay)\n      val autocomplete = new RefreshableAutocomplete(new BigQueryAutocomplete(bigQueryCatalogs, executor), config.requestTimeout, config.firstEmptyStateDelay)\n      val tables = new BigQueryTables(executor, config.requestTimeout)\n\n      val db = new RefreshableDb(catalogs, autocomplete, tables)\n\n      new SqlModule(executor, Some(db), new StopWordSqlSplitter(\"TEMP\", \"FUNCTION\"))\n    }\n\n    for (module <- getModules(env, \"bigquery\"))\n      Registry.modules.update(module, getBigQueryModule(module))\n\n    \"OK\"\n  }\n\n  @Bean def initJdbc(env: Environment): String = {\n    def getJdbcModule(module: String): SqlModule = {\n      val url = env.getRequiredProperty(s\"modules.$module.url\")\n      val user = env.getRequiredProperty(s\"modules.$module.user\")\n      val pass = env.getRequiredProperty(s\"modules.$module.pass\")\n      val driver = env.getRequiredProperty(s\"modules.$module.driver\")\n\n      val emptyDbTimeout = {\n        env.getProperty(s\"modules.$module.db.empty.timeout\", classOf[Long],\n          env.getProperty(\"presto.db.empty.timeout\", classOf[Long], 1000L * 10))\n      }\n\n      try {\n        Class.forName(driver)\n      } catch {\n        case NonFatal(e) =>\n          logger.error(s\"event=[spring-error] message=[failed-to-load-class] class=[$driver]\", e)\n      }\n\n      val config = JdbcConfig(url, user, pass, driver)\n      val executor = new JdbcQueryExecutor(config)\n      val jdbcCatalogs = new JdbcCatalogs(config)\n      val tables = new JdbcTables(config)\n      val jdbcAutocomplete = new JdbcAutocomplete(jdbcCatalogs)\n\n      val catalogs = new RefreshableCatalogs(jdbcCatalogs, emptyDbTimeout, 1000L * 60 * 5)\n      val autocomplete = new RefreshableAutocomplete(jdbcAutocomplete, emptyDbTimeout, 1000L * 60 * 5)\n      val db = new RefreshableDb(catalogs, autocomplete, tables)\n\n      new SqlModule(executor, Option(db))\n    }\n\n    for (module <- getModules(env, \"jdbc\")) {\n      Registry.modules.update(module, getJdbcModule(module))\n    }\n\n    \"OK\"\n  }\n\n  @Bean def initPython(env: Environment): String = {\n    for (moduleName <- getModules(env, \"python\")) {\n      val module = {\n\n        val config = {\n          val indexUrl = env.getProperty(s\"modules.$moduleName.pip.index\", \"https://pypi.python.org/simple\")\n          val extraIndexUrl = env.getProperty(s\"modules.$moduleName.pip.extra.index\", \"\")\n          val packages = env.getProperty(s\"modules.$moduleName.pip.packages\", \"\").split(\",\").map(_.trim).filter(_.nonEmpty)\n          val userScriptsDir = env.getProperty(s\"modules.$moduleName.scripts.dir\", \"/tmp/quix-python\")\n          val additionalCodeFile = env.getProperty(s\"modules.$moduleName.additional.code.file\", \"/tmp/quix-python/code.py\")\n          val additionalCode = {\n            val file = Paths.get(additionalCodeFile)\n            if (Files.exists(file)) \"\\n\\n\" + new String(Files.readAllBytes(file), \"UTF-8\") + \"\\n\\n\"\n            else \"\"\n          }\n\n          PythonConfig(indexUrl, extraIndexUrl, packages, userScriptsDir, additionalCode)\n        }\n\n        val executor = new PythonExecutor(config)\n        new PythonModule(executor)\n      }\n      Registry.modules.update(moduleName, module)\n    }\n\n    \"OK\"\n  }\n\n  @Bean\n  @DependsOn(Array(\"initPresto\", \"initAthena\", \"initJdbc\", \"initBigQuery\", \"initPython\"))\n  def initKnownModules: Map[String, ExecutionModule] = {\n    logger.info(s\"*******************************************************\")\n    logger.info(s\"****************          Modules are\")\n    Registry.modules.keySet.toList.sorted.foreach { module =>\n      logger.info(s\"****************          $module\")\n    }\n    logger.info(s\"*******************************************************\")\n\n    Registry.modules.toMap\n  }\n}\n\n@Configuration\nclass DownloadConfiguration extends LazyLogging {\n\n  @Bean def initDownloadConfig(env: Environment): DownloadConfig = {\n    val downloadsDir = env.getProperty(s\"downloads.temp.dir\", \"/tmp/quix/downloads\")\n\n    val cloud = env.getProperty(\"downloads.cloud.storage\", \"none\")\n\n    val cloudConfig = cloud match {\n      case \"s3\" =>\n        Map(\n          \"bucket\" -> env.getRequiredProperty(\"download.s3.bucket\"),\n          \"region\" -> env.getRequiredProperty(\"download.s3.region\"),\n          \"accessKey\" -> env.getRequiredProperty(\"download.s3.access\"),\n          \"secretKey\" -> env.getRequiredProperty(\"download.s3.secret\")\n        )\n\n      case _ =>\n        Map.empty[String, String]\n    }\n\n    DownloadConfig(downloadsDir, cloudConfig)\n  }\n\n  @Bean def initQueryResultsStorage(downloadConfig: DownloadConfig): QueryResultsStorage = {\n    logger.info(s\"event=[spring-config] bean=[QueryResultsStorage]\")\n\n    QueryResultsStorage(downloadConfig)\n  }\n}\n\n@Configuration\nclass Controllers extends LazyLogging {\n\n  @Bean def initDbController(modules: Map[String, ExecutionModule]): DbController = {\n    logger.info(\"event=[spring-config] bean=[DbController]\")\n    new DbController(modules)\n  }\n\n  @Bean def initDownloadController(queryResultsStorage: QueryResultsStorage): DownloadController = {\n    logger.info(\"event=[spring-config] bean=[DownloadController]\")\n    new DownloadController(queryResultsStorage)\n  }\n\n  @Bean def initHistoryController(historyReadDao: HistoryReadDao): HistoryController = {\n    logger.info(\"event=[spring-config] bean=[HistoryController]\")\n    new HistoryController(historyReadDao)\n  }\n\n  @Bean def initHealthController: HealthController = {\n    logger.info(\"event=[spring-config] bean=[HealthController]\")\n    new HealthController\n  }\n}\n\n@Configuration class JacksonConfiguration {\n  @Bean def objectMapper: ObjectMapper = {\n    val mapper = JsonOps.global\n    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)\n    mapper\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/main/scala/quix/web/spring/WebsocketsConfig.scala",
    "content": "package quix.web.spring\n\nimport java.util\n\nimport com.typesafe.scalalogging.LazyLogging\nimport monix.execution.Scheduler\nimport org.eclipse.jetty.websocket.api.WebSocketPolicy\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.server.{ServerHttpRequest, ServerHttpResponse, ServletServerHttpRequest}\nimport org.springframework.web.socket.WebSocketHandler\nimport org.springframework.web.socket.config.annotation.{EnableWebSocket, WebSocketConfigurer, WebSocketHandlerRegistry}\nimport org.springframework.web.socket.server.HandshakeInterceptor\nimport org.springframework.web.socket.server.jetty.JettyRequestUpgradeStrategy\nimport org.springframework.web.socket.server.support.DefaultHandshakeHandler\nimport quix.api.v1.users.Users\nimport quix.api.v2.execute.ExecutionModule\nimport quix.core.download.{DownloadConfig, QueryResultsStorage}\nimport quix.core.history.dao.HistoryWriteDao\nimport quix.web.controllers.SqlStreamingController\n\n@Configuration\n@EnableWebSocket\nclass WebsocketsConfig extends LazyLogging with WebSocketConfigurer {\n\n  @Autowired var users: Users = _\n  @Autowired var modules: Map[String, ExecutionModule] = _\n  @Autowired var downloadConfig: DownloadConfig = _\n  @Autowired var queryResultsStorage: QueryResultsStorage = _\n  @Autowired var historyWriteDao: HistoryWriteDao = _\n\n  override def registerWebSocketHandlers(registry: WebSocketHandlerRegistry): Unit = {\n    val handler = new SqlStreamingController(\n      modules = modules,\n      users = users,\n      downloadConfig = downloadConfig,\n      queryResultsStorage = queryResultsStorage,\n      historyWriteDao = historyWriteDao,\n      io = Scheduler.io(\"presto-io\"))\n\n    val handshakeHandler = {\n      val policy = WebSocketPolicy.newServerPolicy()\n      policy.setIdleTimeout(10 * 60 * 1000) // 60 seconds\n      policy.setInputBufferSize(8092) // 2 KB\n      policy.setMaxTextMessageSize(1024 * 1024) // 1 MB\n\n      val requestUpgradeStrategy = new JettyRequestUpgradeStrategy(policy)\n\n      new DefaultHandshakeHandler(requestUpgradeStrategy)\n    }\n\n    val endpoints = modules.keys.map(module => \"/api/v1/execute/\" + module).toList\n\n    logger.info(s\"event=[spring-config] bean=[registerWebSocketHandlers] endponts=[$endpoints]\")\n\n    registry.addHandler(handler, endpoints: _*)\n      .addInterceptors(new CookiesInterceptor)\n      .setHandshakeHandler(handshakeHandler)\n      .setAllowedOrigins(\"*\")\n  }\n}\n\nclass CookiesInterceptor extends HandshakeInterceptor {\n  override def beforeHandshake(request: ServerHttpRequest,\n                               response: ServerHttpResponse,\n                               handler: WebSocketHandler,\n                               attributes: util.Map[String, AnyRef]): Boolean = {\n    request match {\n      case servletServerHttpRequest: ServletServerHttpRequest =>\n        val servletRequest = servletServerHttpRequest.getServletRequest\n\n        for {\n          cookie <- Option(servletRequest.getCookies).getOrElse(Array.empty)\n        } attributes.put(cookie.getName, cookie.getValue)\n\n      case _ =>\n    }\n\n    true\n  }\n\n  override def afterHandshake(serverHttpRequest: ServerHttpRequest,\n                              serverHttpResponse: ServerHttpResponse,\n                              webSocketHandler: WebSocketHandler,\n                              e: Exception): Unit = {\n\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/resources/db/001_init.sql",
    "content": "create table empty_table\n(\n    col1 INTEGER NOT NULL\n);\n\ncreate table small_table\n(\n    col1 INTEGER NOT NULL\n);\n\nINSERT INTO small_table\nvalues (1);\n\ncreate table large_table\n(\n    col1 INTEGER NOT NULL\n);\n\nINSERT INTO large_table\nvalues (1),\n       (2),\n       (3),\n       (4),\n       (5),\n       (6),\n       (7),\n       (8),\n       (9),\n       (10);"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\n    <appender name=\"Console\"\n              class=\"ch.qos.logback.core.ConsoleAppender\">\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <Pattern>%date{ISO8601} %-5level [%thread] %40.40logger{40} : %m%n%ex{full}</Pattern>\n        </layout>\n    </appender>\n\n    <!-- LOG everything at INFO level -->\n    <root level=\"info\">\n        <appender-ref ref=\"Console\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/resources/test.properties",
    "content": "modules=presto-prod,presto-dev,athena-prod,prod,dev,snake\n\nmodules.presto-prod.engine=presto\nmodules.presto-prod.api=http://localhost:8889/statement/v1\nmodules.presto-prod.catalog=system\nmodules.presto-prod.schema=runtime\nmodules.presto-prod.source=quix\nmodules.presto-prod.db.empty.timeout=60000\nmodules.presto-prod.db.request.timeout=10000\n\nmodules.presto-dev.engine=presto\nmodules.presto-dev.api=http://localhost:8889/statement/v1\nmodules.presto-dev.catalog=system\nmodules.presto-dev.schema=runtime\nmodules.presto-dev.source=quix\nmodules.presto-dev.db.empty.timeout=60000\nmodules.presto-dev.db.request.timeout=10000\n\nmodules.athena-prod.engine=athena\nmodules.athena-prod.output=s3://valery-athena-test/\nmodules.athena-prod.region=us-east-1\nmodules.athena-prod.database=default\nmodules.athena-prod.db.empty.timeout=60000\nmodules.athena-prod.db.request.timeout=10000\n\nmodules.prod.engine=jdbc\nmodules.prod.driver=com.mysql.jdbc.Driver\nmodules.prod.url=jdbc:mysql://localhost:2222/aschema\nmodules.prod.user=prod-user\nmodules.prod.pass=prod-pass\n\nmodules.dev.engine=jdbc\nmodules.dev.driver=com.mysql.jdbc.Driver\nmodules.dev.url=jdbc:mysql://localhost:3333/aschema\nmodules.dev.user=dev-user\nmodules.dev.pass=dev-pass\n\nmodules.snake.engine=python\n\nserver.port=8888"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/E2EContext.scala",
    "content": "package quix.web\n\n\nimport org.asynchttpclient.Dsl.asyncHttpClient\nimport org.asynchttpclient.ws.{WebSocket, WebSocketListener, WebSocketUpgradeHandler}\nimport quix.api.v1.execute.{ExecutionEvent, StartCommand}\nimport quix.core.utils.JsonOps.Implicits.global\nimport quix.core.utils.StringJsonHelpersSupport\nimport scalaj.http.Http\n\nimport scala.collection.mutable.ListBuffer\nimport scala.concurrent.duration.Duration\nimport scala.concurrent.{Await, Promise}\n\ntrait E2EContext extends StringJsonHelpersSupport {\n  val c = asyncHttpClient()\n\n  val jettyPort = \"8888\"\n\n  def get[T: Manifest](url: String, port: String = jettyPort): T = {\n    Http(s\"http://localhost:$port/\" + url).asString.body.as[T]\n  }\n\n  def getResponse(url: String, port: String = jettyPort) = {\n    Http(s\"http://localhost:$port\" + url).asString\n  }\n\n  def execute(sql: String, session: Map[String, String] = Map.empty,\n              module: String, port: String = jettyPort) = {\n    startSocket(true, List(ExecutionEvent(\"execute\", StartCommand[String](sql, session)).asJsonStr), module, port)\n  }\n\n  def send(text: String,\n           module: String, port: String = jettyPort) = {\n    startSocket(false, List(text), module, port)\n  }\n\n  def runAndDownload(sql: String, module: String, port: String = jettyPort) = {\n    startSocket(false,\n      List(ExecutionEvent(\"execute\", StartCommand[String](sql, Map(\"mode\" -> \"download\"))).asJsonStr),\n      module,\n      port\n    )\n  }\n\n\n  def startSocket(awaitFinish: Boolean, texts: List[String], module: String, port: String) = {\n    val listener = new MyListener(texts)\n\n    val handler = new WebSocketUpgradeHandler.Builder().addWebSocketListener(listener).build()\n\n    c.prepareGet(s\"ws://localhost:$port/api/v1/execute/$module\").execute(handler)\n\n    while (listener.messages.isEmpty)\n      Thread.sleep(10)\n\n    if (awaitFinish) {\n      listener.awaitClosed()\n    }\n\n    listener\n  }\n}\n\nclass MyListener(payloads: List[String]) extends WebSocketListener with StringJsonHelpersSupport {\n\n  import scala.collection.JavaConverters._\n\n  private val closed = Promise[Unit]\n\n  val messages = ListBuffer.empty[String]\n  var opened = false\n\n  def messagesJ = messages.asJava\n\n  override def onOpen(websocket: WebSocket): Unit = {\n    opened = true\n\n    for (payload <- payloads) {\n      websocket.sendTextFrame(payload)\n    }\n  }\n\n  override def onClose(websocket: WebSocket, code: Int, reason: String): Unit = {\n    closed.success(())\n    opened = false\n  }\n\n  override def onError(t: Throwable): Unit = {}\n\n  override def onTextFrame(payload: String, finalFragment: Boolean, rsv: Int): Unit = {\n    messages += payload\n  }\n\n  def await(message: String) = {\n    while (!messages.contains(message))\n      Thread.sleep(10)\n  }\n\n  def awaitClosed(atMost: Duration = Duration.Inf): Unit =\n    Await.result(closed.future, atMost)\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/SpringConfigWithTestExecutor.scala",
    "content": "package quix.web\n\nimport org.springframework.context.annotation.{Bean, Configuration, Import, Primary}\nimport quix.api.v2.execute.ExecutionModule\nimport quix.core.db.{RefreshableAutocomplete, RefreshableCatalogs, RefreshableDb}\nimport quix.core.executions.SqlModule\nimport quix.presto.TestQueryExecutor\nimport quix.presto.db.{PrestoAutocomplete, PrestoCatalogs, PrestoTables}\nimport quix.python.{PythonExecutor, PythonModule}\nimport quix.web.spring._\n\nimport scala.concurrent.duration.FiniteDuration\n\n@Configuration\n@Import(Array(classOf[SpringConfig]))\nclass SpringConfigWithTestExecutor {\n\n  @Bean\n  @Primary\n  def initModules: Map[String, ExecutionModule] = {\n    Map(\n      \"presto-prod\" -> new SqlModule(MockBeans.queryExecutor, Some(MockBeans.db)),\n      \"presto-dev\" -> new SqlModule(MockBeans.queryExecutor, Some(MockBeans.db)),\n      \"snake\" -> new PythonModule(new PythonExecutor)\n    )\n  }\n}\n\nobject MockBeans {\n  val duration = FiniteDuration(5, \"seconds\").toMillis\n  val queryExecutor = new TestQueryExecutor\n\n  val catalogs = new PrestoCatalogs(queryExecutor)\n  val autocomplete = new PrestoAutocomplete(catalogs, queryExecutor)\n  val tables = new PrestoTables(queryExecutor, 60000)\n\n  val refreshableCatalogs = new RefreshableCatalogs(catalogs, 60000, 6000)\n  val refreshableAutocomplete = new RefreshableAutocomplete(autocomplete, 60000, 60000)\n\n  val db = new RefreshableDb(refreshableCatalogs, refreshableAutocomplete, tables)\n}"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/auth/DemoUsersTest.scala",
    "content": "package quix.web.auth\n\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport pdi.jwt.{Jwt, JwtAlgorithm}\n\nclass DemoUsersTest extends SpecWithJUnit {\n\n  class ctx extends Scope {\n    val users = new DemoUsers(new JwtUsers(\"header\", \"secret\"))\n  }\n\n  \"DemoUsers\" should {\n    \"mask email\" in new ctx {\n      val header = Jwt.encode(\"\"\"{\"email\":\"user@quix.com\"}\"\"\", \"secret\", JwtAlgorithm.HS256)\n\n      users.auth(Map(\"header\" -> header))(user => user.email) must_== \"*******@quix.com\"\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/auth/JwtUsersTest.scala",
    "content": "package quix.web.auth\n\nimport org.specs2.mutable.SpecWithJUnit\nimport org.specs2.specification.Scope\nimport pdi.jwt.{Jwt, JwtAlgorithm}\nimport quix.api.v1.users.RequestNotAuthenticated\n\nclass JwtUsersTest extends SpecWithJUnit {\n\n  class ctx extends Scope {\n    val users = new JwtUsers(\"header\", \"secret\")\n  }\n\n  \"JwtUsers\" should {\n    \"throw an exception if header is missing\" in new ctx {\n      users.auth(Map.empty)(_ => \"OK\") must throwA[RequestNotAuthenticated]\n    }\n\n    \"throw an exception if header can't be decoded\" in new ctx {\n      users.auth(Map(\"header\" -> \"foo\"))(_ => \"OK\") must throwA[RequestNotAuthenticated]\n    }\n\n    \"throw an exception if payload can't be read into User class\" in new ctx {\n      val header = Jwt.encode(\"\"\"bad payload\"\"\", \"secret\", JwtAlgorithm.HS256)\n\n      users.auth(Map(\"header\" -> header))(_ => \"OK\") must throwA[RequestNotAuthenticated]\n    }\n\n    \"evaluate code block is header is encoded and decoded correctly\" in new ctx {\n      val header = Jwt.encode(\"\"\"{\"email\":\"user@quix\"}\"\"\", \"secret\", JwtAlgorithm.HS256)\n\n      users.auth(Map(\"header\" -> header))(_ => \"OK\") must_== \"OK\"\n    }\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/DownloadControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers\nimport org.junit.runner.RunWith\nimport org.junit.{Before, Test}\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.junit4.SpringRunner\nimport org.springframework.test.context.{TestContextManager, TestPropertySource}\nimport quix.web.{E2EContext, MockBeans, SpringConfigWithTestExecutor}\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfigWithTestExecutor]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass DownloadControllerTest extends E2EContext {\n\n  new TestContextManager(this.getClass).prepareTestInstance(this)\n  val executor = MockBeans.queryExecutor\n\n  @Before\n  def executeBeforeEachTest: Unit = {\n    executor.clear\n  }\n\n  @Test\n  def passSanity(): Unit = {\n    val response = getResponse(\"/api/download/i-do-not-exist\")\n\n    assertThat(response.code, Matchers.is(404))\n  }\n\n  @Test\n  def sendSingleQuery(): Unit = {\n    executor.withResults(List(List(\"1\")), columns = List(\"_col0\"), queryId = \"query-id-1\")\n    val listener = runAndDownload(\"select 1\", \"presto-prod\")\n\n    listener.await(\"\"\"{\"event\":\"query-download\",\"data\":{\"id\":\"query-id-1\",\"url\":\"/api/download/query-id-1\"}}\"\"\")\n\n    val response = getResponse(\"/api/download/query-id-1\")\n\n    assertThat(response.body, Matchers.is(\n      \"\"\"\"_col0\"\n        |\"1\"\n        |\"\"\".stripMargin))\n  }\n\n  @Test\n  def sendMultipleQueries(): Unit = {\n    executor\n      .withResults(List(List(\"1\")), columns = List(\"foo\"), queryId = \"query-id-1\")\n      .withResults(List(List(\"2\")), columns = List(\"bar\"), queryId = \"query-id-2\")\n\n    val listener = runAndDownload(\"select 1 as foo;\\nselect 2 as bar;\", \"presto-dev\")\n\n    listener.await(\"\"\"{\"event\":\"query-download\",\"data\":{\"id\":\"query-id-1\",\"url\":\"/api/download/query-id-1\"}}\"\"\")\n    val first = getResponse(\"/api/download/query-id-1\")\n\n    listener.await(\"\"\"{\"event\":\"query-download\",\"data\":{\"id\":\"query-id-2\",\"url\":\"/api/download/query-id-2\"}}\"\"\")\n    val second = getResponse(\"/api/download/query-id-2\")\n\n    assertThat(first.body, Matchers.is(\n      \"\"\"\"foo\"\n        |\"1\"\n        |\"\"\".stripMargin))\n    assertThat(second.body, Matchers.is(\n      \"\"\"\"bar\"\n        |\"2\"\n        |\"\"\".stripMargin))\n  }\n\n  @Test\n  def sendSingleQueryWithQuotedJson(): Unit = {\n    executor.withResults(List(List(\"\"\"{\"k1\":1,\"k2\":2}\"\"\")), columns = List(\"data\"), queryId = \"query-id-3\")\n    val listener = runAndDownload(\"select data\", \"presto-prod\")\n\n    listener.await(\"\"\"{\"event\":\"query-download\",\"data\":{\"id\":\"query-id-3\",\"url\":\"/api/download/query-id-3\"}}\"\"\")\n\n    val response = getResponse(\"/api/download/query-id-3\")\n\n    assertThat(response.body, Matchers.is(\n      \"\"\"\"data\"\n        |\"{\"\"k1\"\":1,\"\"k2\"\":2}\"\n        |\"\"\".stripMargin))\n  }\n\n  @Test\n  def sendSingleQueryWithNulls(): Unit = {\n    executor.withResults(List(List(null)), columns = List(\"_col0\"), queryId = \"query-id-1\")\n    val listener = runAndDownload(\"select 1\", \"presto-prod\")\n\n    listener.await(\"\"\"{\"event\":\"query-download\",\"data\":{\"id\":\"query-id-1\",\"url\":\"/api/download/query-id-1\"}}\"\"\")\n\n    val response = getResponse(\"/api/download/query-id-1\")\n\n    assertThat(response.body, Matchers.is(\n      \"\"\"\"_col0\"\n        |\"\"\n        |\"\"\".stripMargin))\n  }\n\n}\n\n\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/EmbeddedMySql.scala",
    "content": "package quix.web.controllers\n\nimport com.wix.mysql.EmbeddedMysql\nimport com.wix.mysql.EmbeddedMysql.anEmbeddedMysql\nimport com.wix.mysql.ScriptResolver.classPathScript\nimport com.wix.mysql.config.Charset.UTF8\nimport com.wix.mysql.config.MysqldConfig\nimport com.wix.mysql.config.MysqldConfig.aMysqldConfig\nimport com.wix.mysql.distribution.Version.v5_6_23\n\nobject EmbeddedMySql {\n  def create(port: Int, user: String, pass: String): EmbeddedMysql.Builder = {\n    val config: MysqldConfig = aMysqldConfig(v5_6_23)\n      .withCharset(UTF8)\n      .withPort(port)\n      .withUser(user, pass)\n      .build()\n\n    val embeddedServer: EmbeddedMysql.Builder = anEmbeddedMysql(config)\n      .addSchema(\"aschema\", classPathScript(\"db/001_init.sql\"))\n\n    embeddedServer\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/ExecutionEventTest.scala",
    "content": "package quix.web.controllers\n\nimport org.specs2.mutable.SpecWithJUnit\nimport quix.api.v1.execute.{Empty, StartCommand}\n\nclass ExecutionEventTest extends SpecWithJUnit {\n\n  \"ExecutionEvent\" should {\n    \"fallback to Empty on unknown payloads\" in {\n\n      \"foo\" match {\n        case ExecutionEvent(_, data) =>\n          data must_=== Empty\n      }\n    }\n\n    \"handle ping command\" in {\n      \"\"\"{\"event\" : \"ping\"}\"\"\" match {\n        case ExecutionEvent(name, data) =>\n          name must_=== \"ping\"\n          data must_=== Empty\n      }\n    }\n\n    \"handle execute command with empty session and text\" in {\n      \"\"\"{\"event\" : \"execute\", \"data\" : {\"code\" : \"\"}}\"\"\" match {\n        case ExecutionEvent(name, data) =>\n          name must_=== \"execute\"\n          data must_=== StartCommand(\"\", Map.empty)\n      }\n    }\n\n    \"handle execute command with empty session and non empty text\" in {\n      \"\"\"{\"event\" : \"execute\", \"data\" : {\"code\" : \"select 1\"}}\"\"\" match {\n        case ExecutionEvent(name, data) =>\n          name must_=== \"execute\"\n          data must_=== StartCommand(\"select 1\", Map.empty)\n      }\n    }\n\n    \"handle execute command with session and text\" in {\n      \"\"\"{\"event\" : \"execute\", \"data\" : {\"code\" : \"select 1\", \"session\" : {\"foo\" : \"123\"}}}\"\"\" match {\n        case ExecutionEvent(name, data) =>\n          name must_=== \"execute\"\n          data must_=== StartCommand(\"select 1\", Map(\"foo\" -> \"123\"))\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/HealthControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.junit4.SpringRunner\nimport org.springframework.test.context.{TestContextManager, TestPropertySource}\nimport quix.web.{E2EContext, SpringConfigWithTestExecutor}\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfigWithTestExecutor]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass HealthControllerTest extends E2EContext {\n\n  new TestContextManager(this.getClass).prepareTestInstance(this)\n\n  @Test\n  def serverShouldBeHealthAfterStartup(): Unit = {\n    val health = getResponse(\"/health/is_alive\")\n\n    assertThat(health.code, Matchers.is(200))\n    assertThat(health.body, Matchers.isEmptyString)\n  }\n}\n\n\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/HistoryControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport com.typesafe.scalalogging.LazyLogging\nimport com.wix.mysql.ScriptResolver.classPathScript\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers\nimport org.junit.runner.RunWith\nimport org.junit.{After, Before, Test}\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.TestPropertySource\nimport org.springframework.test.context.junit4.SpringRunner\nimport quix.web.E2EContext\nimport quix.web.spring.SpringConfig\n\nimport scala.collection.JavaConverters._\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfig]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass HistoryControllerTest extends E2EContext with LazyLogging {\n\n  private val prod = EmbeddedMySql.create(2222, \"prod-user\", \"prod-pass\").start()\n\n  @Before\n  def before(): Unit = {\n    prod.reloadSchema(\"aschema\", classPathScript(\"db/001_init.sql\"))\n  }\n\n  @After\n  def after(): Unit = {\n    prod.stop()\n  }\n\n  @Test(timeout = 30000)\n  def listExecutionsHistory(): Unit = {\n    val query = \"select * from small_table\"\n    execute(query, module = \"prod\")\n\n    val records = get[List[ExecutionDto]](\"api/history/executions\")\n\n    assertThat(records.head.query.asJava, Matchers.contains(query))\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/JdbcSqlStreamingControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport com.typesafe.scalalogging.LazyLogging\nimport com.wix.mysql.ScriptResolver.classPathScript\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers\nimport org.hamcrest.text.MatchesPattern.matchesPattern\nimport org.junit.runner.RunWith\nimport org.junit.{After, Before, Test}\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.junit4.SpringRunner\nimport org.springframework.test.context.{TestContextManager, TestPropertySource}\nimport quix.web.E2EContext\nimport quix.web.controllers.MyMatchers._\nimport quix.web.spring.SpringConfig\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfig]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass JdbcSqlStreamingControllerTest extends E2EContext with LazyLogging {\n\n  new TestContextManager(getClass).prepareTestInstance(this)\n\n  private val prod = EmbeddedMySql.create(2222, \"prod-user\", \"prod-pass\").start()\n  private val dev = EmbeddedMySql.create(3333, \"dev-user\", \"dev-pass\").start()\n\n  @Before\n  def before(): Unit = {\n    prod.reloadSchema(\"aschema\", classPathScript(\"db/001_init.sql\"))\n    dev.reloadSchema(\"aschema\", classPathScript(\"db/001_init.sql\"))\n  }\n\n  @After\n  def after(): Unit = {\n    prod.stop()\n    dev.stop()\n  }\n\n  @Test(timeout = 30000)\n  def queryProdShouldPassSanity(): Unit = {\n    val listener = execute(\"select * from small_table\", module = \"prod\")\n\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"start\",\"data\":{\"id\":\"query-id\",\"numOfQueries\":1}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"query-start\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"query-details\",\"data\":{\"id\":\"query-id\",\"code\":\"select * from small_table\"}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"fields\",\"data\":{\"id\":\"query-id\",\"fields\":[\"col1\"]}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"row\",\"data\":{\"id\":\"query-id\",\"values\":[1]}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"query-end\",\"data\":{\"id\":\"query-id\",\"statistics\":{}}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"end\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n  }\n\n  @Test(timeout = 30000)\n  def queryDevShouldPassSanity(): Unit = {\n    val listener = execute(\"select * from small_table\", module = \"dev\")\n\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"start\",\"data\":{\"id\":\"query-id\",\"numOfQueries\":1}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"query-start\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"query-details\",\"data\":{\"id\":\"query-id\",\"code\":\"select * from small_table\"}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"fields\",\"data\":{\"id\":\"query-id\",\"fields\":[\"col1\"]}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"row\",\"data\":{\"id\":\"query-id\",\"values\":[1]}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"query-end\",\"data\":{\"id\":\"query-id\",\"statistics\":{}}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"end\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n  }\n\n}\n\nobject MyMatchers {\n  def hasEvent(e: String) = {\n    val event = e\n      .replace(\"*\", \"\\\\*\")\n      .replace(\"[\", \"\\\\[\")\n      .replace(\"]\", \"\\\\]\")\n      .replace(\"{\", \"\\\\{\")\n      .replace(\"}\", \"\\\\}\")\n      .replaceAll(\"query-id\", \"\"\".{36,37}\"\"\")\n\n    Matchers.hasItem(matchesPattern(event))\n  }\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/PrestoDbControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers\nimport org.junit.runner.RunWith\nimport org.junit.{Before, Test}\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.junit4.SpringRunner\nimport org.springframework.test.context.{TestContextManager, TestPropertySource}\nimport quix.api.v1.db.{Catalog, Kolumn, Schema, Table}\nimport quix.core.db.State\nimport quix.web.{E2EContext, MockBeans, SpringConfigWithTestExecutor}\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfigWithTestExecutor]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass PrestoDbControllerTest extends E2EContext {\n\n  new TestContextManager(this.getClass).prepareTestInstance(this)\n  val executor = MockBeans.queryExecutor\n  val db = MockBeans.db\n  val prestoCatalogs = MockBeans.refreshableCatalogs\n\n  @Before\n  def executeBeforeEachTest = {\n    executor.clear\n    MockBeans.refreshableAutocomplete.state = State(Map.empty, 0L)\n    MockBeans.refreshableCatalogs.state = State(List.empty, 0L)\n  }\n\n  @Test\n  def returnEmptyCatalogsWhenPrestoIsDown(): Unit = {\n    executor.withExceptions(new Exception(\"presto is down!\"), 100)\n\n    val catalogs = get[List[Catalog]](\"api/db/presto-prod/explore\")\n\n    assertThat(catalogs, Matchers.is(List.empty[Catalog]))\n  }\n\n  @Test\n  def sendFastPrestoQueryWhenDBTreeIsEmptyAndSlowInBackground(): Unit = {\n    executor\n      .withResults(List(List(\"catalog1\")))\n      .withResults(List(List(\"catalog1\", \"schema\", \"table\")))\n\n    val catalogs = get[List[Catalog]](\"api/db/presto-prod/explore\")\n    val resultOfFastQuery = Catalog(\"catalog1\", children = Nil)\n    assertThat(catalogs, Matchers.is(List(resultOfFastQuery)))\n\n  }\n\n  @Test\n  def returnEmptyListForNonMatchingQuery(): Unit = {\n    executor.withResults(List(List(\"catalog\", \"schema\", \"table\")))\n\n    val catalogs = get[List[Catalog]](\"api/db/presto-prod/search?q=foo\")\n\n    assertThat(catalogs, Matchers.is(List.empty[Catalog]))\n  }\n\n  @Test\n  def searchByTableName(): Unit = {\n    val catalog = Catalog(\"catalog\", children = List(Schema(\"schema\", children = List(Table(\"table\", Nil)))))\n    prestoCatalogs.state = prestoCatalogs.state.copy(data = List(catalog), expirationDate = Long.MaxValue)\n\n    val catalogs = get[List[Catalog]](\"api/db/presto-prod/search?q=table\")\n\n    assertThat(catalogs, Matchers.is(List(catalog)))\n  }\n\n  @Test\n  def searchBySchemaName(): Unit = {\n    val catalog = Catalog(\"catalog\", children = List(Schema(\"schema\", children = Nil)))\n    prestoCatalogs.state = prestoCatalogs.state.copy(data = List(catalog), expirationDate = Long.MaxValue)\n\n    val catalogs = get[List[Catalog]](\"api/db/presto-prod/search?q=schema\")\n\n    assertThat(catalogs, Matchers.is(List(catalog)))\n  }\n\n  @Test\n  def searchByCatalogName(): Unit = {\n    executor\n      .withResults(List(List(\"catalog\")))\n      .withResults(List(List(\"catalog\", \"schema\", \"table\")))\n\n    val catalogs = get[List[Catalog]](\"api/db/presto-prod/search?q=catalog\")\n\n    val catalog = Catalog(\"catalog\", children = Nil)\n\n    assertThat(catalogs, Matchers.is(List(catalog)))\n  }\n\n  @Test\n  def handleGetTableRequestWhenPrestoIsOnline(): Unit = {\n    executor.withResults(List(List(\"column1\", \"varchar\"), List(\"column2\", \"int\")))\n\n    val actual = get[Table](\"api/db/presto-prod/explore/catalog/schema/table\")\n\n    val expected = Table(\"table\", List(Kolumn(\"column1\", \"varchar\"), Kolumn(\"column2\", \"int\")))\n\n    assertThat(actual, Matchers.is(expected))\n  }\n\n  @Test\n  def handleGetTableRequestWhenPrestoIsDown(): Unit = {\n    executor.withException(new Exception(\"presto is down!\"))\n\n    val actual = get[Table](\"api/db/presto-prod/explore/catalog/schema/table\")\n\n    val expected = Table(\"table\", children = Nil)\n\n    assertThat(actual, Matchers.is(expected))\n  }\n\n  @Test\n  def handleAutoCompleteRequestWhenPrestoIsOffline(): Unit = {\n    executor.withExceptions(new Exception(\"presto is down\"), 100)\n\n    val actual = get[Map[String, List[String]]](\"api/db/presto-prod/autocomplete\")\n\n    assertThat(actual(\"catalogs\").isEmpty, Matchers.is(true))\n    assertThat(actual(\"schemas\").isEmpty, Matchers.is(true))\n    assertThat(actual(\"tables\").isEmpty, Matchers.is(true))\n    assertThat(actual(\"columns\").isEmpty, Matchers.is(true))\n  }\n\n  @Test\n  def handleAutoCompleteRequestWhenAutocompleteStateIsEmpty(): Unit = {\n    executor\n      .withResults(List(List(\"catalog1\"), List(\"catalog2\")))\n      .withResults(List(List(\"column1\"), List(\"column2\")))\n\n    val actual = get[Map[String, List[String]]](\"api/db/presto-prod/autocomplete\")\n\n    assertThat(actual(\"catalogs\"), Matchers.is(List(\"catalog1\", \"catalog2\")))\n    assertThat(actual(\"columns\"), Matchers.is(List(\"column1\", \"column2\")))\n  }\n\n  @Test\n  def handleAutoCompleteRequestWhenAutocompleteStateExists(): Unit = {\n    MockBeans.refreshableAutocomplete.state = State(Map(\"foo\" -> List(\"boo\")), Long.MaxValue)\n\n    executor.withException(new Exception(\"boom!\"))\n    val actual = get[Map[String, List[String]]](\"api/db/presto-prod/autocomplete\")\n\n    assertThat(actual(\"foo\"), Matchers.is(List(\"boo\")))\n  }\n\n  @Test\n  def returnListOfSchemasOnCorrectCatalogName(): Unit = {\n    val mock = Catalog(\"catalog\", children = List(Schema(\"first\", Nil), Schema(\"second\", List(Table(\"first\", Nil)))))\n    MockBeans.refreshableCatalogs.state = State(List(mock), System.currentTimeMillis() + 1000 * 10)\n\n    val firstResults = get[List[Schema]](\"api/db/presto-prod/explore/catalog\")\n    assertThat(firstResults, Matchers.is(mock.children))\n  }\n\n  @Test\n  def returnEmptyListOfSchemasOnInvalidCatalogName(): Unit = {\n    val mock = Catalog(\"catalog\", children = List(Schema(\"first\", Nil), Schema(\"second\", List(Table(\"first\", Nil)))))\n    MockBeans.refreshableCatalogs.state = State(List(mock), System.currentTimeMillis() + 1000 * 10)\n\n    val firstResults = get[List[Schema]](\"api/db/presto-prod/explore/i-do-not-exist\")\n    assertThat(firstResults, Matchers.is(List.empty[Schema]))\n  }\n\n  @Test\n  def returnListOfTablesOnCorrectCatalogNameAndSchemaName(): Unit = {\n    val mock = Catalog(\"catalog\", children = List(Schema(\"first\", Nil), Schema(\"second\", List(Table(\"first\", Nil)))))\n    MockBeans.refreshableCatalogs.state = State(List(mock), System.currentTimeMillis() + 1000 * 10)\n\n    val firstResults = get[List[Table]](\"api/db/presto-prod/explore/catalog/second\")\n    assertThat(firstResults, Matchers.is(List(Table(\"first\", Nil))))\n  }\n\n  @Test\n  def returnEmptyListOfTablesOnInvalidCatalogNameOrSchemaName(): Unit = {\n    val mock = Catalog(\"catalog\", children = List(Schema(\"first\", Nil), Schema(\"second\", List(Table(\"first\", Nil)))))\n    MockBeans.refreshableCatalogs.state = State(List(mock), System.currentTimeMillis() + 1000 * 10)\n\n    val results = get[List[Table]](\"api/db/presto-prod/explore/catalog/foo\")\n    assertThat(results, Matchers.is(List.empty[Table]))\n  }\n}\n\n\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/PythonStreamingControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport com.typesafe.scalalogging.LazyLogging\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.junit.Test\nimport org.junit.runner.RunWith\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.junit4.SpringRunner\nimport org.springframework.test.context.{TestContextManager, TestPropertySource}\nimport quix.web.controllers.MyMatchers._\nimport quix.web.{E2EContext, SpringConfigWithTestExecutor}\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfigWithTestExecutor]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass PythonStreamingControllerTest extends E2EContext with LazyLogging {\n\n  new TestContextManager(this.getClass).prepareTestInstance(this)\n\n  @Test\n  def passSanity(): Unit = {\n    val listener = execute(\"print(123)\", module = \"snake\")\n\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"start\",\"data\":{\"id\":\"query-id\",\"numOfQueries\":1}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"log\",\"data\":{\"id\":\"query-id\",\"line\":\"123\",\"level\":\"INFO\"}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"end\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n  }\n\n  @Test\n  def installAndUseCustomModule(): Unit = {\n    val listener = execute(sql =\n      \"\"\"packages.install('numpy')\n        |\n        |import numpy as np\n        |a = np.arange(6)\n        |print(a)\n        |\"\"\".stripMargin, module = \"snake\")\n\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"start\",\"data\":{\"id\":\"query-id\",\"numOfQueries\":1}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"log\",\"data\":{\"id\":\"query-id\",\"line\":\"[0 1 2 3 4 5]\",\"level\":\"INFO\"}}\"\"\"))\n    assertThat(listener.messagesJ, hasEvent(\"\"\"{\"event\":\"end\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n  }\n\n\n}\n"
  },
  {
    "path": "quix-backend/quix-webapps/quix-web-spring/src/test/scala/quix/web/controllers/SqlStreamingControllerTest.scala",
    "content": "package quix.web.controllers\n\nimport com.typesafe.scalalogging.LazyLogging\nimport org.hamcrest.MatcherAssert.assertThat\nimport org.hamcrest.Matchers\nimport org.junit.runner.RunWith\nimport org.junit.{Before, Test}\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT\nimport org.springframework.test.annotation.DirtiesContext\nimport org.springframework.test.context.junit4.SpringRunner\nimport org.springframework.test.context.{TestContextManager, TestPropertySource}\nimport quix.web.{E2EContext, MockBeans, SpringConfigWithTestExecutor}\n\n@RunWith(classOf[SpringRunner])\n@DirtiesContext\n@SpringBootTest(webEnvironment = DEFINED_PORT, classes = Array(classOf[SpringConfigWithTestExecutor]))\n@TestPropertySource(locations = Array(\"classpath:test.properties\"))\nclass SqlStreamingControllerTest extends E2EContext with LazyLogging {\n\n  new TestContextManager(this.getClass).prepareTestInstance(this)\n\n  val executor = MockBeans.queryExecutor\n\n  @Before\n  def executeBeforeEachTest(): Unit = executor.clear\n\n  @Test\n  def passSanity(): Unit = {\n    executor.withResults(List(List(\"1\")), columns = List(\"_col0\"))\n    val listener = execute(\"select 1\", module = \"presto-prod\")\n\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-start\",\"data\":{\"id\":\"query-id\"}}\"\"\"))\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-details\",\"data\":{\"id\":\"query-id\",\"code\":\"select 1\"}}\"\"\"))\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"percentage\",\"data\":{\"id\":\"query-id\",\"percentage\":0}}\"\"\"))\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"fields\",\"data\":{\"id\":\"query-id\",\"fields\":[\"_col0\"]}}\"\"\"))\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"row\",\"data\":{\"id\":\"query-id\",\"values\":[\"1\"]}}\"\"\"))\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"percentage\",\"data\":{\"id\":\"query-id\",\"percentage\":100}}\"\"\"))\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-end\",\"data\":{\"id\":\"query-id\",\"statistics\":{}}}\"\"\"))\n  }\n\n  @Test\n  def handleUnknownMessage(): Unit = {\n    executor.withResults(List(List(\"1\")), columns = List(\"_col0\"))\n    val listener = send(\"ping\", \"presto-prod\")\n\n    assertThat(listener.messagesJ, Matchers.hasItem(Matchers.containsString(\"Failed to handle unknown message : [ping]\")))\n  }\n\n  @Test\n  def handlePingEvent(): Unit = {\n    executor.withResults(List(List(\"1\")), columns = List(\"_col0\"))\n    val listener = send(\"\"\"{\"event\":\"ping\"}\"\"\", \"presto-prod\")\n\n    assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"pong\",\"data\":{}}\"\"\"))\n  }\n\n  @Test\n  def handleMultipleStatements(): Unit = {\n    executor\n      .withResults(List(List(\"1\")), queryId = \"query-1\", columns = List(\"foo\"))\n      .withResults(List(List(\"2\")), queryId = \"query-2\", columns = List(\"boo\"))\n\n    val listener = execute(\"select 1 as foo;\\nselect 2 as boo\", module = \"presto-prod\")\n\n    // first query\n    {\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-start\",\"data\":{\"id\":\"query-1\"}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-details\",\"data\":{\"id\":\"query-1\",\"code\":\"select 1 as foo\"}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"fields\",\"data\":{\"id\":\"query-1\",\"fields\":[\"foo\"]}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"percentage\",\"data\":{\"id\":\"query-1\",\"percentage\":0}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"row\",\"data\":{\"id\":\"query-1\",\"values\":[\"1\"]}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"percentage\",\"data\":{\"id\":\"query-1\",\"percentage\":100}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-end\",\"data\":{\"id\":\"query-1\",\"statistics\":{}}}\"\"\"))\n    }\n\n    // second query\n    {\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-start\",\"data\":{\"id\":\"query-2\"}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-details\",\"data\":{\"id\":\"query-2\",\"code\":\"select 2 as boo\"}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"fields\",\"data\":{\"id\":\"query-2\",\"fields\":[\"boo\"]}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"percentage\",\"data\":{\"id\":\"query-2\",\"percentage\":0}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"row\",\"data\":{\"id\":\"query-2\",\"values\":[\"2\"]}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"percentage\",\"data\":{\"id\":\"query-2\",\"percentage\":100}}\"\"\"))\n      assertThat(listener.messagesJ, Matchers.hasItem(\"\"\"{\"event\":\"query-end\",\"data\":{\"id\":\"query-2\",\"statistics\":{}}}\"\"\"))\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "quix-backend/version.sbt",
    "content": "ThisBuild / version := \"1.0.12-SNAPSHOT\""
  },
  {
    "path": "quix-frontend/.dockerignore",
    "content": "**/node_modules/*\n**/dist*\nservice/statics*\n.dockerignore\nDockerfile\n.vscode\n"
  },
  {
    "path": "quix-frontend/.nvmrc",
    "content": "14"
  },
  {
    "path": "quix-frontend/Dockerfile",
    "content": "FROM node:14-buster as build\n\nRUN useradd -ms /bin/bash builduser\nUSER builduser\nCOPY --chown=builduser ./ /app\nWORKDIR /app\nRUN npm install\nWORKDIR /app/service\nRUN npm run build\nWORKDIR /app/shared\nRUN npm prune --prodcution\nWORKDIR /app/service\nRUN npm prune --production\n\nFROM node:14-buster-slim\nRUN useradd -ms /bin/bash appuser\nCOPY --from=build --chown=appuser /app/shared /shared\nCOPY --from=build --chown=appuser /app/service /service\nWORKDIR /shared\nRUN npm link\nWORKDIR /service\nRUN npm link @wix/quix-shared\n\nUSER appuser\nWORKDIR /service\nRUN rm -f .env || true\nUSER root\nRUN npm install -g pm2\nRUN mkdir /logs\nRUN chown appuser /logs\nUSER appuser\n\nEXPOSE 3000\nCMD [\"pm2-runtime\", \"start\", \"ecosystem.config.js\"]\n\n"
  },
  {
    "path": "quix-frontend/README.md",
    "content": "# Quix Frontend\nQuix frontend serves the UI.\n\n\n## Requirements\n* NodeJS\n* MySQL 5.7\n\n## Setup\nYou can set up your DB either by providing environment variables or by directly changing default settings.\n\n### Environment variables\nApplication uses the following environment variables to connect to DB:\n* DB_NAME - defaults to `quix`\n* DB_USER - defaults to `root`\n* DB_PASS - defaults to empty password\n* DB_HOST - defaults to `localhost`\n* DB_PORT - defaults to `3306`\n\n### Default settings\nDefault settings for DB can be found under [service/src/config/env.ts](./service/src/config/env.ts)\n\n### MySQL 8 considerations\nIf you're using MySQL 8, you may need to run the following command on your DB:\n``` \nALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '';\n```\n\n## Docker\n\n### Starting\n```\ndocker build -t quix-frontend . && docker run --name quix-frontend -p 3000:3000 -t quix-frontend\n```\n\n### Stopping \n```\ndocker stop quix-frontend && docker rm quix-frontend\n```\n\n### License\nMIT"
  },
  {
    "path": "quix-frontend/client/.dockerignore",
    "content": "package-lock.json"
  },
  {
    "path": "quix-frontend/client/.gitignore",
    "content": "node_modules\ndist\ntarget\ncoverage\nmaven\nvelocity.private.data.js\ntest/e2e/screenshots\n*npm-debug.log\n.history\n.idea\n*.iml\n.yo-rc.json\n"
  },
  {
    "path": "quix-frontend/client/.npmignore",
    "content": ""
  },
  {
    "path": "quix-frontend/client/.npmrc",
    "content": "registry=https://registry.npmjs.org\n"
  },
  {
    "path": "quix-frontend/client/.nvmrc",
    "content": "14\n"
  },
  {
    "path": "quix-frontend/client/README.md",
    "content": "## Installation\n\n```bash\n$ npm i\n$ cd ../shared\n$ npm i\n$ cd ../client\n```\n\n## Running the app\nServe a local instance of Quix UI with mock data\n\n```bash\n$ npm start\n```\n\n## Test\n\n```bash\n$ npm run test\n```\n"
  },
  {
    "path": "quix-frontend/client/index.js",
    "content": "require('ts-node/register');\nconst {start} = require('./test/dev/server');\n\nstart();\n"
  },
  {
    "path": "quix-frontend/client/package.json",
    "content": "{\n  \"name\": \"@wix/quix-client\",\n  \"version\": \"1.0.138\",\n  \"license\": \"MIT\",\n  \"description\": \"Presto-based notebook manager\",\n  \"author\": {\n    \"name\": \"Anton Podolsky\",\n    \"email\": \"antonp@wix.com\"\n  },\n  \"contributors\": [\n    {\n      \"name\": \"Aviad Hadad\",\n      \"email\": \"aviadh@wix.com\"\n    }\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"files\": [\n    \"dist/src\"\n  ],\n  \"main\": \"dist/src/app.js\",\n  \"types\": \"dist/src/app.d.ts\",\n  \"scripts\": {\n    \"start\": \"tsc -b && yoshi start\",\n    \"precommit\": \"yoshi lint\",\n    \"pretest\": \"npm run build\",\n    \"test\": \"yoshi test\",\n    \"test:ci\": \"yoshi test\",\n    \"build\": \"tsc -b && yoshi build\",\n    \"posttest\": \"yoshi lint\",\n    \"release\": \"yoshi release\"\n  },\n  \"devDependencies\": {\n    \"@types/angular\": \"~1.5.0\",\n    \"@types/chai\": \"~4.0.0\",\n    \"@types/cookie\": \"^0.3.3\",\n    \"@types/daterangepicker\": \"^3.1.4\",\n    \"@types/express\": \"^4.0.0\",\n    \"@types/express-ws\": \"^3.0.0\",\n    \"@types/lodash\": \"^4.14.149\",\n    \"@types/mocha\": \"~2.2.0\",\n    \"@types/node\": \"^8.10.59\",\n    \"@types/puppeteer\": \"^1.20.3\",\n    \"@types/react\": \"^17.0.0\",\n    \"chai\": \"~4.1.0\",\n    \"express\": \"^4.16.4\",\n    \"express-ws\": \"^4.0.0\",\n    \"husky\": \"~0.14.0\",\n    \"puppeteer\": \"^1.20.0\",\n    \"tiny-worker\": \"^2.3.0\",\n    \"typescript\": \"^4.0.0\",\n    \"utility-types\": \"^3.10.0\",\n    \"velocity\": \"~0.7.0\",\n    \"yoshi\": \"^3.23.0\"\n  },\n  \"dependencies\": {\n    \"@popperjs/core\": \"^2.11.0\",\n    \"@wix/quix-shared\": \"^1.0.15\",\n    \"angular\": \"^1.7.9\",\n    \"angular-dragdrop\": \"^1.0.13\",\n    \"angular-resource\": \"^1.7.9\",\n    \"angular-sanitize\": \"^1.7.9\",\n    \"angular-svg-round-progressbar\": \"0.4.8\",\n    \"angular-ui-router\": \"^0.4.2\",\n    \"angular-ui-sortable\": \"^0.19.0\",\n    \"antlr4\": \"4.7.0\",\n    \"bootstrap-daterangepicker\": \"^3.1.0\",\n    \"brace\": \"^0.11.1\",\n    \"bytes\": \"^3.1.0\",\n    \"change-case\": \"^3.1.0\",\n    \"classnames\": \"^2.2.6\",\n    \"debounce-async\": \"0.0.2\",\n    \"dialog-polyfill\": \"^0.4.10\",\n    \"highlight.js\": \"^10.4.1\",\n    \"jquery\": \"^3.3.1\",\n    \"jquery-datetimepicker\": \"^2.5.18\",\n    \"jquery-ui\": \"^1.12.1\",\n    \"js-search\": \"^1.4.3\",\n    \"lodash\": \"^4.17.11\",\n    \"moment\": \"^2.24.0\",\n    \"ng-csv\": \"^0.3.6\",\n    \"node-sass\": \"^4.0.1\",\n    \"popper.js\": \"^1.16.0\",\n    \"react\": \"^16.12.0\",\n    \"react-bootstrap-daterangepicker\": \"^7.0.0\",\n    \"react-dom\": \"^16.12.0\",\n    \"react-highlight-words\": \"^0.16.0\",\n    \"react-infinite-scroller\": \"^1.2.4\",\n    \"react-popper\": \"^2.2.5\",\n    \"react2angular\": \"^4.0.6\",\n    \"redux\": \"^3.7.2\",\n    \"scrollmonitor\": \"^1.2.4\",\n    \"sql-formatter\": \"^2.3.2\",\n    \"transducers.js\": \"^0.3.2\",\n    \"ui-router-extras\": \"^0.1.3\",\n    \"url-pattern\": \"^1.0.3\",\n    \"uuid\": \"^8.3.2\",\n    \"yoshi-angular-dependencies\": \"^4.0.0\",\n    \"yoshi-style-dependencies\": \"^4.0.0\"\n  },\n  \"overrides\": {\n    \"yoshi-style-dependencies\": {\n      \"node-sass\": \"$node-sass\"\n    }\n  },\n  \"yoshi\": {\n    \"cssModules\": false,\n    \"hmr\": \"auto\",\n    \"entry\": {\n      \"app\": \"./app.ts\"\n    },\n    \"servers\": {\n      \"cdn\": {\n        \"port\": 3200,\n        \"dir\": \"dist/statics\",\n        \"ssl\": false\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/app.scss",
    "content": "@import './lib/ui/assets/css/def/colors.def';\n@import './lib/ui/assets/css/def/defaults.def';\n@import './lib/ui/assets/css/def/icon.def';\n\nbody {\n  background-color: $light-bg;\n}\n\nbi-app {\n  $splashWidth: 150px;\n  $splashHeight: 208px;\n\n  > .quix-splash {\n    position: absolute;\n    width: $splashWidth;\n    height: $splashHeight;\n    top: 50%;\n    left: 50%;\n    margin: (-$splashHeight / 2) 0 0 (-$splashWidth / 2);\n  }\n\n  .quix-splash-logo {\n    width: $splashWidth;\n    filter: drop-shadow(2px 2px 5px $grey--400);\n  }\n}\n\n.quix-content {\n  box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.05);\n\n  .bi-section {\n    &.bi-theme--dark {\n      box-shadow: inset 0 1px 6px $darker-bg;\n    }\n  }\n}\n\n.quix-user-avatar {\n  width: 24px;\n  height: 24px;\n  border-radius: 24px;\n}\n\n.quix-checkbox {\n  display: block;\n  line-height: 0;\n\n  .bi-action {\n    width: 30px;\n    overflow: hidden;\n  }\n\n  i {\n    transition: color, 0.1s;\n    color: $grey--300 !important;\n    font-size: 23px;\n\n    &:not([disabled]) {\n      &:hover,\n      &.checked {\n        color: $muted !important;\n      }\n    }\n  }\n}\n\n.quix-popup {\n  display: none !important;\n\n  &.bm--maximized {\n    display: flex !important;\n  }\n\n  &.quix-search-popup {\n    top: 54px !important;\n    left: 0 !important;\n    right: 0 !important;\n    bottom: 0 !important;\n    padding: 0 !important;\n    border-radius: 0 !important;\n\n    & + .bm-backdrop {\n      display: none !important;\n    }\n\n    .bm-toggle {\n      display: none !important;\n    }\n  }\n}\n\n.bi-table-container.bi-table--nav,\nbi-tbl.bi-table--nav {\n  td {\n    [contenteditable='false'] {\n      padding: 0 !important;\n      border: 0 !important;\n    }\n\n    [contenteditable='true'] {\n      position: relative;\n      top: 3px;\n      padding-top: 0 !important;\n    }\n  }\n\n  .mark-column {\n    width: 42px;\n    padding: 0;\n\n    .quix-checkbox {\n      width: 30px;\n      margin: 6px;\n    }\n  }\n\n  .name-column {\n    padding-left: 0;\n  }\n}\n\n.bi-toast {\n  left: 54px !important;\n  bottom: 12px !important;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/app.ts",
    "content": "import { isArray } from 'lodash';\nimport { setupNotifications } from './bootstrap';\nimport create, { App } from './lib/app';\nimport { hooks } from './hooks';\nimport * as components from './components';\nimport * as stateComponents from './state-components';\nimport * as reactComponents from './react-components';\nimport { branches, initCache } from './store';\nimport { config as runnerConfig } from './lib/runner';\nimport { config as resourcesConfig } from './services/resources';\nimport { pluginManager } from './plugins';\nimport { ClientConfigHelper, ModuleComponentType } from '@wix/quix-shared';\nimport { openTempQuery } from './services';\nimport { inject } from './lib/core';\nimport {\n  AUTO_PARAMS,\n  AUTO_PARAM_DEFAULTS,\n  AUTO_PARAM_TYPES,\n} from './lib/code-editor/services/param-parser/param-types';\nimport { Store } from './lib/store';\nimport { setStats } from './store/app/app-actions';\n\nexport { hooks } from './hooks';\n\nconst clientConfig = ClientConfigHelper.load(window.quixConfig);\n\nconst {\n  staticsBaseUrl,\n  executeBaseUrl,\n  apiBasePath,\n} = clientConfig.getClientTopology();\n\nconst appBuilder = create<ClientConfigHelper>(\n  {\n    id: 'quix',\n    title: 'Quix',\n  },\n  {\n    auth: clientConfig.getAuth(),\n    statePrefix: 'base',\n    defaultUrl: '/home',\n    homeState: 'home',\n    logoUrl: `${staticsBaseUrl}assets/logo_big.png`,\n    apiBasePath,\n  },\n  ['bi.app', 'bi.runner', 'bi.fileExplorer']\n)\n  .config(clientConfig)\n  .plugin('app', (plugin) => {\n    plugin.components(components);\n    plugin.stateComponents(stateComponents);\n    plugin.reactComponents(reactComponents);\n    plugin.store(branches, `${apiBasePath}/api/events`, 'Node');\n\n    plugin.menuItem({\n      name: 'Notebooks',\n      icon: 'description',\n      template:\n        '<quix-files-sidebar class=\"bi-c-h bi-grow\"></quix-files-sidebar>',\n    });\n\n    plugin.menuItem({\n      name: 'DB Explorer',\n      icon: 'storage',\n      template: '<quix-db-sidebar class=\"bi-c-h bi-grow\"></quix-db-sidebar>',\n    });\n\n    plugin.onPluginReady((app, store) => {\n      const autoParams = hooks.note.config.editor.autoParams.call(app, store);\n\n      if (isArray(autoParams)) {\n        autoParams.forEach(({ name, type, defaultValue }) => {\n          AUTO_PARAMS.push(name);\n          AUTO_PARAM_TYPES[name] = type;\n          AUTO_PARAM_DEFAULTS[name] = defaultValue;\n        });\n      }\n\n      runnerConfig.set({\n        executeBaseUrl,\n        apiBasePath,\n      });\n\n      resourcesConfig.set({\n        apiBasePath,\n      });\n\n      clientConfig\n        .getModulesByComponent(ModuleComponentType.Db)\n        .forEach(({ id, engine }) => {\n          pluginManager\n            .module(ModuleComponentType.Db)\n            .plugin(id, engine, app, store);\n        });\n\n      clientConfig\n        .getModulesByComponent(ModuleComponentType.Note)\n        .forEach(({ id, engine }) => {\n          pluginManager\n            .module(ModuleComponentType.Note)\n            .plugin(id, engine, app, store);\n        });\n\n      pluginManager\n        .module(ModuleComponentType.Note)\n        .plugin('default', 'default' as any);\n\n      initCache(store);\n      setupNotifications(staticsBaseUrl);\n\n      app.getModule().controller('app', [\n        '$scope',\n        (scope) => {\n          scope.app = app;\n          scope.store = store;\n        },\n      ] as any);\n\n      app.getNavigator().on('ready', (user) => {\n        store.dispatch(setStats(user.getStats()));\n      });\n    });\n  });\n\nhooks.bootstrap.call(appBuilder);\n\nappBuilder.plugin('dummy', (plugin) => {\n  plugin.menuItem({ name: 'separator' });\n  plugin.menuItem({\n    name: 'Trash Bin',\n    icon: (app: App, store: Store, scope: any) => {\n      scope = scope.$new(true);\n      store.subscribe(\n        'app.stats.trashBinCount',\n        (count) => {\n          scope.count = count;\n        },\n        scope\n      );\n\n      const trashIconHtml = /*html*/ `\n       <bi-icon-with-badge count=\"count\"  \n                           hide=\"count <= 0\"\n                           class=\"bi-action\"\n                           >\n         <i class=\"bi-icon\"\n            title=\"Trash Bin\"\n            role=\"button\"\n            data-hook=\"app-menu-trash-bin\"\n          >\n          {{ count > 0 ? 'delete' : 'delete_outline' }}\n          </i>\n       </bi-icon-with-badge>`;\n\n      return inject('$compile')(trashIconHtml)(scope);\n    },\n    onToggle: (app) => {\n      app.go('trashBin');\n    },\n  });\n  plugin.menuItem({\n    name: 'Playground',\n    icon: 'code',\n    onToggle: () => openTempQuery(inject('$rootScope')),\n  });\n});\n\nappBuilder.build();\n"
  },
  {
    "path": "quix-frontend/client/src/bootstrap.ts",
    "content": "import './lib/ui/bootstrap';\nimport './lib/app';\nimport './lib/file-explorer';\nimport UrlPattern from 'url-pattern';\n\nimport {browserNotificationsManager} from './services';\nimport {INotebook, INote} from '@wix/quix-shared';\n\nimport './app.scss';\n\n(window as any).UrlPattern = UrlPattern;  // expose for e2e tests\n\nexport const setupNotifications = (staticsBaseUrl: string) => {\n  browserNotificationsManager.setStaticsBaseUrl(staticsBaseUrl);\n\n  browserNotificationsManager.register({\n    name: 'runnerFinished',\n    icon: 'assets/notification_success.png',\n    title: 'Quix: Run Finished',\n    onlyWhenHidden: true,\n    body: (note: INote, notebook: INotebook) => {\n      return notebook ?\n        `Note \"${note.name}\" on notebook \"${notebook.name}\" finished successfully.` :\n        `Note \"${note.name}\" finished successfully.`;\n    },\n    onClick(window) {\n      window.focus();\n      this.close();\n    }\n  });\n\n  browserNotificationsManager.register({\n    name: 'runnerError',\n    icon: 'assets/notification_error.png',\n    title: 'Quix: Error',\n    onlyWhenHidden: true,\n    body: (note: INote, notebook: INotebook) => {\n      return notebook ?\n        `Note \"${note.name}\" on notebook \"${notebook.name}\" has encountered an error.` :\n        `Note \"${note.name}\" has encountered an error.`;\n    },\n    onClick() {\n      this.close();\n    }\n  });\n}"
  },
  {
    "path": "quix-frontend/client/src/components/User/UserAvatar.tsx",
    "content": "import React from 'react';\nimport {IUser} from '@wix/quix-shared';\n\ninterface Props {\n  user: IUser;\n}\n\nexport const UserAvatar = (props: Props) => {\n  return <>\n    {props.user.avatar && <img className=\"quix-user-avatar\" src={props.user.avatar}/>}\n    {!props.user.avatar && <i className=\"bi-icon bi-muted\">account_circle</i>}\n  </>\n}"
  },
  {
    "path": "quix-frontend/client/src/components/User/UserAvatarAndName.tsx",
    "content": "import React from 'react';\nimport {IUser} from '@wix/quix-shared';\nimport {UserAvatar} from './UserAvatar';\n\ninterface Props {\n  user: IUser;\n}\n\nexport const UserAvatarAndName = (props: Props) => {\n  return <div className=\"bi-align bi-s-h\">\n    <UserAvatar user={props.user}></UserAvatar>\n    <span>{props.user.name}</span>\n  </div>\n}"
  },
  {
    "path": "quix-frontend/client/src/components/actions/actions-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nconst enum Hooks {\n  Menu = 'actions-menu',\n  Delete = 'actions-delete',\n}\n\nexport class ActionsTestkit extends Testkit {\n  async isDeleteEnabled() {\n    return (await this.query.hook(Hooks.Menu)) !== null;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/components/actions/actions-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {IEntity} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  entity: IEntity\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/actions/actions.html",
    "content": "<div \n  class=\"bi-align\"\n  ng-class=\"::{\n    'quix-actions-reverse': options.reverse,\n    'quix-actions-compact': options.compact,\n    'bi-s-h--x15': !options.compact,\n    'bi-s-h': options.compact\n  }\"\n>\n  <bi-dropdown\n    ng-if=\"permissions.delete && !options.bulk\"\n    bd-options=\"::{align: 'right'}\"\n    data-hook=\"actions-menu\"\n  >\n    <bi-toggle>\n      <i \n        class=\"bi-action\"\n        ng-class=\"::{\n          'bi-icon': !options.compact,\n          'bi-icon--sm': options.compact\n        }\"\n        ng-click=\"$event.stopPropagation();\"\n      >more_horiz</i>\n    </bi-toggle>\n    \n    <ul class=\"bi-dropdown-menu\">\n      <li class=\"bi-align bi-s-h\" ng-click=\"$event.stopPropagation(); events.onDelete()\" data-hook=\"actions-delete\">\n        <i class=\"bi-icon--sm bi-muted\">delete</i>\n        <span>Delete {{::type}}</span>\n      </li>\n    </ul>\n  </bi-dropdown>\n\n  <button\n    class=\"bi-button--danger\"\n    ng-if=\"permissions.delete && options.bulk\"\n    ng-click=\"events.onDelete()\"\n    data-hook=\"actions-delete\"\n  >\n    <i class=\"bi-icon--sm\">delete_sweep</i>\n    <span>Delete {{::type}}s</span>\n  </button>\n\n  <bi-tooltip ng-if=\"::permissions.clone\">\n    <bi-toggle>\n      <i \n        class=\"bi-action\"\n        ng-class=\"::{\n          'bi-icon': !options.compact,\n          'bi-icon--sm': options.compact\n        }\"\n        ng-click=\"$event.stopPropagation(); events.onClone()\"\n      >file_copy</i>\n    </bi-toggle>\n    Clone {{::type}}\n  </bi-tooltip>\n    \n  <bi-tooltip ng-if=\"::permissions.share\">\n    <bi-toggle>\n      <i\n        class=\"bi-action\"\n        ng-class=\"::{\n          'bi-icon': !options.compact,\n          'bi-icon--sm': options.compact\n        }\"\n        ng-click=\"$event.stopPropagation(); events.onShare()\"\n      >share</i>\n    </bi-toggle>\n    Share {{::type}}\n  </bi-tooltip>\n      \n  <bi-tooltip ng-if=\"::permissions.like\">\n    <bi-toggle>\n      <i\n        class=\"bi-action\"\n        ng-class=\"{\n          'bi-icon': !options.compact,\n          'bi-icon--sm': options.compact,\n          'bi-danger': context.isLiked\n        }\"\n        ng-click=\"$event.stopPropagation(); events.onLikeToggle()\"\n      >{{context.isLiked ? 'favorite' :'favorite_border'}}</i>\n    </bi-toggle>\n    {{context.isLiked ? 'Remove' : 'Add'}} {{::type}} {{context.isLiked ? 'from' : 'to'}} favorites\n  </bi-tooltip>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/components/actions/actions.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-actions {\n  .quix-actions-reverse {\n    flex-direction: row-reverse;\n\n    > * {\n      margin-right: 0 !important;\n\n      &:not(:first-child) {\n        margin-right: 15px !important;\n      }\n    }\n\n    &.quix-actions-compact {\n      > * {\n        &:not(:first-child) {\n          margin-right: 10px !important;\n        }\n      }\n    }\n  }\n\n  bi-dropdown {\n    .bd-content {\n      margin-top: 5px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/actions/actions.ts",
    "content": "import template from './actions.html';\nimport './actions.scss';\n\nimport { isArray } from 'lodash';\nimport { initNgScope } from '../../lib/core';\nimport { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IScope } from './actions-types';\nimport { confirmAction } from '../../services';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    type: '@',\n    context: '<',\n    permissions: '<',\n    quixActionsOptions: '<',\n    custom: '<',\n    onLikeToggle: '&',\n    onShare: '&',\n    onClone: '&',\n    onDelete: '&',\n  },\n  link: {\n    async pre(scope: IScope) {\n      initNgScope(scope)\n        .withVM({})\n        .withOptions(\n          'quixActionsOptions',\n          {\n            reverse: false,\n            compact: false,\n            customText: '',\n            confirmOnDelete: true,\n            bulk: isArray(scope.context),\n          },\n          true\n        )\n        .withOptions('custom', {\n          actions: [],\n          handler: () => {},\n        })\n        .withEvents({\n          onLikeToggle() {\n            scope.onLikeToggle({ context: scope.context });\n          },\n          onShare() {\n            scope.onShare({ context: scope.context });\n          },\n          onClone() {\n            scope.onClone({ context: scope.context });\n          },\n          onDelete() {\n            const fn = () => scope.onDelete({ context: scope.context });\n\n            if (!scope.options.confirmOnDelete) {\n              fn();\n            } else {\n              confirmAction(\n                isTrashable(scope) ? 'trash' : 'delete',\n                scope.type,\n                scope.context,\n                scope.options.customText\n              ).then(fn);\n            }\n          },\n        });\n    },\n  },\n});\nfunction isTrashable(scope: IScope) {\n  return (\n    scope.type === 'notebook' ||\n    scope.type === 'folder' ||\n    scope.type === 'item'\n  );\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/breadcrumbs/breadcrumbs-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class BreadcrumbsTestkit extends Testkit {\n  async numOfFiles() {\n    return (await this.query.hooks('file-name')).length;\n  }\n\n  async clickFile(index: number) {\n    const file = (await this.query.hooks('file-name'))[index - 1];\n\n    if (!file) {\n      throw new Error(`No breadcrumbs file at index ${index}`);\n    }\n\n    return file.click();\n  }\n\n  async isFileNameFocused() {\n    return (await this.query.hook('file-name', ':focus')) !== null;\n  }\n\n  async isFileNameEditable() {\n    return this.evaluate.hooks('file-name', els => els[els.length - 1].getAttribute('contenteditable') === 'true');\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/breadcrumbs/breadcrumbs-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {IFile} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  breadcrumbs: IFile;\n  quixBreadcrumbsOptions: Record<string, any>;\n  onFolderClick: Function;\n  onNameChange: Function;\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/breadcrumbs/breadcrumbs.html",
    "content": "<bi-breadcrumbs\n  class=\"bi-dont-shrink\"\n  bi-options=\"item as item.name for item in breadcrumbs\"\n>\n  <div>\n    <span ng-show=\"false\">dummy</span>\n\n    <span\n      ng-if=\"breadcrumbs.length === 1 || $index < breadcrumbs.length - 1\"\n      ng-click=\"events.onFolderClick(item, $index)\"\n      data-hook=\"file-name\"\n    >{{::item.name}}</span>\n\n    <span \n      class=\"bi-align bi-s-h--x05\"\n      ng-if=\"breadcrumbs.length > 1 && $index === breadcrumbs.length - 1\"\n    >\n      <span\n        contenteditable=\"{{!readonly}}\"\n        ng-model=\"item.name\"\n        on-change=\"events.onNameChange(item)\"\n        ce-options=\"::{autoEdit: options.focusName}\"\n        data-hook=\"file-name\"\n      ></span>\n    </span>\n  </div>\n</bi-breadcrumbs>"
  },
  {
    "path": "quix-frontend/client/src/components/breadcrumbs/breadcrumbs.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-breadcrumbs {\n\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/breadcrumbs/breadcrumbs.ts",
    "content": "import template from './breadcrumbs.html';\nimport './breadcrumbs.scss';\n\nimport {initNgScope} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './breadcrumbs-types';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    breadcrumbs: '<',\n    quixBreadcrumbsOptions: '<',\n    readonly: '<',\n    onFolderClick: '&',\n    onNameChange: '&'\n  },\n  link: {\n    async pre(scope: IScope) {\n      initNgScope(scope)\n        .withOptions('quixBreadcrumbsOptions', {\n          focusName: false,\n        })\n        .withVM({})\n        .withEvents({\n          onFolderClick(file, index) {\n            scope.onFolderClick({file, isRoot: index === 0});\n          },\n          onNameChange(file) {\n            scope.onNameChange({file});\n          }\n        });\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/db-sidebar/db-sidebar-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class DbSidebarTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/db-sidebar/db-sidebar-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n}\n\nexport interface ServerTreeItem {\n  name: string;\n  type: 'catalog' | 'schema' | 'table' | 'column';\n  children: ServerTreeItem[];\n}"
  },
  {
    "path": "quix-frontend/client/src/components/db-sidebar/db-sidebar.html",
    "content": "<div class=\"bi-center bi-heading bi-fade-in\" ng-show=\"vm.types.length > 1\">\n  <quix-plugin-picker\n    module=\"db\"\n    ng-model=\"vm.type\"\n    on-change=\"events.onPluginPickerChange(plugin)\"\n    on-load=\"events.onPluginPickerLoad(plugin)\"\n  ></quix-plugin-picker>\n</div>\n\n<div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.before('Content')\">\n  <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Initial')\">\n    <div class=\"bi-empty-state-content\">Loading DB...</div>\n  </div>\n\n  <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Result')\">\n    <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n    <div class=\"bi-empty-state-header\">Database is empty</div>\n    <div class=\"bi-empty-state-content\">\n      <a class=\"bi-link\" ng-click=\"events.onRetryClick()\">Retry</a>\n    </div>\n  </div>\n\n  <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Error')\" data-hook=\"db-sidebar-error\">\n    <quix-image class=\"bi-empty-state-image\" name=\"error_{{::vm.state.value().error.status}}.svg\"></quix-image>\n    <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n    <div class=\"bi-empty-state-content\">\n      <a class=\"bi-link\" ng-click=\"events.onRetryClick()\">Retry</a>\n    </div>\n  </div>\n</div>\n\n<div class=\"bi-c-h bi-s-v--x15 bi-grow bi-fade-in\" ng-if=\"vm.state.after('Result')\">\n  <bi-search\n    class=\"quix-db-search bi-dont-shrink\"\n    ng-model=\"vm.search.text\"\n    ng-change=\"events.onSearchChange(vm.search.text)\"\n    bi-focus\n    placeholder=\"Search\"\n    data-hook=\"file-explorer-search\"\n    min-length=\"2\"\n  ></bi-search>\n  \n  <div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.before('SearchContent')\">\n    <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Search')\">\n      <div class=\"bi-empty-state-content\">Searching...</div>\n    </div>\n\n    <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('SearchResult')\">\n      <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n      <div class=\"bi-empty-state-content\">No tables that match \"{{::vm.search.text}}\"</div>\n    </div>\n  </div>\n\n  <div class=\"bi-c-h bi-grow bi-scroll\" ng-show=\"vm.state.after('SearchResult')\">\n    <quix-file-explorer\n      ng-show=\"vm.state.is('Visible')\"\n      tree=\"vm.state.value().dbOriginal\"\n      on-transform-node=\"events.transformNode\"\n      on-fetch-children=\"events.onLazyFolderFetch\"\n      menu-options=\"{\n        table: [{\n          title: 'Select rows (limit 1000)',\n          action: events.onSelectTableRows,\n        }]\n      }\"\n    ></quix-file-explorer>\n\n    <quix-file-explorer\n      ng-if=\"vm.state.is('SearchContent')\"\n      tree=\"vm.state.value().dbOriginalFiltered\"\n      expanded-nodes=\"true\"\n      highlight=\"vm.search.text\"\n      on-transform-node=\"events.transformNode\"\n      on-fetch-children=\"events.onLazyFolderFetch\"\n      menu-options=\"{\n        table: [{\n          title: 'Select rows (limit 1000)',\n          action: events.onSelectTableRows,\n        }]\n      }\"\n    ></quix-file-explorer>\n\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/components/db-sidebar/db-sidebar.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-db-sidebar {\n  bi-file-explorer-static {\n    folder-icon {\n      margin: 3px 5px 0 0;\n    }\n\n    file-icon {\n      margin: 3px 5px 0 0;\n    }\n  }\n\n  .bi-heading {\n    position: relative;\n\n    &:after {\n      content: '';\n      position: absolute;\n      top: 50%;\n      left: 0;\n      right: 0;\n      border-bottom: 1px solid $dark-border-color;\n      z-index: 1;\n    }\n\n    toggle {\n      padding: 0 10px;\n      background-color: $dark-bg;\n      z-index: 2;\n    }\n  }\n\n  .quix-db-search {\n    margin: 12px 12px 0 12px;\n  }\n\n  .bi-scroll {\n    padding-bottom: 300px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/db-sidebar/db-sidebar.ts",
    "content": "import template from './db-sidebar.html';\nimport './db-sidebar.scss';\nimport _ from 'lodash';\n\nimport {initNgScope} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './db-sidebar-types';\nimport {cache} from '../../store';\nimport * as Resources from '../../services/resources';\nimport {Tree} from '../../react-components/file-explorer/FileExplorerComponent';\nimport {openTempQuery, StateManager} from '../../services';\nimport {pluginManager} from '../../plugins';\nimport {debounceAsync} from '../../utils';\nimport {DB} from '../../config';\nimport { DbPlugin } from '../../services/plugins';\n\nenum States {\n  Initial,\n  Error,\n  Result,\n  Content,\n  Search,\n  SearchResult,\n  SearchContent,\n  Visible,\n}\n\nconst getNamePath = (node: Tree, path: string[]) => {\n  const namePath = [node.name];\n  let iteratorNode = node;\n\n  for (let i = 1; i < path.length; i++) {\n    iteratorNode = iteratorNode?.children.find(nodeProps => nodeProps.id === path[i]);\n    namePath.push(iteratorNode.name);\n  }\n\n  return namePath;\n}\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {},\n  link: {\n    async pre(scope: IScope) {\n      const search = debounceAsync(text => Resources.dbSearch(scope.vm.type, text));\n\n      initNgScope(scope)\n        .withVM({\n          types: pluginManager.module('db').plugins().map(plugin => plugin.getId()),\n          type: null,\n          hideRoot: false,\n          search: {\n            text: null\n          },\n          $init() {\n            this.state = new StateManager(States);\n          }\n        })\n        .withEvents({\n          onPluginPickerLoad(plugin: DbPlugin) {\n            if (!store.getState('db.db')) {\n              cache.db.fetch(plugin.getId());\n            }\n          },\n          onPluginPickerChange(plugin: DbPlugin) {\n            scope.vm.search.text = null;\n            scope.vm.state.force('Initial');\n\n            cache.db.fetch(plugin.getId());\n          },\n          onRetryClick() {\n            scope.vm.state.force('Initial');\n            cache.db.fetch(scope.vm.type);\n          },\n          async onLazyFolderFetch(node: Tree, path: string[]): Promise<Tree[]> {\n            const namePath = getNamePath(node, path);\n            let response: any;\n            if (scope.vm.hideRoot) {\n              response = await Resources.dbColumns(\n                scope.vm.type,\n                DB.RootName, // catalog\n                namePath[0], // schema\n                namePath[1], // table\n                );\n            } else {\n              response = await Resources.dbColumns(\n                scope.vm.type,\n                namePath[0], // catalog\n                namePath[1], // schema\n                namePath[2], // table\n                );\n            }\n            return response.children.map(child => {return {...child, textIcon: child.dataType}});\n          },\n          transformNode(node: Tree, path: string[]): Tree {\n            const newNode = _.cloneDeep(node);\n\n            const chooseIcon = (type) => {\n              switch(type) {\n                case 'catalog':\n                  return 'book';\n                case 'schema':\n                  return 'storage';\n                default:\n                  return 'view_module';\n              }\n            }\n\n            newNode.icon = chooseIcon(node.type);\n            newNode.transformed = true;\n            newNode.lazy = newNode.type === 'table';\n            return newNode;\n          },\n          onSelectTableRows(node: Tree, path: string[]) {\n            const namePath = getNamePath(node, path);\n            const query = pluginManager.module('db').plugin(scope.vm.type)\n              .getSampleQuery(\n                {\n                  path: namePath.slice(0, namePath.length - 1).map(el => {\n                    return {\n                      name: el\n                    }\n                  }),\n                  name: namePath[namePath.length - 1],\n                } as any);\n\n            openTempQuery(scope, scope.vm.type, query, true);\n          },\n          onSearchChange(text) {\n            const {state, hideRoot} = scope.vm;\n\n            if (!text) {\n              state.set('Visible', true, {\n                dbOriginalFiltered: [],\n              });\n\n              return;\n            }\n\n            state.force('Search', true);\n\n            search(text)(res => state\n              .set('SearchResult', !!res)\n              .set('SearchContent', () => res.length, () => {\n                const dbOriginalFiltered = hideRoot ? _.flatten(res.map(tree => tree.children)) : res;\n\n                return {dbOriginalFiltered};\n              })\n            );\n          }\n        });\n\n      scope.getFolderPermissions = (folder: any) => {\n        return {\n          menu: folder.nodeType === 'table'\n        };\n      }\n\n      store.subscribe('db.db', (dbOriginal: any) => {\n        if (dbOriginal) {\n          scope.vm.hideRoot = dbOriginal.length === 1 && dbOriginal[0] && dbOriginal[0].name === DB.RootName;\n          dbOriginal = scope.vm.hideRoot ? _.flatten(dbOriginal.map(tree => tree.children)) : dbOriginal;\n        }\n\n        scope.vm.state\n          .force('Result', !!dbOriginal, {dbOriginal})\n          .set('Content', () => !!dbOriginal.length)\n          .set('Visible', !!dbOriginal)\n      }, scope);\n\n      store.subscribe('db.error', (error: any) => {\n        scope.vm.state.force('Error', !!error, {error});\n      }, scope);\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/destination-picker/destination-picker-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class DestinationPickerTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/destination-picker/destination-picker-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {IFile} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n  model: IFile;\n  context: 'folder' | 'notebook'\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/destination-picker/destination-picker.html",
    "content": "<div class=\"bi-c-h bi-grow bi-s-v--x15 bi-fade-in\" ng-if=\"vm.state.is('Content')\" data-hook=\"files-sidebar-content\">\n  <bi-file-explorer\n    class=\"bi-c-h bi-grow bi-scroll\"\n    ng-model=\"vm.state.value().tree\"\n    fe-options=\"::{folderMode: 'select', expandRootFolder: true}\"\n    on-load=\"events.onFileExplorerLoad(fileExplorer)\"\n    on-file-click=\"events.onFileClick(file)\"\n    on-folder-click=\"events.onFolderClick(folder)\"\n    readonly=\"true\"\n  ></bi-file-explorer>\n</div>\n\n<div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.before('Content')\">\n  <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Initial')\">\n    <div class=\"bi-empty-state-content\">Loading {{::context}}s...</div>\n  </div>\n\n  <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Error')\" data-hook=\"files-sidebar-error\">\n    <div class=\"bi-empty-state-icon bi-danger\">\n      <i class=\"bi-icon bi-danger\">error_outline</i>\n    </div>\n    <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n  </div>\n\n  <div\n    class=\"bi-empty-state bi-s-v bi-fade-in\"\n    ng-if=\"vm.state.is('Result')\"\n    data-hook=\"files-sidebar-empty\"\n  >\n    <div class=\"bi-empty-state-icon\">\n      <i class=\"bi-icon\">note_add</i>\n    </div>\n    <div class=\"bi-empty-state-header\">\n      You don't have any {{::context}}s...\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/components/destination-picker/destination-picker.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-destination-picker {\n  display: flex;\n  width: 500px;\n  height: 300px;\n  flex-direction: column;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/destination-picker/destination-picker.ts",
    "content": "import template from './destination-picker.html';\nimport './destination-picker.scss';\n\nimport { initNgScope, createNgModel } from '../../lib/core';\nimport { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IFile, FileType } from '@wix/quix-shared';\nimport { IScope } from './destination-picker-types';\nimport { cache } from '../../store';\nimport {\n  StateManager,\n  fetchRoot,\n  fetchFile,\n  fetchFileParent,\n} from '../../services';\n\nenum States {\n  Initial,\n  Error,\n  Result,\n  Content,\n}\n\nconst listenToNavChange = (scope: IScope, app: App, fileExplorer) => {\n  app\n    .getNavigator()\n    .listen(\n      ['files', 'notebook'],\n      'success',\n      async ({ id }: { id: string }, state: string) => {\n        let file = (await fetchFile(id)) || (await fetchRoot());\n\n        if (!file) {\n          return;\n        }\n\n        if (scope.context === 'folder' && file.type === FileType.notebook) {\n          file = await fetchFileParent(file.id);\n        }\n\n        if (file) {\n          fileExplorer.setActive(file);\n          scope.model = file;\n\n          if (file.type === FileType.folder) {\n            scope.events.onFolderClick(file);\n          } else if (file.type === FileType.notebook) {\n            scope.events.onFileClick(file);\n          }\n        }\n      },\n      scope\n    )\n    .otherwise(() => fileExplorer.clearActive());\n};\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  require: 'ngModel',\n  scope: {\n    context: '@',\n    required: '<',\n  },\n  link: {\n    async pre(scope: IScope, element, attr, ngModel) {\n      createNgModel(scope, ngModel).validateWith(() => ({\n        required: (model) => !scope.required || !!model,\n      }));\n\n      initNgScope(scope)\n        .withVM({\n          $init() {\n            this.state = new StateManager(States);\n          },\n        })\n        .withEvents({\n          onFileExplorerLoad(fileExplorer) {\n            listenToNavChange(scope, app, fileExplorer);\n          },\n          onFileClick(file) {\n            scope.model = scope.context === 'notebook' ? file : null;\n          },\n          onFolderClick(folder) {\n            scope.model = scope.context === 'folder' ? folder : null;\n          },\n        });\n\n      cache.files.get();\n      store.subscribe(\n        'files.files',\n        (files: IFile[]) => {\n          scope.vm.state.force('Result', !!files, { files }).set(\n            'Content',\n            () => files.length > 0,\n            () => ({\n              tree:\n                scope.context === 'folder'\n                  ? files.filter((file) => file.type === FileType.folder)\n                  : files,\n            })\n          );\n        },\n        scope\n      );\n\n      store.subscribe(\n        'files.error',\n        (error: any) => {\n          scope.vm.state.force('Error', !!error, { error });\n        },\n        scope\n      );\n    },\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/files-sidebar/files-sidebar-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class FilesSidebarTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/files-sidebar/files-sidebar-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/files-sidebar/files-sidebar.html",
    "content": "<div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.before('Content')\">\n  <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Initial')\">\n    <div class=\"bi-empty-state-content\">Loading notebooks...</div>\n  </div>\n\n  <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Error')\" data-hook=\"files-sidebar-error\">\n    <quix-image class=\"bi-empty-state-image\" name=\"error_{{::vm.state.value().error.status}}.svg\"></quix-image>\n    <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n  </div>\n\n  <div\n    class=\"bi-empty-state bi-s-v bi-fade-in\"\n    ng-if=\"vm.state.is('Result')\"\n    data-hook=\"files-sidebar-empty\"\n  >\n    <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n\n    <div class=\"bi-empty-state-header\">You don't have any notebooks</div>\n\n    <div class=\"bi-empty-state-content\">\n      <a class=\"bi-link\" ng-click=\"events.onNotebookAdd()\">Add notebook</a>\n    </div>\n  </div>\n</div>\n\n<div\n  class=\"bi-c-h bi-s-v--x15 bi-grow bi-fade-in\"\n  ng-if=\"vm.state.after('Result')\"\n  data-hook=\"files-sidebar-content\"\n>\n  <bi-search\n    class=\"bi-db-schema-content bi-dont-shrink\"\n    ng-model=\"vm.search.text\"\n    ng-change=\"events.onSearch(vm.search.text)\"\n    placeholder=\"Search\"\n    bi-focus\n  ></bi-search>\n\n  <div\n    class=\"bi-empty-state--loading bi-center bi-grow bi-fade-in\"\n    ng-if=\"vm.state.is('SearchInitial')\"\n  >\n    <div class=\"bi-empty-state-content\">Searching...</div>\n  </div>\n\n  <div\n    class=\"bi-empty-state bi-s-v bi-fade-in bi-center bi-grow\"\n    ng-if=\"vm.state.is('SearchResult')\"\n  >\n    <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n\n    <div class=\"bi-empty-state-content\">\n      No notebooks that match \"{{::vm.search.text}}\"\n    </div>\n  </div>\n\n  <bi-file-explorer\n    class=\"bi-scroll bi-fade-in\"\n    ng-show=\"vm.state.is('Content')\"\n    ng-model=\"vm.state.value().tree\"\n    fe-options=\"{\n      fileAlias: ['notebook'],\n      folderMode: 'select',\n      expandRootFolder: true\n    }\"\n    on-load=\"events.onFileExplorerLoad(fileExplorer)\"\n    on-file-click=\"events.onFileClick(file)\"\n    on-folder-click=\"events.onFolderClick(folder)\"\n    permissions=\"getFolderPermissions(folder)\"\n  ></bi-file-explorer>\n\n  <bi-file-explorer\n    class=\"bi-scroll bi-fade-in\"\n    ng-if=\"vm.state.is('SearchContent')\"\n    ng-model=\"vm.state.value().filteredTree\"\n    fe-options=\"{\n      fileAlias: ['notebook'],\n      folderMode: 'select',\n      expandRootFolder: true,\n      expandAllFolders: vm.state.is('SearchContent'),\n      hideEmptyFolders: vm.state.is('SearchContent'),\n    }\"\n    on-file-click=\"events.onFileClick(file)\"\n    on-folder-click=\"events.onFolderClick(folder)\"\n    readonly=\"true\"\n  ></bi-file-explorer>\n</div>\n  "
  },
  {
    "path": "quix-frontend/client/src/components/files-sidebar/files-sidebar.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-files-sidebar {\n  bi-search {\n    margin: 10px 12px 0 12px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/files-sidebar/files-sidebar.ts",
    "content": "import template from './files-sidebar.html';\nimport './files-sidebar.scss';\n\nimport {initNgScope, inject} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {FileActions, NotebookActions, IFile} from '@wix/quix-shared';\nimport {IScope} from './files-sidebar-types';\nimport {cache} from '../../store';\nimport {\n  addNotebook,\n  addFolder,\n  deleteFolder,\n  isRoot,\n  getFolderPermissions,\n  StateManager,\n  goToFile\n} from '../../services';\nimport { goToNotebook } from '../../services/notebook';\nimport { debounceAsync } from '../../utils';\n\nenum States {\n  Initial,\n  Error,\n  Result,\n  Content,\n  SearchInitial,\n  SearchResult,\n  SearchContent,\n}\n\nconst listenToEvents = (scope, app: App, store: Store, fileExplorer) => {\n  fileExplorer\n    .on('fileCreated', ({id, path}) => {\n      addNotebook(store, app, path, {addNote: true}, {id})\n        .then(notebook => goToNotebook(app, notebook, {isNew: true}));\n      }, false, scope)\n    .on('fileMoved', ({id, path}) => store.dispatchAndLog(NotebookActions.moveNotebook(id, path)), false, scope)\n    .on('folderDeleted', (folder) => deleteFolder(store, app, folder), false, scope)\n    .on('folderCreated', ({id, path}) => addFolder(store, app, path, {id}), false, scope)\n    .on('folderRenamed', ({id, name}) => store.dispatchAndLog(FileActions.updateName(id, name)), false, scope)\n    .on('folderMoved', ({id, path}) => store.dispatchAndLog(FileActions.moveFile(id, path)), false, scope);\n}\n\nconst listenToNavChange = (scope: IScope, app: App, fileExplorer) => {\n  app.getNavigator()\n    .listen(['files', 'notebook'], 'success', ({id}: {id: string}) => {\n      const file = scope.vm.state.value().files.find(f => f.id === id);\n\n      return file ? fileExplorer.setActive(file) : fileExplorer.clearActive();\n    }, scope)\n    .otherwise(() => fileExplorer.clearActive());\n}\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {},\n  link: {\n    async pre(scope: IScope) {\n      const search = debounceAsync((text: string, files: IFile[]) => {\n        text = text.toLowerCase();\n\n        const res = files.filter(file => {\n          return file.type === 'folder' || file.name.toLowerCase().includes(text);\n        });\n\n        return inject('$q').when(res);\n      });\n\n      initNgScope(scope)\n        .withVM({\n          search: {\n            text: null,\n          },\n          $init() {\n            this.state = new StateManager(States);\n          }\n        })\n        .withEvents({\n          onFileExplorerLoad(fileExplorer) {\n            listenToEvents(scope, app, store, fileExplorer);\n            listenToNavChange(scope, app, fileExplorer);\n          },\n          onFileClick(file) {\n            goToFile(app, file);\n          }, \n          onFolderClick(folder) {\n            goToFile(app, folder);\n          }, \n          onNotebookAdd() {\n            addNotebook(store, app, [], {addNote: true})\n              .then(notebook => goToNotebook(app, notebook, {isNew: true}));\n          }, \n          onSearch(text: string) {\n            scope.vm.state.force('SearchInitial');\n\n            search(text, scope.vm.state.value().files)(filteredFiles => {\n              if (text) {\n                scope.vm.state\n                  .set('SearchResult', true)\n                  .set('SearchContent', () => filteredFiles.filter(file => file.type !== 'folder').length > 0, {\n                    filteredTree: filteredFiles\n                  });\n              } else {\n                scope.vm.state.force('Content', true, {filteredTree: null});\n              }\n            });\n          }\n        });\n\n      scope.getFolderPermissions = (folder: IFile) => {\n        const isRootFolder = isRoot(folder);\n        const owner = scope.vm.state.value().files[0].owner;\n        const permissions = getFolderPermissions(app, {...folder, owner});\n\n        return {\n          ...getFolderPermissions(app, folder),\n          delete: permissions.delete && !isRootFolder,\n          rename: permissions.rename && !isRootFolder\n        };\n      }\n\n      cache.files.get();\n      store.subscribe('files.files', (files: IFile[]) => {\n        scope.vm.state\n          .force('Result', !!files, {files})\n          .set('Content', () => files.length > 1, () => ({files, tree: files}));\n      }, scope);\n\n      store.subscribe('files.error', (error: any) => {\n        scope.vm.state.force('Error', !!error, {error});\n      }, scope);\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/header/header-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class HeaderTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/header/header-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/header/header.html",
    "content": "<div class=\"quix-header-menu bi-align bi-s-h--x2 bi-text--ui\">\n  <!-- <span class=\"bi-action bi-align bi-s-h--x05\" ng-click=\"events.onFavoritesClick()\">\n    <i class=\"bi-icon--xs\">favorite_border</i>\n    <span class=\"bi-text--600\">Favorites</span>\n  </span> -->\n  <span \n    class=\"bi-action bi-align bi-s-h--x05\"\n    ng-class=\"{'bi-active': vm.currentState === item.targetState}\"\n    ng-repeat=\"item in ::vm.navItems\"\n    ng-click=\"events.onNavItemClick(item)\"\n  >\n    <span>{{::item.title}}</span>\n  </span>\n</div>\n\n<bi-search \n  class=\"bi-search--rnd\"\n  ng-change=\"events.onSearch()\"\n  placeholder=\"Search in notes\"\n  ng-model=\"vm.searchText\"\n></bi-search>\n\n<div ng-bind-html=\"vm.additionalItems\"></div>\n"
  },
  {
    "path": "quix-frontend/client/src/components/header/header.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n@import '../../lib/ui/assets/css/def/state.def';\n@import '../../lib/ui/assets/css/def/border.def';\n\nquix-header {\n  height: 100%;\n  margin-left: 10%;\n\n  .quix-header-menu {\n    .bi-action {\n      @include hover('lighter', $primary);\n      @include active('lighter', $primary);\n\n\n      font-size: 14px;\n      border-radius: 0;\n      border-top: 2px solid transparent;\n      border-bottom: 2px solid transparent;\n      background-color: transparent !important;\n\n      &:hover,\n      &.bi-active {\n        border-bottom-color: currentColor;\n      }\n    }\n  }\n\n  bi-search.bi-search--rnd {\n    position: fixed;\n    width: 400px;\n    top: 8px;\n    left: 50%;\n    margin-left: -200px;\n\n    .bi-input {\n      height: 38px !important;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/header/header.ts",
    "content": "import template from './header.html';\nimport './header.scss';\nimport { isArray } from 'lodash';\nimport { initNgScope } from '../../lib/core';\nimport { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IScope } from './header-types';\nimport { HeaderMenu } from '../../config';\nimport * as AppActions from '../../store/app/app-actions';\nimport { hooks } from '../../hooks';\n\nconst listenToNavChange = (scope: IScope, app: App, store: Store) => {\n  const { navItems } = scope.vm;\n\n  const states = navItems.reduce((res, item) => {\n    return [...res, ...(item.activeStates || [item.targetState])];\n  }, []);\n\n  app.getNavigator()\n    .listen(states, 'success', async (params, state) => {\n      const menuItem = navItems.find(item => {\n        return (item.targetState === state || (item.activeStates && item.activeStates.indexOf(state) !== -1));\n      });\n\n      const procede = await (menuItem && (!menuItem.activeCondition || menuItem.activeCondition(app, store, state, params.id)));\n\n      scope.vm.currentState = procede ? menuItem.targetState : null;\n    }, scope)\n    .otherwise(() => scope.vm.currentState = null);\n}\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {},\n  link: {\n    async pre(scope: IScope) {\n      initNgScope(scope)\n        .withVM({\n          searchText: null,\n          currentState: null,\n          navItems: HeaderMenu(scope)\n        })\n        .withEvents({\n          onSearch() {\n            store.dispatch(AppActions.setInputSearchText(scope.vm.searchText || null));\n          },\n          onNavItemClick(item) {\n            app.go(item.targetState, { id: null });\n          }\n        });\n\n      const additionalItems = hooks.header.additionalItems.call(app, store);\n      scope.vm.additionalItems = isArray(additionalItems) ? additionalItems[0] : null;\n\n      listenToNavChange(scope, app, store);\n\n      store.subscribe('app.inputSearchText', text => scope.vm.searchText = text, scope);\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/image/image-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\n\nexport interface IScope extends ngIscope {\n  name: string;\n  src: string;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/image/image.html",
    "content": "<img ng-src=\"{{::src}}\">"
  },
  {
    "path": "quix-frontend/client/src/components/image/image.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-meta {\n  display: flex;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/image/image.ts",
    "content": "import template from './image.html';\nimport './image.scss';\n\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './image-types';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  replace: true,\n  scope: {\n    name: '@'\n  },\n  link: {\n    async pre(scope: IScope) {\n      scope.src = `${app.getConfig().getClientTopology().staticsBaseUrl}assets/${scope.name}`;\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/index.ts",
    "content": "export {default as quixHeader} from './header/header';\nexport {default as quixNote} from './note/note';\nexport {default as quixBreadcrumbs} from './breadcrumbs/breadcrumbs';\nexport {default as quixFilesSidebar} from './files-sidebar/files-sidebar';\nexport {default as quixDbSidebar} from './db-sidebar/db-sidebar';\nexport {default as quixSearchResults} from './search-results/search-results';\nexport {default as quixActions} from './actions/actions';\nexport {default as quixTempQuery} from './temp-query/temp-query';\nexport {default as quixDestinationPicker} from './destination-picker/destination-picker';\nexport {default as quixPluginPicker} from './plugin-picker/plugin-picker';\nexport {default as quixMeta} from './meta/meta';\nexport {default as quixImage} from './image/image';\nexport {default as quixNpc} from './npc/npc';\nexport {default as quixNoteShare} from './note-share/note-share';\nexport {default as quixNoteHints} from './note-hints/note-hints';\nexport {default as quixRunner} from './runner/runner';\n"
  },
  {
    "path": "quix-frontend/client/src/components/meta/meta-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class ActionsTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/meta/meta-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {IEntity} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  entity: IEntity\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/meta/meta.html",
    "content": "<div class=\"bi-align bi-s-h bi-text--sm bi-muted\">\n  <div>Created <span>{{::entity.dateCreated | biRelativeDate}}</span></div>\n  <div>|</div>\n  <div>Updated <span>{{entity.dateUpdated | biRelativeDate}}</span></div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/components/meta/meta.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-meta {\n  display: flex;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/meta/meta.ts",
    "content": "import template from './meta.html';\nimport './meta.scss';\n\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './meta-types';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    entity: '<'\n  },\n  link: {\n    async pre(scope: IScope) {\n      return;\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/note/note-events.ts",
    "content": "import {inject, utils} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {INote} from '@wix/quix-shared';\nimport {IScope} from './note-types';\nimport {App} from '../../lib/app';\nimport { cloneDeep, isEqual } from 'lodash';\nimport { RunnerComponentInstance } from '../../lib/runner/directives/runner/runner';\n\nexport const onFoldToggle = (scope: IScope, store: Store) => () => {\n  scope.options.focusEditor = true;\n};\n\nexport const onMarkToggle = (scope: IScope, store: Store) => () => {\n  scope.onMarkToggle({note: scope.note});\n};\n\nexport const onNameChange = (scope: IScope, store: Store) => () => {\n  scope.onNameChange({note: scope.note});\n};\n\nexport const onContentChange = (scope: IScope, store: Store) => (textContent: string, richContent: Record<string, any>) => {\n  scope.note.content = textContent;\n  scope.note.richContent = richContent;\n\n  scope.onContentChange({note: scope.note});\n};\n\nexport const onShare = (scope: IScope, store: Store) => (note: INote, params: string) => {\n  scope.onShare({note, params});\n};\n\nexport const onClone = (scope: IScope, store: Store) => (note: INote) => {\n  scope.onClone({note});\n};\n\nexport const onCustomAction = (scope: IScope, store: Store) => (action: any) => {\n  utils.scope.safeApply(scope, () => {\n    const {content, richContent} = action.handler(cloneDeep(scope.note));\n\n    if (scope.note.content !== content || !isEqual(scope.note.richContent, richContent)) {\n      scope.events.onContentChange(content, richContent);\n    }\n  });\n}\n\nexport const onDelete = (scope: IScope, store: Store) => (note: INote) => {\n  scope.onDelete({note});\n};\n\nexport const onSave = (scope: IScope, store: Store) => () => {\n  scope.onSave();\n};\n\nexport const onRun = (scope: IScope, store: Store) => () => {\n  scope.onRun();\n};\n\nexport const onMaximizeToggle = (scope: IScope, store: Store, app: App) => () => {\n  scope.vm.isFolded = false;\n\n  inject('$timeout')(() => scope.vm.editor?.focus());\n};\n\nexport const onEditorInstanceLoad = (scope: IScope, store: Store, app: App) => (editor) => {\n  scope.vm.editor = editor;\n};\n\nexport const onRunnerInstanceLoad = (scope: IScope, store: Store, app: App) => (runner: RunnerComponentInstance) => {\n  scope.vm.runner = runner;\n};\n\nexport const onRunnerCreated = (scope: IScope, store: Store) => (runner) => {\n  scope.onRunnerCreated({runner});\n};\n\nexport const onRunnerDestroyed = (scope: IScope, store: Store) => (runner) => {\n  scope.onRunnerDestroyed({runner});\n};\n"
  },
  {
    "path": "quix-frontend/client/src/components/note/note-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\nimport {ActionsTestkit} from '../actions/actions-testkit';\nimport {RunnerTestkit} from '../runner/runner-testkit';\n\nconst enum Hooks {\n  Name = 'note-name',\n  Select = 'note-select',\n}\n\nexport class NoteTestkit extends Testkit {\n  async getActionsTestkit() {\n    return new ActionsTestkit(await this.query.$('quix-actions'));\n  }\n\n  async getRunnerTestkit() {\n    return new RunnerTestkit(await this.query.$('quix-runner'));\n  }\n\n  async isNameFocused() {\n    return (await this.query.hook(Hooks.Name, ':focus')) !== null;\n  }\n\n  async isSelectEnabled() {\n    return (await this.query.hook(Hooks.Select)) !== null;\n  }\n\n  async isNameEditable() {\n    return this.evaluate.hook(Hooks.Name, el => el.getAttribute('contenteditable') === 'true');\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/components/note/note-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {INote} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  note: INote;\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/note/note.html",
    "content": "<div class=\"bi-r bi-s-h--x05\">\n  <span class=\"quix-checkbox\" ng-if=\"permissions.edit && !vm.isMaximized\" data-hook=\"note-select\">\n    <i\n      class=\"bi-action bi-icon bi-fade-in checked\"\n      ng-if=\"marked\"\n      ng-click=\"$event.stopPropagation(); events.onMarkToggle()\"\n    >\n      check_box_outline\n    </i>\n    <i\n      class=\"bi-action bi-icon bi-fade-in\"\n      ng-if=\"!marked\"\n      ng-click=\"$event.stopPropagation(); events.onMarkToggle()\"\n    >\n      check_box_outline_blank\n    </i>\n  </span>\n    \n  <bi-foldable \n    class=\"bi-theme--lighter bi-c-h bi-grow\"\n    is-folded=\"vm.isFolded\"\n    on-toggle=\"events.onFoldToggle(fold)\"\n  >\n    <div\n      class=\"bi-panel bi-c-h\"\n      bi-maximizable=\"::options.maximizable\"\n      is-maximized=\"vm.isMaximized\"\n      on-toggle=\"events.onMaximizeToggle(maximized)\"\n    >\n      <div class=\"bi-panel-header bi-hover-parent\" ng-class=\"::{'quix-note-hidden-editor': !options.showEditor}\">\n        <span\n          class=\"quix-note-drag-handle quix-note-drag-indicator bi-hover-target\"\n          ng-if=\"permissions.reorder && !vm.isMaximized\"\n        >\n          <i class=\"bi-action bi-icon--sm\">drag_indicator</i>\n        </span>\n\n        <div>\n          <div class=\"bi-align bi-dont-shrink bi-s-h\">\n            <span class=\"bi-align\" ng-show=\"::options.maximizable\">\n              <span bm-toggle></span>\n            </span>  \n      \n            <span class=\"bi-text--ui bi-muted\">{{::note.type | biToHumanCase}}</span>\n          </div>\n\n          <div class=\"bi-align bi-s-h--x3\">\n            <span\n              class=\"bi-panel-title bi-dont-shrink\"\n              contenteditable=\"{{::permissions.rename}}\"\n              ng-model=\"note.name\"\n              on-change=\"events.onNameChange()\"\n              ce-options=\"::{autoEdit: options.focusName}\"\n              data-hook=\"note-name\"\n            ></span>\n\n            <button\n              class=\"bi-button bi-button--sm bi-fade-in\"\n              ng-if=\"hasChanges && vm.isMaximized\"\n              ng-click=\"events.onSave()\"\n              ng-disabled=\"saving\"\n            >\n              <i class=\"bi-icon--xs\" ng-click=\"events.onSave()\">save</i>\n              <span>Save changes</span>\n            </button>\n          </div>\n        </div>\n\n        <div \n          class=\"quix-note-drag-handle bi-hover-parent bi-justify-right\"\n          ng-show=\"!vm.isMaximized\"\n          ng-class=\"{'bi-hover-target': bf.fold}\"\n          bf-toggle\n        >\n          <quix-meta ng-if=\"::options.showDates\" entity=\"note\"></quix-meta>\n\n          <div class=\"bi-align bi-s-h\">\n            <bi-tooltip ng-if=\"::permissions[action.permissions]\" ng-repeat=\"action in ::vm.customActions\">\n              <bi-toggle>\n                <i \n                  class=\"bi-action bi-icon--sm\"\n                  ng-click=\"$event.stopPropagation(); events.onCustomAction(action)\"\n                >{{::action.icon}}</i>\n              </bi-toggle>\n              {{::action.title}}\n            </bi-tooltip>\n\n            <quix-actions\n              type=\"note\"\n              context=\"note\"\n              permissions=\"::permissions\"\n              quix-actions-options=\"{reverse: true, compact: true}\"\n              on-share=\"events.onShare(context)\"\n              on-clone=\"events.onClone(context)\"\n              on-delete=\"events.onDelete(context)\"\n            ></quix-actions>\n          </div>\n        </div>\n      </div>\n\n      <div\n        class=\"bi-panel-content bi-c-h bi-grow bi-fade-in\"\n        ng-if=\"!bf.fold\"\n      >\n        <quix-runner\n          class=\"bi-c-h bi-grow\"\n          type=\"::vm.type\"\n          runner=\"runner\"\n          quix-runner-options=\"::options\"\n          text-content=\"note.content\"\n          rich-content=\"note.richContent\"\n          get-download-file-name=\"getDownloadFileName(query)\"\n          render-stats=\"renderStats()\"\n          on-content-change=\"events.onContentChange(textContent, richContent)\"\n          on-save=\"events.onSave()\"\n          on-run=\"events.onRun()\"\n          on-editor-instance-load=\"events.onEditorInstanceLoad(instance)\"\n          on-runner-instance-load=\"events.onRunnerInstanceLoad(instance)\"\n          on-runner-created=\"events.onRunnerCreated(runner)\"\n          on-runner-destroyed=\"events.onRunnerDestroyed(runner)\"\n          on-params-share=\"events.onShare(note, params)\"\n          readonly=\"!permissions.edit\"\n        ></quix-runner>\n      </div>\n    </div>\n  </bi-foldable>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/components/note/note.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-note {\n  display: flex;\n  flex-direction: column;\n\n  .quix-checkbox {\n    margin-top: 7px;\n  }\n\n  [bf-toggle] {\n    width: 100%;\n    height: 100%;\n  }\n\n  .bm--maximized {\n    top: 10px !important;\n    right: 10px !important;\n    bottom: 10px !important;\n    left: 10px !important;\n\n    .bi-panel-header,\n    .bi-panel-content {\n      padding: 0;\n    }\n\n    .bi-panel-header {\n      margin-top: -10px;\n    }\n  }\n\n  .bi-panel-header {\n    position: relative;\n\n    &.quix-note-hidden-editor {\n      margin-bottom: -10px;\n      border-bottom: 1px solid $grey--200;\n    }\n\n    .quix-note-drag-indicator {\n      position: absolute;\n      top: 11px;\n      left: -2px;\n      margin: 0 !important;\n\n      .bi-action {\n        &:hover {\n          background-color: transparent !important;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/note/note.ts",
    "content": "import template from './note.html';\nimport './note.scss';\n\nimport {assign} from 'lodash';\nimport {initNgScope, inject} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './note-types';\nimport {initEvents} from '../../services/scope';\nimport * as Events from './note-events';\nimport {RunnerQuery} from '../../lib/runner';\nimport {pluginManager} from '../../plugins';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    note: '<',\n    permissions: '<',\n    quixNoteOptions: '<',\n    marked: '<',\n    runner: '<',\n    hasChanges: '<',\n    saving: '<',\n    onContentChange: '&',\n    onNameChange: '&',\n    onShare: '&',\n    onClone: '&',\n    onDelete: '&',\n    onMarkToggle: '&',\n    onSave: '&',\n    onRun: '&',\n    onRunnerCreated: '&',\n    onRunnerDestroyed: '&',\n  },\n  link: {\n    async pre(scope: IScope) {\n      const plugin = pluginManager.module('note').plugin(scope.note.type);\n \n      const conf = initNgScope(scope)\n        .withOptions(\n          'quixNoteOptions',\n          {\n            fold: false,\n            focusName: false,\n            focusEditor: true,\n            showEditor: true,\n            showDates: true,\n            autoRun: false,\n            maximizable: true,\n          },\n          () => {\n            if (scope.options.focusName) {\n              scope.options.focusEditor = false;\n            }\n\n            scope.vm.isFolded = scope.options.fold;\n          },\n        )\n        .withVM({\n          editor: null,\n          runner: null,\n          isFolded: false,\n          isMaximized: false,\n          enabled: false,\n          $init() {\n            this.type = plugin.getId();\n            this.customActions = plugin.getCustomActions();\n          },\n        });\n\n      initEvents(scope, conf, app, store, Events);\n\n      scope.getDownloadFileName = (query: RunnerQuery) => {\n        return `${scope.note.name}${\n          query.getIndex() > 0 ? `_${query.getIndex()}` : ''\n        }.csv`;\n      };\n\n      scope.renderStats = () => {\n        const stats = scope.vm.runner.getCurrentQuery().getStats();\n        const formattedStats = plugin.formatStats(stats);\n\n        const html = inject('$compile')(`\n          <div class=\"bi-c\" ng-repeat=\"stat in ::stats\">\n            <span class=\"bi-text--sm\">{{::stat.title}}</span>\n            <span class=\"bi-text--sm bi-text--700\">{{::stat.value}}</span>\n          </div>\n        `)(assign(scope.$new(), {stats: formattedStats}));\n\n        return {html};\n      };\n    },\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/note-hints/note-hints.html",
    "content": "<bi-tooltip>\n  <bi-toggle>\n    <i class=\"bi-icon bi-disabled\">keyboard</i>\n  </bi-toggle>\n\n  <table>\n    <tr>\n      <th>\n        <span class=\"bi-tag--sm\">{{::ctrlKey}} + Enter</span>\n      </th>\n      <th>\n        Run note\n      </th>\n    </tr>\n    <tr>\n      <th>\n        <span class=\"bi-tag--sm\">{{::ctrlKey}} + S</span>\n      </th>\n      <th>\n        Save note\n      </th>\n    </tr>\n    <tr>\n      <th>\n        <span class=\"bi-tag--sm\">{{::autocompleteKey}} + Space</span>\n      </th>\n      <th>\n        Toggle autocompletion\n      </th>\n    </tr>\n    <tr ng-if=\"::options.params\">\n      <th>\n        <span class=\"bi-tag--sm\">$</span>\n      </th>\n      <th>\n        Insert parameters\n      </th>\n    </tr>\n  </table>\n</bi-tooltip>"
  },
  {
    "path": "quix-frontend/client/src/components/note-hints/note-hints.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-note-hints {\n  display: block;\n  line-height: 0;\n\n  table {\n    tr {\n      line-height: 28px;\n    }\n\n    th:first-child {\n      padding-right: 12px;\n      text-align: right;\n    }\n\n    th:last-child {\n      text-align: left;\n    }\n\n    .bi-tag--sm {\n      color: $white;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/note-hints/note-hints.ts",
    "content": "import template from './note-hints.html';\nimport './note-hints.scss';\n\nexport default () => () => ({\n  restrict: 'E',\n  template,\n  scope: {},\n  link: {\n    pre(scope: any) {\n      scope.ctrlKey = navigator.platform === 'MacIntel' ? 'Command' : 'Ctrl';\n      scope.autocompleteKey = navigator.platform === 'MacIntel' ? 'Option' : 'Ctrl';\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/note-share/note-share-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class NoteSHareTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/note-share/note-share-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {INote, INotebook} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  note: INote;\n  notebook: INotebook;\n  params: any;\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/note-share/note-share.html",
    "content": "<div class=\"bi-c-h bi-s-v--x2\">\n  <div class=\"bi-c-h bi-s-v--x05\">\n    <div class=\"bi-spread\">\n      <div class=\"bi-align bi-s-h--x05 bi-muted\">\n        <i class=\"bi-icon\">link</i>\n        <span class=\"bi-text--ui bi-text--md\">Share</span>\n      </div>\n\n      <bi-copy-to-clipboard text=\"::shareUrl\"></bi-copy-to-clipboard>\n    </div>\n\n\n    <div class=\"bi-panel\">\n      <div class=\"bi-panel-content bi-theme--light\">\n        <span class=\"bi-muted\">{{::shareUrl}}</span>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"bi-border--bottom\"></div>\n\n  <div class=\"bi-c-h bi-s-v--x05\">\n    <div class=\"bi-spread\">\n      <div class=\"bi-align bi-s-h--x05 bi-muted\">\n        <i class=\"bi-icon\">code</i>\n        <span class=\"bi-text--ui bi-text--md\">Embed</span>\n      </div>\n\n      <bi-copy-to-clipboard text=\"::embedHtml\"></bi-copy-to-clipboard>\n    </div>\n\n    <div class=\"bi-panel\">\n      <div class=\"bi-panel-content bi-theme--light\">\n        <span class=\"bi-muted\">{{::embedHtml}}</span>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/components/note-share/note-share.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-note-share {\n  display: flex;\n  max-width: 800px;\n\n  .bi-panel {\n    .bi-panel-content {\n      font-family: Monaco, 'Courier New';\n      font-size: 12px;\n      border-top: 1px solid darken($light-bg, 3);\n      border-left: 1px solid darken($light-bg, 3);\n      box-shadow: inset 1px 1px 5px darken($light-bg, 5);\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/note-share/note-share.ts",
    "content": "import template from './note-share.html';\nimport './note-share.scss';\n\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './note-share-types';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    note: '<',\n    notebook: '<',\n    params: '<',\n  },\n  link: {\n    async pre(scope: IScope) {\n      scope.shareUrl = [app.getNavigator().getUrl(null, {id: scope.notebook.id, note: scope.note.id}), scope.params]\n        .filter(x => !!x)\n        .join('');\n\n      const embedUrl = [app.getNavigator().getUrl('auth.base.embed.notebook', {id: scope.notebook.id, note: scope.note.id}), scope.params]\n        .filter(x => !!x)\n        .join('');\n\n      scope.embedHtml = `<iframe src=\"${embedUrl}\" frameborder=\"0\"></iframe>`;  \n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/npc/npc.html",
    "content": "<div class=\"quix-npc-container bi-fade-in\" ng-if=\"vm.enabled\">\n  <quix-image name=\"npc.gif\"></quix-image>\n  <div class=\"quix-npc-phrase bi-fade-in\" ng-if=\"vm.speech.enabled\">\n    {{vm.speech.currentPhrase}}\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/components/npc/npc.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n@import '../../lib/ui//assets/css/def/animations.def';\n\nquix-npc {\n  @keyframes quix-note-npc {\n    from {\n      left: 100%;\n    }\n\n    to {\n      left: -35px;\n    }\n  }\n\n  position: relative;\n  display: flex;\n  height: 30px;\n  overflow: hidden;\n\n  .quix-npc-container {\n    animation: quix-note-npc 70s linear infinite;\n    position: absolute;\n    top: 1px;\n    left: 100%;\n\n    img {\n      width: 35px;\n    }\n\n    .quix-npc-phrase {\n      position: absolute;\n      top: 0;\n      left: 30px;\n      font-family: 'Bangers';\n      font-size: 9px;\n      white-space: nowrap;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/npc/npc.ts",
    "content": "import template from './npc.html';\nimport './npc.scss';\n\nimport {without} from 'lodash';\nimport {initNgScope, inject} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\n\nconst TriggerChance = 1/5;\nconst TriggerDelayMinutes = 10;\nconst Speed = 25; // pixels per second\nconst Phrases = [\n  'What to do...what to do...',\n  'I wonder...',\n  'Hmm...',\n  'What now...',\n  'Perplexing...',\n];\n\nconst Timeout = {\n  AnimationStart: TriggerDelayMinutes * 60 * 1000,\n  PhraseShow: 10 * 1000,\n  PhraseHide: 5 * 1000,\n};\n\nconst rotatePhrases = (scope: any) => {\n  const timeout = inject('$timeout');\n  const {speech} = scope.vm;\n\n  speech.timeout = timeout(() => {\n    const phrases = without(Phrases, speech.currentPhrase);\n\n    speech.currentPhrase = phrases[Math.floor(Math.random() * phrases.length)];\n    speech.toggle(true);\n\n    speech.timeout = timeout(() => {\n      speech.toggle(false);\n      rotatePhrases(scope);\n    }, Timeout.PhraseHide);\n  }, Timeout.PhraseShow);\n}\n\nconst startAnimation = (scope: any, element: any) => {\n  destroyAnimation(scope);\n\n  const timeout = inject('$timeout');\n  const {vm} = scope;\n\n  vm.timeout = timeout(() => {\n    vm.toggle(true);\n    rotatePhrases(scope);\n\n    timeout(() => {\n      element.find('.quix-npc-container').css({\n        'animation-duration': `${element.width() / Speed}s`,\n      });\n    });\n  }, Timeout.AnimationStart);\n}\n\nconst destroyAnimation = (scope: any) => {\n  const timeout = inject('$timeout');\n  const {vm} = scope;\n  const {speech} = vm;\n\n  vm.toggle(false);\n\n  timeout.cancel(vm.timeout);\n  timeout.cancel(speech.timeout);\n}\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {},\n  link: {\n    async pre(scope: any, element: any) {\n      initNgScope(scope)\n        .withVM({\n          timeout: null,\n          speech: {\n            timeout: null,\n            currentPhrase: null,\n          }\n        });\n      \n      if (Math.random() < TriggerChance) {\n        startAnimation(scope, element);\n        scope.$on('$destroy', () => destroyAnimation(scope));\n      }\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/plugin-picker/plugin-picker-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class PluginPickerTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/plugin-picker/plugin-picker-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {ModuleComponentType} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n  model: string;\n  pluginType: ModuleComponentType;\n  onChange: Function;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/plugin-picker/plugin-picker.html",
    "content": "  <bi-simple-select\n    ng-model=\"model\"\n    ng-change=\"events.onChange(model)\"\n    bi-options=\"plugin as plugin | biToHumanCase for plugin in ::vm.plugins\"\n    bs-options=\"::{alignDropdown: 'center'}\"\n  >\n    <toggle>\n      <button class=\"bi-button bi-align bi-s-h--x05\">\n        <span>{{model | biToHumanCase}}</span>\n        <i class=\"bi-icon--sm\">arrow_drop_down</i>\n      </button>\n    </toggle>\n  </bi-simple-select>"
  },
  {
    "path": "quix-frontend/client/src/components/plugin-picker/plugin-picker.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-plugin-picker {\n  display: block;\n\n  bi-toggle {\n    font-size: 14px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/plugin-picker/plugin-picker.ts",
    "content": "import template from './plugin-picker.html';\nimport './plugin-picker.scss';\n\nimport {initNgScope, createNgModel, inject} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './plugin-picker-types';\nimport {pluginManager} from '../../plugins';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  require: 'ngModel',\n  scope: {\n    module: '@',\n    filter: '&',\n    onChange: '&',\n    onLoad: '&',\n  },\n  link: {\n    async pre(scope: IScope, element, attr, ngModel) {\n      createNgModel(scope, ngModel)\n        .watchWith(() => scope.state.save())\n        .then(() => {\n          initNgScope(scope)\n          .withVM({\n            plugins: pluginManager.module(scope.module)\n              .plugins()\n              .filter(plugin => !scope.filter() || scope.filter()(plugin))\n              .map(plugin => plugin.getId()),\n            $export() {\n              return {type: scope.model};\n            },\n            $import({type}) {\n              scope.model = scope.model || (this.plugins.includes(type) ? type : null);\n            }\n          })\n          .withEvents({\n            onChange(model) {\n              scope.onChange({plugin: pluginManager.module(scope.module).plugin(model)});\n            }\n          })\n          .withState('pluginPicker', 'pluginPicker', {});\n        });\n\n      inject('$timeout')(() => {\n        scope.model = scope.model || scope.vm.plugins[0];\n        scope.onLoad({plugin: pluginManager.module(scope.module).plugin(scope.model)});\n      });  \n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/runner/runner-results-formatter.ts",
    "content": "import { isPlainObject } from 'lodash';\nimport { hooks } from '../../hooks';\nimport { App } from '../../lib/app';\nimport { utils } from '../../lib/core';\nimport { Store } from '../../lib/store';\n\nconst urlFormatter = (name: string, value: any) => {\n  const regex = /^https?:\\/\\/.*/i;\n\n  if (!regex.test(value)) {\n    return null;\n  }\n\n  const escapedValue = utils.dom.escape(value);\n\n  return `<a class=\"bi-link\" href=\"${escapedValue}\" target=\"_blank\">${escapedValue}</a>`;\n}\n\nconst jsonFormatter = (name: string, value: any) => {\n  if (!isPlainObject(value)) {\n    return null;\n  }\n\n  return utils.dom.escape(JSON.stringify(value));\n}\n\nconst identityFormatter = (name: string, value: any) => '' + utils.dom.escape(value);\n\nconst Formatters = [\n  urlFormatter,\n  jsonFormatter,\n  identityFormatter,\n];\n\nexport const getFormatter = (app: App, store: Store, engine: string, id: string) => {\n  const formatters = [\n    ...hooks.note.results.formatters.pre.call([], app, store, engine, id),\n    ...Formatters,\n    ...hooks.note.results.formatters.post.call([], app, store, engine, id),\n  ];\n\n  return (name: string, value: any) => formatters.reduce((res, formatter) => {\n    if (res !== null) {\n      return res;\n    }\n\n    return formatter(name, value);\n  }, null);\n}"
  },
  {
    "path": "quix-frontend/client/src/components/runner/runner-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\nimport {ConsoleResultTestkit} from '../../lib/runner/directives/results/console/console-result-testkit';\n\nconst enum Hooks {\n  ToggleRun = 'runner-toggle-run'\n}\nexport class RunnerTestkit extends Testkit {\n  \n  async getConsoleResultTestkit() {\n    return new ConsoleResultTestkit(await this.query.$('bi-console-result'));\n  }\n\n  async clickRun() {\n    await this.click.hook(Hooks.ToggleRun);\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/components/runner/runner-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\nimport {INote} from '@wix/quix-shared';\n\nexport interface IScope extends ngIscope {\n  note: INote;\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/runner/runner.html",
    "content": "<div class=\"bi-c-h bi-grow\" bi-html=\"::renderRunner()\" bi-html-delay=\"0\"></div>"
  },
  {
    "path": "quix-frontend/client/src/components/runner/runner.scss",
    "content": "@import '../../lib/ui//assets/css/def/colors.def';\n\nquix-runner {\n  display: flex;\n  flex-direction: column;\n\n  .bi-link {\n    color: blue;\n\n    &:hover {\n      text-decoration: underline !important;\n      color: blue;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/components/runner/runner.ts",
    "content": "import template from './runner.html';\nimport './runner.scss';\n\nimport { isArray } from 'lodash';\nimport { initNgScope, inject } from '../../lib/core';\nimport { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IScope } from './runner-types';\nimport { pluginManager } from '../../plugins';\nimport { getFormatter } from './runner-results-formatter';\nimport { hooks } from '../../hooks';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    type: '<',\n    textContent: '=',\n    richContent: '=',\n    runner: '<',\n    quixRunnerOptions: '<',\n    renderStats: '&',\n    getDownloadFileName: '&',\n    onContentChange: '&',\n    onSave: '&',\n    onRun: '&',\n    onEditorInstanceLoad: '&',\n    onRunnerInstanceLoad: '&',\n    onRunnerCreated: '&',\n    onRunnerDestroyed: '&',\n    onParamsShare: '&',\n    readonly: '<',\n  },\n  link: {\n    async pre(scope: IScope) {\n      const plugin = pluginManager.module('note').plugin(scope.type);\n\n      const autocompleteDbFetchers = hooks.note.config.editor.autocompleteDbFetchers.call(\n        app,\n        store,\n        plugin.getEngine()\n      );\n\n      if (isArray(autocompleteDbFetchers)) {\n        scope.autocompleteDbFetchers = autocompleteDbFetchers[0];\n      }\n\n      initNgScope(scope)\n        .withOptions('quixRunnerOptions', {\n          focusEditor: true,\n          showEditor: true,\n          autoRun: false,\n          shareParams: true,\n        })\n        .withVM({\n          $init() {\n            this.type = plugin.getId();\n            this.engine = plugin.getEngine();\n            this.showSyntaxErrors = plugin.getConfig().syntaxValidation;\n            this.dateFormat = plugin.getConfig().dateFormat;\n          },\n        })\n        .withEvents({\n          onContentChange(textContent, richContent) {\n            return (\n              !scope.readonly &&\n              scope.onContentChange({ textContent, richContent })\n            );\n          },\n          onSave() {\n            return !scope.readonly && scope.onSave();\n          },\n          onRun() {\n            return scope.onRun();\n          },\n          onEditorInstanceLoad(instance) {\n            return scope.onEditorInstanceLoad({ instance });\n          },\n          onRunnerInstanceLoad(instance) {\n            instance.setUser(app.getUser());\n\n            return scope.onRunnerInstanceLoad({ instance });\n          },\n          onRunnerCreated(runner) {\n            return scope.onRunnerCreated({ runner });\n          },\n          onRunnerDestroyed(runner) {\n            return scope.onRunnerDestroyed({ runner });\n          },\n          onParamsShare(params) {\n            return scope.onParamsShare({ params });\n          },\n        })\n        .withActions({\n          getDownloadFileName(query) {\n            return scope.getDownloadFileName({ query });\n          },\n          renderStats() {\n            return scope.renderStats();\n          },\n        });\n\n      scope.tableFormatter = () =>\n        getFormatter(app, store, scope.vm.engine, scope.vm.type);\n\n      scope.renderRunner = () => {\n        const html = inject('$compile')(plugin.renderRunner())(scope);\n\n        return { html };\n      };\n    },\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/search-results/search-results-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class SearchResultsTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/search-results/search-results-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/search-results/search-results.html",
    "content": "<div class=\"bi-section bi-c-h bi-grow bi-theme--light\">\n  <div class=\"bi-section-header\">\n    <div>\n      <div class=\"bi-section-title bi-align bi-s-h bi-fade\" ng-if=\"vm.state.after('Result')\">\n        <i class=\"bi-icon\">search</i>\n        <span>\n          <span>\n            Search results \n            <span class=\"bi-fade-in\">\n              ({{vm.currentResults}} / {{vm.state.value().totalResults}})\n            </span>\n          </span>\n        </span>\n      </div>\n    </div>\n\n    <div>\n      <div\n        class=\"quix-search-pagination bi-button-group bi-fade-in\"\n        ng-if=\"vm.state.after('Result')\"\n      >\n        <button \n          class=\"bi-button\"\n          ng-disabled=\"vm.state.value().currentPage === 1\"\n          ng-click=\"events.onPageSelect(vm.state.value().currentPage - 1)\"\n        >\n          <i class=\"bi-icon--sm\">keyboard_arrow_left</i>\n        </button>\n\n        <button \n          class=\"bi-center\"\n          ng-class=\"{\n            'bi-button': page !== vm.state.value().currentPage,\n            'bi-button--primary': page === vm.state.value().currentPage\n          }\"\n          ng-repeat-start=\"page in vm.pages\"\n          ng-click=\"events.onPageSelect(page)\"\n        >{{::page}}</button>\n\n        <button \n          class=\"bi-button bi-center\"\n          ng-if=\"vm.pages[$index + 1] - page > 1\"\n          ng-repeat-end\n          ng-disabled=\"true\"\n        >...</button>\n\n        <button \n          class=\"bi-button\"\n          ng-disabled=\"vm.state.value().currentPage === vm.totalPages\"\n          ng-click=\"events.onPageSelect(vm.state.value().currentPage + 1)\"\n        >\n          <i class=\"bi-icon--sm\">keyboard_arrow_right</i>\n        </button>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"bi-section-content--center\" ng-if=\"vm.state.before('Content')\">\n    <div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.is('Initial')\">\n      <div class=\"bi-empty-state--loading bi-fade-in\">\n        <div class=\"bi-empty-state-content\">Searching...</div>\n      </div>\n    </div>\n\n    <div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.is('Error')\">\n      <div class=\"bi-empty-state bi-fade-in\">\n        <quix-image class=\"bi-empty-state-image\" name=\"error_{{::vm.state.value().error.status}}.svg\"></quix-image>\n        <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n      </div>\n    </div>\n\n    <div class=\"bi-c-h bi-align bi-center bi-grow\" ng-if=\"vm.state.is('Result')\">\n      <div class=\"bi-empty-state bi-fade-in\">\n        <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n        <div class=\"bi-empty-state-header\">No notes that match \"{{::vm.state.value().text}}\"</div>\n      </div>\n    </div>\n  </div>\n\n  <div\n    class=\"bi-section-content--list bi-fade\"\n    ng-class=\"{'bi-faded': vm.state.after('Content')}\"\n    ng-if=\"vm.state.after('Result')\"\n  >\n    <div class=\"bi-section-content-inner bi-c bi-s-v--x15\">\n      <div \n        class=\"bi-c bi-dont-shrink\"\n        ng-repeat=\"note in vm.state.value().notes track by note.id\"\n      >\n        <div\n          class=\"bi-panel bi-dont-shrink bi-theme--lighter bi-pointer bi-elevate\"\n          ng-click=\"events.onNoteClick(note)\"\n        >\n          <div class=\"bi-panel-header\">\n            <div class=\"bi-align bi-s-h--x05\">\n              <span class=\"bi-text--ui bi-muted\">{{::note.type | biToHumanCase}}</span>\n              <a class=\"bi-panel-title bi-link\">{{::note.name}}</a>\n              <span class=\"bi-text--sm bi-muted\">{{::note.owner}}</span>\n            </div>\n\n            <quix-meta entity=\"::note\"></quix-meta>\n          </div>\n          \n          <div class=\"bi-panel-content\">\n            <pre class=\"hljs\" bi-html=\"::renderNoteContent(note)\"></pre>\n          </div>\n        </div>\n      </div>\n    </div>  \n  </div>  \n</div>\n\n"
  },
  {
    "path": "quix-frontend/client/src/components/search-results/search-results.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n\nquix-search-results {\n  .hljs {\n    padding: 0;\n    font-family: Monaco, 'Courier New';\n    font-size: 12px;\n  }\n\n  .bi-section {\n    padding-top: 15px;\n    box-shadow: inset 0 1px 6px rgba(0, 0, 0, .05);\n\n    .bi-section-header,\n    .bi-section-controls,\n    .bi-section-content-inner {\n      margin-left: auto;\n      margin-right: auto;\n      padding-left: 0;\n      padding-right: 0;\n      width: 1024px;\n    }\n  }\n\n  .quix-search-pagination {\n    align-self: flex-end;\n\n    button {\n      min-width: 32px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/search-results/search-results.ts",
    "content": "import template from './search-results.html';\nimport './search-results.scss';\nimport 'highlight.js/styles/tomorrow.css';\n\nimport {assign, debounce} from 'lodash';\nimport hljs from 'highlight.js';\nimport {initNgScope, inject} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {INote, SearchResult, SearchTypes} from '@wix/quix-shared';\nimport {IScope} from './search-results-types';\nimport * as Resources from '../../services/resources';\nimport * as AppActions from '../../store/app/app-actions';\nimport {StateManager, extractLinesAroundMatch} from '../../services';\nimport {paramSerializerFactory} from '../../lib/code-editor';\nimport {Search} from '../../config';\n\nenum States {\n  Initial,\n  Error,\n  Result,\n  Content,\n  LoadingPage,\n}\n\nconst initPagination = (scope: IScope, totalResults: number, currentPage: number) => {\n  const totalPages = Math.ceil(totalResults / Search.ResultsPerPage);\n\n  const leftEdgePages = Math.min(\n    Math.max(0, totalPages - Search.PaginationMiddlePages),\n    Search.PaginationEdgePages\n  );\n\n  const rightEdgePages = Math.min(\n    Math.max(0, totalPages - Search.PaginationEdgePages - Search.PaginationMiddlePages),\n    Search.PaginationEdgePages\n  );\n\n  const middlePages = Math.min(totalPages, Search.PaginationMiddlePages);\n\n  const middleLeftBoundary = Math.min(\n    Math.max(\n      leftEdgePages,\n      currentPage - Math.round(Search.PaginationMiddlePages / 2)\n    ),\n    Math.max(0, totalPages - Search.PaginationMiddlePages - rightEdgePages)\n  );\n\n  scope.vm.pages = [\n    ...[...(Array(leftEdgePages).keys())].map(i => i + 1),\n    ...[...(Array(middlePages).keys())].map(i => i + 1 + middleLeftBoundary),\n    ...[...(Array(rightEdgePages).keys())].map(i => i + 1 + totalPages - rightEdgePages),\n  ];\n\n  scope.vm.currentResults = Math.min(currentPage * Search.ResultsPerPage, totalResults);\n  scope.vm.totalPages = totalPages;\n\n  scope.vm.state.value({currentPage: Math.min(totalPages, currentPage)});\n}\n\nconst initResults = (text: string, notes: INote[]) => {\n  const serializer = paramSerializerFactory('sql');\n\n  return notes.map<INote>(note => ({\n    ...note,\n    content: extractLinesAroundMatch(serializer.removeEmbed(note.content), text)\n  }));\n}\n\nconst search = (scope: IScope, store: Store, text: string, page: number) => {\n  ++scope.vm.currentSearch;\n  return searchDebounce(scope, store, text, page, scope.vm.currentSearch);\n}\n\nconst searchDebounce = debounce((scope: IScope, store: Store, text: string, page: number, searchId: number) => {\n  if (!text) {\n    store.dispatch(AppActions.setUrlSearchText(null, 'user'));\n    return store.dispatch(AppActions.setInputSearchText(null));\n  }\n\n  return Resources.search(text, (page - 1) * Search.ResultsPerPage, Search.ResultsPerPage)\n    .then(({notes, count, term}: SearchResult) => {\n      if (searchId === scope.vm.currentSearch) {\n        scope.vm.state\n          .force('Result', true, {\n            totalResults: count,\n            notes: initResults(text, notes),\n            highlights: term[SearchTypes.content].map(searchObject => searchObject.text),\n          })\n          .set('Content', !!notes.length);\n        initPagination(scope, scope.vm.state.value().totalResults, scope.vm.state.value().currentPage);\n      }\n    })\n    .catch(e => {\n      if (searchId === scope.vm.currentSearch) {\n        scope.vm.state.force('Error', true, {error: {...e.data, status: e.status}});\n      }\n    })\n    .then(() => {\n      if (searchId === scope.vm.currentSearch) {\n        store.dispatch(AppActions.setUrlSearchText(text, 'user'));\n      }\n    });\n}, 300);\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {},\n  link: {\n    async pre(scope: IScope) {\n      initNgScope(scope)\n        .withVM({\n          pages: null,\n          totalPages: 1,\n          currentResults: 1,\n          $init() {\n            this.state = new StateManager(States);\n            this.currentSearch = 1;\n          }\n        })\n        .withEvents({\n          onNoteClick(note: INote) {\n            app.go('notebook', {id: note.notebookId, note: note.id});\n          },\n          onPageSelect(page: number) {\n            store.dispatch(AppActions.setSearchPage(page, 'user'));\n          }\n        });\n\n      store.subscribe('app.inputSearchText', text => {\n        scope.vm.state.force('Initial', true, {text, currentPage: 1});\n\n        return search(scope, store, text, scope.vm.state.value().currentPage);\n      }, scope);\n\n      store.subscribe('app.searchPage', page => {\n        if (page) {\n          scope.vm.state\n            .set('LoadingPage', scope.vm.state.after('Result'), {currentPage: page})\n            .else(() => scope.vm.state.value({currentPage: page}));\n\n          search(scope, store, scope.vm.state.value().text, page);\n        }\n      }, scope);\n\n      scope.renderNoteContent = (note: INote) => ({\n        html: inject('$compile')(`\n          <div ng-bind-html=\"html | biHighlight:vm.state.value().highlights\"></div>\n        `)(assign(scope.$new(), {\n          html: hljs.highlight('sql', note.content).value\n        }))\n      });\n\n      scope.$on('$destroy', () => store.dispatch([\n        AppActions.setSearchPage(null, 'user'),\n        AppActions.setInputSearchText(null, 'user'),\n        AppActions.setUrlSearchText(null, 'user')\n      ]));\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/components/temp-query/temp-query-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class TempQueryTestkit extends Testkit {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/components/temp-query/temp-query-types.ts",
    "content": "import {IScope as ngIscope} from 'angular';\n\nexport interface IScope extends ngIscope {\n  vm: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/temp-query/temp-query.html",
    "content": "<div class=\"bi-c-h bi-grow bi-s-v--x3\">\n  <div class=\"bi-align bi-s-h--x2\">\n    <div class=\"bi-text--lg bi-text--300\">\n      Playground\n    </div>\n\n    <quix-plugin-picker\n      module=\"note\"\n      filter=\"vm.pluginFilter\"\n      ng-model=\"type\"\n      on-load=\"events.onPluginLoad(plugin)\"\n      on-change=\"events.onPluginChange(plugin)\"\n    ></quix-plugin-picker>\n  </div>\n\n  <quix-runner\n    class=\"bi-c-h bi-grow bi-fade-in\"\n    ng-show=\"vm.runner.visible\"\n    ng-if=\"vm.runner.enabled\"\n    type=\"type\"\n    runner=\"runner\"\n    quix-runner-options=\"::{autoRun: autorun, shareParams: false}\"\n    text-content=\"vm.engines[vm.plugin.getEngine()].textContent\"\n    rich-content=\"vm.engines[vm.plugin.getEngine()].richContent\"\n    on-content-change=\"events.onContentChange(textContent, richContent)\"\n    on-save=\"events.onSave()\"\n    on-run=\"events.onRun()\"\n  ></quix-runner>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/components/temp-query/temp-query.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n\nquix-temp-query {\n  quix-plugin-picker {\n    margin-top: 1px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/components/temp-query/temp-query.ts",
    "content": "import template from './temp-query.html';\nimport './temp-query.scss';\n\nimport {initNgScope} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IScope} from './temp-query-types';\nimport { NotePlugin } from '../../services/plugins';\n\nexport default (app: App, store: Store) => () => ({\n  restrict: 'E',\n  template,\n  scope: {\n    type: '<',\n    textContent: '<',\n    richContent: '<',\n    autorun: '<'\n  },\n  link: {\n    pre(scope: IScope) {\n      initNgScope(scope)\n        .withVM({\n          $import({engines} = {engines: {}}) {\n            scope.vm.engines = engines || {};\n          },\n          $export() {\n            return {engines: scope.vm.engines};\n          },\n          runner: {\n            enabled: false,\n          },\n          pluginFilter(plugin: NotePlugin) {\n            return plugin.getConfig().canCreate;\n          },\n          $init() {\n            this.engines = {};\n            this.plugin = null;\n          }\n        })\n        .withEvents({\n          onContentChange(textContent, richContent) {\n            const engine = scope.vm.plugin.getEngine();\n            const engineContent = scope.vm.engines[engine] = scope.vm.engines[engine] || {};\n\n            engineContent.textContent = textContent;\n            engineContent.richContent = richContent;\n\n            scope.state.save();\n          },\n          onPluginLoad(plugin: NotePlugin) {\n            const engine = plugin.getEngine();\n            const engineContent = scope.vm.engines[engine] = scope.vm.engines[engine] || {};\n\n            engineContent.textContent = scope.textContent || engineContent.textContent || '';\n            engineContent.richContent = scope.richContent || engineContent.richContent;\n\n            scope.vm.plugin = plugin;\n            scope.vm.runner.reload();\n          },\n          onPluginChange(plugin: NotePlugin) {\n            const engine = plugin.getEngine();\n            const engineContent = scope.vm.engines[engine] = scope.vm.engines[engine] || {};\n\n            engineContent.textContent = engineContent.textContent || '';\n            engineContent.richContent = engineContent.richContent;\n\n            scope.vm.plugin = plugin;\n            scope.vm.runner.reload();\n          }\n        })\n        .withState('playground', 'playground', {});\n    }\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/config.ts",
    "content": "import { App } from './lib/app';\nimport { Store } from './lib/store';\nimport { isOwner } from './services';\nimport { waitForEntity } from './store';\n\nexport const Time = {\n  Format: 'YYYY-MM-DD HH:mm',\n};\n\nexport const DB = {\n  SampleLimit: 1000,\n  RootName: '__root',\n};\n\nexport const Search = {\n  ResultsPerPage: 20,\n  MaxPages: 100,\n  MaxPaginationButtons: 10,\n  PaginationEdgePages: 2,\n  PaginationMiddlePages: 5,\n};\n\nexport const Import = {\n  FolderName: '__imports__',\n};\n\nexport const QuixFolder = {\n  id: 'quix',\n  name: 'Quix',\n  owner: 'Quix',\n  ownerDetails: {\n    name: 'Quix',\n  } as any,\n};\n\nexport const ExamplesNotebook = {\n  id: 'examples',\n  name: 'Examples',\n  owner: 'Quix',\n  ownerDetails: {\n    name: 'Quix',\n    avatar: 'http://quix.wix.com/assets/logo.png',\n  } as any,\n};\n\nexport const HeaderMenu = (scope) => [\n  {\n    title: 'My notebooks',\n    targetState: 'files',\n    activeStates: ['files', 'notebook'],\n    activeCondition: (app: App, store: Store, state: string, id: string) =>\n      waitForEntity(\n        scope,\n        store,\n        id,\n        state === 'files' ? 'folder' : 'notebook'\n      ).then((entity) => isOwner(app, entity)),\n  },\n  {\n    title: 'Favorites',\n    targetState: 'favorites',\n    activeCondition: null,\n  },\n  {\n    title: 'Users',\n    targetState: 'users',\n    activeCondition: null,\n  },\n  {\n    title: 'History',\n    targetState: 'history',\n    activeCondition: null,\n  },\n];\n"
  },
  {
    "path": "quix-frontend/client/src/custom.d.ts",
    "content": "declare module \"*.svg\" {\n    const content: any;\n    export default content;\n}"
  },
  {
    "path": "quix-frontend/client/src/data/examples-notebook.ts",
    "content": "import {createNotebook, createNote} from '@wix/quix-shared';\nimport {QuixFolder, ExamplesNotebook} from '../config';\n\nconst addNote = (id, name, content) => createNote('examples', {id, name, content, owner: QuixFolder.owner});\n\nexport default () => createNotebook([{\n  id: QuixFolder.id,\n  name: QuixFolder.name\n}], {\n  ...ExamplesNotebook,\n  notes: [\n    addNote('simple', 'Simple query', `-- Hit \"Run\" to execute the query\n\nSELECT \n    shipdate\n    , shipinstruct\n    , shipmode\nFROM tpch.sf1.lineitem\nLIMIT 100\n\n`\n    ),\n    addNote('params', 'Parameters', `/* AUTOGENERATED\n$string_param:string=[Hello World!] $number_param:number=[100] $bool_param:boolean=[true] $date_param:datetime=[2019-05-06 00:00] $list_param:list:Option 1,Option 2,Option 3=[Option 1,Option 2] $option_param:option:Option 1,Option 2,Option 3=[Option 1]\nAUTOGENERATED END */\n\n-- Click the hamburger menu on the left to add or edit parameters\n-- Use $<param name> as placeholders in your query, they will be replaced with actual values when the query is executed\n\nSELECT \n    '$string_param' as string_value\n    , '$number_param' as number_param\n    , '$bool_param' as bool_param\n    , '$date_param' as date_param\n    , '$list_param' as list_param\n    , '$option_param' as option_param\n      \n`\n    ),\n    addNote('start-stop-params', 'START_TIME and STOP_TIME', `/* AUTOGENERATED\n$START_TIME $STOP_TIME\nAUTOGENERATED END */\n\n-- START_TIME and STOP_TIME are handy params that allow to quickly define a range of two days\n-- Values of these params are reset to their defaults each time the note is opened\n-- START_TIME defaults to current_date - 2 days\n-- STOP_TIME defaults to current_date\n\nSELECT \n    '$START_TIME' start\n    , '$STOP_TIME' stop\n    , current_date as \"current_date\"\n    , localtimestamp as \"localtimestamp\"\nWHERE current_date BETWEEN TIMESTAMP '$START_TIME' AND TIMESTAMP '$STOP_TIME';\n\n`\n    ),\n    addNote( 'timeline', 'Timeline chart', `/* AUTOGENERATED\n$schema:option:tpch.tiny,tpch.sf1=[tpch.sf1]\nAUTOGENERATED END */\n\n-- Include at least one date and one numeric column in the result to enable timeline charts\n-- Hit \"Run\" and choose the \"chart\" option from the menu on the left\n\nSELECT\n    date_trunc('year', shipdate) shipyear\n    , shipmode\n    , sum(quantity) quantity\nFROM $schema.lineitem\nGROUP BY 1, 2\nORDER BY 1\n\n`\n    ),\n    addNote('bar', 'Bar chart', `/* AUTOGENERATED\n$schema:option:tpch.tiny,tpch.sf1=[tpch.sf1]\nAUTOGENERATED END */\n\n-- Include at least one string and one numeric column in the result to enable bar charts\n-- Hit \"Run\" and choose the \"chart\" option from the menu on the left\n\nSELECT\n    shipmode\n    , sum(quantity) quantity\nFROM $schema.lineitem\nGROUP BY 1\nORDER BY 1\n\n`\n    ),\n    addNote('pie', 'Pie chart', `/* AUTOGENERATED\n$schema:option:tpch.tiny,tpch.sf1=[tpch.sf1]\nAUTOGENERATED END */\n\n-- Include at least one string and one numeric column in the result to enable pie charts\n-- Hit \"Run\" and choose the \"pie\" option from the menu on the left\n\nSELECT\n    shipmode\n    , sum(quantity) quantity\nFROM $schema.lineitem\nGROUP BY 1\nORDER BY 1\n\n`\n    )\n  ]\n});\n"
  },
  {
    "path": "quix-frontend/client/src/data/index.ts",
    "content": "export {default as createExamplesNotebook} from './examples-notebook';\nexport {default as createQuixFolder} from './quix-folder';\n"
  },
  {
    "path": "quix-frontend/client/src/data/quix-folder.ts",
    "content": "import {createFolderPayload, createFile, } from '@wix/quix-shared';\nimport {QuixFolder, ExamplesNotebook} from '../config';\n\nexport default () => createFolderPayload([], {\n  ...QuixFolder,\n  files: [createFile([{\n    id: QuixFolder.id,\n    name: QuixFolder.name\n  }], {\n    id: ExamplesNotebook.id,\n    name: ExamplesNotebook.name\n  })]\n});\n"
  },
  {
    "path": "quix-frontend/client/src/external-types.d.ts",
    "content": "declare module '*.scss';\ndeclare module '*.json';\ndeclare module '*.html';\ndeclare var browser: any;\n\ndeclare module NodeJS {\n  interface Global {\n    browser: any;\n  }\n}\n\ninterface DedicatedWorkerGlobalScope {}\n\ninterface Window {\n  quixConfig: any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/hooks.ts",
    "content": "import {SyncHook, AsyncSeriesHook, SyncWaterfallHook} from 'tapable';\n\nexport const hooks = {\n  bootstrap: new SyncHook(['appBuilder']),\n  app: {\n    stateChange: new SyncHook(['app', 'state', 'params', 'previousState'])\n  },\n  note: {\n    plugin: new SyncWaterfallHook(['app', 'store', 'engine', 'id']),\n    import: new AsyncSeriesHook(['app', 'store', 'note', 'value']),\n    runStart: new SyncHook(['app', 'store', 'note', 'runner']),\n    runFinish: new SyncHook(['app', 'store', 'note', 'runner']),\n    results: {\n      formatters: {\n        pre: new SyncWaterfallHook(['res', 'app', 'store', 'engine', 'id']),\n        post: new SyncWaterfallHook(['res', 'app', 'store', 'engine', 'id']),\n      },\n      viz: new SyncWaterfallHook(['app', 'store', 'engine']),\n    },\n    config: {\n      editor: {\n        autoParams: new SyncWaterfallHook(['app', 'store']),\n        autocompleteDbFetchers: new SyncWaterfallHook(['app', 'store', 'engine']),\n      }\n    }\n  },\n  header: {\n    additionalItems: new SyncWaterfallHook(['app', 'store']),\n  }\n};\n"
  },
  {
    "path": "quix-frontend/client/src/index.vm",
    "content": "<!DOCTYPE html>\n<html ng-app=\"quix\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Quix</title>\n    <link type=\"image/png\" href=\"${clientTopology.staticsBaseUrl}assets/favicon.png\" rel=\"shortcut icon\">\n    <link href=\"https://fonts.googleapis.com/css?family=Open+Sans:200,300,400,600,700\" rel=\"stylesheet\">\n    <link href=\"https://fonts.googleapis.com/css?family=Bangers:200,300,400,600,700\" rel=\"stylesheet\">\n    <link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\">\n    <link href=\"${clientTopology.staticsBaseUrl}app#if(!${mode.debug}).min#{end}.css\" rel=\"stylesheet\">\n  </head>\n  <body class=\"bi-c\" ng-controller=\"app\">\n    <bi-app app=\"app\" store=\"store\">\n      <header class=\"bi-align bi-grow\">\n        <quix-header class=\"bi-align\"><quix-header>\n      </header>\n      <div class=\"quix-splash bi-c bi-s-v--x3 bi-fade-in\">\n        <img class=\"quix-splash-logo\" src=\"${clientTopology.staticsBaseUrl}assets/logo_big.png\">\n        <span class=\"bi-center bi-text--ui bi-text--large bi-muted\">Loading...</span>\n      </div>\n    </bi-app>\n\n    <script>\n      window.quixConfig = ${quixConfig};\n    </script>\n\n    <script src=\"${clientTopology.staticsBaseUrl}app.bundle#if(!${mode.debug}).min#{end}.js\"></script>\n    <script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/bootstrap.ts",
    "content": "import jQuery from 'jquery';\nwindow.jQuery = jQuery;\nwindow.$ = jQuery;\n\nimport angular from 'angular';\n\nimport 'angular-resource';\nimport 'angular-ui-router';\n\nimport '../core';\nimport '../ui';\n\nexport const ngApp = angular.module('bi.app', [\n  'ngResource',\n  'bi.core',\n  'bi.ui',\n  'ui.router'\n]);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/constants.ts",
    "content": "export const Apps = [];\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/app/app.html",
    "content": "<div\n  class=\"bi-app-header bi-fade-in bi-theme--lighter\"\n  ng-if=\"vm.header.enabled\"\n>\n  <div\n    class=\"bi-app-title bi-pointer\"\n    ng-click=\"events.onTitleClick()\"\n    role=\"button\"\n    data-hook=\"app-title\"\n  >\n    <img\n      class=\"bi-app-logo\"\n      ng-if=\"::app.getLogoUrl()\"\n      ng-src=\"{{::app.getLogoUrl()}}\"\n    />\n    <span>{{::app.getTitle()}}</span>\n  </div>\n\n  <div\n    class=\"bi-grow bi-fade-in\"\n    ng-transclude=\"header\"\n    ng-if=\"user.isLoggedIn()\"\n  ></div>\n\n  <div class=\"bi-fade-in\" ng-if=\"user.isLoggedIn()\">\n    <div class=\"bi-align bi-s-h--x15\">\n      <bi-dropdown bd-options=\"::{align: 'center'}\" ng-if=\"::vm.apps.length\">\n        <bi-toggle class=\"bi-align\">\n          <i class=\"bi-action bi-icon\" role=\"button\" data-hook=\"apps-menu\"\n            >apps</i\n          >\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu bi-r\">\n          <li\n            ng-repeat=\"menuApp in ::vm.apps\"\n            ng-click=\"events.onAppClick(menuApp)\"\n            role=\"button\"\n            data-hook=\"apps-menu-{{::menuApp.name}}\"\n          >\n            <i\n              class=\"bi-icon bi-muted\"\n              ng-class=\"::{'bi-success': menuApp.name === app.getId()}\"\n              >lens</i\n            >\n            <span>{{::menuApp.title}}</span>\n          </li>\n        </ul>\n      </bi-dropdown>\n\n      <span class=\"bi-muted\">{{::user.getName()}}</span>\n\n      <img class=\"bi-app-user-logo\" ng-src=\"{{::user.getAvatar()}}\" />\n    </div>\n  </div>\n</div>\n\n<div class=\"bi-r-h\">\n  <div\n    class=\"bi-app-menu bi-theme--darker bi-dont-shrink bi-fade-in\"\n    ng-if=\"vm.menu.enabled && user.isLoggedIn() && app.getMenuItems().length\"\n  >\n    <ul>\n      <li\n        class=\"bi-c-h bi-muted\"\n        ng-class=\"{\n          'bi-active': item === vm.menu.current,\n          'bi-hover': item.name !== 'separator',\n          'bi-pointer': item.name !== 'separator'\n        }\"\n        ng-click=\"events.onMenuItemToggle(item)\"\n        ng-repeat=\"item in app.getMenuItems()\"\n        bi-html=\"renderMenuItem(scope, item)\"\n      ></li>\n    </ul>\n  </div>\n\n  <div\n    class=\"bi-app-sidebar bi-theme--dark bi-section bi-c bi-dont-shrink\"\n    ng-if=\"user.isLoggedIn() && vm.menu.current && (vm.menu.current.template || vm.menu.current.compiled)\"\n    bi-resizable\n    br-options=\"::{minWidth: 300, handles: 'e', stateName: 'app-sidebar'}\"\n  >\n    <div class=\"bi-section-header\">\n      <div class=\"bi-section-title\">{{vm.menu.current.name}}</div>\n      <div class=\"bi-app-sidebar-toggle\">\n        <i\n          class=\"bi-action bi-icon\"\n          ng-click=\"events.onMenuItemToggle(vm.menu.current)\"\n          >keyboard_arrow_left</i\n        >\n      </div>\n    </div>\n    <div\n      class=\"bi-section-content bi-c-h bi-grow\"\n      ng-if=\"vm.menu.content.enabled\"\n      ng-show=\"vm.menu.content.visible\"\n      bi-html=\"compileMenuItem(vm.menu.current)\"\n    ></div>\n  </div>\n\n  <div class=\"bi-app-content bi-c-h bi-grow\" ui-view>\n    <div class=\"bi-c-h bi-center bi-align bi-grow\">\n      <div\n        class=\"quix-splash bi-c bi-s-v--x3\"\n        ng-if=\"app.getUser().isLoggedIn() === null\"\n      >\n        <img\n          class=\"quix-splash-logo\"\n          ng-if=\"::app.getLogoUrl()\"\n          ng-src=\"{{::app.getLogoUrl()}}\"\n        />\n        <span class=\"bi-center bi-text--ui bi-text--large bi-muted\"\n          >Signing in...</span\n        >\n      </div>\n\n      <bi-app-login\n        app=\"app\"\n        ng-if=\"app.getUser().isLoggedIn() === false\"\n      ></bi-app-login>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/app/app.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n\nbi-app {\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n  overflow: hidden;\n\n  .bi-app-header {\n    [ng-transclude=\"header\"] {\n      header {\n        display: block;\n        height: 54px;\n      }\n    }\n\n    bi-dropdown {\n      bi-toggle {\n        height: 53px;\n      }\n    }\n  }\n\n  .bi-app-menu {\n    .bi-app-menu-separator {\n      width: 100%;\n      border-top: 1px solid darken($darker-bg, 7);\n      border-bottom: 1px solid lighten($darker-bg, 7);\n    }\n  }\n\n  .bi-app-sidebar {\n    width: 300px;\n\n    .bi-app-sidebar-toggle {\n      margin-right: -6px;\n    }\n\n    .bi-section-content {\n      padding: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/app/app.ts",
    "content": "import template from './app.html';\nimport './app.scss';\n\nimport { assign, find, without } from 'lodash';\nimport { initNgScope, inject } from '../../../core';\nimport { IMenuItem } from '../../services/app';\nimport { App } from '../..';\nimport { Apps } from '../../constants';\nimport { Store } from '../../../store';\n\nexport interface IScope extends ng.IScope {\n  app: App;\n  store: Store;\n}\n\nfunction setCurrentMenuItem(scope: IScope, item: IMenuItem) {\n  return (scope.vm.menu.current = item);\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    transclude: {\n      header: '?header',\n    },\n    scope: {\n      app: '=',\n      store: '=',\n    },\n    link: {\n      pre(scope: IScope) {\n        scope.user = scope.app.getUser();\n\n        initNgScope(scope)\n          .withVM({\n            apps: without(Apps, find(Apps, { id: scope.app.getId() } as any)),\n            header: {},\n            menu: {\n              current: null,\n              content: {},\n            },\n            loginHint: {},\n          })\n          .withEvents({\n            onMenuItemToggle(item: IMenuItem) {\n              const { current, content } = scope.vm.menu;\n\n              if (!item.template) {\n                item.onToggle && item.onToggle(scope.app, item);\n                return;\n              }\n\n              if (typeof item.onToggle === 'function') {\n                item.onToggle(scope.app, item);\n                setCurrentMenuItem(scope, item);\n              } else {\n                setCurrentMenuItem(scope, current === item ? null : item);\n              }\n\n              if (scope.vm.menu.current) {\n                content.reload();\n              } else {\n                content.toggle(false);\n              }\n\n              if (current && current.scope) {\n                current.scope.$destroy();\n                delete current.scope;\n              }\n            },\n            onAppClick({ href }) {\n              window.open(href, '_blank');\n            },\n            onTitleClick() {\n              scope.app.getNavigator().goHome();\n            },\n          });\n\n        scope.compileMenuItem = (item: IMenuItem) => {\n          (item as any).scope = scope.$new(true);\n\n          return {\n            html:\n              item.compiled ||\n              inject('$compile')(item.template)((item as any).scope),\n          };\n        };\n\n        scope.app\n          .getNavigator()\n          .listen(\n            scope.app\n              .getMenuItems()\n              .map((item) => item.state)\n              .filter((state) => state),\n            'start',\n            (params, stateName) => {\n              scope.app.getMenuItems().some((item) => {\n                if (!item.state) {\n                  return false;\n                }\n\n                return (\n                  stateName.indexOf(item.state) >= 0 &&\n                  !!(setCurrentMenuItem(scope, item) || true)\n                );\n              });\n            },\n            scope\n          )\n          .otherwise(\n            () =>\n              scope.vm.menu.current &&\n              scope.vm.menu.current.state &&\n              setCurrentMenuItem(scope, null)\n          );\n\n        scope.app.getStore().subscribe(\n          'app',\n          ({ header, menu }) => {\n            scope.vm.header.toggle(header);\n            scope.vm.menu.toggle(menu);\n          },\n          scope\n        );\n\n        scope.renderMenuItem = (_scope: any, menuItem: IMenuItem) => {\n          let html;\n\n          if (\n            typeof menuItem.icon === 'string' ||\n            menuItem.name === 'separator'\n          ) {\n            html = inject('$compile')(\n              menuItem.name === 'separator'\n                ? `<div class=\"bi-app-menu-separator\"></div>`\n                : `<i\n                    class=\"bi-action bi-icon\"\n                    ng-class=\"{'bi-active': item === vm.menu.current}\"\n                    title=\"{{::item.name}}\"\n                    role=\"button\"\n                    data-hook=\"app-menu-{{::item.name}}\"\n                  >{{::item.icon}}</i>`\n            )(assign(_scope.$new(true), { item: menuItem }));\n          } else {\n            html = menuItem.icon(_scope.app, _scope.store, _scope);\n          }\n\n          return { html };\n        };\n\n        inject('$timeout')(() => scope.vm.loginHint.toggle(true), 5000);\n      },\n    },\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/index.ts",
    "content": "export {default as biApp} from './app/app';\nexport {default as biAppLogin} from './login/login';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/login/login.html",
    "content": "<div class=\"bi-center\">\n  <img class=\"quix-splash-logo\" ng-if=\"::app.getLogoUrl()\" ng-src=\"{{::app.getLogoUrl()}}\">\n</div>\n\n<div class=\"bi-panel bi-theme--lighter bi-fade-in\">\n  <div class=\"bi-panel-content bi-c-h\">\n    <button\n      class=\"bi-button--primary bi-center\"\n      ng-click=\"events.onLoginClick()\"\n      ng-disabled=\"vm.pending.enabled\"\n    >{{vm.pending.enabled ? 'Signing in...' : 'Sign in with Google'}}</button>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/login/login.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n\nbi-app-login {\n  img {\n    width: 100px;\n    margin-bottom: 43px;\n  }\n\n  .bi-panel {\n    width: 400px;\n\n    button {\n      height: 40px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/directives/login/login.ts",
    "content": "import template from './login.html';\nimport './login.scss';\n\nimport {initNgScope, utils} from '../../../core';\nimport {App} from '../..';\n\nexport interface IScope extends ng.IScope {\n  app: App;\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      app: '='\n    },\n    link: {\n      pre(scope: IScope) {\n        initNgScope(scope)\n          .withVM({\n            pending: {}\n          })\n          .withEvents({\n            onLoginClick() {\n              scope.vm.pending.toggle(true);\n\n              scope.app.login()\n                .catch(() => utils.scope.safeDigest(scope, () => scope.vm.pending.toggle(false)));\n            }\n          });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/index.ts",
    "content": "import './typings/window';\nimport {forEach} from 'lodash';\nimport {ngApp} from './bootstrap';\nimport {Builder} from './services/builder';\nimport * as directives from './directives';\nimport {Options} from './types';\n\nexport {App} from './services/app';\nexport {PluginBuilder} from './services/plugin-builder';\n\nforEach(directives, (fn, name) => ngApp.directive(name, fn as any));\n\nexport default function app<Config = any>(id: string | {\n  id: string;\n  title: string;\n}, options: Options = {}, modules = []): Builder<Config> {\n  return new Builder<Config>(id, ngApp, options, modules);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/app.ts",
    "content": "import {createStore, Store} from '../../store';\nimport angular from 'angular';\nimport Navigator from './navigator';\nimport {User} from './user';\nimport {login} from './sso';\nimport {Options} from '../types';\nimport { hooks } from '../../../hooks';\n\nexport interface IMenuItem {\n  name: string;\n  icon?: string | Function;\n  state?: string;\n  template?: string;\n  compiled?: string;\n  onToggle?(app?: App, item?: IMenuItem): any;\n}\n\nexport class App<Config = any> {\n  private ngModule: angular.IModule;\n  private readonly store: Store;\n\n  constructor(\n    private readonly id: string,\n    private readonly title: string,\n    private readonly options: Options,\n    private readonly plugins,\n    private readonly user: User,\n    private readonly navigator: Navigator,\n    private readonly menuItems: IMenuItem[],\n    private readonly config: Config,\n  ) {\n    this.store = createStore({\n      app: register => register((state = {\n        header: true,\n        menu: true,\n      }, action) => {\n        switch (action.type) {\n          case 'toggle.header':\n            return {...state, header: action.header};\n          case 'toggle.menu':\n            return {...state, menu: action.menu};\n          default:  \n        }\n\n        return state;\n      })\n    });\n  }\n\n  init(modules: string[] = []) {\n    this.ngModule = angular.module(this.id, ['bi.app'].concat(modules));\n    this.navigator.on('stateChangeSuccess', (name, params, fromState) => {\n      hooks.app.stateChange.call(this, name, params, fromState);\n    });\n\n    return this;\n  }\n\n  login() {\n    return login(this.options.auth.googleClientId, this.options.apiBasePath)\n      .then(data => this.navigator.finishLogin(data));\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  getTitle() {\n    return this.title;\n  }\n\n  getLogoUrl() {\n    return this.options.logoUrl;\n  }\n\n  getUser(): User {\n    return this.user;\n  }\n\n  getModule(): angular.IModule {\n    return this.ngModule;\n  }\n\n  getNavigator(): Navigator {\n    return this.navigator;\n  }\n\n  getPlugin(id: string) {\n    return this.plugins[id];\n  }\n\n  getMenuItems() {\n    return this.menuItems;\n  }\n\n  getStore() {\n    return this.store;\n  }\n\n  getConfig() {\n    return this.config;\n  }\n\n  toggleHeader(state: boolean) {\n    this.store.dispatch({type: 'toggle.header', header: state});\n  }\n\n  toggleMenu(state: boolean) {\n    this.store.dispatch({type: 'toggle.menu', menu: state});\n  }\n\n  go(state: string, params?: Object, options?) {\n    this.navigator.go(state, params, options);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/appStoreProvider.tsx",
    "content": "import React from 'react';\nimport { Subtract } from 'utility-types';\nimport {Store} from '../../store';\nimport {App} from '../../app';\n\nconst AppStoreContext = React.createContext<InjectedAppStoreProps>({\n  app: null,\n  store: null\n});\n\nexport interface InjectedAppStoreProps {\n    app:App,\n    store: Store\n}\n\nexport const withAppStoreProvider = <P extends {}>(app: App, store: Store, ComponentToWrap: React.ComponentType<P> ):React.FC<P> => \n(props) => <AppStoreContext.Provider value={{app, store}}>\n  <ComponentToWrap {...props}/>\n</AppStoreContext.Provider>\n\nexport const withAppStore = <P extends InjectedAppStoreProps>(\n  ComponentToWrap: React.ComponentType<P>,\n): React.ComponentType<Subtract<P, InjectedAppStoreProps>> => props => (\n  <AppStoreContext.Consumer>\n    {({ app, store }) => {\n      const injectedProps = { ...props, app, store } as P;\n      return <ComponentToWrap {...injectedProps} />;\n    }}\n  </AppStoreContext.Consumer>\n);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/builder.ts",
    "content": "import {mapValues, last} from 'lodash';\nimport {paramCase, camelCase, headerCase} from 'change-case';\nimport {srv, inject, utils} from '../../core';\nimport {createStore, Store} from '../../../lib/store';\nimport Navigator from './navigator';\nimport {App, IMenuItem} from './app';\nimport {\n  PluginBuilder,\n  IPluginComponent,\n  IStateFactory,\n  IPluginBranches,\n  IStateComponentFactory,\n  IUrlParamListener,\n  IReactStateComponentConfig,\n  IAngularStateComponentConfig,\n  IStateComponentConfig,\n  IPluginReactComponent\n} from './plugin-builder';\nimport {initScopeListeners} from '../utils/scope-utils';\nimport {User} from './user';\nimport {LocalStorage} from '../../core/srv/local-storage';\nimport {Options} from '../types';\nimport {react2angular} from 'react2angular';\nimport { withAppStoreProvider } from './appStoreProvider';\n\nexport type PluginFactory<Config> = (app: PluginBuilder<Config>) => any;\n\nconst userActionToUrlParam = {};\nconst urlMiddleware = str => next => action => {\n  next(action);\n\n  if (action.origin !== 'user' || !userActionToUrlParam[action.type]) {\n    return;\n  }\n\n  const location = inject('$location');\n  const {param, listener} = userActionToUrlParam[action.type];\n\n  location.search({...location.search(), [param]: listener.to(action)});\n};\n\n/**\n * Application instance builder\n *\n * Allows to:\n *  - register application plugins\n *  - register application states\n *  - register menu items\n */\nexport class Builder<Config = any> extends srv.eventEmitter.EventEmitter {\n  private readonly plugins: {[key: string]: PluginBuilder<Config>} = {};\n  private readonly navigator: Navigator;\n  private readonly user: User;\n  private readonly menuItems: IMenuItem[] = [];\n  private readonly title: string;\n  private conf: Config;\n\n  constructor(\n    private readonly id: string | {\n      id: string;\n      title: string;\n    },\n    private readonly ngApp: angular.IModule,\n    private readonly options: Options,\n    private ngmodules = []\n  ) {\n    super();\n\n    this.user = new User();\n\n    if (typeof id === 'object') {\n      this.id = id.id;\n      this.title = id.title;\n    } else {\n      this.title = id;\n    }\n\n    this.navigator = new Navigator({\n      ...options,\n      statePrefix: typeof options.statePrefix === 'undefined' ? 'auth.content.' : options.statePrefix,\n      defaultUrl: options.defaultUrl || '/',\n    }).init(this.user, ngApp);\n  }\n\n  /**\n   * Registers an application plugin\n   *\n   * @param id        plugin id\n   * @param factory   plugin factory\n   */\n  plugin(id: string, factory: (pluginBuilder: PluginBuilder<Config>) => any): Builder<Config> {\n    this.plugins[id] = new PluginBuilder(id, this);\n\n    factory(this.plugins[id]);\n\n    return this;\n  }\n\n  /**\n   * Registers a ui-router state\n   *\n   * @param options   ui-router state options\n   */\n  state(options: any): Builder<Config> {\n    const {name} = options;\n    delete options.name;\n\n    this.navigator.state(name, options);\n\n    return this;\n  }\n\n  /**\n   * Registers an angular directive\n   *\n   * @param name      component name\n   * @param factory   component factory\n   */\n  component(name: string, factory: angular.IDirectiveFactory): Builder<Config> {\n    this.ngApp.directive(name, factory);\n    return this;\n  }\n\n  reactComponent(name: string, factory: angular.IComponentOptions): Builder<Config> {\n    this.ngApp.component(name, factory);\n    return this;\n  }\n\n  /**\n   * Registers a state component\n   *\n   * @param config    state component config\n   */\n  stateComponent(config: IStateComponentConfig, app: App, store: Store): Builder<Config> {\n    function fromUrl(scope, url: {[key: string]: IUrlParamListener}, params: object) {\n      const actions = Object.keys(url).map(param => (url as any)[param].from(params[param]));\n\n      utils.scope.safeDigest(scope, () => store.dispatch(actions));\n    }\n\n    const [fullStateName, paramName] = config.name.split(':');\n    const stateParts = fullStateName.split('.');\n    const stateName = last(stateParts);\n    const componentName = [app.getId(), paramCase(stateParts.join('_'))].filter(x => !!x).join('-');\n    const stateUrl = config.abstract ? '' : `/${fullStateName.replace(/\\./g, '/')}${paramName ? `/:${paramName}` : ''}?${Object.keys(config.url)}`;\n\n    this.state({\n      name: fullStateName,\n      abstract: config.abstract || false,\n      url: stateUrl,\n      reloadOnSearch: false,\n      template: `\n        <${componentName}\n          class=\"bi-c-h bi-grow\"\n          ${Object.keys(config.scope).map(prop => `${paramCase(prop)}=\"${prop}\"`).join(' ')}\n          $state-options=\"$stateOptions\"\n        ></${componentName}>\n      `,\n      params: config.options || {},\n      onEnter: config.onEnter,\n      onExit: config.onExit,\n      controller: ['$scope', '$stateParams', 'user', (scope, params) => {\n        config.controller(scope, params, {\n          syncUrl(getArgs = () => []) {\n            let {url} = config;\n\n            url = mapValues(url, (listener: IUrlParamListener, param) => {\n              let normalizedListener = listener;\n\n              if (typeof listener === 'function') {\n                normalizedListener = {from: listener, to: action => listener(action[param])[param]};\n              }\n\n              const enrichedListener = mapValues(normalizedListener, (l, key) => value => normalizedListener[key](typeof value === 'undefined' ? null : value, ...getArgs()));\n\n              userActionToUrlParam[(enrichedListener as any).from().type] = {param, listener: enrichedListener};\n\n              return enrichedListener;\n            }) as {[key: string]: IUrlParamListener};\n\n            fromUrl(scope, url, inject('$location').search());\n            inject('$timeout')(() => {\n              const cleaner = scope.$on('$locationChangeSuccess', () => fromUrl(scope, url, inject('$location').search()));\n              scope.$on('$destroy', () => cleaner());\n            });\n          },\n          setTitle(getTitle = () => [app.getTitle(), headerCase(stateName)]) {\n            document.title = getTitle({\n              appTitle: app.getTitle(),\n              stateName: headerCase(stateName)\n            }).join(' · ');\n          }\n        });\n\n        scope.$stateOptions = Object.keys(config.options || {})\n          .reduce((res, key) => {\n            res[key] = params[key];\n            return res;\n          }, {});\n      }]\n    });\n\n    const isAngularConfig = (unknownConfig: IStateComponentConfig): unknownConfig is IAngularStateComponentConfig => {\n      return typeof (unknownConfig as IAngularStateComponentConfig).template === 'string';\n    };\n\n    const createAngularFactory = (angularConfig: IAngularStateComponentConfig) => () => ({\n      restrict: 'E',\n      template: angularConfig.template,\n      scope: mapValues({...angularConfig.scope, $stateOptions: true}, () => '<'),\n      link: {\n        pre(scope, ...args) {\n          initScopeListeners(scope, store, angularConfig.scope);\n          (angularConfig.link as any)(scope, ...args);\n        }\n      }\n    });\n\n    const createReactFactory = (reactConfig: IReactStateComponentConfig) =>\n      react2angular(withAppStoreProvider(app, store, reactConfig.template),\n        Object.keys(reactConfig.scope));\n\n    isAngularConfig(config) ?\n      this.component(camelCase(componentName), createAngularFactory(config)):\n      this.reactComponent(camelCase(componentName), createReactFactory(config));\n\n    return this;\n  }\n\n  modules(modules: string[]) {\n    this.ngmodules = this.ngmodules.concat(modules);\n  }\n\n  menuItem(item: IMenuItem) {\n    this.menuItems.push(item);\n    return this;\n  }\n\n  config(config: Config) {\n    this.conf = config;\n    return this;\n  }\n\n  getUser() {\n    return this.user;\n  }\n\n  /**\n   * Creates an application instance\n   */\n  build(): App<Config> {\n    const app = new App<Config>(\n      this.id as string,\n      this.title,\n      this.options,\n      this.plugins,\n      this.user,\n      this.navigator,\n      this.menuItems,\n      this.conf,\n    )\n      .init(this.ngmodules);\n\n    Object.keys(this.plugins).forEach(name => {\n      const plugin = this.plugins[name];\n      const {branches, logUrl, server} = plugin.store() as IPluginBranches<Config>;\n\n      const intializedBranches = mapValues({\n        ...branches,\n        _global: () => next => next(x => null, urlMiddleware)\n      } as any, branch => branch(app))\n\n      const store = createStore(intializedBranches, {logUrl, server});\n\n      (plugin.states() as IStateFactory<Config>[]).forEach(factory => this.state(factory(app, store)));\n      (plugin.components() as IPluginComponent<Config>[]).forEach(({name: componentName, factory}) => this.component(componentName, factory(app, store)));\n      (plugin.stateComponents() as IStateComponentFactory[]).forEach(factory => this.stateComponent(factory(app, store), app, store));\n      (plugin.reactComponents() as IPluginReactComponent[]).forEach(\n        ({name: componentName, factory}) =>\n          this.reactComponent(\n            camelCase(componentName),\n            react2angular(\n              factory().template,\n              factory().scope\n            )\n          )\n      );\n\n      this.fire(`ready|${plugin.getId()}`, app, store);\n    });\n\n    LocalStorage.setPrefix(`${this.id}-`);\n\n    this.fire('ready', app);\n\n    return app;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/navigator.ts",
    "content": "import { IModule } from 'angular';\nimport { inject, srv } from '../../core';\nimport { User } from './user';\nimport { Options } from '../types';\n\nconst EVENT_MAP = {\n  start: 'stateChangeStart',\n  success: 'stateChangeSuccess',\n  visible: 'viewLoaded',\n};\n\nexport type TEventType = 'start' | 'success' | 'visible';\n\nexport type INavigatorCallback = (params: any, stateName: string) => any;\n\nexport default class Navigator extends srv.eventEmitter.EventEmitter {\n  private readonly states = [];\n  private prefix;\n  private resolveLogin: (data: any) => any;\n\n  constructor(private readonly options: Options) {\n    super();\n  }\n\n  init(user: User, ngApp: IModule) {\n    this.prefix = this.options.statePrefix;\n\n    if (this.options.auth) {\n      const self = this;\n\n      this.states.push({\n        name: 'auth',\n        options: {\n          abstract: true,\n          template:\n            '<div class=\"bi-c-h bi-grow\" ui-view bi-state-loader></div>',\n          resolve: {\n            user() {\n              return user\n                .fetch(self.options.apiBasePath)\n                .catch(() => {\n                  user.toggleLoggedIn(false);\n                  return new Promise(\n                    (resolve) => (self.resolveLogin = resolve)\n                  );\n                })\n                .then((data: any) => {\n                  user.toggleLoggedIn(true);\n                  self.trigger('ready', user);\n                });\n            },\n          },\n        },\n      });\n\n      this.prefix = `auth.${this.prefix}`;\n    }\n\n    ngApp.config([\n      '$stateProvider',\n      '$locationProvider',\n      '$urlRouterProvider',\n      ($stateProvider, $locationProvider, $urlRouterProvider) => {\n        $locationProvider.hashPrefix('');\n        $urlRouterProvider.otherwise(this.options.defaultUrl);\n\n        this.states.forEach(({ name, options }) => {\n          try {\n            $stateProvider.state(name, options);\n          } catch (e) {\n            console.warn(e);\n          }\n        });\n      },\n    ]);\n\n    ngApp.run([\n      '$rootScope',\n      (scope) => {\n        scope.$on('$stateChangeStart', (e, state, params, fromState) => {\n          this.trigger('stateChangeStart', state.name, params, fromState.name);\n        });\n\n        scope.$on('$stateChangeSuccess', (e, state, params, fromState) => {\n          this.trigger(\n            'stateChangeSuccess',\n            state.name,\n            params,\n            fromState.name\n          );\n        });\n\n        scope.$on('$viewContentLoaded', (e, viewConfig) =>\n          this.trigger('viewLoaded')\n        );\n      },\n    ]);\n\n    return this;\n  }\n\n  finishLogin(data: any) {\n    if (this.resolveLogin) {\n      this.resolveLogin(data);\n    }\n  }\n\n  getStatePrefix() {\n    return this.prefix;\n  }\n\n  state(name, options) {\n    this.states.push({\n      name: `${this.prefix}${name ? `.${name}` : ''}`,\n      options,\n    });\n  }\n\n  go(\n    state: string,\n    params?: Object,\n    options: { reload: boolean | string } = { reload: false }\n  ): PromiseLike<any> {\n    if (typeof options.reload === 'string') {\n      options.reload = `${this.prefix}.${options.reload}`;\n    }\n\n    return inject('$state').go(`${this.prefix}.${state}`, params, options);\n  }\n\n  getUrl(state?: string, params?: Object): string {\n    state = state || inject('$state').current.name;\n\n    return `${document.location.protocol}//${document.location.host}${\n      document.location.pathname\n    }${inject('$state').href(state, params, {\n      relative: true,\n      inherit: false,\n    })}`;\n  }\n\n  goHome() {\n    return inject('$state').go(`${this.prefix}.${this.options.homeState}`);\n  }\n\n  listen(\n    state: string | string[],\n    type: TEventType,\n    fn: INavigatorCallback,\n    scope?\n  ) {\n    const states = typeof state === 'string' ? [state] : state || [];\n    const eventName = EVENT_MAP[type];\n    let otherwise: INavigatorCallback = null;\n\n    this.on(\n      eventName,\n      (stateName = '', params = {}) => {\n        stateName = stateName.replace(`${this.getStatePrefix()}.`, '');\n        if (states.some((s) => stateName.indexOf(s) >= 0)) {\n          fn(params, stateName);\n        } else if (otherwise) {\n          otherwise(params, stateName);\n        }\n      },\n      true,\n      scope\n    );\n\n    return {\n      otherwise(f: INavigatorCallback) {\n        otherwise = f;\n      },\n    };\n  }\n\n  listenFrom(\n    state: string | string[],\n    type: TEventType,\n    fn: Function,\n    invoke = false,\n    scope?\n  ) {\n    const states = typeof state === 'string' ? [state] : state || [];\n    const eventName = EVENT_MAP[type];\n    let otherwise = null;\n\n    this.on(\n      eventName,\n      (_, __, stateName) => {\n        if (states.some((s) => stateName.indexOf(s) >= 0)) {\n          fn();\n        } else if (otherwise) {\n          otherwise();\n        }\n      },\n      invoke,\n      scope\n    );\n\n    return {\n      otherwise(f: Function) {\n        otherwise = f;\n      },\n    };\n  }\n\n  reload(state?: string) {\n    inject('$state').reload(state);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/plugin-builder.ts",
    "content": "import {forEach} from 'lodash';\nimport {IDirectiveFactory, IDirectiveLinkFn} from 'angular';\nimport {Store, IBranch} from '../../store';\nimport {Builder} from './builder';\nimport {App, IMenuItem} from './app';\nimport {ServerFrameworkType} from '../../store/services/store-logger';\nimport * as React from 'react';\n\nexport type IComponentFactory<Config = any> = (app: App<Config>, store: Store) => IDirectiveFactory;\nexport type IReactComponentFactory = () => IReactComponentConfig;\nexport type IStateComponentFactory<Config = any> = (app: App<Config>, store: Store) => IStateComponentConfig;\n\nexport type IStateFactory<Config = any> = (app: App<Config>, store: Store) => object;\n\nexport type IBranchFactory<Config = any> = (app: App<Config>) => IBranch;\n\nexport interface IPluginComponent<Config = any> {\n  name: string;\n  factory: IComponentFactory<Config>;\n}\n\nexport interface IPluginReactComponent {\n  name: string;\n  factory: IReactComponentFactory;\n}\n\nexport interface IPluginBranches<Config = any> {\n  branches: {[key: string]: IBranchFactory};\n  logUrl: string;\n  server?: ServerFrameworkType;\n}\n\nexport type IUrlParamListener = Function | {from: Function; to: Function};\n\nexport type IScopeListener = (scope, current: any, previous: any, store: Store) => any\ninterface IScopeListeners extends Record<string, IScopeListener | IScopeListeners> {}\n\nexport interface IStateComponentConfigBase {\n  name: string;\n  abstract?: boolean;\n  url: {[key: string]: IUrlParamListener};\n  scope: IScopeListeners;\n  options?: Record<string, any>,\n  controller(scope: any, params: {[key: string]: any}, api: {\n    syncUrl(getArgs?: () => any): any;\n    setTitle(getTitle?: (args: {\n      appTitle?: string;\n      stateName?: string;\n    }) => string[]): any;\n  }): any;\n  onEnter?(): any;\n  onExit?(): any;\n}\n\nexport interface IAngularStateComponentConfig extends IStateComponentConfigBase{\n  template: string;\n  link: IDirectiveLinkFn;\n}\n\nexport interface IReactStateComponentConfig extends IStateComponentConfigBase{\n  template: React.ComponentType<any>;\n}\nexport type IStateComponentConfig = IAngularStateComponentConfig | IReactStateComponentConfig;\n\nexport interface IReactComponentConfig{\n  name: string;\n  scope: string[];\n  template: React.ComponentType<any>;\n}\n\n/**\n * A subset of Builder which is exposed to plugin factories\n */\nexport class PluginBuilder<Config> {\n  private readonly pluginStates = [];\n  private readonly pluginComponents: IPluginComponent[] = [];\n  private readonly pluginReactComponents: IPluginReactComponent[] = [];\n  private readonly pluginStateComponents: IStateComponentFactory[] = [];\n  private pluginBranches: IPluginBranches = {logUrl: '', server: null, branches: {}};\n\n  constructor(private readonly id: string, private readonly builder: Builder) {\n\n  }\n\n  /**\n   * Registers a ui-router state\n   *\n   * @param options   ui-router state options\n   */\n  state(options: Object): PluginBuilder<Config> {\n    this.builder.state(options);\n    return this;\n  }\n\n  /**\n   * Registers ui-router states\n   *\n   * @param states   ui-router states\n   */\n  states(states?: {[name: string]: IStateFactory}) {\n    if (states) {\n      forEach(states, factory => this.pluginStates.push(factory));\n      return this;\n    }\n    return this.pluginStates;\n\n  }\n\n  /**\n   * Registers a react component\n   *\n   * @param name      component name\n   * @param factory   component factory\n   */\n  reactComponent(name: string, factory: IReactComponentFactory): PluginBuilder<Config> {\n    this.pluginReactComponents.push({name, factory});\n    return this;\n  }\n\n  /**\n   * Registers react components\n   *\n   * @param components      components\n   */\n  reactComponents(components?: {[name: string]: IReactComponentFactory}) {\n    if (components) {\n      forEach(components, (factory, name) => this.reactComponent(name, factory));\n      return this;\n    }\n    return this.pluginReactComponents;\n\n  }\n\n  /**\n   * Registers an angular directive\n   *\n   * @param name      component name\n   * @param factory   component factory\n   */\n  component(name: string, factory: IComponentFactory): PluginBuilder<Config> {\n    this.pluginComponents.push({name, factory});\n    return this;\n  }\n\n  /**\n   * Registers angular directives\n   *\n   * @param components  directives\n   */\n  components(components?: {[name: string]: IComponentFactory}) {\n    if (components) {\n      forEach(components, (factory, name) => this.component(name, factory));\n      return this;\n    }\n    return this.pluginComponents;\n\n  }\n\n   /**\n   * Registers a react state component\n   *\n   * @param factory   component factory\n   */\n  stateComponent(factory?: IStateComponentFactory) {\n    this.pluginStateComponents.push(factory);\n    return this;\n  }\n\n   /**\n   * Registers a react state components\n   *\n   * @param stateComponents      components\n   */\n  stateComponents(stateComponents?: {[name: string]: IStateComponentFactory}) {\n    if (stateComponents) {\n      forEach(stateComponents, (factory, name) => this.stateComponent(factory));\n      return this;\n    }\n    return this.pluginStateComponents;\n\n  }\n\n  /**\n   * Registers store branches\n   *\n   * @param branches    store branches\n   * @param logUrl      log url\n   * @param server\n   */\n  store(branches?: Record<string, IBranchFactory> , logUrl?: string, server?: ServerFrameworkType) {\n    if (branches) {\n      this.pluginBranches = {branches, logUrl, server};\n      return this;\n    }\n\n    return this.pluginBranches;\n  }\n\n  modules(modules) {\n    this.builder.modules(modules);\n    return this;\n  }\n\n  menuItem(item: IMenuItem) {\n    this.builder.menuItem(item);\n    return this;\n  }\n\n  getUser() {\n    return this.builder.getUser();\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  /**\n   * Subscribes to application ready event\n   *\n   * @param fn  will be called with app's instance after app.build() was called\n   */\n  ready(fn: (app: App) => any) {\n    this.builder.on('ready', fn);\n  }\n\n  /**\n   * Subscribes to application ready event per plugin\n   *\n   * @param fn  will be called with app's instance after app.build() was called\n   */\n  onPluginReady(fn: (app: App<Config>, store: Store) => any) {\n    this.builder.on(`ready|${this.id}`, fn);\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/sso.ts",
    "content": "import {inject} from '../../core';\n\ndeclare const gapi;\n\nconst insertScript = file => {\n  const deferred = inject('$q').defer();\n\n  const po = document.createElement('script');\n  po.type = 'text/javascript';\n  po.async = true;\n  po.src = file;\n  po.onload = () => deferred.resolve();\n\n  const s = document.getElementsByTagName('script')[0];\n  s.parentNode.insertBefore(po, s);\n\n  return deferred.promise;\n};\n\nconst insertGoogleSdk = () => {\n  return insertScript('https://apis.google.com/js/platform.js');\n};\n\nconst authenticate = (apiBasePath: string, code?: string) => {\n  const url = (apiBasePath ? apiBasePath : '') + '/api/authenticate' + (code ? `?code=${code}` : '');\n  return inject('$resource')(url).get().$promise;\n};\n\nexport const init = () => {\n  return insertGoogleSdk();\n};\n\nexport const login = async (clientId, apiBasePath?: string): Promise<any> => {\n  await init();\n\n  const deferred = inject('$q').defer();\n\n  $(() => gapi.load('auth2', () => {\n    try {\n      const auth2 = gapi.auth2.init({\n        client_id: clientId,\n        scope: 'email profile',\n      });\n\n      auth2.grantOfflineAccess().then(res => authenticate(apiBasePath, res.code)\n        .then(deferred.resolve)\n        .catch(deferred.reject));\n    } catch(e) {\n      console.error(e);\n      deferred.reject(e);\n    }\n  }));\n\n  return deferred.promise;\n};\n\nexport const logout = () => {\n  (window as any).gapi.auth.signOut();\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/services/user.ts",
    "content": "import { inject } from '../../core';\n\nexport class Permission {\n  private timeout;\n\n  private password: string;\n\n  elevate(password) {\n    this.password = password;\n  }\n\n  deelevate() {\n    this.password = null;\n  }\n\n  isElevated() {\n    return !!this.password;\n  }\n\n  getPassword() {\n    return this.password;\n  }\n\n  renew() {\n    if (!this.isElevated()) {\n      return;\n    }\n\n    const timeout = inject('$timeout');\n\n    timeout.cancel(this.timeout);\n    this.timeout = timeout(() => this.deelevate(), 30 * 60 * 10000); // 30 minutes\n  }\n}\n\nconst addPrefixSlash = (s: string) => (s[0] === '/' ? s : '/' + s);\n\nexport class User {\n  private email: string;\n  private name: string;\n  private avatar: string;\n  private loggedIn;\n  private role: string;\n  private id: string;\n  private stats: { trashBinCount: number };\n  private readonly permission = new Permission();\n\n  fetch(apiBasePath?: string) {\n    return inject('$resource')(\n      `${apiBasePath ? addPrefixSlash(apiBasePath) : ''}/api/user`\n    )\n      .get()\n      .$promise.then((data) => this.set(data.payload || data));\n  }\n\n  set({ email, name, avatar, role, id, stats }: Record<string, string>) {\n    this.email = email;\n    this.name = name;\n    this.avatar = avatar;\n    this.role = role || 'user';\n    this.loggedIn = null;\n    this.id = id;\n    this.stats = stats as any;\n\n    return this;\n  }\n\n  getStats() {\n    return this.stats;\n  }\n\n  getEmail() {\n    return this.email;\n  }\n\n  getName() {\n    return this.name;\n  }\n\n  getAvatar() {\n    return this.avatar;\n  }\n\n  getRole() {\n    return this.role;\n  }\n\n  getId() {\n    return this.id;\n  }\n\n  getPermission() {\n    return this.permission;\n  }\n\n  isLoggedIn() {\n    return this.loggedIn;\n  }\n\n  toggleLoggedIn(loggedIn) {\n    return (this.loggedIn = loggedIn);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/types.ts",
    "content": "export interface Options {\n  statePrefix?: string;\n  defaultUrl?: string;\n  homeState?: string;\n  logoUrl?: string;\n  apiBasePath?: string;\n  auth?: {\n    googleClientId: string;\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/typings/story-builder.ts",
    "content": "import {PluginBuilder} from '../services/plugin-builder';\n\nexport interface StoryBuilder extends PluginBuilder<any> {\n  story(folder: string, name: string): any;\n}\n\nexport type StoryDefiniton = (sb: StoryBuilder) => any;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/typings/types.d.ts",
    "content": "declare module '*.scss';\ndeclare module '*.html';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/app/typings/window.ts",
    "content": "import * as angular from 'angular';\nimport {StoryDefiniton} from './story-builder';\n\ndeclare global {\n  interface Window {\n    angular: angular.IAngularStatic;\n    $: JQueryStatic;\n    jQuery: JQueryStatic;\n  }\n  var biStorybook: {\n    create(stories: StoryDefiniton | StoryDefiniton[], moduleDependencies: string[]): any;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/app/utils/scope-utils.ts",
    "content": "import {isPlainObject} from 'lodash';\nimport {Store} from '../../../lib/store';\n\nexport const initScopeListeners = (scope, store: Store, listeners) => {\n  Object.keys(listeners).forEach(key => {\n    const listener = listeners[key];\n    const watched = {};\n\n    scope.$watch(key, (current, prev) => {\n      if (isPlainObject(listener)) {\n        const {self, ...props} = listener;\n\n        Object.keys(props).forEach(prop => {\n          if (!current || (prev && current[prop] === prev[prop] && watched[key + prop])) {\n            return;\n          }\n\n          listener[prop](scope, current[prop], prev && prev[prop], store);\n          watched[key + prop] = true;\n        });\n\n        if (self) {\n          self(scope, current, prev, store);\n        }\n      } else {\n        listener(scope, current, prev, store);\n      }\n    });\n  });\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/ace-extensions/index.ts",
    "content": "import {setupLanguageTools} from './language-tools';\nimport {setupPrestoMode} from './presto.mode';\nimport {setupSnippets} from './presto-snippets';\nimport {setupSearchbox} from './searchbox';\nimport 'brace/mode/json';\nimport 'brace/mode/python';\n\nexport const setupAce = (ace) => {\n  setupLanguageTools(ace);\n  setupPrestoMode(ace);\n  setupSnippets(ace);\n  setupSearchbox(ace);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/ace-extensions/language-tools.ts",
    "content": "/* tslint:disable */\n\nexport const setupLanguageTools = (ace) => {\n  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) {\n    var oop = require(\"./lib/oop\");\n    var EventEmitter = require(\"./lib/event_emitter\").EventEmitter;\n    var lang = require(\"./lib/lang\");\n    var Range = require(\"./range\").Range;\n    var Anchor = require(\"./anchor\").Anchor;\n    var HashHandler = require(\"./keyboard/hash_handler\").HashHandler;\n    var Tokenizer = require(\"./tokenizer\").Tokenizer;\n    var comparePoints = Range.comparePoints;\n\n    var SnippetManager: any = function () {\n      this.snippetMap = {};\n      this.snippetNameMap = {};\n    };\n\n    (function () {\n      oop.implement(this, EventEmitter);\n\n      this.getTokenizer = function () {\n        function TabstopToken(str, _, stack) {\n          str = str.substr(1);\n          if (/^\\d+$/.test(str) && !stack.inFormatString)\n            return [{tabstopId: parseInt(str, 10)}];\n          return [{text: str}];\n        }\n        function escape(ch) {\n          return \"(?:[^\\\\\\\\\" + ch + \"]|\\\\\\\\.)\";\n        }\n        SnippetManager.$tokenizer = new Tokenizer({\n          start: [\n            {\n              regex: /:/, onMatch: function (val, state, stack) {\n                if (stack.length && stack[0].expectIf) {\n                  stack[0].expectIf = false;\n                  stack[0].elseBranch = stack[0];\n                  return [stack[0]];\n                }\n                return \":\";\n              }\n            },\n            {\n              regex: /\\\\./, onMatch: function (val, state, stack) {\n                var ch = val[1];\n                if (ch == \"}\" && stack.length) {\n                  val = ch;\n                } else if (\"`$\\\\\".indexOf(ch) != -1) {\n                  val = ch;\n                } else if (stack.inFormatString) {\n                  if (ch == \"n\")\n                    val = \"\\n\";\n                  else if (ch == \"t\")\n                    val = \"\\n\";\n                  else if (\"ulULE\".indexOf(ch) != -1) {\n                    val = {changeCase: ch, local: ch > \"a\"};\n                  }\n                }\n\n                return [val];\n              }\n            },\n            {\n              regex: /}/, onMatch: function (val, state, stack) {\n                return [stack.length ? stack.shift() : val];\n              }\n            },\n            {regex: /\\$(?:\\d+|\\w+)/, onMatch: TabstopToken},\n            {\n              regex: /\\$\\{[\\dA-Z_a-z]+/, onMatch: function (str, state, stack) {\n                var t = TabstopToken(str.substr(1), state, stack);\n                stack.unshift(t[0]);\n                return t;\n              }, next: \"snippetVar\"\n            },\n            {regex: /\\n/, token: \"newline\", merge: false}\n          ],\n          snippetVar: [\n            {\n              regex: \"\\\\|\" + escape(\"\\\\|\") + \"*\\\\|\", onMatch: function (val, state, stack) {\n                stack[0].choices = val.slice(1, -1).split(\",\");\n              }, next: \"start\"\n            },\n            {\n              regex: \"/(\" + escape(\"/\") + \"+)/(?:(\" + escape(\"/\") + \"*)/)(\\\\w*):?\",\n              onMatch: function (val, state, stack) {\n                var ts = stack[0];\n                ts.fmtString = val;\n\n                val = this.splitRegex.exec(val);\n                ts.guard = val[1];\n                ts.fmt = val[2];\n                ts.flag = val[3];\n                return \"\";\n              }, next: \"start\"\n            },\n            {\n              regex: \"`\" + escape(\"`\") + \"*`\", onMatch: function (val, state, stack) {\n                stack[0].code = val.splice(1, -1);\n                return \"\";\n              }, next: \"start\"\n            },\n            {\n              regex: \"\\\\?\", onMatch: function (val, state, stack) {\n                if (stack[0])\n                  stack[0].expectIf = true;\n              }, next: \"start\"\n            },\n            {regex: \"([^:}\\\\\\\\]|\\\\\\\\.)*:?\", token: \"\", next: \"start\"}\n          ],\n          formatString: [\n            {regex: \"/(\" + escape(\"/\") + \"+)/\", token: \"regex\"},\n            {\n              regex: \"\", onMatch: function (val, state, stack) {\n                stack.inFormatString = true;\n              }, next: \"start\"\n            }\n          ]\n        });\n        SnippetManager.prototype.getTokenizer = function () {\n          return SnippetManager.$tokenizer;\n        };\n        return SnippetManager.$tokenizer;\n      };\n\n      this.tokenizeTmSnippet = function (str, startState) {\n        return this.getTokenizer().getLineTokens(str, startState).tokens.map(function (x) {\n          return x.value || x;\n        });\n      };\n\n      this.$getDefaultValue = function (editor, name) {\n        if (/^[A-Z]\\d+$/.test(name)) {\n          var i = name.substr(1);\n          return (this.variables[name[0] + \"__\"] || {})[i];\n        }\n        if (/^\\d+$/.test(name)) {\n          return (this.variables.__ || {})[name];\n        }\n        name = name.replace(/^TM_/, \"\");\n\n        if (!editor)\n          return;\n        var s = editor.session;\n        switch (name) {\n          case \"CURRENT_WORD\":\n            var r = s.getWordRange();\n          case \"SELECTION\":\n          case \"SELECTED_TEXT\":\n            return s.getTextRange(r);\n          case \"CURRENT_LINE\":\n            return s.getLine(editor.getCursorPosition().row);\n          case \"PREV_LINE\": // not possible in textmate\n            return s.getLine(editor.getCursorPosition().row - 1);\n          case \"LINE_INDEX\":\n            return editor.getCursorPosition().column;\n          case \"LINE_NUMBER\":\n            return editor.getCursorPosition().row + 1;\n          case \"SOFT_TABS\":\n            return s.getUseSoftTabs() ? \"YES\" : \"NO\";\n          case \"TAB_SIZE\":\n            return s.getTabSize();\n          case \"FILENAME\":\n          case \"FILEPATH\":\n            return \"\";\n          case \"FULLNAME\":\n            return \"Ace\";\n        }\n      };\n      this.variables = {};\n      this.getVariableValue = function (editor, varName) {\n        if (this.variables.hasOwnProperty(varName))\n          return this.variables[varName](editor, varName) || \"\";\n        return this.$getDefaultValue(editor, varName) || \"\";\n      };\n      this.tmStrFormat = function (str, ch, editor) {\n        var flag = ch.flag || \"\";\n        var re = ch.guard;\n        re = new RegExp(re, flag.replace(/[^gi]/, \"\"));\n        var fmtTokens = this.tokenizeTmSnippet(ch.fmt, \"formatString\");\n        var _self = this;\n        var formatted = str.replace(re, function () {\n          _self.variables.__ = arguments;\n          var fmtParts = _self.resolveVariables(fmtTokens, editor);\n          var gChangeCase = \"E\";\n          for (var i = 0; i < fmtParts.length; i++) {\n            var ch = fmtParts[i];\n            if (typeof ch == \"object\") {\n              fmtParts[i] = \"\";\n              if (ch.changeCase && ch.local) {\n                var next = fmtParts[i + 1];\n                if (next && typeof next == \"string\") {\n                  if (ch.changeCase == \"u\")\n                    fmtParts[i] = next[0].toUpperCase();\n                  else\n                    fmtParts[i] = next[0].toLowerCase();\n                  fmtParts[i + 1] = next.substr(1);\n                }\n              } else if (ch.changeCase) {\n                gChangeCase = ch.changeCase;\n              }\n            } else if (gChangeCase == \"U\") {\n              fmtParts[i] = ch.toUpperCase();\n            } else if (gChangeCase == \"L\") {\n              fmtParts[i] = ch.toLowerCase();\n            }\n          }\n          return fmtParts.join(\"\");\n        });\n        this.variables.__ = null;\n        return formatted;\n      };\n\n      this.resolveVariables = function (snippet, editor) {\n        var result = [];\n        for (var i = 0; i < snippet.length; i++) {\n          var ch = snippet[i];\n          if (typeof ch == \"string\") {\n            result.push(ch);\n          } else if (typeof ch != \"object\") {\n            continue;\n          } else if (ch.skip) {\n            gotoNext(ch);\n          } else if (ch.processed < i) {\n            continue;\n          } else if (ch.text) {\n            var value = this.getVariableValue(editor, ch.text);\n            if (value && ch.fmtString)\n              value = this.tmStrFormat(value, ch);\n            ch.processed = i;\n            if (ch.expectIf == null) {\n              if (value) {\n                result.push(value);\n                gotoNext(ch);\n              }\n            } else {\n              if (value) {\n                ch.skip = ch.elseBranch;\n              } else\n                gotoNext(ch);\n            }\n          } else if (ch.tabstopId != null) {\n            result.push(ch);\n          } else if (ch.changeCase != null) {\n            result.push(ch);\n          }\n        }\n        function gotoNext(ch) {\n          var i1 = snippet.indexOf(ch, i + 1);\n          if (i1 != -1)\n            i = i1;\n        }\n        return result;\n      };\n\n      this.insertSnippetForSelection = function (editor, snippetText) {\n        var cursor = editor.getCursorPosition();\n        var line = editor.session.getLine(cursor.row);\n        var tabString = editor.session.getTabString();\n        var indentString = line.match(/^\\s*/)[0];\n\n        if (cursor.column < indentString.length)\n          indentString = indentString.slice(0, cursor.column);\n\n        snippetText = snippetText.replace(/\\r/g, \"\");\n        var tokens = this.tokenizeTmSnippet(snippetText);\n        tokens = this.resolveVariables(tokens, editor);\n        tokens = tokens.map(function (x) {\n          if (x == \"\\n\")\n            return x + indentString;\n          if (typeof x == \"string\")\n            return x.replace(/\\t/g, tabString);\n          return x;\n        });\n        var tabstops = [];\n        tokens.forEach(function (p, i) {\n          if (typeof p != \"object\")\n            return;\n          var id = p.tabstopId;\n          var ts = tabstops[id];\n          if (!ts) {\n            ts = tabstops[id] = [];\n            ts.index = id;\n            ts.value = \"\";\n          }\n          if (ts.indexOf(p) !== -1)\n            return;\n          ts.push(p);\n          var i1 = tokens.indexOf(p, i + 1);\n          if (i1 === -1)\n            return;\n\n          var value = tokens.slice(i + 1, i1);\n          var isNested = value.some(function (t) {return typeof t === \"object\"});\n          if (isNested && !ts.value) {\n            ts.value = value;\n          } else if (value.length && (!ts.value || typeof ts.value !== \"string\")) {\n            ts.value = value.join(\"\");\n          }\n        });\n        tabstops.forEach(function (ts) {ts.length = 0});\n        var expanding = {};\n        function copyValue(val) {\n          var copy = [];\n          for (var i = 0; i < val.length; i++) {\n            var p = val[i];\n            if (typeof p == \"object\") {\n              if (expanding[p.tabstopId])\n                continue;\n              var j = val.lastIndexOf(p, i - 1);\n              p = copy[j] || {tabstopId: p.tabstopId};\n            }\n            copy[i] = p;\n          }\n          return copy;\n        }\n        for (var i = 0; i < tokens.length; i++) {\n          var p = tokens[i];\n          if (typeof p != \"object\")\n            continue;\n          var id = p.tabstopId;\n          var i1 = tokens.indexOf(p, i + 1);\n          if (expanding[id]) {\n            if (expanding[id] === p)\n              expanding[id] = null;\n            continue;\n          }\n\n          var ts = tabstops[id];\n          var arg = typeof ts.value == \"string\" ? [ts.value] : copyValue(ts.value);\n          arg.unshift(i + 1, Math.max(0, i1 - i));\n          arg.push(p);\n          expanding[id] = p;\n          tokens.splice.apply(tokens, arg);\n\n          if (ts.indexOf(p) === -1)\n            ts.push(p);\n        }\n        var row = 0, column = 0;\n        var text = \"\";\n        tokens.forEach(function (t) {\n          if (typeof t === \"string\") {\n            var lines = t.split(\"\\n\");\n            if (lines.length > 1) {\n              column = lines[lines.length - 1].length;\n              row += lines.length - 1;\n            } else\n              column += t.length;\n            text += t;\n          } else {\n            if (!t.start)\n              t.start = {row: row, column: column};\n            else\n              t.end = {row: row, column: column};\n          }\n        });\n        var range = editor.getSelectionRange();\n        var end = editor.session.replace(range, text);\n\n        var tabstopManager = new TabstopManager(editor);\n        var selectionId = editor.inVirtualSelectionMode && editor.selection.index;\n        tabstopManager.addTabstops(tabstops, range.start, end, selectionId);\n      };\n\n      this.insertSnippet = function (editor, snippetText) {\n        var self = this;\n        if (editor.inVirtualSelectionMode)\n          return self.insertSnippetForSelection(editor, snippetText);\n\n        editor.forEachSelection(function () {\n          self.insertSnippetForSelection(editor, snippetText);\n        }, null, {keepOrder: true});\n\n        if (editor.tabstopManager)\n          editor.tabstopManager.tabNext();\n      };\n\n      this.$getScope = function (editor) {\n        var scope = editor.session.$mode.$id || \"\";\n        scope = scope.split(\"/\").pop();\n        if (scope === \"html\" || scope === \"php\") {\n          if (scope === \"php\" && !editor.session.$mode.inlinePhp)\n            scope = \"html\";\n          var c = editor.getCursorPosition();\n          var state = editor.session.getState(c.row);\n          if (typeof state === \"object\") {\n            state = state[0];\n          }\n          if (state.substring) {\n            if (state.substring(0, 3) == \"js-\")\n              scope = \"javascript\";\n            else if (state.substring(0, 4) == \"css-\")\n              scope = \"css\";\n            else if (state.substring(0, 4) == \"php-\")\n              scope = \"php\";\n          }\n        }\n\n        return scope;\n      };\n\n      this.getActiveScopes = function (editor) {\n        var scope = this.$getScope(editor);\n        var scopes = [scope];\n        var snippetMap = this.snippetMap;\n        if (snippetMap[scope] && snippetMap[scope].includeScopes) {\n          scopes.push.apply(scopes, snippetMap[scope].includeScopes);\n        }\n        scopes.push(\"_\");\n        return scopes;\n      };\n\n      this.expandWithTab = function (editor, options) {\n        var self = this;\n        var result = editor.forEachSelection(function () {\n          return self.expandSnippetForSelection(editor, options);\n        }, null, {keepOrder: true});\n        if (result && editor.tabstopManager)\n          editor.tabstopManager.tabNext();\n        return result;\n      };\n\n      this.expandSnippetForSelection = function (editor, options) {\n        var cursor = editor.getCursorPosition();\n        var line = editor.session.getLine(cursor.row);\n        var before = line.substring(0, cursor.column);\n        var after = line.substr(cursor.column);\n\n        var snippetMap = this.snippetMap;\n        var snippet;\n        this.getActiveScopes(editor).some(function (scope) {\n          var snippets = snippetMap[scope];\n          if (snippets)\n            snippet = this.findMatchingSnippet(snippets, before, after);\n          return !!snippet;\n        }, this);\n        if (!snippet)\n          return false;\n        if (options && options.dryRun)\n          return true;\n        editor.session.doc.removeInLine(cursor.row,\n          cursor.column - snippet.replaceBefore.length,\n          cursor.column + snippet.replaceAfter.length\n        );\n\n        this.variables.M__ = snippet.matchBefore;\n        this.variables.T__ = snippet.matchAfter;\n        this.insertSnippetForSelection(editor, snippet.content);\n\n        this.variables.M__ = this.variables.T__ = null;\n        return true;\n      };\n\n      this.findMatchingSnippet = function (snippetList, before, after) {\n        for (var i = snippetList.length; i--;) {\n          var s = snippetList[i];\n          if (s.startRe && !s.startRe.test(before))\n            continue;\n          if (s.endRe && !s.endRe.test(after))\n            continue;\n          if (!s.startRe && !s.endRe)\n            continue;\n\n          s.matchBefore = s.startRe ? s.startRe.exec(before) : [\"\"];\n          s.matchAfter = s.endRe ? s.endRe.exec(after) : [\"\"];\n          s.replaceBefore = s.triggerRe ? s.triggerRe.exec(before)[0] : \"\";\n          s.replaceAfter = s.endTriggerRe ? s.endTriggerRe.exec(after)[0] : \"\";\n          return s;\n        }\n      };\n\n      this.snippetMap = {};\n      this.snippetNameMap = {};\n      this.register = function (snippets, scope) {\n        var snippetMap = this.snippetMap;\n        var snippetNameMap = this.snippetNameMap;\n        var self = this;\n\n        if (!snippets)\n          snippets = [];\n\n        function wrapRegexp(src) {\n          if (src && !/^\\^?\\(.*\\)\\$?$|^\\\\b$/.test(src))\n            src = \"(?:\" + src + \")\";\n\n          return src || \"\";\n        }\n        function guardedRegexp(re, guard, opening) {\n          re = wrapRegexp(re);\n          guard = wrapRegexp(guard);\n          if (opening) {\n            re = guard + re;\n            if (re && re[re.length - 1] != \"$\")\n              re = re + \"$\";\n          } else {\n            re = re + guard;\n            if (re && re[0] != \"^\")\n              re = \"^\" + re;\n          }\n          return new RegExp(re);\n        }\n\n        function addSnippet(s) {\n          if (!s.scope)\n            s.scope = scope || \"_\";\n          scope = s.scope;\n          if (!snippetMap[scope]) {\n            snippetMap[scope] = [];\n            snippetNameMap[scope] = {};\n          }\n\n          var map = snippetNameMap[scope];\n          if (s.name) {\n            var old = map[s.name];\n            if (old)\n              self.unregister(old);\n            map[s.name] = s;\n          }\n          snippetMap[scope].push(s);\n\n          if (s.tabTrigger && !s.trigger) {\n            if (!s.guard && /^\\w/.test(s.tabTrigger))\n              s.guard = \"\\\\b\";\n            s.trigger = lang.escapeRegExp(s.tabTrigger);\n          }\n\n          if (!s.trigger && !s.guard && !s.endTrigger && !s.endGuard)\n            return;\n\n          s.startRe = guardedRegexp(s.trigger, s.guard, true);\n          s.triggerRe = new (RegExp as any)(s.trigger, \"\", true);\n\n          s.endRe = guardedRegexp(s.endTrigger, s.endGuard, true);\n          s.endTriggerRe = new (RegExp as any)(s.endTrigger, \"\", true);\n        }\n\n        if (snippets && snippets.content)\n          addSnippet(snippets);\n        else if (Array.isArray(snippets))\n          snippets.forEach(addSnippet);\n\n        this._signal(\"registerSnippets\", {scope: scope});\n      };\n      this.unregister = function (snippets, scope) {\n        var snippetMap = this.snippetMap;\n        var snippetNameMap = this.snippetNameMap;\n\n        function removeSnippet(s) {\n          var nameMap = snippetNameMap[s.scope || scope];\n          if (nameMap && nameMap[s.name]) {\n            delete nameMap[s.name];\n            var map = snippetMap[s.scope || scope];\n            var i = map && map.indexOf(s);\n            if (i >= 0)\n              map.splice(i, 1);\n          }\n        }\n        if (snippets.content)\n          removeSnippet(snippets);\n        else if (Array.isArray(snippets))\n          snippets.forEach(removeSnippet);\n      };\n      this.parseSnippetFile = function (str) {\n        str = str.replace(/\\r/g, \"\");\n        var list = [], snippet: any = {};\n        var re = /^#.*|^({[\\s\\S]*})\\s*$|^(\\S+) (.*)$|^((?:\\n*\\t.*)+)/gm;\n        var m;\n        while (m = re.exec(str)) {\n          if (m[1]) {\n            try {\n              snippet = JSON.parse(m[1]);\n              list.push(snippet);\n            } catch (e) {}\n          } if (m[4]) {\n            snippet.content = m[4].replace(/^\\t/gm, \"\");\n            list.push(snippet);\n            snippet = {};\n          } else {\n            var key = m[2], val = m[3];\n            if (key == \"regex\") {\n              var guardRe = /\\/((?:[^\\/\\\\]|\\\\.)*)|$/g;\n              snippet.guard = guardRe.exec(val)[1];\n              snippet.trigger = guardRe.exec(val)[1];\n              snippet.endTrigger = guardRe.exec(val)[1];\n              snippet.endGuard = guardRe.exec(val)[1];\n            } else if (key == \"snippet\") {\n              snippet.tabTrigger = val.match(/^\\S*/)[0];\n              if (!snippet.name)\n                snippet.name = val;\n            } else {\n              snippet[key] = val;\n            }\n          }\n        }\n        return list;\n      };\n      this.getSnippetByName = function (name, editor) {\n        var snippetMap = this.snippetNameMap;\n        var snippet;\n        this.getActiveScopes(editor).some(function (scope) {\n          var snippets = snippetMap[scope];\n          if (snippets)\n            snippet = snippets[name];\n          return !!snippet;\n        }, this);\n        return snippet;\n      };\n\n    }).call(SnippetManager.prototype);\n\n\n    var TabstopManager: any = function (editor) {\n      if (editor.tabstopManager)\n        return editor.tabstopManager;\n      editor.tabstopManager = this;\n      this.$onChange = this.onChange.bind(this);\n      this.$onChangeSelection = lang.delayedCall(this.onChangeSelection.bind(this)).schedule;\n      this.$onChangeSession = this.onChangeSession.bind(this);\n      this.$onAfterExec = this.onAfterExec.bind(this);\n      this.attach(editor);\n    };\n    (function () {\n      this.attach = function (editor) {\n        this.index = 0;\n        this.ranges = [];\n        this.tabstops = [];\n        this.$openTabstops = null;\n        this.selectedTabstop = null;\n\n        this.editor = editor;\n        this.editor.on(\"change\", this.$onChange);\n        this.editor.on(\"changeSelection\", this.$onChangeSelection);\n        this.editor.on(\"changeSession\", this.$onChangeSession);\n        this.editor.commands.on(\"afterExec\", this.$onAfterExec);\n        this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler);\n      };\n      this.detach = function () {\n        this.tabstops.forEach(this.removeTabstopMarkers, this);\n        this.ranges = null;\n        this.tabstops = null;\n        this.selectedTabstop = null;\n        this.editor.removeListener(\"change\", this.$onChange);\n        this.editor.removeListener(\"changeSelection\", this.$onChangeSelection);\n        this.editor.removeListener(\"changeSession\", this.$onChangeSession);\n        this.editor.commands.removeListener(\"afterExec\", this.$onAfterExec);\n        this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);\n        this.editor.tabstopManager = null;\n        this.editor = null;\n      };\n\n      this.onChange = function (delta) {\n        // var changeRange = delta;\n        var isRemove = delta.action[0] == \"r\";\n        var start = delta.start;\n        var end = delta.end;\n        var startRow = start.row;\n        var endRow = end.row;\n        var lineDif = endRow - startRow;\n        var colDiff = end.column - start.column;\n\n        if (isRemove) {\n          lineDif = -lineDif;\n          colDiff = -colDiff;\n        }\n        if (!this.$inChange && isRemove) {\n          var ts = this.selectedTabstop;\n          var changedOutside = ts && !ts.some(function (r) {\n            return comparePoints(r.start, start) <= 0 && comparePoints(r.end, end) >= 0;\n          });\n          if (changedOutside)\n            return this.detach();\n        }\n        var ranges = this.ranges;\n        for (var i = 0; i < ranges.length; i++) {\n          var r = ranges[i];\n          if (r.end.row < start.row)\n            continue;\n\n          if (isRemove && comparePoints(start, r.start) < 0 && comparePoints(end, r.end) > 0) {\n            this.removeRange(r);\n            i--;\n            continue;\n          }\n\n          if (r.start.row == startRow && r.start.column > start.column)\n            r.start.column += colDiff;\n          if (r.end.row == startRow && r.end.column >= start.column)\n            r.end.column += colDiff;\n          if (r.start.row >= startRow)\n            r.start.row += lineDif;\n          if (r.end.row >= startRow)\n            r.end.row += lineDif;\n\n          if (comparePoints(r.start, r.end) > 0)\n            this.removeRange(r);\n        }\n        if (!ranges.length)\n          this.detach();\n      };\n      this.updateLinkedFields = function () {\n        var ts = this.selectedTabstop;\n        if (!ts || !ts.hasLinkedRanges)\n          return;\n        this.$inChange = true;\n        var session = this.editor.session;\n        var text = session.getTextRange(ts.firstNonLinked);\n        for (var i = ts.length; i--;) {\n          var range = ts[i];\n          if (!range.linked)\n            continue;\n          var fmt = exports.snippetManager.tmStrFormat(text, range.original);\n          session.replace(range, fmt);\n        }\n        this.$inChange = false;\n      };\n      this.onAfterExec = function (e) {\n        if (e.command && !e.command.readOnly)\n          this.updateLinkedFields();\n      };\n      this.onChangeSelection = function () {\n        if (!this.editor)\n          return;\n        var lead = this.editor.selection.lead;\n        var anchor = this.editor.selection.anchor;\n        var isEmpty = this.editor.selection.isEmpty();\n        for (var i = this.ranges.length; i--;) {\n          if (this.ranges[i].linked)\n            continue;\n          var containsLead = this.ranges[i].contains(lead.row, lead.column);\n          var containsAnchor = isEmpty || this.ranges[i].contains(anchor.row, anchor.column);\n          if (containsLead && containsAnchor)\n            return;\n        }\n        this.detach();\n      };\n      this.onChangeSession = function () {\n        this.detach();\n      };\n      this.tabNext = function (dir) {\n        var max = this.tabstops.length;\n        var index = this.index + (dir || 1);\n        index = Math.min(Math.max(index, 1), max);\n        if (index == max)\n          index = 0;\n        this.selectTabstop(index);\n        if (index === 0)\n          this.detach();\n      };\n      this.selectTabstop = function (index) {\n        this.$openTabstops = null;\n        var ts = this.tabstops[this.index];\n        if (ts)\n          this.addTabstopMarkers(ts);\n        this.index = index;\n        ts = this.tabstops[this.index];\n        if (!ts || !ts.length)\n          return;\n\n        this.selectedTabstop = ts;\n        if (!this.editor.inVirtualSelectionMode) {\n          var sel = this.editor.multiSelect;\n          sel.toSingleRange(ts.firstNonLinked.clone());\n          for (var i = ts.length; i--;) {\n            if (ts.hasLinkedRanges && ts[i].linked)\n              continue;\n            sel.addRange(ts[i].clone(), true);\n          }\n          if (sel.ranges[0])\n            sel.addRange(sel.ranges[0].clone());\n        } else {\n          this.editor.selection.setRange(ts.firstNonLinked);\n        }\n\n        this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler);\n      };\n      this.addTabstops = function (tabstops, start, end) {\n        if (!this.$openTabstops)\n          this.$openTabstops = [];\n        if (!tabstops[0]) {\n          var p = Range.fromPoints(end, end);\n          moveRelative(p.start, start);\n          moveRelative(p.end, start);\n          tabstops[0] = [p];\n          tabstops[0].index = 0;\n        }\n\n        var i = this.index;\n        var arg = [i + 1, 0];\n        var ranges = this.ranges;\n        tabstops.forEach(function (ts, index) {\n          var dest = this.$openTabstops[index] || ts;\n\n          for (var i = ts.length; i--;) {\n            var p = ts[i];\n            var range = Range.fromPoints(p.start, p.end || p.start);\n            movePoint(range.start, start);\n            movePoint(range.end, start);\n            range.original = p;\n            range.tabstop = dest;\n            ranges.push(range);\n            if (dest != ts)\n              dest.unshift(range);\n            else\n              dest[i] = range;\n            if (p.fmtString) {\n              range.linked = true;\n              dest.hasLinkedRanges = true;\n            } else if (!dest.firstNonLinked)\n              dest.firstNonLinked = range;\n          }\n          if (!dest.firstNonLinked)\n            dest.hasLinkedRanges = false;\n          if (dest === ts) {\n            arg.push(dest);\n            this.$openTabstops[index] = dest;\n          }\n          this.addTabstopMarkers(dest);\n        }, this);\n\n        if (arg.length > 2) {\n          if (this.tabstops.length)\n            arg.push(arg.splice(2, 1)[0]);\n          this.tabstops.splice.apply(this.tabstops, arg);\n        }\n      };\n\n      this.addTabstopMarkers = function (ts) {\n        var session = this.editor.session;\n        ts.forEach(function (range) {\n          if (!range.markerId)\n            range.markerId = session.addMarker(range, \"ace_snippet-marker\", \"text\");\n        });\n      };\n      this.removeTabstopMarkers = function (ts) {\n        var session = this.editor.session;\n        ts.forEach(function (range) {\n          session.removeMarker(range.markerId);\n          range.markerId = null;\n        });\n      };\n      this.removeRange = function (range) {\n        var i = range.tabstop.indexOf(range);\n        range.tabstop.splice(i, 1);\n        i = this.ranges.indexOf(range);\n        this.ranges.splice(i, 1);\n        this.editor.session.removeMarker(range.markerId);\n        if (!range.tabstop.length) {\n          i = this.tabstops.indexOf(range.tabstop);\n          if (i != -1)\n            this.tabstops.splice(i, 1);\n          if (!this.tabstops.length)\n            this.detach();\n        }\n      };\n\n      this.keyboardHandler = new HashHandler();\n      this.keyboardHandler.bindKeys({\n        \"Tab\": function (ed) {\n          if (exports.snippetManager && exports.snippetManager.expandWithTab(ed)) {\n            return;\n          }\n\n          ed.tabstopManager.tabNext(1);\n        },\n        \"Shift-Tab\": function (ed) {\n          ed.tabstopManager.tabNext(-1);\n        },\n        \"Esc\": function (ed) {\n          ed.tabstopManager.detach();\n        },\n        \"Return\": function (ed) {\n          return false;\n        }\n      });\n    }).call(TabstopManager.prototype);\n\n\n\n    var changeTracker: any = {};\n    changeTracker.onChange = Anchor.prototype.onChange;\n    changeTracker.setPosition = function (row, column) {\n      this.pos.row = row;\n      this.pos.column = column;\n    };\n    changeTracker.update = function (pos, delta, $insertRight) {\n      this.$insertRight = $insertRight;\n      this.pos = pos;\n      this.onChange(delta);\n    };\n\n    var movePoint = function (point, diff) {\n      if (point.row == 0)\n        point.column += diff.column;\n      point.row += diff.row;\n    };\n\n    var moveRelative = function (point, start) {\n      if (point.row == start.row)\n        point.column -= start.column;\n      point.row -= start.row;\n    };\n\n\n    require(\"./lib/dom\").importCssString(\"\\\n.ace_snippet-marker {\\\n    -moz-box-sizing: border-box;\\\n    box-sizing: border-box;\\\n    background: rgba(194, 193, 208, 0.09);\\\n    border: 1px dotted rgba(211, 208, 235, 0.62);\\\n    position: absolute;\\\n}\");\n\n    exports.snippetManager = new SnippetManager();\n\n\n    var Editor = require(\"./editor\").Editor;\n    (function () {\n      this.insertSnippet = function (content, options) {\n        return exports.snippetManager.insertSnippet(this, content, options);\n      };\n      this.expandSnippet = function (options) {\n        return exports.snippetManager.expandWithTab(this, options);\n      };\n    }).call(Editor.prototype);\n\n  });\n\n  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) {\n    \"use strict\";\n\n    var Renderer = require(\"../virtual_renderer\").VirtualRenderer;\n    var Editor = require(\"../editor\").Editor;\n    var Range = require(\"../range\").Range;\n    var event = require(\"../lib/event\");\n    var lang = require(\"../lib/lang\");\n    var dom = require(\"../lib/dom\");\n\n    var $singleLineEditor: any = function (el) {\n      var renderer = new Renderer(el);\n\n      renderer.$maxLines = 4;\n\n      var editor = new Editor(renderer);\n\n      editor.setHighlightActiveLine(false);\n      editor.setShowPrintMargin(false);\n      editor.renderer.setShowGutter(false);\n      editor.renderer.setHighlightGutterLine(false);\n\n      editor.$mouseHandler.$focusWaitTimout = 0;\n      editor.$highlightTagPending = true;\n\n      return editor;\n    };\n\n    var AcePopup = function (parentNode) {\n      var el = dom.createElement(\"div\");\n      var popup = new $singleLineEditor(el);\n\n      if (parentNode)\n        parentNode.appendChild(el);\n      el.style.display = \"none\";\n      popup.renderer.content.style.cursor = \"default\";\n      popup.renderer.setStyle(\"ace_autocomplete\");\n\n      popup.setOption(\"displayIndentGuides\", false);\n      popup.setOption(\"dragDelay\", 150);\n\n      var noop = function () {};\n\n      popup.focus = noop;\n      popup.$isFocused = true;\n\n      popup.renderer.$cursorLayer.restartTimer = noop;\n      popup.renderer.$cursorLayer.element.style.opacity = 0;\n\n      popup.renderer.$maxLines = 8;\n      popup.renderer.$keepTextAreaAtCursor = false;\n\n      popup.setHighlightActiveLine(false);\n      popup.session.highlight(\"\");\n      popup.session.$searchHighlight.clazz = \"ace_highlight-marker\";\n\n      popup.on(\"mousedown\", function (e) {\n        var pos = e.getDocumentPosition();\n        popup.selection.moveToPosition(pos);\n        selectionMarker.start.row = selectionMarker.end.row = pos.row;\n        e.stop();\n      });\n\n      var lastMouseEvent;\n      var hoverMarker = new Range(-1, 0, -1, Infinity);\n      var selectionMarker = new Range(-1, 0, -1, Infinity);\n      selectionMarker.id = popup.session.addMarker(selectionMarker, \"ace_active-line\", \"fullLine\");\n      popup.setSelectOnHover = function (val) {\n        if (!val) {\n          hoverMarker.id = popup.session.addMarker(hoverMarker, \"ace_line-hover\", \"fullLine\");\n        } else if (hoverMarker.id) {\n          popup.session.removeMarker(hoverMarker.id);\n          hoverMarker.id = null;\n        }\n      };\n      popup.setSelectOnHover(false);\n      popup.on(\"mousemove\", function (e) {\n        if (!lastMouseEvent) {\n          lastMouseEvent = e;\n          return;\n        }\n        if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) {\n          return;\n        }\n        lastMouseEvent = e;\n        lastMouseEvent.scrollTop = popup.renderer.scrollTop;\n        var row = lastMouseEvent.getDocumentPosition().row;\n        if (hoverMarker.start.row != row) {\n          if (!hoverMarker.id)\n            popup.setRow(row);\n          setHoverMarker(row, false);\n        }\n      });\n      popup.renderer.on(\"beforeRender\", function () {\n        if (lastMouseEvent && hoverMarker.start.row != -1) {\n          lastMouseEvent.$pos = null;\n          var row = lastMouseEvent.getDocumentPosition().row;\n          if (!hoverMarker.id)\n            popup.setRow(row);\n          setHoverMarker(row, true);\n        }\n      });\n      popup.renderer.on(\"afterRender\", function () {\n        var row = popup.getRow();\n        var t = popup.renderer.$textLayer;\n        var selected = t.element.childNodes[row - t.config.firstRow];\n        if (selected == t.selectedNode)\n          return;\n        if (t.selectedNode)\n          dom.removeCssClass(t.selectedNode, \"ace_selected\");\n        t.selectedNode = selected;\n        if (selected)\n          dom.addCssClass(selected, \"ace_selected\");\n      });\n      var hideHoverMarker = function () {setHoverMarker(-1, false)};\n      var setHoverMarker = function (row, suppressRedraw) {\n        if (row !== hoverMarker.start.row) {\n          hoverMarker.start.row = hoverMarker.end.row = row;\n          if (!suppressRedraw)\n            popup.session._emit(\"changeBackMarker\");\n          popup._emit(\"changeHoverMarker\");\n        }\n      };\n      popup.getHoveredRow = function () {\n        return hoverMarker.start.row;\n      };\n\n      event.addListener(popup.container, \"mouseout\", hideHoverMarker);\n      popup.on(\"hide\", hideHoverMarker);\n      popup.on(\"changeSelection\", hideHoverMarker);\n\n      popup.session.doc.getLength = function () {\n        return popup.data.length;\n      };\n      popup.session.doc.getLine = function (i) {\n        var data = popup.data[i];\n        if (typeof data == \"string\")\n          return data;\n        return (data && data.value) || \"\";\n      };\n\n      var bgTokenizer = popup.session.bgTokenizer;\n      bgTokenizer.$tokenizeRow = function (row) {\n        var data = popup.data[row];\n        var tokens = [];\n        if (!data)\n          return tokens;\n        if (typeof data == \"string\")\n          data = {value: data};\n        if (!data.caption)\n          data.caption = data.value || data.name;\n\n        var last = -1;\n        var flag, c;\n        for (var i = 0; i < data.caption.length; i++) {\n          c = data.caption[i];\n          var matchMask = data.matchMask ? data.matchMask[i % 31] : 0;\n          flag = matchMask & (1 << (i - (i % 31) * 31)) ? 1 : 0;\n          if (last !== flag) {\n            tokens.push({type: data.className || \"\" + (flag ? \"completion-highlight\" : \"\"), value: c});\n            last = flag;\n          } else {\n            tokens[tokens.length - 1].value += c;\n          }\n        }\n\n        if (data.meta) {\n          var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth;\n          var metaData = data.meta;\n          if (metaData.length + data.caption.length > maxW - 2) {\n            metaData = metaData.substr(0, maxW - data.caption.length - 3) + \"\\u2026\"\n          }\n          tokens.push({type: \"rightAlignedText\", value: metaData});\n        }\n        return tokens;\n      };\n      bgTokenizer.$updateOnChange = noop;\n      bgTokenizer.start = noop;\n\n      popup.session.$computeWidth = function () {\n        return this.screenWidth = 0;\n      };\n\n      popup.$blockScrolling = Infinity;\n      popup.isOpen = false;\n      popup.isTopdown = false;\n      popup.autoSelect = true;\n\n      popup.data = [];\n      popup.setData = function (list) {\n        popup.setValue(lang.stringRepeat(\"\\n\", list.length), -1);\n        popup.data = list || [];\n        popup.setRow(0);\n      };\n      popup.getData = function (row) {\n        return popup.data[row];\n      };\n\n      popup.getRow = function () {\n        return selectionMarker.start.row;\n      };\n      popup.setRow = function (line) {\n        line = Math.max(this.autoSelect ? 0 : -1, Math.min(this.data.length, line));\n        if (selectionMarker.start.row != line) {\n          popup.selection.clearSelection();\n          selectionMarker.start.row = selectionMarker.end.row = line || 0;\n          popup.session._emit(\"changeBackMarker\");\n          popup.moveCursorTo(line || 0, 0);\n          if (popup.isOpen)\n            popup._signal(\"select\");\n        }\n      };\n\n      popup.on(\"changeSelection\", function () {\n        if (popup.isOpen)\n          popup.setRow(popup.selection.lead.row);\n        popup.renderer.scrollCursorIntoView();\n      });\n\n      popup.hide = function () {\n        this.container.style.display = \"none\";\n        this._signal(\"hide\");\n        popup.isOpen = false;\n      };\n      popup.show = function (pos, lineHeight, topdownOnly) {\n        var el = this.container;\n        var screenHeight = window.innerHeight;\n        var screenWidth = window.innerWidth;\n        var renderer = this.renderer;\n        var maxH = renderer.$maxLines * lineHeight * 1.4;\n        var top = pos.top + this.$borderSize;\n        var allowTopdown = top > screenHeight / 2 && !topdownOnly;\n        if (allowTopdown && top + lineHeight + maxH > screenHeight) {\n          renderer.$maxPixelHeight = top - 2 * this.$borderSize;\n          el.style.top = \"\";\n          el.style.bottom = screenHeight - top + \"px\";\n          popup.isTopdown = false;\n        } else {\n          top += lineHeight;\n          renderer.$maxPixelHeight = screenHeight - top - 0.2 * lineHeight;\n          el.style.top = top + \"px\";\n          el.style.bottom = \"\";\n          popup.isTopdown = true;\n        }\n\n        el.style.display = \"\";\n        this.renderer.$textLayer.checkForSizeChanges();\n\n        var left = pos.left;\n        if (left + el.offsetWidth > screenWidth)\n          left = screenWidth - el.offsetWidth;\n\n        el.style.left = left + \"px\";\n\n        this._signal(\"show\");\n        lastMouseEvent = null;\n        popup.isOpen = true;\n      };\n\n      popup.getTextLeftOffset = function () {\n        return this.$borderSize + this.renderer.$padding + this.$imageSize;\n      };\n\n      popup.$imageSize = 0;\n      popup.$borderSize = 1;\n\n      return popup;\n    };\n\n    dom.importCssString(\"\\\n.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {\\\n    background-color: #CAD6FA;\\\n    z-index: 1;\\\n}\\\n.ace_editor.ace_autocomplete .ace_line-hover {\\\n    border: 1px solid #abbffe;\\\n    margin-top: -1px;\\\n    background: rgba(233,233,253,0.4);\\\n}\\\n.ace_editor.ace_autocomplete .ace_line-hover {\\\n    position: absolute;\\\n    z-index: 2;\\\n}\\\n.ace_editor.ace_autocomplete .ace_scroller {\\\n   background: none;\\\n   border: none;\\\n   box-shadow: none;\\\n}\\\n.ace_rightAlignedText {\\\n    color: gray;\\\n    display: inline-block;\\\n    position: absolute;\\\n    right: 4px;\\\n    text-align: right;\\\n    z-index: -1;\\\n}\\\n.ace_editor.ace_autocomplete .ace_completion-highlight{\\\n    color: #000;\\\n    text-shadow: 0 0 0.01em;\\\n}\\\n.ace_editor.ace_autocomplete {\\\n    width: 280px;\\\n    z-index: 200000;\\\n    background: #fbfbfb;\\\n    color: #444;\\\n    border: 1px lightgray solid;\\\n    position: fixed;\\\n    box-shadow: 2px 3px 5px rgba(0,0,0,.2);\\\n    line-height: 1.4;\\\n}\");\n\n    exports.AcePopup = AcePopup;\n\n  });\n\n  ace.define(\"ace/autocomplete/util\", [\"require\", \"exports\", \"module\"], function (require, exports, module) {\n    \"use strict\";\n\n    exports.parForEach = function (array, fn, callback) {\n      var completed = 0;\n      var arLength = array.length;\n      if (arLength === 0)\n        callback();\n      for (var i = 0; i < arLength; i++) {\n        fn(array[i], function (result, err) {\n          completed++;\n          if (completed === arLength)\n            callback(result, err);\n        });\n      }\n    };\n\n    var ID_REGEX = /[a-zA-Z_0-9\\$\\-\\u00A2-\\uFFFF]/;\n\n    exports.retrievePrecedingIdentifier = function (text, pos, regex) {\n      regex = regex || ID_REGEX;\n      var buf = [];\n      for (var i = pos - 1; i >= 0; i--) {\n        if (regex.test(text[i]))\n          buf.push(text[i]);\n        else\n          break;\n      }\n      return buf.reverse().join(\"\");\n    };\n\n    exports.retrieveFollowingIdentifier = function (text, pos, regex) {\n      regex = regex || ID_REGEX;\n      var buf = [];\n      for (var i = pos; i < text.length; i++) {\n        if (regex.test(text[i]))\n          buf.push(text[i]);\n        else\n          break;\n      }\n      return buf;\n    };\n\n    //not used anymore\n    exports.getCompletionPrefix = function (editor) {\n      const pos = editor.getCursorPosition();\n      const line = editor.session.getLine(pos.row);\n      let prefix;\n      editor.completers.forEach(function (completer) {\n        if (completer.identifierRegexps) {\n          completer.identifierRegexps.forEach(function (identifierRegex) {\n            if (!prefix && identifierRegex)\n              prefix = this.retrievePrecedingIdentifier(line, pos.column, identifierRegex);\n          }.bind(this));\n        }\n      }.bind(this));\n      return prefix || this.retrievePrecedingIdentifier(line, pos.column);\n    };\n\n    const getCompletionPrefixByRegex = function (editor, regexArr) {\n      const pos = editor.getCursorPosition();\n      const line = editor.session.getLine(pos.row);\n      let prefix;\n      if (regexArr) {\n        regexArr.forEach((identifierRegex) => {\n          if (!prefix && identifierRegex) {\n            prefix = exports.retrievePrecedingIdentifier(line, pos.column, identifierRegex);\n          }\n        });\n      }\n      return prefix;\n    };\n\n    exports.getCompletionPrefixByCompleter = function (editor, completer) {\n      if (completer.linePredicate) {\n        const pos = editor.getCursorPosition();\n        const line = editor.session.getLine(pos.row);\n        const str = line.substr(0, pos.column);\n        const shouldUseCompleter = completer.linePredicate(str);\n        if (!shouldUseCompleter) {\n          return;\n        }\n      }\n      const prefix = getCompletionPrefixByRegex(editor, completer.identifierRegexps);\n      if (prefix === '' && !completer.acceptEmptyString) {\n        return;\n      }\n      return prefix;\n    }\n  });\n\n  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) {\n    \"use strict\";\n\n    var HashHandler = require(\"./keyboard/hash_handler\").HashHandler;\n    var AcePopup = require(\"./autocomplete/popup\").AcePopup;\n    var util = require(\"./autocomplete/util\");\n    // var event = require(\"./lib/event\");\n    var lang = require(\"./lib/lang\");\n    var dom = require(\"./lib/dom\");\n    var snippetManager = require(\"./snippets\").snippetManager;\n\n    var Autocomplete: any = function () {\n      this.autoInsert = false;\n      this.autoSelect = true;\n      this.exactMatch = false;\n      this.gatherCompletionsId = 0;\n      this.keyboardHandler = new HashHandler();\n      this.keyboardHandler.bindKeys(this.commands);\n\n      this.blurListener = this.blurListener.bind(this);\n      this.changeListener = this.changeListener.bind(this);\n      this.mousedownListener = this.mousedownListener.bind(this);\n      this.mousewheelListener = this.mousewheelListener.bind(this);\n\n      this.changeTimer = lang.delayedCall(function () {\n        this.updateCompletions(true);\n      }.bind(this));\n\n      this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50);\n    };\n\n    (function () {\n\n      this.$init = function () {\n        this.popup = new AcePopup(document.body || document.documentElement);\n        this.popup.on(\"click\", function (e) {\n          this.insertMatch();\n          e.stop();\n        }.bind(this));\n        this.popup.focus = this.editor.focus.bind(this.editor);\n        this.popup.on(\"show\", this.tooltipTimer.bind(null, null));\n        this.popup.on(\"select\", this.tooltipTimer.bind(null, null));\n        this.popup.on(\"changeHoverMarker\", this.tooltipTimer.bind(null, null));\n        return this.popup;\n      };\n\n      this.getPopup = function () {\n        return this.popup || this.$init();\n      };\n\n      this.openPopup = function (editor, prefix, keepPopupPosition) {\n        if (!this.popup)\n          this.$init();\n\n        this.popup.autoSelect = this.autoSelect;\n\n        this.popup.setData(this.completions.filtered);\n\n        editor.keyBinding.addKeyboardHandler(this.keyboardHandler);\n\n        var renderer = editor.renderer;\n        this.popup.setRow(this.autoSelect ? 0 : -1);\n        if (!keepPopupPosition) {\n          this.popup.setTheme(editor.getTheme());\n          this.popup.setFontSize(editor.getFontSize());\n\n          var lineHeight = renderer.layerConfig.lineHeight;\n\n          var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);\n          pos.left -= this.popup.getTextLeftOffset();\n\n          var rect = editor.container.getBoundingClientRect();\n          pos.top += rect.top - renderer.layerConfig.offset;\n          pos.left += rect.left - editor.renderer.scrollLeft;\n          pos.left += renderer.gutterWidth;\n\n          this.popup.show(pos, lineHeight);\n        } else if (keepPopupPosition && !prefix) {\n          this.detach();\n        }\n      };\n\n      this.detach = function () {\n        this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);\n        this.editor.off(\"changeSelection\", this.changeListener);\n        this.editor.off(\"blur\", this.blurListener);\n        this.editor.off(\"mousedown\", this.mousedownListener);\n        this.editor.off(\"mousewheel\", this.mousewheelListener);\n        this.changeTimer.cancel();\n        this.hideDocTooltip();\n\n        this.gatherCompletionsId += 1;\n        if (this.popup && this.popup.isOpen)\n          this.popup.hide();\n\n        if (this.base)\n          this.base.detach();\n        this.activated = false;\n        this.completions = this.base = null;\n      };\n\n      this.changeListener = function (e) {\n        var cursor = this.editor.selection.lead;\n        if (cursor.row != this.base.row || cursor.column < this.base.column) {\n          this.detach();\n        }\n        if (this.activated)\n          this.changeTimer.schedule();\n        else\n          this.detach();\n      };\n\n      this.blurListener = function (e) {\n        var el = document.activeElement;\n        var text = this.editor.textInput.getElement();\n        var fromTooltip = e.relatedTarget && this.tooltipNode && this.tooltipNode.contains(e.relatedTarget);\n        var container = this.popup && this.popup.container;\n        if (el != text && el.parentNode != container && !fromTooltip\n          && el != this.tooltipNode && e.relatedTarget != text\n        ) {\n          this.detach();\n        }\n      };\n\n      this.mousedownListener = function (e) {\n        this.detach();\n      };\n\n      this.mousewheelListener = function (e) {\n        this.detach();\n      };\n\n      this.goTo = function (where) {\n        var row = this.popup.getRow();\n        var max = this.popup.session.getLength() - 1;\n\n        switch (where) {\n          case \"up\": row = row <= 0 ? max : row - 1; break;\n          case \"down\": row = row >= max ? -1 : row + 1; break;\n          case \"start\": row = 0; break;\n          case \"end\": row = max; break;\n        }\n\n        this.popup.setRow(row);\n      };\n\n      this.insertMatch = function (data, options) {\n        if (!data)\n          data = this.popup.getData(this.popup.getRow());\n        if (!data)\n          return false;\n\n        if (data.completer && data.completer.insertMatch) {\n          data.completer.insertMatch(this.editor, data);\n        } else {\n          if (this.completions.filterText) {\n            var ranges = this.editor.selection.getAllRanges();\n            for (var i = 0, range; range = ranges[i]; i++) {\n              range.start.column -= this.completions.filterText.length;\n              this.editor.session.remove(range);\n            }\n          }\n          if (data.snippet)\n            snippetManager.insertSnippet(this.editor, data.snippet);\n          else\n            this.editor.execCommand(\"insertstring\", data.value || data);\n        }\n        this.detach();\n      };\n\n\n      this.commands = {\n        \"Up\": function (editor) {editor.completer.goTo(\"up\");},\n        \"Down\": function (editor) {editor.completer.goTo(\"down\");},\n        \"Ctrl-Up|Ctrl-Home\": function (editor) {editor.completer.goTo(\"start\");},\n        \"Ctrl-Down|Ctrl-End\": function (editor) {editor.completer.goTo(\"end\");},\n\n        \"Esc\": function (editor) {editor.completer.detach();},\n        // \"Return\": function (editor) {return editor.completer.insertMatch();},\n        \"Shift-Return\": function (editor) {editor.completer.insertMatch(null, {deleteSuffix: true});},\n        \"Tab\": function (editor) {\n          var result = editor.completer.insertMatch();\n          if (!result && !editor.tabstopManager)\n            editor.completer.goTo(\"down\");\n          else\n            return result;\n        },\n\n        \"PageUp\": function (editor) {editor.completer.popup.gotoPageUp();},\n        \"PageDown\": function (editor) {editor.completer.popup.gotoPageDown();}\n      };\n\n      this.gatherCompletions = function (editor, callback) {\n        const session = editor.getSession();\n        const pos = editor.getCursorPosition();\n\n        // const prefix = util.getCompletionPrefix(editor);\n\n\n        let matches = [];\n        // let total = editor.completers.length;\n        const success = editor.completers.some((completer, i) => {\n\n          const prefix = util.getCompletionPrefixByCompleter(editor, completer);\n          if (typeof prefix !== 'undefined') {\n\n            this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length);\n            this.base.$insertRight = true;\n\n            completer.getCompletions(editor, session, pos, prefix, function (err, results) {\n              if (!err && results)\n                matches = matches.concat(results);\n              callback(null, {\n                prefix,\n                matches: matches,\n                finished: true\n              });\n            });\n            return true;\n          }\n          return false;\n        });\n\n        if (!success) {\n          callback(null, {prefix: null, matches: [], finished: true});\n        }\n      };\n\n      this.showPopup = function (editor) {\n        if (this.editor)\n          this.detach();\n\n        this.activated = true;\n\n        this.editor = editor;\n        if (editor.completer != this) {\n          if (editor.completer)\n            editor.completer.detach();\n          editor.completer = this;\n        }\n\n        editor.on(\"changeSelection\", this.changeListener);\n        editor.on(\"blur\", this.blurListener);\n        editor.on(\"mousedown\", this.mousedownListener);\n        editor.on(\"mousewheel\", this.mousewheelListener);\n\n        this.updateCompletions();\n      };\n\n      this.updateCompletions = function (keepPopupPosition) {\n        if (keepPopupPosition && this.base && this.completions) { /* if updating an existing popup */\n          var pos = this.editor.getCursorPosition();\n          var prefix = this.editor.session.getTextRange({start: this.base, end: pos});\n          if (prefix === this.completions.filterText)\n            return;\n          if (prefix === '')\n            return;\n          // this.completions.setFilter(prefix);\n\n          this.gatherCompletions(this.editor, (err, results) => {\n            this.latestPrefix = results.prefix;\n            const matches = results && results.matches;\n            this.completions = new FilteredList(matches);\n            this.completions.setFilter(this.latestPrefix);\n\n            if (!this.completions.filtered.length)\n              return this.detach();\n            if (this.completions.filtered.length == 1\n              && this.completions.filtered[0].value == prefix\n              && !this.completions.filtered[0].snippet)\n              return this.detach();\n            this.openPopup(this.editor, prefix, keepPopupPosition);\n          });\n          return;\n        }\n        /* new popup */\n        var _id = this.gatherCompletionsId;\n        this.gatherCompletions(this.editor, function (err, results) {\n          var detachIfFinished = function () {\n            if (!results.finished) return;\n            return this.detach();\n          }.bind(this);\n\n          var prefix = this.latestPrefix = results.prefix;\n          var matches = results && results.matches;\n\n          if (!matches || !matches.length)\n            return detachIfFinished();\n          if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId)\n            return;\n\n          this.completions = new FilteredList(matches);\n\n          if (this.exactMatch)\n            this.completions.exactMatch = true;\n\n          this.completions.setFilter(prefix);\n          var filtered = this.completions.filtered;\n          if (!filtered.length)\n            return detachIfFinished();\n          if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet)\n            return detachIfFinished();\n          if (this.autoInsert && filtered.length == 1 && results.finished)\n            return this.insertMatch(filtered[0]);\n\n          this.openPopup(this.editor, prefix, keepPopupPosition);\n        }.bind(this));\n      };\n\n      this.cancelContextMenu = function () {\n        this.editor.$mouseHandler.cancelContextMenu();\n      };\n\n      this.updateDocTooltip = function () {\n        var popup = this.popup;\n        var all = popup.data;\n        var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]);\n        var doc = null;\n        if (!selected || !this.editor || !this.popup.isOpen)\n          return this.hideDocTooltip();\n        this.editor.completers.some(function (completer) {\n          if (completer.getDocTooltip)\n            doc = completer.getDocTooltip(selected);\n          return doc;\n        });\n        if (!doc)\n          doc = selected;\n\n        if (typeof doc == \"string\")\n          doc = {docText: doc};\n        if (!doc || !(doc.docHTML || doc.docText))\n          return this.hideDocTooltip();\n        this.showDocTooltip(doc);\n      };\n\n      this.showDocTooltip = function (item) {\n        if (!this.tooltipNode) {\n          this.tooltipNode = dom.createElement(\"div\");\n          this.tooltipNode.className = \"ace_tooltip ace_doc-tooltip\";\n          this.tooltipNode.style.margin = 0;\n          this.tooltipNode.style.pointerEvents = \"auto\";\n          this.tooltipNode.tabIndex = -1;\n          this.tooltipNode.onblur = this.blurListener.bind(this);\n          this.tooltipNode.onclick = this.onTooltipClick.bind(this);\n        }\n\n        var tooltipNode = this.tooltipNode;\n        if (item.docHTML) {\n          tooltipNode.innerHTML = item.docHTML;\n        } else if (item.docText) {\n          tooltipNode.textContent = item.docText;\n        }\n\n        if (!tooltipNode.parentNode)\n          document.body.appendChild(tooltipNode);\n        var popup = this.popup;\n        var rect = popup.container.getBoundingClientRect();\n        tooltipNode.style.top = popup.container.style.top;\n        tooltipNode.style.bottom = popup.container.style.bottom;\n\n        if (window.innerWidth - rect.right < 320) {\n          tooltipNode.style.right = window.innerWidth - rect.left + \"px\";\n          tooltipNode.style.left = \"\";\n        } else {\n          tooltipNode.style.left = (rect.right + 1) + \"px\";\n          tooltipNode.style.right = \"\";\n        }\n        tooltipNode.style.display = \"block\";\n      };\n\n      this.hideDocTooltip = function () {\n        this.tooltipTimer.cancel();\n        if (!this.tooltipNode) return;\n        var el = this.tooltipNode;\n        if (!this.editor.isFocused() && document.activeElement == el)\n          this.editor.focus();\n        this.tooltipNode = null;\n        if (el.parentNode)\n          el.parentNode.removeChild(el);\n      };\n\n      this.onTooltipClick = function (e) {\n        var a = e.target;\n        while (a && a != this.tooltipNode) {\n          if (a.nodeName == \"A\" && a.href) {\n            a.rel = \"noreferrer\";\n            a.target = \"_blank\";\n            break;\n          }\n          a = a.parentNode;\n        }\n      }\n\n    }).call(Autocomplete.prototype);\n\n    Autocomplete.startCommand = {\n      name: \"startAutocomplete\",\n      exec: function (editor) {\n        if (!editor.completer)\n          editor.completer = new Autocomplete();\n        editor.completer.autoInsert = false;\n        editor.completer.autoSelect = true;\n        editor.completer.showPopup(editor);\n        editor.completer.cancelContextMenu();\n      },\n      bindKey: \"Ctrl-Space|Ctrl-Shift-Space|Alt-Space\"\n    };\n\n    var FilteredList = function (array, filterText?) {\n      this.all = array;\n      this.filtered = array;\n      this.filterText = filterText || \"\";\n      this.exactMatch = false;\n    };\n    (function () {\n      this.setFilter = function (str) {\n        if (str && str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0)\n          var matches = this.filtered;\n        else\n          var matches = this.all;\n\n        this.filterText = str;\n        // matches = this.filterCompletions(matches, this.filterText);\n        matches = matches.sort(function(a, b) {\n          return b.exactMatch - a.exactMatch || b.score - a.score;\n        });\n        var prev = null;\n        matches = matches.filter(function (item) {\n          var caption = item.snippet || item.caption || item.value;\n          if (caption === prev) return false;\n          prev = caption;\n          return true;\n        });\n\n        this.filtered = matches;\n      };\n      this.filterCompletions = function (items, needle) {\n        var results = [];\n        var upper = needle.toUpperCase();\n        var lower = needle.toLowerCase();\n        loop: for (var i = 0, item; item = items[i]; i++) {\n          var caption = item.value || item.caption || item.snippet;\n          if (!caption) continue;\n          var lastIndex = -1;\n          var matchMask = 0;\n          var penalty = 0;\n          var index, distance;\n\n          if (this.exactMatch) {\n            if (needle !== caption.substr(0, needle.length))\n              continue loop;\n          } else {\n            for (var j = 0; j < needle.length; j++) {\n              var i1 = caption.indexOf(lower[j], lastIndex + 1);\n              var i2 = caption.indexOf(upper[j], lastIndex + 1);\n              index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2;\n              if (index < 0)\n                continue loop;\n              distance = index - lastIndex - 1;\n              if (distance > 0) {\n                if (lastIndex === -1)\n                  penalty += 10;\n                penalty += distance;\n              }\n              matchMask = matchMask | (1 << index);\n              lastIndex = index;\n            }\n          }\n          item.matchMask = matchMask;\n          item.exactMatch = penalty ? 0 : 1;\n          item.score = (item.score || 0) - penalty;\n          results.push(item);\n        }\n        return results;\n      };\n    }).call(FilteredList.prototype);\n\n    exports.Autocomplete = Autocomplete;\n    exports.FilteredList = FilteredList;\n\n  });\n\n  ace.define(\"ace/autocomplete/text_completer\", [\"require\", \"exports\", \"module\", \"ace/range\"], function (require, exports, module) {\n    var Range = require(\"../range\").Range;\n\n    var splitRegex = /[^a-zA-Z_0-9\\$\\-\\u00C0-\\u1FFF\\u2C00-\\uD7FF\\w]+/;\n\n    function getWordIndex(doc, pos) {\n      var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column: 0}, pos));\n      return textBefore.split(splitRegex).length - 1;\n    }\n    function wordDistance(doc, pos, _) {\n      var prefixPos = getWordIndex(doc, pos);\n      var words = doc.getValue().split(splitRegex);\n      var wordScores = Object.create(null);\n\n      var currentWord = words[prefixPos];\n\n      words.forEach(function (word, idx) {\n        if (!word || word === currentWord) return;\n\n        var distance = Math.abs(prefixPos - idx);\n        var score = words.length - distance;\n        if (wordScores[word]) {\n          wordScores[word] = Math.max(score, wordScores[word]);\n        } else {\n          wordScores[word] = score;\n        }\n      });\n      return wordScores;\n    }\n\n    exports.getCompletions = function (editor, session, pos, prefix, callback) {\n      var wordScore = wordDistance(session, pos, prefix);\n      var wordList = Object.keys(wordScore);\n      callback(null, wordList.map(function (word) {\n        return {\n          caption: word,\n          value: word,\n          score: wordScore[word],\n          meta: \"local\"\n        };\n      }));\n    };\n  });\n\n  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) {\n    \"use strict\";\n\n    var snippetManager = require(\"../snippets\").snippetManager;\n    var Autocomplete = require(\"../autocomplete\").Autocomplete;\n    var config = require(\"../config\");\n    var lang = require(\"../lib/lang\");\n    var util = require(\"../autocomplete/util\");\n\n    var textCompleter = require(\"../autocomplete/text_completer\");\n    var keyWordCompleter = {\n      getCompletions: function (editor, session, pos, prefix, callback) {\n        if (session.$mode.completer) {\n          return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback);\n        }\n        var state = editor.session.getState(pos.row);\n        var completions = session.$mode.getCompletions(state, session, pos, prefix);\n        callback(null, completions);\n      }\n    };\n\n    var snippetCompleter = {\n      getCompletions: function (editor, session, pos, prefix, callback) {\n        var snippetMap = snippetManager.snippetMap;\n        var completions = [];\n        snippetManager.getActiveScopes(editor).forEach(function (scope) {\n          var snippets = snippetMap[scope] || [];\n          for (var i = snippets.length; i--;) {\n            var s = snippets[i];\n            var caption = s.name || s.tabTrigger;\n            if (!caption)\n              continue;\n            completions.push({\n              caption: caption,\n              snippet: s.content,\n              meta: s.tabTrigger && !s.name ? s.tabTrigger + \"\\u21E5 \" : \"snippet\",\n              type: \"snippet\"\n            });\n          }\n        }, this);\n        callback(null, completions);\n      },\n      getDocTooltip: function (item) {\n        if (item.type == \"snippet\" && !item.docHTML) {\n          item.docHTML = [\n            \"<b>\", lang.escapeHTML(item.caption), \"</b>\", \"<hr></hr>\",\n            lang.escapeHTML(item.snippet)\n          ].join(\"\");\n        }\n      }\n    };\n\n    var completers = [snippetCompleter, textCompleter, keyWordCompleter];\n    exports.setCompleters = function (val) {\n      completers.length = 0;\n      if (val) completers.push.apply(completers, val);\n    };\n    exports.addCompleter = function (completer) {\n      completers.push(completer);\n    };\n    exports.textCompleter = textCompleter;\n    exports.keyWordCompleter = keyWordCompleter;\n    exports.snippetCompleter = snippetCompleter;\n\n    var expandSnippet = {\n      name: \"expandSnippet\",\n      exec: function (editor) {\n        return snippetManager.expandWithTab(editor);\n      },\n      bindKey: \"Tab\"\n    };\n\n    var onChangeMode = function (e, editor) {\n      loadSnippetsForMode(editor.session.$mode);\n    };\n\n    var loadSnippetsForMode = function (mode) {\n      var id = mode.$id;\n      if (!snippetManager.files)\n        snippetManager.files = {};\n      loadSnippetFile(id);\n      if (mode.modes)\n        mode.modes.forEach(loadSnippetsForMode);\n    };\n\n    var loadSnippetFile = function (id) {\n      if (!id || snippetManager.files[id])\n        return;\n      var snippetFilePath = id.replace(\"mode\", \"snippets\");\n      snippetManager.files[id] = {};\n      config.loadModule(snippetFilePath, function (m) {\n        if (m) {\n          snippetManager.files[id] = m;\n          if (!m.snippets && m.snippetText)\n            m.snippets = snippetManager.parseSnippetFile(m.snippetText);\n          snippetManager.register(m.snippets || [], m.scope);\n          if (m.includeScopes) {\n            snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes;\n            m.includeScopes.forEach(function (x) {\n              loadSnippetFile(\"ace/mode/\" + x);\n            });\n          }\n        }\n      });\n    };\n\n    var doLiveAutocomplete = function (e) {\n      var editor = e.editor;\n      var hasCompleter = editor.completer && editor.completer.activated;\n      if (e.command.name === \"backspace\") {\n        if (hasCompleter && !util.getCompletionPrefix(editor))\n          editor.completer.detach();\n      }\n      else if (e.command.name === \"insertstring\") {\n        var prefix = util.getCompletionPrefix(editor);\n        if (prefix && !hasCompleter) {\n          if (!editor.completer) {\n            editor.completer = new Autocomplete();\n          }\n          editor.completer.autoInsert = false;\n          editor.completer.showPopup(editor);\n        }\n      }\n    };\n\n    var Editor = require(\"../editor\").Editor;\n    require(\"../config\").defineOptions(Editor.prototype, \"editor\", {\n      enableBasicAutocompletion: {\n        set: function (val) {\n          if (val) {\n            if (!this.completers)\n              this.completers = Array.isArray(val) ? val : completers;\n            this.commands.addCommand(Autocomplete.startCommand);\n          } else {\n            this.commands.removeCommand(Autocomplete.startCommand);\n          }\n        },\n        value: false\n      },\n      enableLiveAutocompletion: {\n        set: function (val) {\n          if (val) {\n            if (!this.completers)\n              this.completers = Array.isArray(val) ? val : completers;\n            this.commands.on('afterExec', doLiveAutocomplete);\n          } else {\n            this.commands.removeListener('afterExec', doLiveAutocomplete);\n          }\n        },\n        value: false\n      },\n      enableSnippets: {\n        set: function (val) {\n          if (val) {\n            this.commands.addCommand(expandSnippet);\n            this.on(\"changeMode\", onChangeMode);\n            onChangeMode(null, this);\n          } else {\n            this.commands.removeCommand(expandSnippet);\n            this.off(\"changeMode\", onChangeMode);\n          }\n        },\n        value: false\n      }\n    });\n  });\n  (function () {\n    ace.acequire([\"ace/ext/language_tools-bi\"], function () {});\n  })();\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/ace-extensions/presto-snippets.ts",
    "content": "/* tslint:disable */\n\nexport const setupSnippets = (ace) => {\n  ace.define(\"ace/snippets/presto\", [\"require\", \"exports\", \"module\"], function (e, t, n) {\n    \"use strict\";\n    t.snippetText = \"snippet tbl\\n\tcreate table ${1:table} (\\n\t\t${2:columns}\\n\t);\\nsnippet col\\n\t${1:name}\t${2:type}\t${3:default ''}\t${4:not null}\\nsnippet ccol\\n\t${1:name}\tvarchar2(${2:size})\t${3:default ''}\t${4:not null}\\nsnippet ncol\\n\t${1:name}\tnumber\t${3:default 0}\t${4:not null}\\nsnippet dcol\\n\t${1:name}\tdate\t${3:default sysdate}\t${4:not null}\\nsnippet ind\\n\tcreate index ${3:$1_$2} on ${1:table}(${2:column});\\nsnippet uind\\n\tcreate unique index ${1:name} on ${2:table}(${3:column});\\nsnippet tblcom\\n\tcomment on table ${1:table} is '${2:comment}';\\nsnippet colcom\\n\tcomment on column ${1:table}.${2:column} is '${3:comment}';\\nsnippet addcol\\n\talter table ${1:table} add (${2:column} ${3:type});\\nsnippet seq\\n\tcreate sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\\nsnippet s*\\n\tselect * from ${1:table}\\n\", t.scope = \"sql\"})\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/ace-extensions/presto.mode.ts",
    "content": "/* tslint:disable */\n\nexport const setupPrestoMode = (ace) => {\n  ace.define(\"ace/mode/presto_highlight_rules\", [\"require\", \"exports\", \"module\", \"ace/lib/oop\", \"ace/mode/text_highlight_rules\"], function (require, exports, module) {\n    \"use strict\";\n\n    var oop = require(\"../lib/oop\");\n    var TextHighlightRules = require(\"./text_highlight_rules\").TextHighlightRules;\n\n    var SqlHighlightRules = function () {\n\n      var keywords = (\n        \"select|insert|update|delete|from|where|and|or|group|by|order|limit|offset|having|as|case|\" +\n        \"when|else|end|type|left|right|join|on|outer|desc|asc|union|create|table|primary|key|if|\" +\n        \"foreign|not|references|default|null|inner|cross|natural|database|drop|grant\"\n      );\n\n      var prestoKeywords = (\n        \"|ALL|ALL PRIVILEGES|ALTER TABLE|ADD COLUMN|RENAME COLUMN TO|RENAME TO|AS|ASC|CALL|COMMIT|CREATE|CREATE TABLE\" +\n        \"|CROSS JOIN|CUBE|DATA|DELETE FROM|DESC|DESCRIBE|DISTINCT|DISTRIBUTED|DROP TABLE|DROP VIEW|EXPLAIN\" +\n        \"|EXPLAIN ANALYZE|FORMAT|FROM|FULL|GRANT|GRANT OPTION FOR|GRAPHVIZ|GROUP BY|GROUPING SETS|HAVING|IF EXISTS\" +\n        \"|IF NOT EXISTS|INNER|INSERT INTO|ISOLATION LEVEL|JOIN|LEFT|LIKE|LIMIT|LOGICAL|NO|ON|ONLY|OR REPLACE|ORDER BY\" +\n        \"|OUTER|PUBLIC|READ|READ COMMITTED|READ UNCOMMITTED|REPEATABLE READ|RESET SESSION|REVOKE|RIGHT|ROLLBACK|ROLLUP\" +\n        \"|SELECT|SERIALIZABLE|SET SESSION|SHOW CATALOGS|SHOW COLUMNS FROM|SHOW CREATE TABLE|SHOW CREATE VIEW\" +\n        \"|SHOW FUNCTIONS|SHOW PARTITIONS FROM|SHOW SCHEMAS|SHOW SESSION|SHOW TABLES|START TRANSACTION|TABLE\" +\n        \"|TEXT|TO|TYPE|UNION|USE|USING|VALUES|VIEW AS|WHERE|WITH|WITH GRANT OPTION|WORK|WRITE\"\n      );\n\n      var builtinConstants = (\n        \"true|false\"\n      );\n\n      var builtinFunctions = (\n        \"avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|\" +\n        \"coalesce|ifnull|isnull|nvl\"\n      );\n\n      var prestoFunctions = (\n        \"|abs|acos|approx_distinct|approx_percentile|arbitrary|array_agg|array_distinct|array_intersect|array_join|\" +\n        \"array_max|array_min|array_position|array_remove|array_sort|asin|atan|atan2|avg|bar|bit_count|bitwise_and|\" +\n        \"bitwise_not|bitwise_or|bitwise_xor|bool_and|bool_or|cardinality|cardinality|cast|cbrt|ceil|ceiling|\" +\n        \"char2hexint|checksum|chr|color|concat|concat|contains|corr|cos|cosh|cosine_similarity|count|count_if|\" +\n        \"covar_pop|covar_samp|cume_dist|current_timezone|date_add|date_diff|date_format|date_parse|date_trunc|day|\" +\n        \"day_of_month|day_of_week|day_of_year|degrees|dense_rank|dow|doy|e|element_at|element_at|every|exp|extract|\" +\n        \"first_value|flatten|floor|format_datetime|from_base|from_base64|from_base64url|from_hex|from_iso8601_date|\" +\n        \"from_iso8601_timestamp|from_unixtime|from_utf8|geometric_mean|greatest|histogram|hour|index|infinity|is_finite|\" +\n        \"is_infinite|is_nan|json_array_contains|json_array_get|json_array_length|json_extract|json_extract_scalar|\" +\n        \"json_format|json_parse|json_size|lag|last_value|lead|least|length|length|ln|log|log10|log2|lower|lpad|ltrim|\" +\n        \"map|map_agg|map_concat|map_keys|map_union|map_values|max|max_by|md5|min|min_by|minute|mod|month|multimap_agg|\" +\n        \"nan|normalize|now|nth_value|ntile|numeric_histogram|parse_datetime|percent_rank|pi|position|pow|power|quarter|\" +\n        \"radians|rand|random|rank|regexp_extract|regexp_extract_all|regexp_like|regexp_replace|regexp_split|\" +\n        \"regr_intercept|regr_slope|render|replace|reverse|rgb|round|row_number|rpad|rtrim|second|sequence|\" +\n        \"sha1|sha256|sha512|sign|sin|slice|split|split_part|split_to_map|sqrt|stddev|stddev_pop|stddev_samp|strpos|\" +\n        \"substr|substring|sum|tan|tanh|timezone_hour|timezone_minute|to_base|to_base64|to_base64url|to_char|to_date|\" +\n        \"to_hex|to_iso8601|to_timestamp|to_unixtime|to_utf8|trim|truncate|try_cast|upper|url_decode|url_encode|\" +\n        \"url_extract_fragment|url_extract_host|url_extract_parameter|url_extract_path|url_extract_port|\" +\n        \"url_extract_protocol|url_extract_query|var_pop|var_samp|variance|week|week_of_year|width_bucket|\" +\n        \"year|year_of_week|yow|zip\"\n      );\n\n      var dataTypes = (\n        \"int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|\" +\n        \"money|real|number|integer\"\n      );\n\n      var prestoDataTypes = \"|varbinary|json|time|interval|array|map\";\n\n      var keywordMapper = this.createKeywordMapper({\n        \"support.function\": builtinFunctions + prestoFunctions,\n        \"keyword\": keywords + prestoKeywords,\n        \"constant.language\": builtinConstants,\n        \"storage.type\": dataTypes + prestoDataTypes\n      }, \"identifier\", true);\n\n      this.$rules = {\n        \"start\": [{\n          token: \"comment\",\n          regex: \"--.*$\"\n        }, {\n          token: \"comment\",\n          start: \"/\\\\*\",\n          end: \"\\\\*/\"\n        }, {\n          token: \"string\",           // \" string\n          start: '\"',\n          end: '\"'\n        }, {\n          token: \"string\",           // ' string\n          start: \"'\",\n          end:   \"'\"\n        }, {\n          token: \"constant.numeric\", // float\n          regex: \"[+-]?\\\\d+(?:(?:\\\\.\\\\d*)?(?:[eE][+-]?\\\\d+)?)?\\\\b\"\n        }, {\n          token: keywordMapper,\n          regex: \"[a-zA-Z_$][a-zA-Z0-9_$]*\\\\b\"\n        }, {\n          token: \"keyword.operator\",\n          regex: \"\\\\+|\\\\-|\\\\/|\\\\/\\\\/|%|<@>|@>|<@|&|\\\\^|~|<|>|<=|=>|==|!=|<>|=\"\n        }, {\n          token: \"paren.lparen\",\n          regex: \"[\\\\(]\"\n        }, {\n          token: \"paren.rparen\",\n          regex: \"[\\\\)]\"\n        }, {\n          token: \"text\",\n          regex: \"\\\\s+\"\n        }, {\n          token: \"custom-keyword--reference\",\n          regex: \"@[^\\\\s@]+\"\n        }]\n      };\n      this.normalizeRules();\n    };\n\n    oop.inherits(SqlHighlightRules, TextHighlightRules);\n\n    exports.SqlHighlightRules = SqlHighlightRules;\n  });\n\n\n  ace.define(\"ace/mode/folding/presto\", [\"require\", \"exports\", \"module\", \"ace/lib/oop\", \"ace/mode/folding/fold_mode\", \"ace/range\"],\n    function (require, exports, module) {\n      \"use strict\";\n\n      // function escapeRegExp(str) {\n      //   return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n      // }\n\n      var oop = require(\"../../lib/oop\");\n      var Range = require(\"../../range\").Range;\n      var BaseFoldMode = require(\"./fold_mode\").FoldMode;\n      var TokenIterator = require(\"../../token_iterator\").TokenIterator;\n\n      var FoldMode = exports.FoldMode = function () {};\n      oop.inherits(FoldMode, BaseFoldMode);\n\n      (function () {\n        this.foldingStartMarker = /(\\()[^)]*$|^\\s*(\\/\\*)/;\n        this.foldingStopMarker = /^[^(]*(\\))|^.*(\\*\\/)/;\n        this.singleLineBlockCommentRe = /^.*(\\/\\*).*\\*\\/.*$/;\n        this.tripleStarBlockCommentRe = /^\\s*(\\/\\*\\*\\*).*\\*\\/\\s*$/;\n        this.startRegionRe = /^\\s*--#?region\\b/;\n        this.sqlCommentRe = /^--.*/;\n        this._getFoldWidgetBase = this.getFoldWidget;\n\n        this.getFoldWidget = function (session, foldStyle, row) {\n          var line = session.getLine(row);\n\n          // if (this.sqlCommentRe.test(line)) {\n          //   return this.sqlCommentFoldWidget(session, foldStyle, row);\n          // }\n\n          if (this.singleLineBlockCommentRe.test(line)) {\n            if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line))\n              return \"\";\n          }\n\n          var fw = this._getFoldWidgetBase(session, foldStyle, row);\n\n          if (!fw && this.startRegionRe.test(line))\n            return \"start\"; // lineCommentRegionStart\n\n          if (!fw && this.isStartIndentationBlock(session, line, row)) {\n            return \"start\";\n          }\n\n          return fw;\n        };\n\n        this.getFoldWidgetRange = function (session, foldStyle, row, forceMultiline) {\n          var line = session.getLine(row);\n\n          if (this.startRegionRe.test(line))\n            return this.getCommentRegionBlock(session, line, row);\n\n          // if (this.sqlCommentRe.test(line)) {\n          //   var type = this.sqlCommentFoldWidget(session, foldStyle, row);\n          //   if (type === \"start\") {\n          //     return  this.getCommentFoldRange(session, row, 0, 1);\n          //   } else if (type === \"end\") {\n          //     return  this.getCommentFoldRange(session, row, line.length - 1, -1);\n          //   } else {\n          //     return;\n          //   }\n          // }\n\n          var match = line.match(this.foldingStartMarker);\n          if (match) {\n            var i = match.index;\n\n            if (match[1])\n              return this.openingBracketBlock(session, match[1], row, i);\n\n            var range = this.getCommentFoldRange(session, row, i + match[0].length, 1);\n\n            if (range && !range.isMultiLine()) {\n              if (forceMultiline) {\n                range = this.getSectionRange(session, row);\n              } else if (foldStyle != \"all\")\n                range = null;\n            }\n\n            return range;\n          }\n\n          if (foldStyle === \"markbegin\")\n            return;\n\n          var match = line.match(this.foldingStopMarker);\n          if (match) {\n            var i = match.index + match[0].length;\n\n            if (match[1])\n              return this.closingBracketBlock(session, match[1], row, i);\n\n            return this.getCommentFoldRange(session, row, i, -1);\n          }\n\n          if (this.isStartIndentationBlock(session, line, row)) {\n            return this.indentationBlock(session, row);\n          }\n\n        };\n\n        this.isStartIndentationBlock = function (session, line, row) {\n          if (session.getLength() - 1 === row) {\n            return;\n          }\n          var re = /\\S/;\n          var nextLineRow = row + 1;\n          var firstCharPosNextLine;\n          var firstCharPos = line.search(re);\n          if (firstCharPos !== -1) {\n            do {\n              firstCharPosNextLine = session.getLine(nextLineRow).search(re);\n            } while (firstCharPosNextLine === -1 && session.getLength() > ++nextLineRow);\n            if (firstCharPosNextLine !== -1 && firstCharPos < firstCharPosNextLine) {\n              return 'start';\n            }\n          }\n        };\n\n        // this.sqlCommentFoldWidget = function (session, foldStyle, row) {\n        //   var nextLine = session.getLine(row + 1);\n        //   var prevLine = session.getLine(row - 1);\n        //   var nextLineIsComment = this.sqlCommentRe.test(nextLine);\n        //   var prevLineIsComment = this.sqlCommentRe.test(prevLine);\n        //   if (nextLineIsComment && !prevLineIsComment) {\n        //     return 'start';\n        //   } else if (foldStyle === 'markbeginend' && !nextLineIsComment && prevLineIsComment) {\n        //     return 'end';\n        //   } else {\n        //     return '';\n        //   }\n        // };\n\n        this.getCommentFoldRange = function (session, row, column, dir) {\n          var iterator = new TokenIterator(session, row, column);\n          var token = iterator.getCurrentToken();\n          if (token && /^comment|string/.test(token.type)) {\n            var range = new Range();\n            var re = new RegExp(token.type.replace(/\\..*/, \"\"));\n            if (dir != 1) {\n              do {\n                token = iterator.stepBackward();\n              } while (token && re.test(token.type));\n              iterator.stepForward();\n            }\n\n            range.start.row = iterator.getCurrentTokenRow();\n            // range.start.row = iterator.getCurrentTokenRow() + 1;\n            // range.start.column = iterator.getCurrentTokenColumn() + 2;\n            range.start.column = session.getLine(iterator.getCurrentTokenRow()).length;\n\n\n            iterator = new TokenIterator(session, row, column);\n\n            if (dir != -1) {\n              do {\n                token = iterator.stepForward();\n              } while (token && re.test(token.type));\n              token = iterator.stepBackward();\n            } else\n              token = iterator.getCurrentToken();\n\n            range.end.row = iterator.getCurrentTokenRow();\n            range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2;\n            return range;\n          }\n        };\n\n        this.getSectionRange = function (session, row) {\n          var line = session.getLine(row);\n          var startIndent = line.search(/\\S/);\n          var startRow = row;\n          var startColumn = line.length;\n          row = row + 1;\n          var endRow = row;\n          var maxRow = session.getLength();\n          while (++row < maxRow) {\n            line = session.getLine(row);\n            var indent = line.search(/\\S/);\n            if (indent === -1)\n              continue;\n            if (startIndent > indent)\n              break;\n            var subRange = this.getFoldWidgetRange(session, \"all\", row);\n\n            if (subRange) {\n              if (subRange.start.row <= startRow) {\n                break;\n              } else if (subRange.isMultiLine()) {\n                row = subRange.end.row;\n              } else if (startIndent == indent) {\n                break;\n              }\n            }\n            endRow = row;\n          }\n\n          return new Range(startRow, startColumn, endRow, session.getLine(endRow).length);\n        };\n        this.getCommentRegionBlock = function (session, line, row) {\n          var startColumn = line.search(/\\s*$/);\n          var maxRow = session.getLength();\n          var startRow = row;\n\n          var re = /^\\s*--#?(end)?region\\b/;\n          var depth = 1;\n          while (++row < maxRow) {\n            line = session.getLine(row);\n            var m = re.exec(line);\n            if (!m) continue;\n            if (m[1]) depth--;\n            else depth++;\n\n            if (!depth) break;\n          }\n\n          var endRow = row;\n          if (endRow > startRow) {\n            return new Range(startRow, startColumn, endRow, line.length);\n          }\n        };\n\n      }).call(FoldMode.prototype);\n\n    });\n\n  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) {\n    \"use strict\";\n\n    var oop = require(\"../lib/oop\");\n    var TextMode = require(\"./text\").Mode;\n    var SqlHighlightRules = require(\"./presto_highlight_rules\").SqlHighlightRules;\n    // var Range = require(\"../range\").Range;\n    var SqlFoldMode = require(\"./folding/presto\").FoldMode;\n\n    var Mode = function () {\n      this.HighlightRules = SqlHighlightRules;\n      this.foldingRules = new SqlFoldMode();\n\n    };\n    oop.inherits(Mode, TextMode);\n\n    (function () {\n      this.lineCommentStart = \"--\";\n      this.$id = \"ace/mode/presto\";\n\n      // syntax validation worker\n      // var WorkerClient = require(\"ace/worker/worker_client\").WorkerClient;\n      // this.createWorker = function(session) {\n      //   var document = session.getDocument();\n\n      //   this.$worker = new WorkerClient([\"ace\"], \"ace/worker/sql-worker\", \"SqlWorker\", \"3rd-party/ace/modes/sql-worker.js\");\n      //   this.$worker.attachToDocument(document);\n\n      //   this.$worker.on('annotate', function(e) {\n      //     session.setAnnotations(e.data);\n      //   });\n\n      //   this.$worker.on('terminate', function() {\n      //     session.clearAnnotations();\n      //   });\n\n      //   return this.$worker;\n      // };\n    }).call(Mode.prototype);\n\n    exports.Mode = Mode;\n\n  });\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/ace-extensions/searchbox.ts",
    "content": "/* This is searchbox from ace 1.2.9, if we upgrade, this can be removed */\n/* tslint:disable */\n\nexport const setupSearchbox = (ace) => {\n  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) {\n    \"use strict\";\n\n    var dom = require(\"../lib/dom\");\n    var lang = require(\"../lib/lang\");\n    var event = require(\"../lib/event\");\n    var searchboxCss = \"\\\n.ace_search {\\\nbackground-color: #ddd;\\\ncolor: #666;\\\nborder: 1px solid #cbcbcb;\\\nborder-top: 0 none;\\\noverflow: hidden;\\\nmargin: 0;\\\npadding: 4px 6px 0 4px;\\\nposition: absolute;\\\ntop: 0;\\\nz-index: 99;\\\nwhite-space: normal;\\\n}\\\n.ace_search.left {\\\nborder-left: 0 none;\\\nborder-radius: 0px 0px 5px 0px;\\\nleft: 0;\\\n}\\\n.ace_search.right {\\\nborder-radius: 0px 0px 0px 5px;\\\nborder-right: 0 none;\\\nright: 0;\\\n}\\\n.ace_search_form, .ace_replace_form {\\\nmargin: 0 20px 4px 0;\\\noverflow: hidden;\\\nline-height: 1.9;\\\n}\\\n.ace_replace_form {\\\nmargin-right: 0;\\\n}\\\n.ace_search_form.ace_nomatch {\\\noutline: 1px solid red;\\\n}\\\n.ace_search_field {\\\nborder-radius: 3px 0 0 3px;\\\nbackground-color: white;\\\ncolor: black;\\\nborder: 1px solid #cbcbcb;\\\nborder-right: 0 none;\\\nbox-sizing: border-box!important;\\\noutline: 0;\\\npadding: 0;\\\nfont-size: inherit;\\\nmargin: 0;\\\nline-height: inherit;\\\npadding: 0 6px;\\\nmin-width: 17em;\\\nvertical-align: top;\\\n}\\\n.ace_searchbtn {\\\nborder: 1px solid #cbcbcb;\\\nline-height: inherit;\\\ndisplay: inline-block;\\\npadding: 0 6px;\\\nbackground: #fff;\\\nborder-right: 0 none;\\\nborder-left: 1px solid #dcdcdc;\\\ncursor: pointer;\\\nmargin: 0;\\\nposition: relative;\\\nbox-sizing: content-box!important;\\\ncolor: #666;\\\n}\\\n.ace_searchbtn:last-child {\\\nborder-radius: 0 3px 3px 0;\\\nborder-right: 1px solid #cbcbcb;\\\n}\\\n.ace_searchbtn:disabled {\\\nbackground: none;\\\ncursor: default;\\\n}\\\n.ace_searchbtn:hover {\\\nbackground-color: #eef1f6;\\\n}\\\n.ace_searchbtn.prev, .ace_searchbtn.next {\\\npadding: 0px 0.7em\\\n}\\\n.ace_searchbtn.prev:after, .ace_searchbtn.next:after {\\\ncontent: \\\"\\\";\\\nborder: solid 2px #888;\\\nwidth: 0.5em;\\\nheight: 0.5em;\\\nborder-width:  2px 0 0 2px;\\\ndisplay:inline-block;\\\ntransform: rotate(-45deg);\\\n}\\\n.ace_searchbtn.next:after {\\\nborder-width: 0 2px 2px 0 ;\\\n}\\\n.ace_searchbtn_close {\\\nbackground: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;\\\nborder-radius: 50%;\\\nborder: 0 none;\\\ncolor: #656565;\\\ncursor: pointer;\\\nfont: 16px/16px Arial;\\\npadding: 0;\\\nheight: 14px;\\\nwidth: 14px;\\\ntop: 9px;\\\nright: 7px;\\\nposition: absolute;\\\n}\\\n.ace_searchbtn_close:hover {\\\nbackground-color: #656565;\\\nbackground-position: 50% 100%;\\\ncolor: white;\\\n}\\\n.ace_button {\\\nmargin-left: 2px;\\\ncursor: pointer;\\\n-webkit-user-select: none;\\\n-moz-user-select: none;\\\n-o-user-select: none;\\\n-ms-user-select: none;\\\nuser-select: none;\\\noverflow: hidden;\\\nopacity: 0.7;\\\nborder: 1px solid rgba(100,100,100,0.23);\\\npadding: 1px;\\\nbox-sizing:    border-box!important;\\\ncolor: black;\\\n}\\\n.ace_button:hover {\\\nbackground-color: #eee;\\\nopacity:1;\\\n}\\\n.ace_button:active {\\\nbackground-color: #ddd;\\\n}\\\n.ace_button.checked {\\\nborder-color: #3399ff;\\\nopacity:1;\\\n}\\\n.ace_search_options{\\\nmargin-bottom: 3px;\\\ntext-align: right;\\\n-webkit-user-select: none;\\\n-moz-user-select: none;\\\n-o-user-select: none;\\\n-ms-user-select: none;\\\nuser-select: none;\\\nclear: both;\\\n}\\\n.ace_search_counter {\\\nfloat: left;\\\nfont-family: arial;\\\npadding: 0 8px;\\\n}\";\n    var HashHandler = require(\"../keyboard/hash_handler\").HashHandler;\n    var keyUtil = require(\"../lib/keys\");\n\n    var MAX_COUNT = 999;\n\n    dom.importCssString(searchboxCss, \"ace_searchbox\");\n\n    var html = '<div class=\"ace_search right\">\\\n    <span action=\"hide\" class=\"ace_searchbtn_close\"></span>\\\n    <div class=\"ace_search_form\">\\\n        <input class=\"ace_search_field\" placeholder=\"Search for\" spellcheck=\"false\"></input>\\\n        <span action=\"findPrev\" class=\"ace_searchbtn prev\"></span>\\\n        <span action=\"findNext\" class=\"ace_searchbtn next\"></span>\\\n        <span action=\"findAll\" class=\"ace_searchbtn\" title=\"Alt-Enter\">All</span>\\\n    </div>\\\n    <div class=\"ace_replace_form\">\\\n        <input class=\"ace_search_field\" placeholder=\"Replace with\" spellcheck=\"false\"></input>\\\n        <span action=\"replaceAndFindNext\" class=\"ace_searchbtn\">Replace</span>\\\n        <span action=\"replaceAll\" class=\"ace_searchbtn\">All</span>\\\n    </div>\\\n    <div class=\"ace_search_options\">\\\n        <span action=\"toggleReplace\" class=\"ace_button\" title=\"Toggel Replace mode\"\\\n            style=\"float:left;margin-top:-2px;padding:0 5px;\">+</span>\\\n        <span class=\"ace_search_counter\"></span>\\\n        <span action=\"toggleRegexpMode\" class=\"ace_button\" title=\"RegExp Search\">.*</span>\\\n        <span action=\"toggleCaseSensitive\" class=\"ace_button\" title=\"CaseSensitive Search\">Aa</span>\\\n        <span action=\"toggleWholeWords\" class=\"ace_button\" title=\"Whole Word Search\">\\\\b</span>\\\n        <span action=\"searchInSelection\" class=\"ace_button\" title=\"Search In Selection\">S</span>\\\n    </div>\\\n</div>'.replace(/> +/g, \">\");\n\n    var SearchBox = function (editor, range?, showReplaceForm?) {\n      var div = dom.createElement(\"div\");\n      div.innerHTML = html;\n      this.element = div.firstChild;\n\n      this.setSession = this.setSession.bind(this);\n\n      this.$init();\n      this.setEditor(editor);\n    };\n\n    (function () {\n      this.setEditor = function (editor) {\n        editor.searchBox = this;\n        editor.renderer.scroller.appendChild(this.element);\n        this.editor = editor;\n      };\n\n      this.setSession = function (e) {\n        this.searchRange = null;\n        this.$syncOptions(true);\n      };\n\n      this.$initElements = function (sb) {\n        this.searchBox = sb.querySelector(\".ace_search_form\");\n        this.replaceBox = sb.querySelector(\".ace_replace_form\");\n        this.searchOption = sb.querySelector(\"[action=searchInSelection]\");\n        this.replaceOption = sb.querySelector(\"[action=toggleReplace]\");\n        this.regExpOption = sb.querySelector(\"[action=toggleRegexpMode]\");\n        this.caseSensitiveOption = sb.querySelector(\"[action=toggleCaseSensitive]\");\n        this.wholeWordOption = sb.querySelector(\"[action=toggleWholeWords]\");\n        this.searchInput = this.searchBox.querySelector(\".ace_search_field\");\n        this.replaceInput = this.replaceBox.querySelector(\".ace_search_field\");\n        this.searchCounter = sb.querySelector(\".ace_search_counter\");\n      };\n\n      this.$init = function () {\n        var sb = this.element;\n\n        this.$initElements(sb);\n\n        var _this = this;\n        event.addListener(sb, \"mousedown\", function (e) {\n          setTimeout(function () {\n            _this.activeInput.focus();\n          }, 0);\n          event.stopPropagation(e);\n        });\n        event.addListener(sb, \"click\", function (e) {\n          var t = e.target || e.srcElement;\n          var action = t.getAttribute(\"action\");\n          if (action && _this[action])\n            _this[action]();\n          else if (_this.$searchBarKb.commands[action])\n            _this.$searchBarKb.commands[action].exec(_this);\n          event.stopPropagation(e);\n        });\n\n        event.addCommandKeyListener(sb, function (e, hashId, keyCode) {\n          var keyString = keyUtil.keyCodeToString(keyCode);\n          var command = _this.$searchBarKb.findKeyCommand(hashId, keyString);\n          if (command && command.exec) {\n            command.exec(_this);\n            event.stopEvent(e);\n          }\n        });\n\n        this.$onChange = lang.delayedCall(function () {\n          _this.find(false, false);\n        });\n\n        event.addListener(this.searchInput, \"input\", function () {\n          _this.$onChange.schedule(20);\n        });\n        event.addListener(this.searchInput, \"focus\", function () {\n          _this.activeInput = _this.searchInput;\n          _this.searchInput.value && _this.highlight();\n        });\n        event.addListener(this.replaceInput, \"focus\", function () {\n          _this.activeInput = _this.replaceInput;\n          _this.searchInput.value && _this.highlight();\n        });\n      };\n      this.$closeSearchBarKb = new HashHandler([{\n        bindKey: \"Esc\",\n        name: \"closeSearchBar\",\n        exec: function (editor) {\n          editor.searchBox.hide();\n        }\n      }]);\n      this.$searchBarKb = new HashHandler();\n      this.$searchBarKb.bindKeys({\n        \"Ctrl-f|Command-f\": function (sb) {\n          var isReplace = sb.isReplace = !sb.isReplace;\n          sb.replaceBox.style.display = isReplace ? \"\" : \"none\";\n          sb.replaceOption.checked = isReplace;\n          sb.$syncOptions();\n          sb.searchInput.focus();\n        },\n        \"Ctrl-H|Command-Option-F\": function (sb) {\n          sb.replaceOption.checked = true;\n          sb.$syncOptions();\n          sb.replaceInput.focus();\n        },\n        \"Ctrl-G|Command-G\": function (sb) {\n          sb.findNext();\n        },\n        \"Ctrl-Shift-G|Command-Shift-G\": function (sb) {\n          sb.findPrev();\n        },\n        \"esc\": function (sb) {\n          setTimeout(function () {sb.hide();});\n        },\n        \"Return\": function (sb) {\n          if (sb.activeInput == sb.replaceInput)\n            sb.replace();\n          sb.findNext();\n        },\n        \"Shift-Return\": function (sb) {\n          if (sb.activeInput == sb.replaceInput)\n            sb.replace();\n          sb.findPrev();\n        },\n        \"Alt-Return\": function (sb) {\n          if (sb.activeInput == sb.replaceInput)\n            sb.replaceAll();\n          sb.findAll();\n        },\n        \"Tab\": function (sb) {\n          (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus();\n        }\n      });\n\n      this.$searchBarKb.addCommands([{\n        name: \"toggleRegexpMode\",\n        bindKey: {win: \"Alt-R|Alt-/\", mac: \"Ctrl-Alt-R|Ctrl-Alt-/\"},\n        exec: function (sb) {\n          sb.regExpOption.checked = !sb.regExpOption.checked;\n          sb.$syncOptions();\n        }\n      }, {\n        name: \"toggleCaseSensitive\",\n        bindKey: {win: \"Alt-C|Alt-I\", mac: \"Ctrl-Alt-R|Ctrl-Alt-I\"},\n        exec: function (sb) {\n          sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked;\n          sb.$syncOptions();\n        }\n      }, {\n        name: \"toggleWholeWords\",\n        bindKey: {win: \"Alt-B|Alt-W\", mac: \"Ctrl-Alt-B|Ctrl-Alt-W\"},\n        exec: function (sb) {\n          sb.wholeWordOption.checked = !sb.wholeWordOption.checked;\n          sb.$syncOptions();\n        }\n      }, {\n        name: \"toggleReplace\",\n        exec: function (sb) {\n          sb.replaceOption.checked = !sb.replaceOption.checked;\n          sb.$syncOptions();\n        }\n      }, {\n        name: \"searchInSelection\",\n        exec: function (sb) {\n          sb.searchOption.checked = !sb.searchRange;\n          sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange());\n          sb.$syncOptions();\n        }\n      }]);\n\n      this.setSearchRange = function (range) {\n        this.searchRange = range;\n        if (range) {\n          this.searchRangeMarker = this.editor.session.addMarker(range, \"ace_active-line\");\n        } else if (this.searchRangeMarker) {\n          this.editor.session.removeMarker(this.searchRangeMarker);\n          this.searchRangeMarker = null;\n        }\n      };\n\n      this.$syncOptions = function (preventScroll) {\n        // dom.setCssClass(this.replaceOption, \"checked\", this.searchRange);\n        dom.setCssClass(this.searchOption, \"checked\", this.searchOption.checked);\n        this.replaceOption.textContent = this.replaceOption.checked ? \"-\" : \"+\";\n        dom.setCssClass(this.regExpOption, \"checked\", this.regExpOption.checked);\n        dom.setCssClass(this.wholeWordOption, \"checked\", this.wholeWordOption.checked);\n        dom.setCssClass(this.caseSensitiveOption, \"checked\", this.caseSensitiveOption.checked);\n        this.replaceBox.style.display = this.replaceOption.checked ? \"\" : \"none\";\n        this.find(false, false, preventScroll);\n      };\n\n      this.highlight = function (re) {\n        this.editor.session.highlight(re || this.editor.$search.$options.re);\n        this.editor.renderer.updateBackMarkers();\n      };\n      this.find = function (skipCurrent, backwards, preventScroll) {\n        var range = this.editor.find(this.searchInput.value, {\n          skipCurrent: skipCurrent,\n          backwards: backwards,\n          wrap: true,\n          regExp: this.regExpOption.checked,\n          caseSensitive: this.caseSensitiveOption.checked,\n          wholeWord: this.wholeWordOption.checked,\n          preventScroll: preventScroll,\n          range: this.searchRange\n        });\n        var noMatch = !range && this.searchInput.value;\n        dom.setCssClass(this.searchBox, \"ace_nomatch\", noMatch);\n        this.editor._emit(\"findSearchBox\", {match: !noMatch});\n        this.highlight();\n        this.updateCounter();\n      };\n      this.updateCounter = function () {\n        var editor = this.editor;\n        var regex = editor.$search.$options.re;\n        var all = 0;\n        var before = 0;\n        if (regex) {\n          var value = this.searchRange\n            ? editor.session.getTextRange(this.searchRange)\n            : editor.getValue();\n\n          var offset = editor.session.doc.positionToIndex(editor.selection.anchor);\n          if (this.searchRange)\n            offset -= editor.session.doc.positionToIndex(this.searchRange.start);\n\n          var last = regex.lastIndex = 0;\n          var m;\n          while ((m = regex.exec(value))) {\n            all++;\n            last = m.index;\n            if (last <= offset)\n              before++;\n            if (all > MAX_COUNT)\n              break;\n            if (!m[0]) {\n              regex.lastIndex = last += 1;\n              if (last >= value.length)\n                break;\n            }\n          }\n        }\n        this.searchCounter.textContent = before + \" of \" + (all > MAX_COUNT ? MAX_COUNT + \"+\" : all);\n      };\n      this.findNext = function () {\n        this.find(true, false);\n      };\n      this.findPrev = function () {\n        this.find(true, true);\n      };\n      this.findAll = function () {\n        var range = this.editor.findAll(this.searchInput.value, {\n          regExp: this.regExpOption.checked,\n          caseSensitive: this.caseSensitiveOption.checked,\n          wholeWord: this.wholeWordOption.checked\n        });\n        var noMatch = !range && this.searchInput.value;\n        dom.setCssClass(this.searchBox, \"ace_nomatch\", noMatch);\n        this.editor._emit(\"findSearchBox\", {match: !noMatch});\n        this.highlight();\n        this.hide();\n      };\n      this.replace = function () {\n        if (!this.editor.getReadOnly())\n          this.editor.replace(this.replaceInput.value);\n      };\n      this.replaceAndFindNext = function () {\n        if (!this.editor.getReadOnly()) {\n          this.editor.replace(this.replaceInput.value);\n          this.findNext();\n        }\n      };\n      this.replaceAll = function () {\n        if (!this.editor.getReadOnly())\n          this.editor.replaceAll(this.replaceInput.value);\n      };\n\n      this.hide = function () {\n        this.isReplace = false;\n        this.active = false;\n        this.setSearchRange(null);\n        this.editor.off(\"changeSession\", this.setSession);\n\n        this.element.style.display = \"none\";\n        this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb);\n        this.editor.focus();\n      };\n      this.show = function (value, isReplace) {\n        this.active = true;\n        this.editor.on(\"changeSession\", this.setSession);\n        this.element.style.display = \"\";\n\n        this.replaceOption.checked = isReplace;\n\n        if (value)\n          this.searchInput.value = value;\n\n        this.searchInput.focus();\n        this.searchInput.select();\n\n        this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);\n\n        this.$syncOptions(true);\n      };\n\n      this.isFocused = function () {\n        var el = document.activeElement;\n        return el == this.searchInput || el == this.replaceInput;\n      };\n    }).call(SearchBox.prototype);\n\n    exports.SearchBox = SearchBox;\n\n    exports.Search = function (editor, isReplace) {\n      var sb = editor.searchBox || new SearchBox(editor);\n      sb.show(editor.session.getTextRange(), isReplace);\n    };\n\n  });\n  (function () {\n    ace.acequire([\"ace/ext/searchbox\"], function () {});\n  })();\n\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/bootstrap.ts",
    "content": "import angular from 'angular';\nimport 'jquery-ui/ui/widgets/sortable';\nimport 'angular-ui-sortable';\n\nimport ace from 'brace';\n\nimport {setupAce} from './ace-extensions';\nsetupAce(ace);\n\nimport 'brace/theme/tomorrow';\nimport '../core';\nimport '../ui';\n\nexport default angular.module('bi.codeEditor', ['bi.core', 'bi.ui', 'ui.sortable']);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/directives/code-editor.html",
    "content": "<div class=\"bce-container bi-r-h bi-grow\">\n  <div\n    class=\"bce-params bi-c-h bi-fade-in\"\n    ng-class=\"{'bce-params--closed': !vm.params.visible}\"\n    ng-if=\"::options.params && (!readonly || vm.params.all.length)\"\n  >\n    <div class=\"bce-params-inner bi-c-h bi-s-v--x15 bi-fade-in\" ng-show=\"vm.params.visible\">\n      <bi-editable ng-model=\"vm.param.model\" on-change=\"events.onParamAdd()\" be-options=\"::{saveText: 'Add'}\">\n        <div class=\"bi-spread\">\n          <i \n            class=\"bi-action bi-icon\"\n            ng-if=\"!be.edit\"\n            ng-click=\"events.onParamsToggle()\"\n          >menu</i>\n\n          <div class=\"bi-center\" ng-show=\"::!readonly\" be-controls>\n            <div class=\"bi-r bi-s-h--x05\">\n              <button class=\"bce-custom-param-toggle bi-button bi-button--sm bi-align\">\n                <i class=\"bi-icon--sm\">add</i>\n                <span>Custom param</span>\n              </button>\n\n              <button class=\"bce-auto-param-toggle bi-button bi-button--sm bi-align\">\n                <i class=\"bi-icon--sm\">add</i>\n                <span>Auto param</span>\n              </button>\n            </div>\n          </div>\n\n          <div class=\"bi-align bi-s-h--x15\">\n            <bi-tooltip ng-if=\"options.shareParams && !be.edit && vm.params.all.length\" bt-text=\"Share with parameters\">\n              <bi-toggle>\n                <i class=\"bi-action bi-icon--sm\" ng-click=\"events.onShareClick()\">share</i>\n              </bi-toggle>\n            </bi-tooltip>\n          </div>\n        </div>\n\n        <div class=\"bi-c bi-s-v--x05\" ng-if=\"be.edit\">\n          <div class=\"bi-form--vertical bi-fade-in\" ng-if=\"vm.param.current === 'custom'\">\n            <div class=\"bi-form-row\">\n              <div class=\"bi-form-label--required\">Name</div>\n              <input\n                class=\"bi-form-input bi-input\"\n                ng-model=\"be.value.key\"\n                ng-pattern=\"/^[a-zA-Z_]+$/\"\n                placeholder=\"Enter name\"\n                required=\"true\"\n                bi-focus\n              >\n            </div>\n\n            <div class=\"bi-form-row\">\n              <div class=\"bi-form-label--required\">Type</div>\n              <bi-simple-select\n                class=\"bi-form-input\"\n                bi-options=\"type for type in ::vm.param.types\"\n                ng-model=\"be.value.type\"\n              ></bi-simple-select>\n            </div>\n\n            <div class=\"bi-form-row\" ng-if=\"be.value.type === 'option' || be.value.type === 'list'\" >\n              <div class=\"bi-form-label\">Options</div>\n              <input class=\"bi-input\" ng-list ng-model=\"be.value.options\" placeholder=\"Custom param options\">\n            </div>\n          </div>\n\n          <div class=\"bce-auto-param-list bi-form--vertical bi-fade-in\" ng-if=\"vm.param.current === 'auto'\">\n            <div class=\"bi-form-row\">\n              <div class=\"bi-form-label\">Select an auto param</div>\n              <ul class=\"bi-form-input bi-dropdown-menu\">\n                <li ng-repeat=\"param in ::vm.param.autoParams\" ng-click=\"be.value.key = param; be.save();\">\n                  {{::param}}\n                </li>\n              </ul>\n            </div>\n          </div>\n        </div>\n      </bi-editable>\n\n      <div class=\"bi-border--top\" ng-if=\"vm.params.all.length\"></div>\n\n      <div class=\"bce-params-list bi-grow bi-scroll\">\n        <div\n          class=\"bce-params-list-inner bi-form--vertical bi-s-v--x2\"\n          ui-sortable=\"::{\n            axis: 'y',\n            handle: '.bce-param-handle',\n            opacity: '0.8',\n            update: events.onParamChange,\n            disabled: readonly,\n          }\"\n          ng-model=\"vm.params.all\"\n        >\n          <div class=\"bi-form-row bi-dont-shrink\" ng-repeat=\"param in vm.params.all\">\n            <div class=\"bi-spread bi-hover-parent\">\n              <i class=\"bce-param-handle bi-action bi-icon--sm bi-hover-target\" ng-if=\"!readonly\">drag_indicator</i>\n\n              <div class=\"bi-grow\">\n                <div class=\"bi-form-label bi-spread\">\n                  <span class=\"bi-text--600\">{{::param.key}}</span>\n                  <span class=\"bi-text--sm bi-muted\">{{::param.type}}</span>\n                </div>\n\n                <div class=\"bi-form-input bi-r\" bi-html=\"renderParam(param)\"></div>\n              </div>\n\n              <i \n                class=\"bce-param-remove bi-action bi-icon--sm bi-danger bi-hover-target\"\n                ng-if=\"::!readonly\"\n                ng-click=\"events.onParamRemove(param)\"\n              >close</i>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <div class=\"bce-params-inner\" ng-if=\"!vm.params.visible\">\n      <i class=\"bi-action bi-icon\" ng-click=\"events.onParamsToggle()\">menu</i>\n    </div>\n  </div>\n\n  <div class=\"bce-editor-wrapper bi-c-h bi-grow\">\n    <div class=\"bce-editor-container bi-grow\"></div>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/directives/code-editor.scss",
    "content": "@import '../../ui/assets/css/def/defaults.def';\n@import '../../ui/assets/css/def/colors.def';\n@import '../../ui/assets/css/def/flex.def';\n@import '../../ui/assets/css/def/space.def';\n\nbi-code-editor {\n  display: flex;\n\n  .bce-params-list {\n    padding-bottom: 60px;\n\n    .bce-params-list-inner {\n      &.bi-form--vertical {\n        .bi-form-row {\n          .bi-form-input {\n            margin-top: 3px;\n          }\n\n          .bce-param-handle,\n          .bce-param-remove {\n            padding: 0;\n\n            &:hover {\n              background: none;\n            }\n          }\n\n          .bce-param-handle {\n            margin: 19px 1px 0 -5px;\n          }\n\n          .bce-param-remove {\n            margin: 20px 1px 0 4px;\n          }\n        }\n      }\n    }\n  }\n\n  .bce-params {\n    position: relative;\n    min-width: 300px;\n    max-width: 300px;\n\n    .bce-params-inner {\n      margin-right: 15px;\n    }\n\n    .bce-auto-param-list {\n      .bi-dropdown-menu {\n        box-shadow: none;\n      }\n    }\n\n    &.bce-params--closed {\n      min-width: 0;\n    }\n  }\n\n  &.bce-narrow {\n    .bce-container {\n      @include flex(column);\n      @include space-v__inner();\n\n      .bce-params {\n        padding-bottom: $default-space;\n        border-right: 0;\n        border-bottom: 1px solid $grey--300;\n\n        .bce-params-inner {\n          @include flex(column);\n          @include space-v__inner();\n\n          max-height: 300px;\n          padding-left: 0;\n        }\n      }\n    }\n  }\n\n  .bce-container {\n    .bce-editor-wrapper {\n      transition: border-color, .3s;\n      border-left: 3px solid $grey--200;\n\n      &.bce-valid {\n        border-color: lighten($success, 12);\n      }\n\n      &.bce-invalid {\n        border-color: lighten($danger, 12);\n      }\n    }\n\n    .bce-editor-container {\n      height: 400px;\n\n      &.bce-readonly {\n        background-color: $grey--50;\n\n        .ace_cursor {\n          display: none;\n        }\n      }\n\n      .ace_gutter {\n        background-color: transparent !important;\n\n        .ace_gutter-layer {\n          width: auto;\n          min-width: 26px;\n        }\n\n        .ace_gutter-cell {\n          padding: 0 13px 0 5px;\n          color: lighten($muted, 5);\n        }\n\n        .ace_gutter-active-line {\n          background-color: transparent !important;\n        }\n      }\n\n      .ace_marker-layer {\n        .ace_active-line {\n          background-color: $grey--100 !important;\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/directives/code-editor.ts",
    "content": "import template from './code-editor.html';\nimport './code-editor.scss';\n\nimport {uniq} from 'lodash';\nimport jquery from 'jquery';\nimport {IScope} from 'angular';\nimport {utils, createNgModel, initNgScope, inject} from '../../core';\nimport CodeEditor from '../services/code-editor-service';\nimport Instance from '../services/code-editor-instance';\nimport {IParam, ParamParser} from '../services/param-parser';\nimport {renderParam} from '../services/param-parser/param-renderers';\n\nconst {safeApply} = utils.scope;\n\nfunction initEditor(scope, element, container, text) {\n  const editor = new CodeEditor(scope, container, text, scope.options);\n\n  editor\n    .on('change', value => !scope.readonly && safeApply(scope, () => scope.model = value))\n    .on('validToggle', valid => {\n      container.parent().removeClass('bce-valid bce-invalid');\n      container.parent().addClass({true: 'bce-valid', false: 'bce-invalid'}[valid]);\n    })\n    .on('resize', () => element.toggleClass('bce-narrow', element.width() < 1000));\n\n  scope.$watch('readonly', (readonly = false) =>  {\n    editor.setReadonly(readonly);\n    container.toggleClass('bce-readonly', readonly);\n  });\n\n  editor.getShortcuts().addShortcut('Ctrl-S', 'Command-S', () => scope.onSave(), scope);\n\n  return editor;\n}\n\nfunction exportParams(editor: CodeEditor) {\n  const params = editor.getParams();\n  const serializer = params.getParser().getSerializer();\n\n  return params.getParams().reduce((res, {key, value}) => {\n    res[`var_${key}`] = serializer.toString(value);\n    return res;\n  }, {});\n}\n\nfunction importParams(editor: CodeEditor, urlImports) {\n  const params = editor.getParams();\n  const serializer = params.getParser().getSerializer();\n\n  params.getParams().forEach(({key, value, type}) => {\n    const urlParam = urlImports[`var_${key}`];\n\n    if (typeof urlParam === 'undefined') {\n      return;\n    }\n\n    params.overrideParam(key, {value: serializer.toJs(urlParam, type) || null});\n  });\n}\n\nfunction render(scope, element, text, editor: CodeEditor, urlImports): CodeEditor {\n  if (!editor) {\n    editor = initEditor(scope, element, element.find('.bce-editor-container'), text);\n\n    if (editor.getParams().hasParams()) {\n      importParams(editor, urlImports);\n    } else {\n      scope.vm.params.toggleVisible(false);\n    }\n\n    scope.vm.param.types = ParamParser.TYPES;\n    scope.vm.param.autoParams = ParamParser.AUTO_PARAMS;\n  } else {\n    editor.setValue(text);\n  }\n\n  return editor;\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    require: 'ngModel',\n    scope: {\n      onSave: '&',\n      onLoad: '&',\n      onParamsShare: '&',\n      readonly: '=',\n      bceOptions: '<'\n    },\n\n    link: {\n      pre (scope: IScope & {model: string}, element, attrs, ngModel) {\n        let editor: CodeEditor;\n        let urlImports = {};\n\n        createNgModel(scope, ngModel)\n          .renderWith(text => editor = render(scope, element, text, editor, urlImports))\n          .then(() => {\n            scope.onLoad({instance: new Instance(editor, scope)});\n          });\n\n        initNgScope(scope)\n          .withOptions('bceOptions', {\n            ace: {},\n            focus: false,\n            params: false,\n            customParams: true,\n            fitContent: false,\n            shareParams: false,\n            dateFormat: null,\n          })\n          .withVM({\n            param: {\n              types: [],\n              kinds: ['auto', 'custom'],\n              current: null,\n              $init() {\n                this.init();\n              },\n              init() {\n                this.model = {\n                  key: '',\n                  type: (this.model && this.model.type) || 'string',\n                  options: undefined\n                };\n              }\n            },\n            params: {\n              visible: true,\n              $init() {\n                Object.defineProperty(this, 'all', {\n                  get() {\n                    return editor && editor.getParams().getParams();\n                  }\n                });\n              },\n              $export(provider) {\n                if (provider === 'url') {\n                  return exportParams(editor);\n                } \n                  return {paramsOpen: this.visible};\n                \n              },\n              $import(obj) {\n                urlImports = obj;\n\n                if (typeof obj.paramsOpen === 'boolean') {\n                  this.toggleVisible(obj.paramsOpen);\n                }\n              }\n            }\n          })\n          .withEvents({\n            onParamChange() {\n              inject('$timeout')(() => editor.getParams().syncParams());\n            },\n            onParamsToggle() {\n              scope.vm.params.toggleVisible();\n              scope.state.save();\n            },\n            onParamAdd() {\n              const {key, type, options} = scope.vm.param.model;\n\n              editor.getParams().addParam(key, type, undefined, uniq(options));\n              scope.vm.param.init();\n            },\n            onParamRemove({key}) {\n              editor.getParams().removeParam(key);\n            },\n            onShareClick() {\n              scope.onParamsShare({params: scope.state.state.exportAsURL('url')});\n            }\n          })\n          .withState('bce', 'bce', {});\n\n        scope.renderParam = (param: IParam) => ({\n          html: renderParam(scope, param, {dateFormat: scope.options.dateFormat}, editor.getParams().getParamOverrides(param.key))\n        });\n\n        if (!scope.options.customParams) {\n          inject('$timeout')(() => element.find('.bce-custom-param-toggle').remove());\n        }\n\n        // this is needed because angular directives dont work inside be-controls\n        element.on('mousedown', '.bce-custom-param-toggle, .bce-auto-param-toggle', (e) => {\n          const target = jquery(e.currentTarget);\n\n          utils.scope.safeApply(scope, () => {\n            scope.vm.param.current = target.is('.bce-custom-param-toggle') ? 'custom' : 'auto';\n          });\n        });\n\n        scope.$on('$destroy', () => editor.destroy());\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/directives/index.ts",
    "content": "export {default as codeEditor} from './code-editor';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/index.ts",
    "content": "import ngApp from './bootstrap';\nimport init from './init';\n\nexport {default as CodeEditorInstance} from './services/code-editor-instance';\nexport {paramParserFactory} from './services/param-parser';\nexport {paramSerializerFactory} from './services/param-parser/param-serializers';\n\ninit(ngApp);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/init.ts",
    "content": "import {forEach} from 'lodash';\nimport * as directives from './directives';\n\nfunction toDirectiveName(name: string) {\n  return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`;\n}\n\nexport default function init(ngApp: angular.IModule) {\n  forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any));\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-annotator.ts",
    "content": "export default class CodeEditorAnnotator {\n  constructor (private readonly ace) {\n\n  }\n\n  showError(row: number, message: string) {\n    this.ace.getSession().setAnnotations([{\n      row: row - 1,\n      column: 0,\n      text: message,\n      type: 'error'\n    }]);\n  }\n\n  hideAll() {\n    this.ace.getSession().clearAnnotations();\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-completer.ts",
    "content": "import { find, isFunction, escapeRegExp } from 'lodash';\nimport { Editor, IEditSession } from 'brace';\n\nexport type ICompleterFn = (prefix: string, session?: IEditSession) => ng.IPromise<ICompleterItem[]> | ICompleterItem[];\nconst isPromise = <T>(maybePromise: T | ng.IPromise<T>): maybePromise is ng.IPromise<T> =>\n  (maybePromise as any).then && isFunction(((maybePromise as any).then));\n\nexport interface ICompleterItem {\n  value: string;\n  meta: string;\n  caption?: string;\n  matchMask?: number[];\n  score?: number\n}\n\nexport interface IAceCompleter {\n  identifierRegexps: RegExp[];\n  getCompletions(editor, session: IEditSession, pos, prefix: string, callback): void;\n  linePredicate?(line: string): boolean; /* do another check on the line that isn't (necessarily) regex based */\n  acceptEmptyString?: boolean;\n  prefix?: string; /* for live completion */\n}\n\nfunction createCompleter(fn: ICompleterFn, prefixRegex: RegExp,\n  options: {prefix?: string; acceptEmptyString?: boolean; linePredicate?: any } = {}): IAceCompleter {\n\n  return {\n    identifierRegexps: [prefixRegex],\n    getCompletions(editor, session: IEditSession, pos, prefix: string, callback) {\n      const completions = fn(prefix, session);\n\n      if (!completions) {\n        return;\n      }\n\n      if (isPromise(completions)) {\n        completions.then(c => callback(null, c));\n      } else {\n        callback(null, completions);\n      }\n    },\n    ...options\n  };\n}\n\nfunction createLiveCompleter(prefix: string, fn: ICompleterFn) {\n  const regex = new RegExp(escapeRegExp(prefix));\n  const completer = createCompleter(_prefix => _prefix === prefix && fn(prefix), regex, {prefix});\n\n  return completer;\n}\n\nexport default class CodeEditorCompleter {\n  private readonly completers = [];\n\n  constructor(ace: Editor) {\n    ace.setOptions({\n      enableBasicAutocompletion: this.completers,\n      enableSnippets: false,\n      enableLiveAutocompletion: false\n    });\n    \n    ace.getSession().on('change', e => {\n      if (e.action === 'insert' && find(this.completers, {prefix: e.lines[0]})) {\n        setTimeout(() => ace.commands.byName.startAutocomplete.exec(ace), 0);\n      }\n    });\n  }\n\n  addLiveCompleter(prefix: string, fn: ICompleterFn) {\n    this.completers.push(createLiveCompleter(prefix, fn));\n  }\n\n  addOnDemandCompleter(identifierRegex: RegExp, fn: ICompleterFn, options?) {\n    this.completers.push(createCompleter(fn, identifierRegex, options));\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-instance.ts",
    "content": "import {utils, srv} from '../../core';\nimport CodeEditor from './code-editor-service';\nimport {ICompleterFn} from './code-editor-completer';\nimport {default as Annotator} from './code-editor-annotator';\nimport {default as Selection} from './code-editor-selection';\nimport {default as Params} from './code-editor-params';\n\nconst {safeApply} = utils.scope;\n\nexport default class CodeEditorInstance extends srv.eventEmitter.EventEmitter {\n  constructor(private readonly editor: CodeEditor, scope) {\n    super();\n\n    editor.getSelection()\n      .on('select', text => safeApply(scope, () => this.fire('select', text)))\n      .on('deselect', () => safeApply(scope, () => this.fire('deselect')));\n  }\n\n  setValid(valid: boolean): CodeEditorInstance {\n    this.editor.setValid(valid);\n\n    return this;\n  }\n\n  addLiveCompleter(prefix: string, fn: ICompleterFn): CodeEditorInstance {\n    this.editor.getCompleter().addLiveCompleter(prefix, fn);\n\n    return this;\n  }\n\n  addOnDemandCompleter(identifierRegex: RegExp, fn: ICompleterFn, options?: {prefix?: string; acceptEmptyString?: boolean; linePredicate?: any }): CodeEditorInstance {\n    this.editor.getCompleter().addOnDemandCompleter(identifierRegex, fn, options);\n    return this;\n  }\n\n  setLiveAutocompletion(value: boolean) {\n    this.editor.setLiveAutocompletion(value);\n    \n    return this;\n  }\n\n  addShortcut(winShortcut: string, macShortcut: string, fn: Function, scope): CodeEditorInstance {\n    this.editor.getShortcuts().addShortcut(winShortcut, macShortcut, fn, scope);\n\n    return this;\n  }\n\n  getAnnotator(): Annotator {\n    return this.editor.getAnnotator();\n  }\n\n  getSelection(): Selection {\n    return this.editor.getSelection();\n  }\n\n  getParams(): Params {\n    return this.editor.getParams();\n  }\n\n  getLockedRange() {\n    return this.editor.getLockedRange();\n  }\n\n  resize(): CodeEditorInstance {\n    this.editor.resize();\n\n    return this;\n  }\n\n  focus(): CodeEditorInstance {\n    this.editor.focus();\n\n    return this;\n  }\n\n  getValue() {\n    return this.editor.getValue();\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-params.ts",
    "content": "import {debounce, pull, find, clone, flatten, last} from 'lodash';\nimport {utils} from '../../core';\nimport {UndoManager} from 'brace';\nimport {ParamParser, TType, IParam} from './param-parser';\nimport {paramSerializerFactory} from './param-parser/param-serializers';\nimport CodeEditor from './code-editor-service';\nimport { AUTO_PARAM_TYPES, AUTO_PARAM_DEFAULTS } from './param-parser/param-types';\n\nexport default class CodeEditorParams {\n  private params: IParam[] = [];\n  private readonly parser: ParamParser;\n  private mute = false;\n  private folded = false;\n  private readonly paramOverrides: {[key: string]: Partial<IParam>} = {};\n  private readonly parserOptions: {customParamsEnabled: boolean};\n\n  constructor(private readonly editor: CodeEditor, private readonly ace, private readonly options, private readonly scope) {\n    const type = last(`${options.ace.mode}`.split('/'));\n    this.parser = new ParamParser(paramSerializerFactory(type));\n\n    if (!options.params) {\n      return;\n    }\n\n    this.parserOptions = {customParamsEnabled: this.options.customParams};\n\n    this.init(scope);\n  }\n\n  private init(scope) {\n    this.params = this.parser.params(this.editor.getValue(), this.parserOptions);\n    this.syncParams();\n    this.ace.getSession().setUndoManager(new UndoManager());  // reset undo stack\n    this.mute = false;\n\n    this.editor.on('change', debounce((value, {isInLockRange, isMultilineInsert}) => {\n      if (this.mute) {\n        this.mute = false;\n        return;\n      }\n\n      if (isInLockRange || isMultilineInsert) {\n        utils.scope.safeApply(scope, () => {\n          this.params = this.parser.params(value, this.parserOptions, this.getParams());\n          this.setLock(this.getParser().getSerializer().getLockRange(value));\n        });\n      }\n    }, 100));\n  }\n\n  private replace(text, needle, replacement): string {\n    if (needle === replacement) {\n      return text;\n    }\n\n    this.mute = true;\n\n    if (text === '') {\n      this.editor.setValue(replacement);\n    } else {\n      this.ace.replaceAll(replacement, {needle});\n    }\n\n    return this.editor.getValue();\n  }\n\n  private setLock(ranges: [number, number][]) {\n    this.editor.unlockLines();\n\n    if (this.hasParams()) {\n      this.editor.lockLines(ranges);\n    }\n  }\n\n  private setFold(ranges: [number, number][]) {\n    if (!this.hasParams()) {\n      return;\n    }\n\n    let foldRange = flatten(ranges);\n    foldRange = [foldRange[0], foldRange[foldRange.length - 1]];\n\n    if (!this.folded) {\n      this.folded = true;\n      setTimeout(() => this.ace.getSession().foldAll(...foldRange));\n    } else {\n      this.ace.getSession().foldAll(...foldRange);\n    }\n  }\n\n  getParser(): ParamParser {\n    return this.parser;\n  }\n\n  getParams(): IParam[] {\n    return this.params;\n  }\n\n  hasParams(): boolean {\n    return !!this.getParams().length;\n  }\n\n  addParam(key: string, type: TType, value, options?: string[]): CodeEditorParams {\n    if (!find(this.getParams(), {key})) {\n      this.getParams().push(this.parser.createParam(key, type, value, options));\n      this.syncParams();\n    }\n\n    return this;\n  }\n\n  addAutoParam(key: string): CodeEditorParams {\n    this.addParam(key, AUTO_PARAM_TYPES[key], AUTO_PARAM_DEFAULTS[key]);\n\n    return this;\n  }\n\n  removeParam(key: string): CodeEditorParams {\n    pull(this.getParams(), find(this.getParams(), {key}));\n    this.syncParams();\n\n    return this;\n  }\n\n  removeAllParams(): CodeEditorParams {\n    this.params = [];\n    this.syncParams();\n\n    return this;\n  }\n\n  getParamOverrides(key: string) {\n    return this.paramOverrides[key];\n  }\n\n  overrideParam(key: string, param: Partial<IParam>): CodeEditorParams {\n    this.paramOverrides[key] = param;\n\n    if (typeof param.value !== 'undefined') {\n      const p = find(this.params, {key});\n      p.value = param.value;\n    }\n\n    // trigger watchers\n    utils.scope.safeApply(this.scope, () => {\n      this.params = this.params.map((p: any) => {\n        delete p.$$hashKey;\n        return clone(p);\n      });\n    });\n\n    return this;\n  }\n\n  /**\n   * Sync params array to editor\n   */\n  syncParams() {\n    const ranges = this.parser.sync(this.editor.getValue(), this.getParams(), this.parserOptions, (text, needle, replacement) => {\n      return this.replace(text, needle, replacement);\n    });\n\n    this.setLock(ranges);\n    this.setFold(ranges);\n\n    return ranges;\n  }\n\n  /**\n   * Replaces params in text with their respective values\n   */\n  format(text?: string): string {\n    return this.parser.format(typeof text !== 'undefined' ? text : this.editor.getValue(), this.getParams(), {\n      customParamsEnabled: this.options.customParams,\n      keepEmbed: false\n    });\n  }\n\n  formatEmbed(options?): string {\n    const embed = this.getParser().getSerializer().extract(this.editor.getValue(), options);\n\n    return this.parser.format(embed, this.getParams(), {\n      customParamsEnabled: this.options.customParams,\n      keepEmbed: true\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-selection.ts",
    "content": "import {throttle} from 'lodash';\nimport {srv, utils} from '../../core';\n\nexport default class CodeEditorSelection extends srv.eventEmitter.EventEmitter {\n  private range;\n\n  constructor (private readonly ace, scope) {\n    super();\n\n    const self = this;\n    const selectionEvents = {\n      onSelection: throttle(text => utils.scope.safeApply(scope, () => self.fire('select', text)), 200),\n      onDeselection: () => utils.scope.safeApply(scope, () => self.fire('deselect'))\n    };\n\n    ace.getSession().getSelection().on('changeSelection', (e, selection) => {\n      const range = selection.getRange();\n      const selectedText = ace.getSession().getDocument().getTextRange(selection.getRange()).trim();\n\n      if (selectedText && selectedText.split(/\\s|\\n/, 2).length >= 2) {\n        selectionEvents.onSelection(selectedText);\n        this.range = range;\n      } else {\n        selectionEvents.onDeselection();\n        this.range = null;\n      }\n    });\n  }\n\n  getRange() {\n    return this.range;\n  }\n\n  clearSelection() {\n    this.ace.getSelection().clearSelection();\n    this.fire('deselect');\n  }\n\n  getOffset() {\n    return (this.range && this.range.start.row) || 0;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-service.ts",
    "content": "import { flatten, last } from 'lodash';\nimport ace from 'brace';\nimport { srv, inject } from '../../core';\nimport { default as Completer } from './code-editor-completer';\nimport { default as Annotator } from './code-editor-annotator';\nimport { default as Selection } from './code-editor-selection';\nimport { default as Shortcuts } from './code-editor-shortcuts';\nimport { default as Params } from './code-editor-params';\n\ndeclare const ResizeObserver;\n\nexport interface AceEditorOptions {\n  mode?: string;\n  theme?: string;\n  enableMultiselect?: boolean;\n  showGutter?: boolean;\n  highlightActiveLine?: boolean;\n  focus?: boolean;\n}\n\nexport interface CodeEditorOptions {\n  ace?: AceEditorOptions;\n  focus?: boolean;\n  fitContent?: boolean;\n}\n\nconst aceDefaults = {\n  mode: 'ace/mode/presto',\n  theme: 'ace/theme/tomorrow',\n  enableMultiselect: false,\n  highlightActiveLine: true,\n  showGutter: true\n};\nfunction getHeight(_ace) {\n  // tslint:disable-next-line: restrict-plus-operands\n  return _ace.getSession().getScreenLength() * 16 + _ace.renderer.scrollBar.getWidth();\n}\n\nfunction setHeight(_ace, element) {\n  // tslint:disable-next-line: restrict-plus-operands\n  element.css('height', Math.min(getHeight(_ace), 400) + 'px');\n}\n\nexport default class CodeEditor extends srv.eventEmitter.EventEmitter {\n  private readonly ace;\n  private valid: boolean = null;\n  private locked: [number, number][] = null;\n\n  private readonly completer: Completer = null;\n  private readonly annotator: Annotator = null;\n  private readonly selection: Selection = null;\n  private readonly shortcuts: Shortcuts = null;\n  private readonly params: Params = null;\n\n  constructor(scope, private readonly element, text, options?: CodeEditorOptions) {\n    super();\n\n    this.ace = ace.edit(element.text(text).get(0));\n\n    this.completer = new Completer(this.ace);\n    this.annotator = new Annotator(this.ace);\n    this.selection = new Selection(this.ace, scope);\n    this.shortcuts = new Shortcuts(this.ace);\n    this.params = new Params(this, this.ace, scope.options, scope);\n\n    this.init(options);\n  }\n\n  private init(options: CodeEditorOptions = {}): CodeEditor {\n    this.ace.setOptions({...aceDefaults, ...options.ace});\n\n    this.ace.$blockScrolling = Infinity;\n    this.ace.session.setFoldStyle('markbeginend');\n\n    this.ace.getSession().on('change', ({start, lines}) => {\n      this.setValid(null);\n\n      this.fire('change', this.ace.getValue(), {\n        isInLockRange: this.locked && start.row < last(flatten(this.locked)),\n        isMultilineInsert: lines.length > 1\n      });\n    });\n\n    const lockExceptions = ['golinedown', 'golineup', 'gotoright', 'gotoleft'];\n    this.ace.commands.on('exec', e => {\n      const range = this.getSelection().getRange();\n\n      if (!this.locked || (range && ['paste', 'del', 'backspace'].indexOf(e.command.name) !== -1 && range.start.row === 0 && range.end.row >= 1)) {\n        return;\n      }\n\n      const {row, column} = this.ace.selection.getCursor();\n      const lock = this.locked.some(([start, end]) => {\n        return (row >= start && row <= end && lockExceptions.indexOf(e.command.name) === -1)\n          || (e.command.name === 'backspace' && row === end + 1 && column === 0);\n      });\n\n      if (lock) {\n        e.preventDefault();\n        e.stopPropagation();\n      }\n    });\n\n    if (options.focus) {\n      this.ace.focus();\n    }\n\n    if (options.fitContent) {\n      setHeight(this.ace, this.element);\n    \n      this.ace.getSession().on('change', () => {\n        setHeight(this.ace, this.element);\n        this.resize();\n      });\n    }\n\n    if (typeof ResizeObserver !== 'undefined') {\n      // listen to element resize natively\n      new ResizeObserver(() => this.resize()).observe(this.element.get(0));\n    } else {\n      // resize the editor corectly inside a hidden container\n      inject('$timeout')(() => this.resize());\n    }\n\n    return this;\n  }\n\n  isValid(): boolean {\n    return this.valid;\n  }\n\n  getCompleter(): Completer {\n    return this.completer;\n  }\n\n  getAnnotator(): Annotator {\n    return this.annotator;\n  }\n\n  getSelection(): Selection {\n    return this.selection;\n  }\n\n  getShortcuts(): Shortcuts {\n    return this.shortcuts;\n  }\n\n  getParams(): Params {\n    return this.params;\n  }\n\n  getValue(): string {\n    return this.ace.getValue();\n  }\n\n  getLockedRange(): [number, number][] {\n    return this.locked;\n  }\n\n  setReadonly(readonly: boolean): CodeEditor {\n    this.ace.setReadOnly(readonly);\n    this.ace.setOption('highlightActiveLine', !readonly);\n    this.ace.setOption('highlightGutterLine', !readonly);\n\n    return this;\n  }\n\n  setLiveAutocompletion(value: boolean) {\n    this.ace.setOption('enableLiveAutocompletion', value);\n\n    return this;\n  }\n\n  setValid(valid: boolean): CodeEditor {\n    this.valid = valid;\n\n    this.fire('validToggle', valid);\n\n    return this;\n  }\n\n  setValue(value): CodeEditor {\n    this.ace.setValue(value, -1);\n    this.getSelection().clearSelection();\n\n    return this;\n  }\n\n  lockLines(range: [number, number][]): CodeEditor {\n    this.locked = range;\n\n    return this;\n  }\n\n  unlockLines(): CodeEditor {\n    this.locked = null;\n\n    return this;\n  }\n\n  resize(): CodeEditor {\n    this.ace.resize();\n    this.fire('resize', this.element.width());\n\n    return this;\n  }\n\n  focus(): CodeEditor {\n    this.ace.focus();\n\n    return this;\n  }\n\n  destroy(): CodeEditor {\n    this.ace.session.setUseWorker(false);\n    this.ace.destroy();\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/code-editor-shortcuts.ts",
    "content": "import {utils} from '../../core';\n\nexport default class CodeEditorShortcuts {\n  constructor (private readonly ace) {\n\n  }\n\n  addShortcut(winShortcut: string, macShortcut: string, fn, scope) {\n    this.ace.commands.addCommand({\n      name: macShortcut,\n      bindKey: {win: winShortcut, mac: macShortcut},\n      exec: () => utils.scope.safeApply(scope, fn)\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/index.ts",
    "content": "import {ParamParser} from './params-parser';\nimport {paramSerializerFactory} from './param-serializers';\n\nexport {IParam, TType} from './param-types';\nexport {ParamParser} from './params-parser';\n\nexport const paramParserFactory = type => {\n  return new ParamParser(paramSerializerFactory(type));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/boolean-param-renderer.ts",
    "content": "export default function () {\n  return `\n    <bi-simple-select\n      class=\"bi-grow\"\n      ng-model=\"param.value\"\n      ng-change=\"events.onParamChange(param)\"\n      bi-options=\"option for option in ::[true, false]\"\n    ></bi-simple-select\n  `;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/datetime-param-renderer.ts",
    "content": "export default function (dateFormat: string = 'YYYY-MM-DD HH:mm', widgetDateFormat: string = 'Y-m-d H:i') {\n  return `\n    <bi-date-picker\n      class=\"bi-r-i bi-grow\"\n      ng-model=\"param.widgetValue\"\n      ng-change=\"param.value = param.widgetValue; events.onParamChange(param)\"\n      bdp-options=\"::{\n        dateFormat: '${dateFormat}',\n        widgetDateFormat: '${widgetDateFormat}'\n      }\"\n      placeholder=\"Enter value\"\n    ></bi-date-picker>\n  `;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/index.ts",
    "content": "import {isArray} from 'lodash';\nimport {inject} from '../../../../core';\nimport {IParam} from '../param-types';\nimport {default as renderInput} from './input-param-renderer';\nimport {default as renderBoolean} from './boolean-param-renderer';\nimport {default as renderDatetime} from './datetime-param-renderer';\nimport {default as renderOption} from './option-param-renderer';\nimport {default as renderList} from './list-param-renderer';\nimport {default as renderTextarea} from './textarea-param-renderer';\n\nfunction compile(scope, param, html, overrides: Partial<IParam> = {}) {\n  const childScope = scope.$new();\n\n  childScope.param = param;\n  childScope.options = overrides.options || param.options;\n  childScope.getOptionTitle = option => {\n    return isArray(option) ? option[1] : option;\n  };\n\n  return inject('$compile')(html)(childScope);\n}\n\nfunction getHtml(param: IParam, options: {dateFormat?: string} = {}) {\n  switch (param.type) {\n    case 'string':\n      return renderInput('text');\n    case 'number':\n      return renderInput('number');\n    case 'boolean':\n      return renderBoolean();\n    case 'datetime':\n      (param as any).widgetValue = param.value;\n\n      return renderDatetime(options.dateFormat);\n    case 'option':\n      return renderOption();\n    case 'list':\n      return renderList();\n    case 'text':\n      return renderTextarea();\n    default:\n      return renderInput('text');\n  }\n}\n\nexport function renderParam(scope, param: IParam, options, overrides?: Partial<IParam>) {\n  return compile(scope, param, getHtml(param, options), overrides);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/input-param-renderer.ts",
    "content": "export default function (type: 'text' | 'number' = 'text') {\n  return `\n    <input\n      class=\"bi-input bi-grow\"\n      type=\"${type}\"\n      ng-model=\"param.value\"\n      ng-model-options=\"::{debounce: 100}\"\n      ng-change=\"events.onParamChange(param)\"\n      placeholder=\"Enter value\"\n    >\n  `;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/list-param-renderer.ts",
    "content": "export default function () {\n  return `\n    <bi-tags\n      class=\"bi-grow\"\n      ng-model=\"param.value\"\n      ng-change=\"events.onParamChange(param)\"\n      bi-options=\"option as getOptionTitle(option) for option in ::options\"\n      placeholder=\"Select values\"\n    ></bi-tags>\n  `;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/option-param-renderer.ts",
    "content": "export default function () {\n  return `\n    <bi-simple-select\n      class=\"bi-grow\"\n      ng-model=\"param.value\"\n      ng-change=\"events.onParamChange(param)\"\n      bi-options=\"option as getOptionTitle(option) for option in ::options\"\n      bs-options=\"::{dropdownMinWidth: 'toggle', typeahead: true}\"\n    ></bi-simple-select>\n  `;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-renderers/textarea-param-renderer.ts",
    "content": "export default function () {\n  return `\n    <textarea\n      class=\"bi-input bi-grow\"\n      ng-model=\"param.value\"\n      ng-model-options=\"::{debounce: 100}\"\n      ng-change=\"events.onParamChange(param)\"\n      placeholder=\"Enter value\"\n    ></textarea>\n  `;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/default-param-serializer.ts",
    "content": "import {IParam, AUTO_PARAMS, TType} from '../param-types';\nimport {ParamSerializer, ITokenizedParam} from './param-serializer';\n\nconst EMBED_PREFIX = 'AUTOGENERATED';\nconst EMBED_SUFFIX = 'AUTOGENERATED END';\n\nexport class DefaultParamSerializer extends ParamSerializer {\n  public *parse(text: string): Iterable<string[]> {\n    const regex = new RegExp('\\\\$([a-z0-9_]+)(?:\\\\:([a-z_]+))?(?:\\\\:([^=]+))?=\\\\[([^\\\\[\\\\]]*)]|(\\\\$([a-z0-9_]+))|' + '(\\\\$((' + AUTO_PARAMS.join(')|(') + ')))', 'g');\n    let param = null;\n\n    // tslint:disable-next-line: no-conditional-assignment\n    while ((param = regex.exec(text))) {\n      yield param;\n    }\n  }\n\n  public stringify(param: any[]): string {\n    let pair = param;\n\n    if (param.length > 1) {\n      const value = param.pop();\n      pair = [param.join(':'), `[${value}]`];\n    }\n\n    return pair.join('=');\n  }\n\n  public convert([match, key, type, options, value, keyOnlyParamMatch, keyOnlyParam, autoParamMatch, autoParamKey]: string[]): any[] {\n    value = this.toJs(value, type as TType);\n    options = (options && this.toJs(options, 'list')) || [];\n\n    return [match, key, type, options, value, keyOnlyParamMatch, keyOnlyParam, autoParamMatch, autoParamKey];\n  }\n\n  public unconvert(param: any[]): string[] {\n    return param;\n  }\n\n  public transform(param: ITokenizedParam): ITokenizedParam {\n    return param;\n  }\n\n  public untransform(param: ITokenizedParam): ITokenizedParam {\n    return param;\n  }\n\n  public tokenize([match, key, type, options, value, keyOnlyParamMatch, keyOnlyParam, autoParamMatch, autoParamKey]: any[]): ITokenizedParam {\n    let isAutoParam = false;\n    let isKeyOnlyParam = false;\n\n    if (autoParamMatch) {\n      match = autoParamMatch;\n      key = autoParamKey;\n      isAutoParam = true;\n    } else if (keyOnlyParamMatch) {\n      match = keyOnlyParamMatch;\n      key = keyOnlyParam;\n      isKeyOnlyParam = true;\n    }\n\n    return {match, key, value, type, isAutoParam, isKeyOnlyParam, options};\n  }\n\n  public detokenize({key, type, value, isAutoParam, isKeyOnlyParam, options}: ITokenizedParam, serializationType: 'serialize' | 'value'): string[] {\n    const res = [];\n\n    switch (serializationType) {\n      case 'serialize':\n        res.push(`$${key}`);\n\n        if (!isAutoParam && !isKeyOnlyParam) {\n          res.push(type);\n\n          if (options && options.length) {\n            res.push(options);\n          }\n\n          res.push(value);\n        }\n\n        break;\n      case 'value':\n        res.push(value);\n        break;\n      default:\n    }\n\n    return res;\n  }\n\n  public embed(text: string, params: IParam[]): string {\n    const paramsText = params.map(param => this.serialize(param as ITokenizedParam)).join(' ');\n\n    return `/* ${EMBED_PREFIX}\\n${paramsText}\\n${EMBED_SUFFIX} */\\n`;\n  }\n\n  public extract(text: string): string {\n    const match = new RegExp(`^\\\\/\\\\*[\\\\s\\\\S]+${EMBED_PREFIX}[\\\\s\\\\S]+${EMBED_SUFFIX}[\\\\s\\\\S]+?\\\\*\\\\/\\\\n?`).exec(text);\n\n    return (match && match[0]) || '';\n  }\n\n  public getLockRange(text: string): [number, number][] {\n    return [[0, this.extract(text).split('\\n').length - 2]];\n  }\n\n  public toJs(value: string, type: TType = 'string'): any {\n    if (typeof value === 'undefined') {\n      return null;\n    } \n    \n    if (type === 'boolean') {\n      return value === 'true' ? true : false;\n    } \n    \n    if (type === 'number') {\n      return parseInt(value, 10);\n    } \n  \n    if (type === 'list') {\n      return value.split(',');\n    } \n    \n    return value;\n  }\n\n  public toString(value: any, type: TType = 'string'): any {\n    // tslint:disable-next-line: restrict-plus-operands\n    return '' + value;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/index.ts",
    "content": "import {DefaultParamSerializer} from './default-param-serializer';\nimport {PythonParamSerializer} from './python-param-serializer';\n\nexport {ParamSerializer, ITokenizedParam} from './param-serializer';\n\nexport function paramSerializerFactory(type) {\n  switch (type) {\n    case 'python':\n      return new PythonParamSerializer();\n    default:\n      return new DefaultParamSerializer();\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/param-serializer.ts",
    "content": "import {TType, IParam} from '../param-types';\n\nexport interface ITokenizedParam {\n  match: string;\n  key: string;\n  type: TType;\n  value: any;\n  isAutoParam: boolean;\n  isKeyOnlyParam: boolean;\n  options: string[];\n}\n\nexport abstract class ParamSerializer {\n  // serialization pipileine\n  public abstract untransform(param: ITokenizedParam): ITokenizedParam;\n  public abstract detokenize(param: ITokenizedParam, serializationType: 'serialize' | 'value'): any[];\n  public abstract unconvert(param: any[], type: TType): string[];\n  public abstract stringify(param: any[]): string;\n\n  // parsing pipeline\n  public abstract parse(text: string): Iterable<string[]>;\n  public abstract convert(param: string[]): any[];\n  public abstract tokenize(param: any[]): ITokenizedParam;\n  public abstract transform(param: ITokenizedParam): ITokenizedParam;\n\n  /**\n * Generates an embed string\n */\n  public abstract embed(text: string, params: IParam[]): string;\n\n  /**\n   * Extracts the embed string\n   */\n  public abstract extract(text: string, options?: {[key: string]: any}): string;\n\n  /**\n   * Converts value to js\n   */\n  public abstract toJs(value: string, type: TType): any;\n\n    /**\n   * Converts value to string\n   */\n  public abstract toString(value: any, type?: TType): any;\n\n  /**\n   * Ranges of rows to lock\n   */\n  public abstract getLockRange(text: string): [number, number][];\n\n  /**\n   * Returns a serialized param\n   */\n  public serialize(param: ITokenizedParam, serializationType: 'serialize' | 'value' = 'serialize'): string {\n    return this.stringify(this.unconvert(this.detokenize(this.untransform(param), serializationType), param.type));\n  }\n\n  /**\n   * Params iterator\n   */\n  public params(text: string): Iterable<ITokenizedParam> {\n    return Array.from(this.parse(text)).map(param => this.transform(this.tokenize(this.convert(param))));\n  }\n\n  /**\n   * Params iterator\n   */\n  public removeEmbed(text: string): string {\n    return text.replace(this.extract(text), '');\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-serializers/python-param-serializer.ts",
    "content": "import {isArray, isPlainObject, assign} from 'lodash';\nimport {IParam, AUTO_PARAMS, TType} from '../param-types';\nimport {ParamSerializer, ITokenizedParam} from './param-serializer';\n\nconst EMBED_PREFIX = '# AUTOGENERATED {';\nconst EMBED_SUFFIX = '# AUTOGENERATED END }';\nconst CUSTOM_FN_DEF = 'def __custom__():';\nconst CUSTOM_FN_CALL = '__custom__()';\nconst INIT_FN_DEF = 'def __init__(c):';\nconst INIT_FN_CALL = '__init__(False)';\nconst CUSTOM_REGEX = `(${CUSTOM_FN_DEF.replace(/(\\(|\\))/g, '\\\\$1')})([\\\\s\\\\S]+)(${INIT_FN_DEF.replace(/(\\(|\\))/g, '\\\\$1')})`;\nconst EMBED_REGEX = `^${EMBED_PREFIX}[\\\\s\\\\S]+${EMBED_SUFFIX}\\\\n`;\nconst PARAM_REGEX = `\\\\((?:\"([a-zA-Z0-9_]+)\",\"([a-z]+)\",(.+?),(\\\\[.*?\\\\]))\\\\)|(\\\\(\"(${AUTO_PARAMS.join('|')})\",None,(?:(?:\"\\\\$[a-zA-Z_]+\")|None),\\\\[[^\\\\[\\\\]]*\\\\]\\\\))`;\nconst PARAMS_VAR = 'p';\n\nconst PYTHON_TO_JS = {\n  None: null,\n  True: true,\n  False: false\n};\n\nconst PYTHON_TO_JS_BY_TYPE = {\n  list: {\n    '\\\\(': '[',\n    '\\\\)': ']'\n  }\n};\n\nconst JS_TO_PYTHON = {\n  null: 'None',\n  true: 'True',\n  false: 'False'\n};\n\nconst JS_TO_PYTHON_BY_TYPE = {\n  list: {\n    '\\\\[': '(',\n    '\\\\]': ')'\n  }\n};\n\nfunction transform(value, transformations) {\n  return Object.keys(transformations).reduce((res, k) => res.replace(new RegExp(`(${k})`, 'g'), transformations[k]), value);\n}\n\nfunction getSerializedParamsText(serializedParams: string[]) {\n  return `${PARAMS_VAR} = [${serializedParams}]`;\n}\n\nfunction getEmbedText(params: IParam[], serializedParams: any[]): string {\n  return `${EMBED_PREFIX}\ndef __param__(key, options, value = None):\n    _fields('k', 'o', 'v')\n    _row(key, options, value)\n${CUSTOM_FN_DEF}\n\n    pass\n${INIT_FN_DEF}\n    ${getSerializedParamsText(serializedParams)}\n    if c:\n        ${CUSTOM_FN_CALL}\n    return {t[0]: t[2] for t in ${PARAMS_VAR}}\nq = ${INIT_FN_CALL}\n${EMBED_SUFFIX}\n`;\n}\n\nexport class PythonParamSerializer extends ParamSerializer {\n  public *parse(text: string): Iterable<string[]> {\n    const regex = new RegExp(PARAM_REGEX, 'g');\n    let param = null;\n\n    // tslint:disable-next-line: no-conditional-assignment\n    while ((param = regex.exec(this.extract(text)))) {\n      yield param;\n    }\n  }\n\n  public stringify(param: any[]): string {\n    return `(${param})`;\n  }\n\n  public convert([match, key, type, value, options, autoParamMatch, autoParamKey]: string[]): any[] {\n    value = this.toJs(value, type as TType);\n    options = (options && this.toJs(options, 'list')) || [];\n\n    return [match, key, type, value, options, autoParamMatch, autoParamKey];\n  }\n\n  public unconvert(param: any[], type: TType): string[] {\n    return param.map(p => this.toString(p, type));\n  }\n\n  public tokenize([match, key, type, value, options, autoParamMatch, autoParamKey]: any[]): ITokenizedParam {\n    let isAutoParam = false;\n    const isKeyOnlyParam = false;\n\n    if (autoParamMatch) {\n      match = autoParamMatch;\n      key = autoParamKey;\n      isAutoParam = true;\n    }\n\n    return {match, key, value, type, isAutoParam, isKeyOnlyParam, options};\n  }\n\n  public detokenize({key, type, value, isAutoParam, options}: ITokenizedParam, serializationType: 'serialize' | 'value' = 'serialize'): any[] {\n    let res;\n\n    switch (serializationType) {\n      case 'serialize':\n        if (isAutoParam) {\n          res = [key, null, `$${key}`, []];\n        } else {\n          res = [key, type, value, options];\n        }\n        break;\n      case 'value':\n        res = [key, null, value, null];\n        break;\n      default:\n    }\n\n    return res;\n  }\n\n  public transform(param: ITokenizedParam): ITokenizedParam {\n    return param;\n  }\n\n  public untransform(param: ITokenizedParam): ITokenizedParam {\n    return param;\n  }\n\n  public embed(text: string, params: IParam[]): string {\n    let res = getEmbedText(params, params.map(param => this.serialize(param as ITokenizedParam)));\n    const custom = new RegExp(CUSTOM_REGEX).exec(text);\n\n    if (custom) {\n      res = res.replace(new RegExp(CUSTOM_REGEX), `$1${custom[2]}$3`);\n    }\n\n    return res;\n  }\n\n  public extract(text: string, options = {runCustom: false}): string {\n    const match = new RegExp(EMBED_REGEX).exec(text);\n    let res = '';\n\n    if (!match) {\n      return res;\n    }\n\n    res = match[0];\n\n    if (options.runCustom) {\n      res = res.replace(INIT_FN_CALL, INIT_FN_CALL.replace(this.toString(false), this.toString(true)));\n    }\n\n    return res;\n  }\n\n  public getLockRange(text: string): [number, number][] {\n    const range = [];\n    const rows = this.extract(text).split('\\n');\n\n    for (let i = 0; i < rows.length; i++) {\n      const row = rows[i];\n\n      if (row.includes(CUSTOM_FN_DEF)) {\n        range.push([0, i]);\n      } else if (row.includes(INIT_FN_DEF)) {\n        range.push([i, rows.length - 2]);\n        break;\n      }\n    }\n\n    return range;\n  }\n\n  public toJs(value: string, type: TType): any {\n    if (!value) {\n      return value;\n    }\n\n    value = transform(value, assign({}, PYTHON_TO_JS, PYTHON_TO_JS_BY_TYPE[type]));\n\n    return type === 'string' ? value.replace(/^\"/, '').replace(/\"$/, '') : JSON.parse(value);\n  }\n\n  public toString(value: any, type: TType = 'string'): string {\n    if ((typeof value === 'boolean' || value === null) && typeof JS_TO_PYTHON[value] !== 'undefined') {\n      return JS_TO_PYTHON[value];\n    } \n    \n    if (isArray(value)) {\n      return `[${value.map(v => transform(this.toString(v), JS_TO_PYTHON_BY_TYPE.list))}]`;\n    } \n    \n    if (isPlainObject(value)) {\n      return `{${Object.keys(value).map(k => `\"${k}\":${this.toString(value[k])}`).join(',')}}`;\n    } \n    \n    if (typeof value === 'string' && value.length) {\n      if (JS_TO_PYTHON_BY_TYPE[type]) {\n        value = transform(value, JS_TO_PYTHON_BY_TYPE[type]);\n      }\n\n      return JSON.stringify(value);\n    } \n    \n    if (typeof value === 'number') {\n      // tslint:disable-next-line: restrict-plus-operands\n      return '' + value;\n    }\n\n    return 'None';\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/param-types.ts",
    "content": "import BiDate from '../../../../lib/ui/services/date';\nimport {TPredefindListsTypes} from './params-predefined-types';\n\nexport const DATE_FORMAT = BiDate.DATE_FORMAT.replace(/\\//g, '-');\n\nexport type TType = 'string' | 'number' | 'boolean' | 'option' | 'list' | 'datetime' | 'text';\nexport const TYPES: TType[] = ['string', 'number', 'boolean', 'option', 'list', 'datetime', 'text'];\nexport type TUserSelectableTypes = TPredefindListsTypes | TType;\n\nexport const TYPE_DEFAULTS = {\n  string: null,\n  number: null,\n  boolean: null,\n  option: null,\n  list: [],\n  datetime: null,\n  text: null\n};\n\nexport const AUTO_PARAMS = [\n  'START_TIME',\n  'STOP_TIME',\n];\n\nexport const AUTO_PARAM_TYPES = {\n  START_TIME: 'datetime',\n  STOP_TIME: 'datetime',\n};\n\nexport const AUTO_PARAM_DEFAULTS = {\n  get START_TIME() {\n    return new BiDate(new BiDate().asMoment().utc().subtract(2, 'days').startOf('day').valueOf()).fromUTC().format(DATE_FORMAT);\n  },\n\n  get STOP_TIME() {\n    return new BiDate(new BiDate().asMoment().utc().startOf('day').valueOf()).fromUTC().format(DATE_FORMAT);\n  }\n};\n\nexport interface IParam {\n  key: string;\n  type: TType;\n  value: any;\n  isAutoParam: boolean;\n  options?: string[];\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/params-parser.ts",
    "content": "import {\n  IParam, TType, TYPES, AUTO_PARAMS, TYPE_DEFAULTS, AUTO_PARAM_TYPES, AUTO_PARAM_DEFAULTS, TUserSelectableTypes\n} from './param-types';\n\nimport {TPredefindListsTypes, PREDEFINED_LISTS, PREDEFINED_LISTS_DATA} from './params-predefined-types';\nimport {ParamSerializer, ITokenizedParam} from './param-serializers';\n\nexport type IParamTransformer = (param: ITokenizedParam) => string;\n\nexport type IParamReplacer = (text: string, oldParam: string, newParam: string) => string;\n\nfunction defaultReplacer(text: string, oldParam: string, newParam: string) {\n  return text.replace(oldParam, newParam);\n}\n\nconst isPredefinedListType = (type: TUserSelectableTypes): type is TPredefindListsTypes =>\n  PREDEFINED_LISTS.some(value => value === type);\n\nexport class ParamParser {\n  constructor(private readonly serializer: ParamSerializer) {\n\n  }\n\n  static TYPES: TUserSelectableTypes[] = [...TYPES, ...PREDEFINED_LISTS];\n  static AUTO_PARAMS = AUTO_PARAMS;\n\n  /**\n   * Iterates over params in text\n   * By default, doesn't interate over more than one instance of param\n   */\n  public *each(text: string, all: boolean = false): Iterable<ITokenizedParam> {\n    const processed = {};\n\n    for (const param of this.serializer.params(text)) {\n      if (!all && (param.isKeyOnlyParam || processed[param.key])) {\n        continue;\n      }\n\n      processed[param.key] = true;\n\n      yield param;\n    }\n  }\n\n  /**\n   * Iterates over all params in text\n   */\n  private all(text: string): Iterable<ITokenizedParam> {\n    return this.each(text, true);\n  }\n\n  /**\n   * Iterates over params in text and replaces them\n   */\n  private replace(text: string, transformer: IParamTransformer, replacer: IParamReplacer = defaultReplacer): string {\n    return Array.from(this.all(text)).reduce((res, param) => replacer(res, param.match, transformer(param)), text);\n  }\n\n  /**\n   * Indexes params by key\n   */\n  private paramsByKey(params: IParam[]): {[key: string]: IParam} {\n    return params.reduce((res, param: IParam) => {\n      res[param.key] = param;\n      return res;\n    }, {});\n  }\n\n  /**********************************************\n   * PUBLIC\n   **********************************************/\n\n  public getSerializer(): ParamSerializer {\n    return this.serializer;\n  }\n\n  /**\n   * Checks for differences between the params encoded in the text and the array of params\n   */\n  public isSynced(params: IParam[], text: string): boolean {\n    let res = true;\n    const paramsByKey = this.paramsByKey(params);\n\n    for (const {key, value, isAutoParam} of this.all(text)) {\n      if (!isAutoParam && (!paramsByKey[key] || paramsByKey[key].value !== value)) {\n        res = false;\n        break;\n      }\n    }\n\n    return res;\n  }\n\n  /**\n   * Embeds params into text\n   */\n  public embed(text, params: IParam[], replacer: IParamReplacer = defaultReplacer): string {\n    const embeded = this.serializer.extract(text);\n\n    if (!embeded) {\n      return params.length ? replacer(text, text, `${this.serializer.embed(text, params)}${text}`) : text;\n    }\n\n    return replacer(text, embeded, params.length ? this.serializer.embed(text, params) : '');  \n  }\n\n  /**\n   * Creates an array of params encoded in the text\n   */\n  public params(text: string, {customParamsEnabled} = {customParamsEnabled: true}, params: IParam[] = []): IParam[] {\n    const paramsByKey = this.paramsByKey(params);\n\n    return Array.from(this.each(text)).reduce((res, {key, value, type, isAutoParam, options}) => {\n      if (!isAutoParam && !customParamsEnabled) {\n        return res;\n      }\n\n      res.push(this.createParam(key, type, isAutoParam && paramsByKey[key] ? paramsByKey[key].value : value, options));\n\n      return res;\n    }, []);\n  }\n\n  /**\n   * Updates params encoded in the text with values in the params array\n   * Returns lock ranges\n   */\n  public sync(text: string, params: IParam[], {customParamsEnabled} = {customParamsEnabled: true}, replacer: IParamReplacer = defaultReplacer): [number, number][] {\n    let res = this.embed(text, params, replacer);\n    const paramsByKey = this.paramsByKey(params);\n\n    res = this.replace(res, param => {\n      if (!paramsByKey[param.key] || (!param.isAutoParam && !customParamsEnabled)) {\n        return param.match;\n      }\n\n      return this.serializer.serialize({...param, ...paramsByKey[param.key] || {}});\n    }, replacer);\n\n    return this.serializer.getLockRange(res);\n  }\n\n  /**\n   * Replaces params in text with their respective values\n   */\n  public format(text: string, params: IParam[], options = {customParamsEnabled: true, keepEmbed: false}): string {\n    if (!text) {\n      return text;\n    }\n\n    const res = options.keepEmbed ? text : this.embed(text, []);\n    const paramsByKey = this.paramsByKey(params);\n\n    return this.replace(res, param => {\n      if (!paramsByKey[param.key] || (!param.isAutoParam && !options.customParamsEnabled)) {\n        return param.match;\n      }\n\n      return this.serializer.serialize({...param, ...paramsByKey[param.key] || {}}, 'value');\n    });\n  }\n\n  public createParam(key: string, type: TUserSelectableTypes = 'string', value: any, options?: string[]): IParam {\n    const isAutoParam = AUTO_PARAMS.indexOf(key) !== -1;\n\n    type = isAutoParam ? AUTO_PARAM_TYPES[key] : type || 'string';\n\n    if (isAutoParam) {\n      type = AUTO_PARAM_TYPES[key];\n      value = value || AUTO_PARAM_DEFAULTS[key];\n    }\n\n    const actualType: TType = isPredefinedListType(type) ? 'list' : type;\n\n    if (isPredefinedListType(type)) {\n      options = PREDEFINED_LISTS_DATA[type];\n    }\n\n    if (typeof value === 'undefined') {\n      value = TYPE_DEFAULTS[type];\n    }\n\n    return {\n      key,\n      type: actualType,\n      value,\n      isAutoParam,\n      options\n    };\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/code-editor/services/param-parser/params-predefined-types.ts",
    "content": "export const PREDEFINED_LISTS_DATA = {\n  browser_family: ['Chrome',\n    'Edge',\n    'Epiphany',\n    'Firefox',\n    'Internet Explorer',\n    'Maxthon',\n    'Mozilla',\n    'NativeMobile',\n    'Opera',\n    'Playstation Browser',\n    'Puffin Mobile',\n    'Safari',\n    'YaBrowser'],\n\n  country_code: ['AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX',\n    'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BW',\n    'BY', 'BZ', 'CA', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY',\n    'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FM', 'FO', 'FR', 'GA',\n    'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM',\n    'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IQ', 'IR', 'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG',\n    'KH', 'KM', 'KN', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA',\n    'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MT', 'MU', 'MV', 'MW', 'MX',\n    'MY', 'MZ', 'NA', 'NC', 'NE', 'NG', 'NI', 'NL', 'NO', 'NP', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK',\n    'PL', 'PM', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG',\n    'SH', 'SI', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TG', 'TH', 'TJ', 'TL',\n    'TM', 'TN', 'TO', 'TR', 'TT', 'TW', 'TZ', 'UA', 'UG', 'US', 'UY', 'UZ', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF',\n    'WS', 'XK', 'YE', 'YT', 'ZA', 'ZM', 'ZW'],\n\n  device_type: [\n    'Mobile', 'Tablet', 'Unknown', 'Computer'\n  ]\n};\nexport const PREDEFINED_LISTS: TPredefindListsTypes[] = [];\nexport type TPredefindListsTypes = keyof typeof PREDEFINED_LISTS_DATA;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/drv/bi-options.drv.ts",
    "content": "'use strict';\n\nimport {lodash as _} from '../../utils';\nimport {get as inject} from '../../srv/injector';\n\nexport function biOptions() {\n  const $parse: ng.IParseService = inject('$parse');\n  const $interpolate: ng.IInterpolateService = inject('$interpolate');\n\n  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]+?))?$/;\n  // 1: value expression (valueFn)\n  // 2: label expression (displayFn)\n  // 3: group by expression (groupByFn)\n  // 4: disable when expression (disableWhenFn)\n  // 5: array item variable name\n  // 6: object item key variable name\n  // 7: object item value variable name\n  // 8: collection expression\n  // 9: track by expression\n\n  function parseExpression(str: string) {\n    const match = str.match(NG_OPTIONS_REGEXP);\n\n    if (!(match)) {\n      throw new Error('biOptions: bad expression \"' + str + '\"');\n    }\n\n    // The variable name for the value of the item in the collection\n    const valueName = match[5] || match[7];\n    // The variable name for the key of the item in the collection\n    const keyName = match[6];\n\n    // An expression that generates the viewValue for an option if there is a label expression\n    const selectAs = / as /.test(match[0]) && match[1];\n    // An expression that is used to track the id of each object in the options collection\n    const trackBy = match[10];\n    // An expression that generates the viewValue for an option if there is no label expression\n    const valueFn = $parse(match[2] ? match[1] : valueName);\n    const selectAsFn = selectAs && $parse(selectAs);\n    const viewValueFn = selectAsFn || valueFn;\n    const trackByFn = trackBy && $parse(trackBy);\n\n    const orderBy = match[9];\n    const orderByFn = orderBy && $parse(orderBy);\n\n    const displayFn = $parse(match[2] || match[1]);\n    const groupBy = match[3] || '';\n    const groupByFn = $parse(match[3] || '');\n    const disableWhen = match[4] || '';\n    const disableWhenFn = $parse(disableWhen);\n    const values = match[8];\n    const valuesFn = $parse(values);\n\n    return {valueName, keyName, selectAs, trackBy, valueFn, selectAsFn, viewValueFn, orderBy, orderByFn, trackByFn, displayFn, groupBy, groupByFn, disableWhen, disableWhenFn, valuesFn, values};\n  }\n\n  function getLocals(options: {valueName: string}, value) {\n    const locals = {};\n    locals[options.valueName] = value;\n\n    return locals;\n  }\n\n  return {\n    restrict: 'A',\n    require: ['biOptions', 'ngModel'],\n    scope: false,\n\n    controller: ['$scope', '$attrs', function ($scope, $attrs) {\n      const options = parseExpression($interpolate($attrs.biOptions)($scope));\n      let watcher = null;\n\n      $scope.$watch(options.values, values => _.isFunction(watcher) && watcher(values));\n\n      this.hasGroupBy = function () {\n        return !!options.groupBy;\n      };\n\n      this.hasOrderBy = function () {\n        return !!options.orderBy;\n      };\n\n      this.hasTrackBy = function () {\n        return !!options.trackBy;\n      };\n\n      this.hasDisabledWhen = function () {\n        return !!options.disableWhen;\n      };\n\n      this.getKey = function () {\n        return options.keyName;\n      };\n\n      this.getItemName = function () {\n        return options.valueName;\n      };\n\n      this.getCollection = function () {\n        return options.valuesFn($scope);\n      };\n\n      this.groupBy = function (value) {\n        return options.groupByFn($scope, getLocals(options, value));\n      };\n\n      this.isDisabled = function (value) {\n        return options.disableWhenFn($scope, getLocals(options, value));\n      };\n\n      this.orderBy = function (value) {\n        return options.orderByFn($scope, getLocals(options, value));\n      };\n\n      this.trackBy = function (value) {\n        return options.trackByFn($scope, getLocals(options, value));\n      };\n\n      this.render = function (value) {\n        return options.displayFn($scope, getLocals(options, value));\n      };\n\n      this.format = function (value) {\n        if (!options.selectAsFn) {\n          return value;\n        }\n\n        const collection = this.getCollection();\n        return (_.isArray(collection) && _.find(collection, item => {\n          return options.selectAsFn($scope, getLocals(options, item)) === value;\n        })) || value;\n      };\n\n      this.parse = function (value) {\n        if (!options.selectAsFn) {\n          return value;\n        }\n\n        return options.selectAsFn($scope, getLocals(options, value));\n      };\n\n      this.eval = function (str, value) {\n        return $parse(str)($scope, getLocals(options, value));\n      };\n\n      this.watch = function (fn) {\n        watcher = fn;\n      };\n    }]\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/drv/bi-validator.drv.ts",
    "content": "import {forEach} from 'lodash';\nimport {inject} from '../../';\nimport {IDirective, IQService, IParseService} from 'angular';\n\nexport default (): IDirective => {\n  const $q: IQService = inject('$q');\n  const $parse: IParseService = inject('$parse');\n\n  return {\n    restrict: 'A',\n    require: 'ngModel',\n\n    link(scope: ng.IScope, element, attrs, ngCtrl) {\n      const ngModel = ngCtrl as ng.INgModelController;\n      const validators = $parse(attrs.validators)(scope);\n      const asyncValidators = $parse(attrs.asyncValidators)(scope);\n      const validatorsPromise = $q.when(validators || {});\n      const asyncValidatorsPromise = $q.when(asyncValidators || {});\n\n      ngModel.$validators = ngModel.$validators || {};\n      ngModel.$asyncValidators = ngModel.$asyncValidators || {};\n\n      asyncValidatorsPromise.then(vals => {\n        forEach(vals, (validator, name: string) => ngModel.$asyncValidators[name] = validator);\n      });\n\n      validatorsPromise.then(vals => {\n        forEach(vals, (validator, name: string) => ngModel.$validators[name] = validator);\n      });\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/srv/ng-model/ng-model-test.drv.ts",
    "content": "'use strict';\nimport {create as createNgModel} from './ng-model';\n\n  /* @ngInject */\n  export function ngModelTest() {\n    return {\n      template: 'create-model-test',\n      restrict: 'E',\n      require: 'ngModel',\n      scope: {\n        template: '=',\n        formatter: '&',\n        parser: '&',\n        validator: '&',\n        asyncValidator: '&',\n        renderer: '&',\n        watcher: '&',\n        then: '&',\n        keepReference: '=',\n        watchDeep: '='\n      },\n\n      link: function postLink(scope, element, attrs, ngModel) {\n        createNgModel(scope, ngModel)\n          .fromTemplate(scope.template)\n          .formatWith(scope.formatter())\n          .parseWith(scope.parser())\n          .validateWith(scope.validator())\n          .validateAsyncWith(scope.asyncValidator())\n          .renderWith(scope.renderer())\n          .watchWith(scope.watcher())\n          .keepReference(scope.keepReference)\n          .watchDeep(scope.watchDeep)\n          .then(scope.then());\n\n        scope.ngModel = ngModel;\n      }\n    };\n  }\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/srv/ng-model/ng-model.test.ts",
    "content": "'use strict';\nimport * as angular from 'angular';\nimport {ngModelTest} from './ng-model-test.drv';\n\ndescribe('bi.core.drv.createModel()', function () {\n  let scope, $rootScope, $compile, $timeout, $q: angular.IQService;\n\n  function createModel(params) {\n    let {data, template, formatter, parser, validator, asyncValidator, renderer, watcher, keepReference, watchDeep, then} = <any>(params || {});\n    let scope = $rootScope.$new();\n    let directiveScope;\n\n    scope.data = data;\n    scope.template = template;\n    scope.formatter = formatter;\n    scope.parser = parser;\n    scope.asyncValidator = asyncValidator;\n    scope.validator = validator;\n    scope.renderer = renderer;\n    scope.watcher = watcher;\n    scope.keepReference = keepReference;\n    scope.watchDeep = watchDeep;\n    scope.then = then;\n\n    const element = angular.element('<create-model-test ng-model=\"data\" template=\"template\" async-validator=\"asyncValidator\" formatter=\"formatter\" parser=\"parser\" validator=\"validator\" renderer=\"renderer\" watcher=\"watcher\" keep-reference=\"keepReference\" watch-deep=\"watchDeep\" then=\"then\"></create-model-test>');\n    $compile(element)(scope);\n    directiveScope = element.isolateScope();\n\n    $rootScope.$digest();\n    $timeout.flush();\n\n    return {\n      get data() {\n        return scope.data;\n      },\n      set data(_data) {\n        scope.data = _data;\n      },\n      get directiveData() {\n        return directiveScope.model;\n      },\n      set directiveData(data) {\n        directiveScope.model = data;\n      },\n      get ngModel() {\n        return directiveScope.ngModel;\n      }\n    };\n  }\n\n  beforeAll(() => {\n    angular\n      .module('bi.core')\n      .directive('createModelTest', ngModelTest);\n  });\n\n  beforeEach(function () {\n      angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$rootScope_, _$compile_, _$timeout_, _$q_) {\n    scope = _$rootScope_.$new();\n    $compile = _$compile_;\n    $rootScope = _$rootScope_;\n    $timeout = _$timeout_;\n    $q = _$q_;\n  }));\n\n  describe('createModel', function () {\n    describe('creation', function () {\n      it('should be undefined if no data and template were set', function () {\n        const model = createModel({});\n\n        expect(model.data).toEqual(undefined);\n        expect(model.directiveData).toEqual(undefined);\n      });\n\n      it('should use the data object as is if template is undefined', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n\n        expect(model.data).toEqual(data);\n        expect(model.directiveData).toEqual(data);\n      });\n\n      it('should create a model with the provided data and null template', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n\n        expect(model.data).toEqual(data);\n        expect(model.directiveData).toEqual(data);\n      });\n\n      it('should populate undefined model with template values', function () {\n        const template = {a: 1};\n        const model = createModel({template});\n\n        expect(model.data).toEqual(template);\n        expect(model.directiveData).toEqual(template);\n      });\n\n      it('should populate null model with template values', function () {\n        const template = {a: 1};\n        const model = createModel({template, data: null});\n\n        expect(model.data).toEqual(template);\n        expect(model.directiveData).toEqual(template);\n      });\n\n      it('should populate empty model with template values', function () {\n        const data = {};\n        const template = {a: 1};\n        const model = createModel({data, template});\n\n        expect(model.data).toEqual(template);\n        expect(model.directiveData).toEqual(template);\n      });\n\n      it('should fill model with default template values', function () {\n        const data = {a: 0};\n        const template = {a: 1, b: []};\n        const model = createModel({data, template});\n\n        expect(model.data).toEqual({a: 0, b: []});\n        expect(model.directiveData).toEqual({a: 0, b: []});\n      });\n\n      it('should support nesting', function () {\n        let data = {a: 0, b: {d: 4}};\n        const template = {a: 1, b: {c: 3, d: 4}};\n\n        let model = createModel({data, template});\n\n        expect(model.data).toEqual({a: 0, b: {c: 3, d: 4}});\n        expect(model.directiveData).toEqual({a: 0, b: {c: 3, d: 4}});\n\n        data = {a: 0, b: {d: 4}};\n        model = createModel({data, template: {a: 1, b: null}});\n\n        expect(model.data).toEqual({a: 0, b: {d: 4}});\n        expect(model.directiveData).toEqual({a: 0, b: {d: 4}});\n      });\n    });\n\n    describe('original model reference', function () {\n      it('should not keep the reference by default', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n\n        expect(model.data).not.toBe(data);\n        expect(model.data).toEqual(data);\n        expect(model.directiveData).not.toBe(data);\n        expect(model.directiveData).toEqual(data);\n      });\n\n      it('should not keep the reference', function () {\n        const data = {a: 1};\n        const model = createModel({data, keepReference: false});\n\n        expect(model.data).not.toBe(data);\n        expect(model.data).toEqual(data);\n        expect(model.directiveData).not.toBe(data);\n        expect(model.directiveData).toEqual(data);\n      });\n\n      it('should keep the reference (with data)', function () {\n        const data = {a: 1};\n        const model = createModel({data, keepReference: true});\n\n        expect(model.directiveData).toBe(data);\n        expect(model.directiveData).toBe(model.data);\n      });\n\n      it('should keep the reference (with template)', function () {\n        const template = {a: 1};\n        const model = createModel({template, keepReference: true});\n\n        expect(model.directiveData).toBe(model.data);\n      });\n\n      it('should keep the reference (with parser)', function () {\n        const data = {a: 1};\n        const model = createModel({\n          data,\n          parser(model) {\n            return {a: 2};\n          },\n          keepReference: true\n        });\n\n        expect(model.data).toBe(data);\n        expect(model.data).toEqual({a: 2});\n      });\n\n      it('should keep the reference (with formatter)', function () {\n        const data = {a: 1};\n        const model = createModel({\n          data,\n          formatter(model) {\n            return {a: 2};\n          },\n          keepReference: true\n        });\n\n        expect(model.data).toBe(data);\n        expect(model.data).toEqual({a: 2});\n      });\n\n      it('should not override primitive values', function () {\n        const data = 1;\n        const model = createModel(data);\n\n        model.directiveData = 2;\n        $rootScope.$digest();\n\n        expect(model.data).toBe(2);\n        expect(model.directiveData).toBe(2);\n      });\n    });\n\n    describe('changing directive model reference', function () {\n      it('should change the model accordingly', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n\n        model.directiveData = {a: 2};\n        $rootScope.$digest();\n\n        expect(model.data).toEqual({a: 2});\n        expect(model.directiveData).toEqual({a: 2});\n      });\n\n      it('should call model.$clone method if it is defined', function () {\n        const clonedData = {a: 2};\n        const data = {a: 1};\n        const model = createModel({data});\n\n        model.directiveData = {\n          $clone: function () {\n            return clonedData;\n          }\n        };\n        $rootScope.$digest();\n\n        expect(model.data).toBe(clonedData);\n      });\n    });\n\n    describe('changing directive model property', function () {\n      it('should not change the model', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n        model.directiveData.a = 2;\n        $rootScope.$digest();\n\n        expect(model.data).toEqual({a: 1});\n        expect(model.directiveData).toEqual({a: 2});\n      });\n    });\n\n    describe('changing model reference', function () {\n      it('should change the directive model accordingly', function () {\n        const data = {a: 1};\n        const model = createModel({data, template: {a: null}});\n        model.data = {a: 2};\n        $rootScope.$digest();\n\n        expect(model.data).toEqual({a: 2});\n        expect(model.directiveData).toEqual({a: 2});\n      });\n    });\n\n    describe('formatter', function () {\n      it('should format the data with provided formatter', function () {\n        const data = {a: 1};\n        const formatter = jasmine.createSpy('formatter').and.returnValue({a: 2});\n        const model = createModel({data, formatter});\n\n        expect(model.data).toEqual({a: 2});\n        expect(model.directiveData).toEqual({a: 2});\n      });\n\n      it('should keep class structure when formatting the data with provided formatter', function () {\n        const data = {a: 1};\n\n        class DemoClass {\n          private a;\n          constructor(data) {\n            this.a = data.a + 1;\n          }\n\n          foobar() {\n            return this.a;\n          }\n        }\n\n        const formatter = {\n          formatter: (model) => new DemoClass(model)\n        };\n\n        spyOn(formatter, 'formatter').and.callThrough();\n\n        const model = createModel({data, formatter: formatter.formatter});\n\n        expect(formatter.formatter).toHaveBeenCalled();\n        expect(model.data).toEqual({a: 2});\n        expect(model.directiveData.foobar()).toEqual(2);\n      });\n\n    });\n\n    describe('parser', function () {\n      it('should parse the model with provided parser', function () {\n        const data = {a: 1};\n        const parser = jasmine.createSpy('parser').and.returnValue({a: 2});\n        const model = createModel({data, parser});\n\n        expect(model.data).toEqual({a: 2});\n        expect(model.directiveData).toEqual({a: 1});\n      });\n    });\n\n    describe('formatter + parser', function () {\n      it('should format and parse the model', function () {\n        const data = {a: 1};\n        const formatter = jasmine.createSpy('formatter').and.returnValue({a: 2});\n        const parser = jasmine.createSpy('parser').and.returnValue({a: 3});\n        const model = createModel({data, formatter, parser});\n\n        expect(model.data).toEqual({a: 3});\n        expect(model.directiveData).toEqual({a: 2});\n      });\n    });\n\n    describe('validator', function () {\n      it('should validate the data with provided validator', function () {\n        const data = {a: 1};\n        const testValidator = jasmine.createSpy('testValidator');\n        const validator = function () {\n          return {\n            testValidator: testValidator\n          };\n        };\n\n        createModel({data, validator});\n\n        expect(testValidator).toHaveBeenCalled();\n      });\n\n      it('should set model to be \"undefined\" if validation fails', function () {\n        const data = {a: 1};\n        const testValidator = jasmine.createSpy('testValidator').and.returnValue(false);\n        const validator = function () {\n          return {\n            testValidator: testValidator\n          };\n        };\n\n        const model = createModel({data, validator});\n\n        expect(model.data).toBeUndefined();\n        expect(model.directiveData).toEqual(data);\n      });\n\n      it('should preserve the model if validation succeeds', function () {\n        const data = {a: 1};\n        const testValidator = jasmine.createSpy('testValidator').and.returnValue(true);\n        const validator = function () {\n          return {\n            testValidator: testValidator\n          };\n        };\n\n        const model = createModel({data, validator});\n\n        expect(model.data).toEqual(data);\n        expect(model.directiveData).toEqual(data);\n      });\n\n      it('should trigger validation after model reference change', function () {\n        const data = {a: 1};\n        const testValidator = jasmine.createSpy('testValidator').and.callFake(function (model) {\n          return model.valid;\n        });\n\n        const validator = function () {\n          return {\n            testValidator: testValidator\n          };\n        };\n\n        const model = createModel({data, validator});\n        model.directiveData = {a: 1};\n        $rootScope.$digest();\n\n        expect(model.data).toBeUndefined();\n        expect(model.directiveData).toEqual({a: 1});\n      });\n    });\n\n    describe('asyncValidator', function () {\n      it('should validate the data with provided validator', function (done) {\n        const data = {a: 1};\n        const deferred = $q.defer();\n        const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise);\n        const asyncValidator = () => ({testValidator});\n\n        createModel({data, asyncValidator});\n        deferred.resolve(true);\n        deferred.promise.finally(() => {\n          expect(testValidator).toHaveBeenCalled();\n          done();\n        });\n        $rootScope.$apply();\n      });\n\n      it('should set model to be \"undefined\" if validation fails', function (done) {\n        const data = {a: 1};\n        const deferred = $q.defer();\n\n        const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise);\n        const asyncValidator = () => ({testValidator});\n\n        const model = createModel({data, asyncValidator});\n\n        deferred.reject();\n        $rootScope.$digest();\n\n        deferred.promise.finally(() => {\n          expect(model.data).toBeUndefined();\n          expect(model.directiveData).toEqual(data);\n          done();\n        });\n        $rootScope.$digest();\n      });\n\n      it('should preserve the model if validation succeeds', function (done) {\n        const data = {a: 1};\n        const deferred = $q.defer();\n\n        const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise);\n        const asyncValidator = () => ({testValidator});\n\n        const model = createModel({data, asyncValidator});\n        deferred.resolve();\n        $rootScope.$digest();\n\n        deferred.promise.finally(() => {\n          expect(model.data).toEqual(data);\n          expect(model.directiveData).toEqual(data);\n          done();\n        });\n        $rootScope.$digest();\n      });\n\n      it('should trigger validation after model reference change', function (done) {\n        const data = {a: 1};\n        const deferred = $q.defer();\n\n        const testValidator = jasmine.createSpy('testValidator').and.returnValue(deferred.promise);\n\n        const asyncValidator = () => ({testValidator});\n        const model = createModel({data, asyncValidator});\n\n        deferred.reject();\n        $rootScope.$digest();\n\n        model.directiveData = {a: 1};\n        $rootScope.$digest();\n\n        deferred.promise.finally(() => {\n          expect(testValidator.calls.count()).toEqual(3);\n          expect(model.data).toBeUndefined();\n          expect(model.directiveData).toEqual({a: 1});\n          done();\n        });\n        $rootScope.$digest();\n      });\n    });\n\n    describe('watcher', function () {\n      it('should run when the model is created', function () {\n        const data = {a: 1};\n        const watcher = jasmine.createSpy('testWatcher');\n\n        createModel({data, watcher});\n\n        expect(watcher).toHaveBeenCalledWith(data, data);\n      });\n\n      it('should run the watcher every time the model reference changes', function () {\n        const data = {a: 1};\n        const watcher = jasmine.createSpy('testWatcher');\n\n        const model = createModel({data, watcher});\n\n        model.directiveData = {a: 1};\n        $rootScope.$digest();\n        expect(watcher).toHaveBeenCalledWith({a: 1}, {a: 1});\n      });\n    });\n\n    describe('renderer', function () {\n      it('should run when the model is created', function () {\n        const data = {a: 1};\n        const renderer = jasmine.createSpy('testRenderer');\n\n        createModel({data, renderer});\n\n        expect(renderer).toHaveBeenCalledWith(data);\n      });\n    });\n\n    describe('unique id', function () {\n      it('should assign unique id to array items (no template)', function () {\n        const data = {a: [{}]};\n\n        const model = createModel({data});\n\n        expect(model.data.a[0].$id).toBeDefined();\n      });\n\n      it('should assign unique id to the model (with template)', function () {\n        const data = {a: [{}]};\n        const template = {a: []};\n\n        const model = createModel({data, template});\n\n        expect(model.data.a[0].$id).toBeDefined();\n      });\n\n      it('should ingore primitive values', function () {\n        const data = {a: [1]};\n\n        const model = createModel({data});\n\n        expect(model.data.a[0]).toBe(1);\n      });\n\n      it('should ingore null values', function () {\n        const data = {a: [null]};\n\n        const model = createModel({data});\n\n        expect(model.data.a[0]).toBe(null);\n      });\n\n      it('should preserve the original id and reference', function () {\n        const data = {$id: 1};\n        const model = createModel({data});\n\n        model.directiveData = {a: 2};\n\n        $rootScope.$digest();\n\n        expect(model.data).toBe(data);\n        expect(model.data).toEqual({$id: 1, a: 2});\n      });\n\n      it('should not preserve the original reference (no id)', function () {\n        const data = {};\n\n        const model = createModel({data});\n        model.directiveData = {a: 2};\n\n        $rootScope.$digest();\n\n        expect(model.data).not.toBe(data);\n        expect(model.data).toEqual({a: 2});\n      });\n\n      it('should not preserve the original reference (id + keepReference === false)', function () {\n        const data = {$id: 1};\n\n        const model = createModel({data, keepReference: false});\n        model.directiveData = {a: 2};\n\n        $rootScope.$digest();\n\n        expect(model.data).not.toBe(data);\n        expect(model.data).toEqual({a: 2});\n      });\n    });\n\n    describe('watchDeep', function () {\n      it('should deep watch the model', function () {\n        const data = {a: 1};\n        const model = createModel({data, watchDeep: true});\n\n        model.directiveData.a = 2;\n        $rootScope.$digest();\n\n        expect(model.data).toEqual({a: 2});\n      });\n\n      it('should not deep watch the model', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n\n        model.directiveData.a = 2;\n        $rootScope.$digest();\n\n        expect(data).toEqual({a: 1});\n      });\n    });\n\n    describe('call then function', function () {\n      it('should call function in an async manner', function (done) {\n        const then = function () {\n          done();\n        };\n        const data = {a: 1};\n        createModel({data, then});\n        $rootScope.$digest();\n      });\n    });\n\n    describe('pristine state', function () {\n      it('should leave ngModel in pristine state on initial change', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n        $rootScope.$digest();\n\n        expect(model.ngModel.$dirty).toBe(false);\n      });\n\n      it('should not set ngModel to pristine state after making changes', function () {\n        const data = {a: 1};\n        const model = createModel({data});\n        $rootScope.$digest();\n\n        model.directiveData = {a: 2};\n        $rootScope.$digest();\n\n        expect(model.ngModel.$dirty).toBe(true);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/srv/ng-model/ng-model.ts",
    "content": "'use strict';\n\n/**\n * Core directive tools\n *\n * @author Our One Creator Which Flies and is Spaghetti and a Monster\n */\n\nimport {lodash as _} from '../../../utils';\n\nexport interface OptionalCloneable<T> {\n  $clone?(): T;\n}\n\nexport interface IScope<T> extends angular.IScope {\n  model: T;\n}\n\nconst tools = {\n  createItem(item: any = {}) {\n    if (!_.isPlainObject(item)) {\n      return item;\n    }\n\n    item.$id = item.$id || _.uniqueId('model');\n\n    return item;\n  },\n\n  defaultsDeep(data, defaults) {\n    let res;\n\n    if (typeof defaults === 'undefined') {\n      return data;\n    }  if (_.isArray(defaults) || _.isArray(data)) {\n      res = _.isArray(data) ? data : defaults;\n      res = res.map(item => this.createItem(_.cloneDeep(item)));\n    } else if (_.isPlainObject(defaults)) {\n      res = _.defaults({}, data, defaults);\n\n      _.forOwn(res, (value, key) => {\n        res[key] = this.defaultsDeep(value, defaults[key]);\n      });\n    } else {\n      res = typeof data !== 'undefined' ? data : defaults;\n    }\n\n    return res;\n  }\n};\n\nexport class ModelConf {\n  public template;\n  public formatter;\n  public parser;\n  public validator;\n  public validatorAsync;\n  public renderer;\n  public watcher;\n  public doThen;\n\n  public opts = {\n    watchDeep: false,\n    log: false,\n    feedBack: true\n  };\n\n  fromTemplate(template): ModelConf {\n    this.template = template;\n    return this;\n  }\n\n  formatWith(formatter: (model) => any): ModelConf {\n    this.formatter = formatter;\n    return this;\n  }\n\n  parseWith(parser: (model) => any): ModelConf {\n    this.parser = parser;\n    return this;\n  }\n\n  validateWith(validator: () => Object): ModelConf {\n    this.validator = validator;\n    return this;\n  }\n\n  validateAsyncWith(validator: () => Object): ModelConf {\n    this.validatorAsync = validator;\n    return this;\n  }\n\n  renderWith(renderer: (model) => void): ModelConf {\n    this.renderer = renderer;\n    return this;\n  }\n\n  watchWith(watcher: (model, prevModel) => void): ModelConf {\n    this.watcher = watcher;\n    return this;\n  }\n\n  watchDeep(val: boolean): ModelConf {\n    this.opts.watchDeep = val;\n    return this;\n  }\n\n  feedBack(val: boolean): ModelConf {\n    this.opts.feedBack = val;\n    return this;\n  }\n\n  log(): ModelConf {\n    this.opts.log = true;\n    return this;\n  }\n\n  then(doThen: Function): ModelConf {\n    this.doThen = doThen;\n    return this;\n  }\n}\n\nexport class Model<T extends OptionalCloneable<T>> {\n  private feedBack = false;\n\n  constructor(private readonly scope: IScope<T>, private readonly ngModel: angular.INgModelController, private readonly conf: ModelConf) {\n    this.initFormat();\n\n    this.initRender(_.once(() => {\n      this.initWatch();\n      this.initParse();\n      this.initValidate();\n      if (_.isFunction(conf.doThen)) {\n        conf.doThen();\n      }\n    }));\n  }\n\n  private initFormat() {\n    this.ngModel.$formatters.push(model => {\n      if (this.conf.opts.log) {\n        // tslint:disable-next-line: no-console\n        console.log('Formatting from', model);\n      }\n\n      let res = tools.defaultsDeep(model, this.conf.template || model);\n\n      res = this.conf.formatter ? this.conf.formatter(model) : model;\n\n      if (this.conf.opts.log) {\n        // tslint:disable-next-line: no-console\n        console.log('Formatted to', res);\n      }\n\n      return res;\n    });\n  }\n\n  private initRender(then) {\n    this.ngModel.$render = () => {\n      this.scope.model = this.ngModel.$viewValue;\n\n      if (this.conf.renderer) {\n        this.conf.renderer(this.scope.model);\n      }\n\n      if (this.conf.opts.log) {\n        // tslint:disable-next-line: no-console\n        console.log('Rendering', this.scope.model);\n      }\n\n      this.feedBack = false;\n\n      then();\n    };\n  }\n\n  private initWatch() {\n    let isFirst = true;\n\n    this.scope.$watch('model', (model, prevModel) => {\n      const data = this.scope.model && this.scope.model.$clone ? this.scope.model.$clone() : _.clone(this.scope.model);\n\n      if (this.conf.opts.log) {\n        // tslint:disable-next-line: no-console\n        console.log('Watching', this.scope.model, data, {isFirst, feedBack: this.feedBack});\n      }\n\n\n      if (this.feedBack || (isFirst && this.conf.opts.feedBack)) {\n        this.ngModel.$setViewValue(data);\n      }\n\n      if (isFirst) {\n        this.ngModel.$setPristine();\n      }\n\n      if (this.conf.watcher) {\n        this.conf.watcher(model, prevModel);\n      }\n\n      isFirst = false;\n      this.feedBack = true;\n    }, !!this.conf.opts.watchDeep);\n  }\n\n  private initParse() {\n    this.ngModel.$parsers.push(model => {\n      if (this.conf.opts.log) {\n        // tslint:disable-next-line: no-console\n        console.log('Parsing from', model);\n      }\n\n      const res = this.conf.parser ? this.conf.parser(model) : model;\n\n      if (this.conf.opts.log) {\n        // tslint:disable-next-line: no-console\n        console.log('Parsed', res);\n      }\n\n      return res;\n    });\n  }\n\n  private initValidate() {\n    if (this.conf.validator) {\n      _.forOwn(this.conf.validator(), (fn, name) => {\n        this.ngModel.$validators[name] = fn;\n      });\n    }\n\n    if (this.conf.validatorAsync) {\n      _.forOwn(this.conf.validatorAsync(), (fn, name) => {\n        this.ngModel.$asyncValidators[name] = fn;\n      });\n    }\n  }\n}\n\nexport function create<T>(scope: IScope<T>, ngModel: angular.INgModelController): ModelConf {\n  const conf = new ModelConf();\n  // tslint:disable-next-line: no-unused-expression-chai\n  new Model(scope, ngModel, conf);\n\n  return conf;\n}\n\nexport const createItem = tools.createItem;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/srv/scope/index.ts",
    "content": "export {init, ScopeHelper} from './scope';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/srv/scope/scope.test.ts",
    "content": "'use strict';\nimport {ViewModel} from '../../../srv/view-model/view-model';\nimport {init as initScope} from './scope';\nimport * as angular from 'angular';\n\ndescribe('Scope: scopeHelper', function () {\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  let $rootScope, $location, $browser, $q, $timeout;\n\n  beforeEach(inject(function (_$rootScope_, _$location_, _$browser_, _$q_, _$timeout_) {\n    $rootScope = _$rootScope_;\n    $location = _$location_;\n    $browser = _$browser_;\n    $q = _$q_;\n    $timeout = _$timeout_;\n  }));\n\n  describe('withEvents()', function () {\n    it('should define actions on scope for read and edit modes', function () {\n      const scope: any = {};\n      const events = {onClick: angular.noop};\n\n      initScope(scope).withEvents(events);\n\n      expect(scope.events.onClick).toBe(events.onClick);\n    });\n  });\n\n  describe('withEditableEvents()', function () {\n    it('should define actions on scope for edit mode only', function () {\n      const scope: any = {};\n      const events = {onClick: angular.noop};\n\n      initScope(scope).readonly(true).withEditableEvents(events);\n\n      expect(scope.events.onClick).toBeUndefined();\n    });\n  });\n\n  describe('events', function () {\n    it('should set both event types', function () {\n      const scope: any = {};\n\n      initScope(scope)\n        .withEvents({onSelect: angular.noop})\n        .withEditableEvents({onClick: angular.noop});\n\n      expect(scope.events.onSelect).toBeDefined();\n      expect(scope.events.onClick).toBeDefined();\n    });\n  });\n\n  describe('withActions()', function () {\n    it('should define actions on scope for read and edit modes', function () {\n      const scope: any = {};\n      const actions = {toggle: angular.noop};\n\n      initScope(scope).withActions(actions);\n\n      expect(scope.actions.toggle).toBe(actions.toggle);\n    });\n  });\n\n  describe('withEditableActions()', function () {\n    it('should define actions for edit mode only', function () {\n      const scope: any = {};\n      const actions = {toggle: angular.noop};\n\n      initScope(scope).readonly(true).withEditableActions(actions);\n\n      expect(scope.actions.toggle).toBeUndefined();\n    });\n  });\n\n  describe('actions', function () {\n    it('should set both action types', function () {\n      const scope: any = {};\n\n      initScope(scope)\n        .withActions({select: angular.noop})\n        .withEditableActions({click: angular.noop});\n\n      expect(scope.actions.select).toBeDefined();\n      expect(scope.actions.click).toBeDefined();\n    });\n  });\n\n  describe('withVM()', function () {\n    it('should define vm object on scope', function () {\n      const scope: any = {};\n\n      initScope(scope).withVM({test: true});\n\n      expect(scope.vm.test).toBe(true);\n    });\n\n    it('should persist the vm by assigning it to the $vm scope variable', function () {\n      const scope: any = {};\n\n      initScope(scope).withVM({test: true});\n\n      expect(scope.vm.test).toBe(true);\n      expect(scope.$vm.test).toBe(true);\n    });\n\n    it('should use and init the scope.$vm view model', function () {\n      const scope: any = {\n        $vm: {\n          init: jasmine.createSpy('scope.$vm.init')\n        }\n      };\n\n      initScope(scope).withVM({});\n\n      expect(scope.vm).toBe(scope.$vm);\n      expect(scope.$vm.init).toHaveBeenCalled();\n    });\n\n    it('should define model as custom VM param', function () {\n      const scope: any = {\n        model: {}\n      };\n\n      initScope(scope).withVM({});\n\n      expect(scope.vm.$params.model).toBe(scope.model);\n    });\n\n    it('should define ngModel.$modelValue and ngModel.$viewValue as custom VM param', function () {\n      const scope: any = {};\n      const ngModel = {\n        $modelValue: {},\n        $viewValue: {}\n      };\n\n      initScope(scope, {ngModel}).withVM({});\n\n      expect(scope.vm.$params.modelValue).toBe(ngModel.$modelValue);\n      expect(scope.vm.$params.viewValue).toBe(ngModel.$viewValue);\n    });\n\n    it('should define custom VM params', function () {\n      const scope: any = {};\n      const params = {\n        foo: 1,\n        goo: 2\n      };\n\n      initScope(scope).withVM({}, params);\n\n      expect(scope.vm.$params.foo).toBe(1);\n      expect(scope.vm.$params.goo).toBe(2);\n    });\n\n    it('should throw errors when using ngModel.$modelValue and ngModel.$viewValue if ngModel controller was not passed', function () {\n      const scope: any = {};\n\n      initScope(scope).withVM({});\n\n      expect(function () {\n        return scope.vm.$params.modelValue;\n      }).toThrow('scopeHelper: ngModel controller is required when accesing vm.$params.modelValue');\n\n      expect(function () {\n        return scope.vm.$params.viewValue;\n      }).toThrow('scopeHelper: ngModel controller is required when accesing vm.$params.viewValue');\n    });\n  });\n\n  describe('withErrors()', function () {\n    it('should set messages on the errors controller', function () {\n      const scope: any = {};\n      const errors = {\n        setMessages: jasmine.createSpy('controllers.errors')\n      };\n      const messages = [{\n        name: 'required',\n        text: 'Value is required'\n      }];\n\n      initScope(scope, {errors}).withErrors(messages);\n\n      expect(errors.setMessages).toHaveBeenCalledWith(messages);\n    });\n  });\n\n  describe('readonly()', function () {\n    it('should not set events and actions in readonly mode', function () {\n      const scope: any = {};\n\n      initScope(scope).readonly(true)\n        .withEditableEvents({foo: angular.noop})\n        .withEditableActions({foo: angular.noop});\n\n      expect(scope.events.foo).toBeUndefined();\n      expect(scope.actions.foo).toBeUndefined();\n    });\n  });\n\n  describe('thenIfNotReadonly()', function () {\n    it('should run when not readonly', function () {\n      const scope: any = {};\n      const fn = jasmine.createSpy('not readonly');\n\n      initScope(scope)\n        .thenIfNotReadonly(fn);\n\n      expect(fn).toHaveBeenCalled();\n    });\n\n    it('should not run when readonly', function () {\n      const scope: any = {};\n      const fn = jasmine.createSpy('not readonly');\n\n      initScope(scope)\n        .readonly(true)\n        .thenIfNotReadonly(fn);\n\n      expect(fn).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('withOptions()', function () {\n    it('should set default options when no options where passed', function () {\n      const scope: any = {\n        testOptions: undefined\n      };\n\n      initScope(scope)\n        .withOptions(scope.testOptions, {\n          opt1: true\n        });\n\n      expect(scope.options).toEqual({\n        opt1: true\n      });\n    });\n\n    it('should set default options when options where passed', function () {\n      const scope: any = {\n        testOptions: {\n          opt1: true\n        }\n      };\n\n      initScope(scope)\n        .withOptions(scope.testOptions, {\n          opt2: true\n        });\n\n      expect(scope.options).toEqual({\n        opt1: true,\n        opt2: true\n      });\n    });\n\n    it('should support string as object name', function () {\n      const scope: any = {\n        testOptions: {\n          opt1: true\n        }\n      };\n\n      initScope(scope)\n        .withOptions('testOptions', {\n          opt2: true\n        });\n\n      expect(scope.options).toEqual({\n        opt1: true,\n        opt2: true\n      });\n    });\n\n    it('should deep watch options and update scope.options', function () {\n      const scope = $rootScope.$new();\n\n      scope.testOptions = {\n        opt1: true\n      };\n\n      initScope(scope)\n        .withOptions('testOptions', {\n          opt1: true\n        }, true);\n\n      scope.testOptions.opt1 = false;\n      $rootScope.$digest();\n\n      expect(scope.options).toEqual({\n        opt1: false\n      });\n    });\n\n    it('should deep watch options and call handler when no options where passed', function () {\n      const scope = $rootScope.$new();\n      const handler = jasmine.createSpy('watch handler');\n\n      scope.testOptions = undefined;\n\n      initScope(scope)\n        .withOptions('testOptions', {\n          opt1: true\n        }, handler);\n\n      $rootScope.$digest();\n\n      expect(handler).toHaveBeenCalledWith({\n        opt1: true\n      }, undefined);\n    });\n\n    it('should deep watch options and call handler', function () {\n      const scope = $rootScope.$new();\n      const handler = jasmine.createSpy('watch handler');\n\n      scope.testOptions = {\n        opt1: true\n      };\n\n      initScope(scope)\n        .withOptions('testOptions', {\n          opt1: true\n        }, handler);\n\n      $rootScope.$digest();\n\n      scope.testOptions = {\n        opt1: false\n      };\n\n      $rootScope.$digest();\n\n      expect(handler).toHaveBeenCalledWith({\n        opt1: false\n      }, {\n        opt1: true\n      });\n    });\n  });\n\n  describe('withState', function () {\n\n    let scope;\n    function updateURL(url) {\n      $location.url(url);\n      $browser.poll();\n    }\n\n    beforeEach(() => {\n      window.localStorage.clear();\n    });\n\n    beforeEach(function () {\n      scope = $rootScope.$new();\n      scope.vm = new ViewModel({\n        a: '1',\n        b: '2',\n        c: '3',\n        nestedObj: {\n          d: '4',\n          $export: function () {\n            return {d: this.d};\n          },\n          $import: function (params) {\n            this.d = params.d;\n          }\n        },\n        $export: function () {\n          return {a: this.a, b: this.b};\n        },\n        $import: function (params) {\n          this.a = params.a; this.b = params.b;\n        }\n      });\n    });\n\n    it('should save and load variables from localStorage', function () {\n      const expectedData = {\n        a: '1',\n        b: '2',\n        c: '100',\n        nestedObj: jasmine.objectContaining({\n          d: '4'\n        })\n      };\n\n      initScope(scope).withState('testState', 'testClient', {doClientLoad: false});\n\n      scope.state.save();\n      ['a', 'b', 'c'].forEach(field => scope.vm[field] = '100');\n      scope.vm.nestedObj.d = 100;\n      scope.state.load();\n      expect(scope.vm).toEqual(jasmine.objectContaining(expectedData));\n    });\n\n    it('should load variables from URL', function () {\n      updateURL('/loc1?testState-data=testClient-a:2;');\n\n      initScope(scope).withState('testState', 'testClient', {doClientLoad: true});\n      expect(scope.vm.a).toEqual('2');\n    });\n\n    it('should handle doClientLoad passed as a promise', function (done) {\n      const deferred = $q.defer();\n\n      updateURL('/loc1?testState-data=testClient-a:2;');\n      initScope(scope).withState('testState', 'testClient', {doClientLoad: deferred.promise});\n      expect(scope.vm.a).toEqual('1');\n      deferred.resolve(true);\n      scope.$apply();\n      setTimeout(() => {\n        expect(scope.vm.a).toEqual('2');\n        done();\n      });\n    });\n\n    it('should accept state from parent scope', function () {\n      const scope2 = scope.$new();\n      scope.vm = new ViewModel({\n        a: '1',\n        $export: function() {\n          return {a: this.a};\n        },\n        $import: function(params) {\n          this.a = params.a;\n        }\n      });\n      scope2.vm = new ViewModel({\n        $export: function() {\n          return {b: this.b};\n        },\n        $import: function(params) {\n          this.b = params.b;\n        },\n        b: '2'\n      });\n      initScope(scope).withState('testState', 'testClient1', {doClientLoad: false});\n      initScope(scope2).withState(scope.state, 'testClient2', {doClientLoad: false});\n      scope.state.save('testClient2');\n      scope2.vm.b = '3';\n      scope2.state.load();\n      expect(scope2.vm.b).toEqual('2');\n    });\n\n    it('should unregister on scope destroy', function () {\n      scope.vm = {a: '1'};\n      initScope(scope).withState('testState', 'testClient', {doClientLoad: false});\n      spyOn(scope.state, 'unregister');\n      scope.$destroy();\n      expect(scope.state.unregister).toHaveBeenCalled();\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/ang/srv/scope/scope.ts",
    "content": "'use strict';\nimport {ViewModel} from '../../../srv/view-model/view-model';\nimport {StateWrapper, StateWrapperOptions} from '../../../srv/state/state-wrapper';\n\nimport {lodash as _} from '../../../utils';\n\nexport class ScopeHelper {\n  private _readonly = false;\n\n  constructor(private readonly scope, private readonly controllers = {ngModel: null, errors: null}) {\n    scope.events = {};\n    scope.actions = {};\n  }\n\n  readonly(readonly) {\n    this._readonly = readonly;\n\n    return this;\n  }\n\n  withEvents(events = {}) {\n    _.assign(this.scope.events, events);\n\n    return this;\n  }\n\n  withEditableEvents(events = {}) {\n    if (!this._readonly) {\n      _.assign(this.scope.events, events);\n    }\n\n    return this;\n  }\n\n  withPermissionEvents<T extends {[eventName: string]: Function}>(events: T, permissions: (eventName: keyof T) => boolean) {\n    events = _.reduce(events, (res, fn, name) => {\n      if (permissions(name)) {\n        res[name] = fn;\n      }\n\n      return res;\n    }, {});\n\n    this.withEvents(events);\n\n    return this;\n  }\n\n  withActions(actions = {}) {\n    _.assign(this.scope.actions, actions);\n\n    return this;\n  }\n\n  withEditableActions(actions = {}) {\n    if (!this._readonly) {\n      _.assign(this.scope.actions, actions);\n    }\n\n    return this;\n  }\n\n  withVM(vm, params = {}) {\n\n    if (this.scope.$vm) {\n      vm = this.scope.$vm;\n    } else {\n      vm = _.isFunction(vm) ? new vm() : new ViewModel(vm);\n    }\n\n    const {scope, controllers} = this; /* clousre var for getters on the VM */\n\n\n    Object.defineProperty(params, 'model', {\n      get() {\n        return scope.model;\n      }\n    });\n\n    Object.defineProperty(params, 'modelValue', {\n      get() {\n        if (!controllers.ngModel) {\n          throw new Error('scopeHelper: ngModel controller is required when accesing vm.$params.modelValue');\n        }\n\n        return controllers.ngModel.$modelValue;\n      }\n    });\n\n    Object.defineProperty(params, 'viewValue', {\n      get() {\n        if (!controllers.ngModel) {\n          throw new Error('scopeHelper: ngModel controller is required when accesing vm.$params.viewValue');\n        }\n\n        return controllers.ngModel.$viewValue;\n      }\n    });\n\n\n    vm.init(params);\n\n    this.scope.vm = this.scope.$vm = vm;\n\n    return this;\n  }\n\n  withErrors(messages: any[]) {\n    if (this.controllers.errors) {\n      this.controllers.errors.setMessages(messages);\n    }\n\n    return this;\n  }\n\n  withOptions(options, defaults, watch?: any) {\n    this.scope.options = _.defaults({}, typeof options === 'string' ? this.scope[options] : options, defaults);\n\n    if (watch && typeof options === 'string') {\n      this.scope.$watch(options, (opts, prevOptions) => {\n        this.scope.options = _.defaults({}, opts, defaults);\n\n        if (typeof watch === 'function') {\n          watch(this.scope.options, prevOptions);\n        }\n      }, true);\n    }\n\n    return this;\n  }\n\n  withState(state: StateWrapper | string, clientName, options: StateWrapperOptions) {\n    if (!state || !this.scope.vm) {\n      return this;\n    }\n\n    const builder = StateWrapper.build()\n      .withOptions(options)\n      .withCustomTraverse(function (vm: ViewModel, callback, args) {\n        vm.forEach(function (model) {\n          callback(model, args);\n        });\n      }).setClientName(clientName)\n      .useObject(this.scope.vm);\n\n    if (typeof state === 'string') {\n      builder.withNewState(state);\n    } else {\n      builder.withState(state);\n    }\n\n    this.scope.state = builder.end();\n\n    this.scope.$on('$destroy', () => {\n      this.scope.state.unregister();\n    });\n\n    return this;\n  }\n\n  thenIfNotReadonly(fn) {\n    if (!this._readonly) {\n      fn();\n    }\n\n    return this;\n  }\n}\n\nexport function init(scope, {ngModel = null, errors = null} = {}) {\n  return new ScopeHelper(scope, {ngModel, errors});\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/config/index.ts",
    "content": "export class Config<T> {\n  private options: Partial<T> = {};\n\n  get() {\n    return this.options;\n  }\n\n  set(options: Partial<T>) {\n    this.options = {...this.options as any, ...options as any};\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/index.ts",
    "content": "/* This file is the bundle entry point */\nimport {Socket} from './srv/socket/socket';\nimport {BufferedCollection, Collection, PartitionedCollection} from './srv/collections';\nimport {EventEmitter} from './srv/event-emitter';\nimport {injector} from './srv/injector';\nimport {init} from './ang/srv/scope';\nimport {create, IScope as IScope_, Model} from './ang/srv/ng-model/ng-model';\nimport {create as createVM, ViewModel as ViewModel_} from './srv/view-model/view-model';\nimport * as biUtils from './utils';\n\nimport './main.angular';\n\nexport const utils = biUtils;\nexport const srv = {\n  collections: {BufferedCollection, Collection, PartitionedCollection},\n  Model,\n  Socket,\n  eventEmitter: {\n    EventEmitter\n  },\n  viewModel: {\n    ViewModel: ViewModel_\n  },\n  injector\n};\nexport const initNgScope = init;\nexport const createNgModel = create;\nexport const inject = injector.get;\nexport const createViewModel = createVM;\nexport type IScope<T> = IScope_<T>;\nexport {Config} from './config';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/main.angular.ts",
    "content": "import * as angular from 'angular';\nimport {biOptions} from './ang/drv/bi-options.drv';\nimport {default as biValidator} from './ang/drv/bi-validator.drv';\nimport {LocalStorage} from './srv/local-storage/local-storage';\n\nangular.module('bi.core', [])\n  .run(['$injector', ($injector: angular.auto.IInjectorService) => {\n    window.dispatchEvent(new CustomEvent('biCore.injector.ready', {detail: $injector}));\n  }])\n  .provider('biLocalStorage', () => {\n    return {\n      setPrefix(name) {\n        LocalStorage.setPrefix(name);\n      },\n      $get() {\n        return new LocalStorage();\n      }\n    };\n  });\n\nif ((window as any).__biCoreLoaded) {\n  console.warn('warning: multiple bi-core instances.');\n} else {\n  (window as any).__biCoreLoaded = true;\n}\n\nangular.module('bi.core')\n  .directive('biOptions', biOptions)\n  .directive('biValidator', biValidator);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/buffered-collection.test.ts",
    "content": "import {Model} from '../../ang/srv/ng-model/ng-model';\nimport {BufferedCollection} from './buffered-collection';\nimport * as angular from 'angular';\n\ndescribe('Collection: BufferedCollection', function () {\n  let $rootScope;\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$rootScope_) {\n    $rootScope = _$rootScope_;\n  }));\n\n  function createCollection(chunkSize?) {\n    const collection = new BufferedCollection();\n    collection.setChunkSize(chunkSize);\n\n    return collection;\n  }\n\n  describe('Collection creation', function () {\n    it('should create an empty collection', function () {\n      const collection = createCollection();\n\n      expect(collection).toBeDefined();\n      expect(collection.models.length).toBe(0);\n    });\n  });\n\n  describe('fetch()', function () {\n    it('should resolve after the next chunk of models is received', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2]);\n\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(2);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}]);\n    });\n\n    it('should populate models with next chunk only', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2, 3, 4]);\n\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(2);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}]);\n    });\n\n    it('should reset the buffer and models', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2, 3, 4]);\n      $rootScope.$digest();\n\n      collection.fetch();\n      collection.feed([10, 20]);\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(2);\n      expect(collection.models).toEqual([{data: 10}, {data: 20}]);\n    });\n\n    it('should note be sealed', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2, 3, 4]);\n      collection.seal();\n      $rootScope.$digest();\n\n      collection.fetch();\n      collection.feed([10, 20]);\n      $rootScope.$digest();\n\n      expect(collection.isSealed()).toBe(false);\n    });\n\n    it('should be resolved with self', function () {\n      const collection = createCollection(2);\n      const promise = collection.fetch();\n      const spy = jasmine.createSpy('then callback');\n\n      collection.feed([1, 2]);\n\n      collection.promise.then(spy);\n      promise.then(spy);\n\n      $rootScope.$digest();\n\n      expect(spy.calls.allArgs()).toEqual([[collection], [collection]]);\n    });\n  });\n\n  describe('feed()', function () {\n    it('should support one-at-a-time feed', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed(1);\n      collection.feed(2);\n\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(2);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}]);\n    });\n\n    it('should not populate models with next chunk when called subsequently', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2]);\n      $rootScope.$digest();\n\n      collection.feed([3, 4]);\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(2);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}]);\n    });\n  });\n\n  describe('more()', function () {\n    it('should populate models with the next chunk if it is available', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2, 3, 4]);\n      $rootScope.$digest();\n\n      collection.more();\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(4);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}, {data: 3}, {data: 4}]);\n    });\n\n    it('should populate models with the next chunk after it is fed', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2]);\n      $rootScope.$digest();\n\n      collection.more();\n      collection.feed([3, 4]);\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(4);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}, {data: 3}, {data: 4}]);\n    });\n\n    it('should note ignore consequent calls', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2]);\n      $rootScope.$digest();\n\n      collection.feed([3, 4, 5, 6]);\n      collection.more();\n      $rootScope.$digest();\n      collection.more();\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(6);\n      expect(collection.models).toEqual([{data: 1}, {data: 2}, {data: 3}, {data: 4}, {data: 5}, {data: 6}]);\n    });\n\n    it('should be resolved with self', function () {\n      const collection = createCollection(2);\n      const spy = jasmine.createSpy('then callback');\n\n      collection.fetch();\n      collection.feed([1, 2, 3, 4]);\n      $rootScope.$digest();\n\n      const promise = collection.more();\n      collection.promise.then(spy);\n      promise.then(spy);\n\n      $rootScope.$digest();\n\n      expect(spy.calls.allArgs()).toEqual([[collection], [collection]]);\n    });\n  });\n\n  describe('hasMore()', function () {\n    it('should be false by default', function () {\n      const collection = createCollection(2);\n\n      expect(collection.hasMore()).toBe(false);\n    });\n\n    it('should be true if buffered is bigger than the models', function () {\n      const collection = createCollection(2);\n      collection.feed(1);\n\n      expect(collection.hasMore()).toBe(true);\n    });\n  });\n\n  describe('seal()', function () {\n    it('should populate models if there only one chunk', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed(1);\n      $rootScope.$digest();\n\n      collection.seal();\n      $rootScope.$digest();\n\n      expect(collection.size()).toBe(1);\n      expect(collection.models).toEqual([{data: 1}]);\n    });\n  });\n\n  describe('isSealed()', function () {\n    it('should return false if the collection isnt sealed', function () {\n      const collection = createCollection(2);\n\n      expect(collection.isSealed()).toBe(false);\n    });\n\n    it('should return true when the collection is sealed', function () {\n      const collection = createCollection(2);\n      collection.seal();\n\n      expect(collection.isSealed()).toBe(true);\n    });\n  });\n\n  describe('bufferSize()', function () {\n    it('should return the buffer array length', function () {\n      const collection = createCollection(2);\n      collection.feed([1, 2, 3]);\n\n      expect(collection.bufferSize()).toBe(3);\n    });\n  });\n\n  describe('buffer', function () {\n    it('should return the buffer array', function () {\n      const collection = createCollection(2);\n      collection.feed([1, 2, 3]);\n\n      expect(collection.buffer).toEqual([1, 2, 3]);\n    });\n  });\n\n  describe('rewind()', function () {\n    it('should reset the models array', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1, 2, 3]);\n      $rootScope.$digest();\n\n      collection.rewind();\n\n      expect(collection.size()).toBe(0);\n    });\n  });\n\n  describe('flush()', function () {\n    it('should flush the buffer into the models array', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n      collection.feed([1]);\n      $rootScope.$digest();\n\n      collection.flush();\n      $rootScope.$digest();\n\n      expect(collection.models).toEqual([{data: 1}]);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/buffered-collection.ts",
    "content": "'use strict';\nimport {PartitionedCollection} from './partitioned-collection';\nimport {injector} from '../injector';\nimport {IBaseModel, Model} from '../model/model';\nimport {ModelCtor} from './collection';\nconst inject = injector.get;\n\nexport class BufferedCollection<T extends IBaseModel = any>  extends PartitionedCollection<T> {\n  _buffer: T[] | Model<T>[] = [];\n  _hasMore = true;\n  _isSealed = false;\n  _deferred;\n\n  constructor(Mdl?: ModelCtor<T>) {\n    super(Mdl);\n  }\n\n  // PRIVATE\n  _getAction() {\n    return () => {\n      const deferred = inject('$q').defer();\n      deferred.$promise = deferred.promise;\n\n      return deferred;\n    };\n  }\n\n  _startRequestHook(deferred) {\n    this._deferred = deferred;\n  }\n\n  _finishRequestHook(models) {\n    this._deferred = null;\n\n    return models;\n  }\n\n  _getNextChunk() {\n    const offset = this.size();\n\n    return this._buffer.slice(offset, offset + this._chunkSize);\n  }\n\n  _resolveNextChunk() {\n    this._deferred.resolve(this._getNextChunk());\n  }\n\n  _isNextChunkReady() {\n    return this.bufferSize() - this.size() >= this._chunkSize;\n  }\n\n  _isRequestPending() {\n    return !!this._deferred;\n  }\n\n  // PUBLIC\n  // getters\n  get buffer() {\n    return this._buffer;\n  }\n\n  // methods\n  isSealed() {\n    return this._isSealed;\n  }\n\n  hasMore() {\n    return this._buffer.length - this.models.length > 0;\n  }\n\n  bufferSize() {\n    return this._buffer.length;\n  }\n\n  fetch() {\n    this._buffer = [];\n    this._models = [];\n    this._deferred = null;\n    this._isSealed = false;\n\n    return super.fetch();\n  }\n\n  more() {\n    if (this._isSealed && !this.hasMore()) {\n      return this._resolveAsSelf(inject('$q').when());\n    }  {\n      const promise = this._more();\n\n      if (this.hasMore()) {\n        this._resolveNextChunk();\n      }\n\n      return this._resolveAsSelf(promise);\n    }\n  }\n\n  feed(models: T | Model<T> | T[] | Model<T>[]) {\n    this._buffer.push.apply(this._buffer, models instanceof Array ? models : [models]);\n\n    if (this._isRequestPending() && this._isNextChunkReady()) {\n      this._resolveNextChunk();\n    }\n\n    return this;\n  }\n\n  seal() {\n    this.flush();\n    this._isSealed = true;\n\n    return this;\n  }\n\n  rewind() {\n    this._models = [];\n    return this;\n  }\n\n  flush() {\n    if (this._isRequestPending()) {\n      this._resolveNextChunk();\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/collection.test.ts",
    "content": "import {Model} from '../model/model';\nimport {Collection} from './collection';\nimport * as angular from 'angular';\n\ndescribe('Collection: Collection', function () {\n  let $httpBackend, $resource, TestModel;\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$httpBackend_, _$resource_) {\n    $httpBackend = _$httpBackend_;\n    $resource = _$resource_;\n\n    TestModel = createModelClass();\n  }));\n\n  function createModelClass() {\n    const resource = $resource('/:action', {}, {\n      query: {\n        method: 'GET',\n        isArray: true,\n        params: {\n          action: 'query'\n        }\n      }\n    });\n\n    class TestModel extends Model {\n      constructor(data) {\n        super(data, {\n          id: null\n        });\n\n        this._Resource = resource;\n      }\n\n      static Resource = resource;\n    }\n\n    return TestModel;\n  }\n\n  function createCollection(Model?, action?) {\n    return new Collection(Model, action);\n  }\n\n  function toDataArray(collection) {\n    return (collection.models || collection).map(function (model) {\n      return model.data;\n    });\n  }\n\n  describe('Collection creation', function () {\n    it('should create an empty collection', function () {\n      const collection = createCollection();\n\n      expect(collection).toBeDefined();\n      expect(collection.models.length).toBe(0);\n    });\n  });\n\n  describe('fetch() (GET)', function () {\n    it('should call resource.query and update the models array', function () {\n      const collection = createCollection(TestModel);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query').respond(200, [{id: 1}, {id: 2}]);\n      $httpBackend.flush();\n\n      expect(collection.models.length).toBe(2);\n    });\n\n    it('should call resource.query with provided params', function () {\n      const collection = createCollection(TestModel);\n      collection.fetch({\n        myData: 1\n      });\n\n      $httpBackend.expectGET('/query?myData=1').respond(200, [{id: 1}, {id: 2}]);\n      $httpBackend.flush();\n\n      expect(collection.models.length).toBe(2);\n    });\n\n    it('should transform each item in array into a Model', function () {\n      const collection = createCollection(TestModel);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query').respond(200, [{id: 1}, {id: 2}]);\n      $httpBackend.flush();\n\n      expect(collection.models[0] instanceof TestModel).toBe(true);\n      expect(collection.models[1] instanceof TestModel).toBe(true);\n      expect(collection.models[0].data).toEqual({id: 1});\n      expect(collection.models[1].data).toEqual({id: 2});\n    });\n\n    it('should be resolved with self', function () {\n      const collection = createCollection(TestModel);\n      const promise = collection.fetch();\n      const spy = jasmine.createSpy('then callback');\n\n      promise.then(spy);\n\n      $httpBackend.expectGET('/query').respond(200, []);\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith(collection);\n    });\n\n    it('should throw an exception if action is unsupported', function () {\n      const collection = createCollection(TestModel, 'invalidaction');\n\n      expect(function () {\n        collection.fetch();\n      }).toThrow('Collection: resource is missing definition for \"invalidaction\" action');\n    });\n  });\n\n  describe('resolved', function () {\n    it('should not be resolved until theres a response from server', function () {\n      const collection = createCollection(TestModel);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query').respond(200, []);\n\n      expect(collection.resolved).toBe(false);\n    });\n\n    it('should be resolved after a server response', function () {\n      const collection = createCollection(TestModel);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query').respond(200, []);\n      $httpBackend.flush();\n\n      expect(collection.resolved).toBe(true);\n    });\n  });\n\n  describe('promise', function () {\n    it('should be set to the latest resource.$promise', function () {\n      const collection = createCollection(TestModel);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query').respond(200, []);\n      $httpBackend.flush();\n\n      expect(collection.promise).toBeDefined();\n    });\n\n    it('should be resolved with self', function () {\n      const collection = createCollection(TestModel);\n      const spy = jasmine.createSpy('then callback');\n\n      collection.fetch();\n      collection.promise.then(spy);\n\n      $httpBackend.expectGET('/query').respond(200, []);\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith(collection);\n    });\n  });\n\n  describe('add()', function () {\n    it('should return the added item', function () {\n      const collection = createCollection(TestModel);\n      const item = collection.add({id: 1});\n\n      expect(toDataArray(collection)).toEqual([item.data]);\n      expect(item).toBeDefined();\n      expect(item.id).toBe(1);\n    });\n\n    it('should add multiple items', function () {\n      const collection = createCollection(TestModel);\n      collection.add([{id: 1}, {id: 2}]);\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]);\n    });\n\n    it('should return the added items', function () {\n      const collection = createCollection(TestModel);\n      const items = collection.add([{id: 1}, {id: 2}]);\n\n      expect(items.length).toBe(2);\n      expect(items[0].id).toBe(1);\n      expect(items[1].id).toBe(2);\n    });\n\n    it('should transform added item into Model', function () {\n      const collection = createCollection(TestModel);\n      collection.add({id: 1});\n\n      expect(collection.models[0] instanceof TestModel).toBe(true);\n      expect(collection.models[0].data).toEqual({id: 1});\n    });\n\n    it('should wrap item in object with data property if Model was not provided', function () {\n      const collection = createCollection();\n      collection.add({id: 1});\n\n      expect(collection.models[0]).toEqual({data: {id: 1}});\n    });\n\n    it('should not transform added item into Model if item is already a Model', function () {\n      const collection = createCollection(TestModel);\n      const model = new TestModel({id: 1});\n      collection.add(model);\n\n      expect(collection.models[0]).toBe(model);\n    });\n\n    it('should not transform added item into Model if Model was not provided', function () {\n      const collection = createCollection();\n      const model = {id: 1};\n      collection.add(model);\n\n      expect(collection.models[0].data).toBe(model);\n    });\n  });\n\n  describe('remove()', function () {\n    it('should remove a model and return it', function () {\n      const collection = createCollection(TestModel);\n      const modelToRemove = collection.add({id: 1});\n      const modelToRemain = collection.add({id: 2});\n\n      const removedModel = collection.remove(modelToRemove);\n\n      expect(collection.models).toEqual([modelToRemain]);\n      expect(removedModel).toBe(modelToRemove);\n    });\n  });\n\n  describe('filter()', function () {\n    it('should return all items matching the criteria', function () {\n      const collection = createCollection(TestModel);\n      collection.add({id: 1, status: 'a'});\n      collection.add({id: 2, status: 'a'});\n      collection.add({id: 3, status: 'b'});\n\n      const items = collection.filter('status', 'a');\n\n      expect(toDataArray(items)).toEqual([{id: 1, status: 'a'}, {id: 2, status: 'a'}]);\n    });\n  });\n\n  describe('format()', function () {\n    it('should call model.format() for each mdoel', function () {\n      const collection = createCollection(TestModel);\n      const model = collection.add({id: 1});\n\n      spyOn(model, 'format').and.callThrough();\n\n      const formatted = collection.format();\n\n      expect(model.format).toHaveBeenCalled();\n      expect(formatted).toEqual([{id: 1}]);\n    });\n  });\n\n  describe('has()', function () {\n    it('should return true if the collection has a mdoel with given id', function () {\n      const collection = createCollection(TestModel);\n      collection.add({id: 1});\n\n      expect(collection.has(1)).toBe(true);\n      expect(collection.has(2)).toBe(false);\n    });\n  });\n\n  describe('size()', function () {\n    it('should return the length of the models array', function () {\n      const collection = createCollection(TestModel);\n      collection.add({id: 1});\n\n      expect(collection.size()).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/collection.ts",
    "content": "'use strict';\n\nimport {lodash as _} from '../../utils';\nimport {Model, IBaseModel} from '../model/model';\nexport type ModelCtor<T> = new (...args: any[]) => Model<T>;\nexport class Collection<T extends IBaseModel = any> {\n  _Resource;\n  _Model;\n  _action;\n  _models: (Model<T> | {data: T})[];\n  _resolved;\n  _promise;\n\n  static Model;\n\n  constructor(Mdl?: ModelCtor<T>, action = 'query') {\n    this._Model = Mdl;\n    this._action = action;\n    this._models = [];\n  }\n\n  // PRIVATE\n  // tslint:disable-next-line:no-empty\n  _startRequestHook(deferred) {\n    return deferred;\n   }\n\n  _finishRequestHook(models) {\n    return models;\n  }\n\n  _getAction() {\n    const action = (this._Resource || this._Model.Resource)[this._action];\n\n    if (!action) {\n      // tslint:disable-next-line: restrict-plus-operands\n      throw new Error('Collection: resource is missing definition for \"' + this._action + '\" action');\n    }\n\n    return action;\n  }\n\n  _fetch(params) {\n    const promise = this._startRequest(params);\n    return this._finishRequest(promise);\n  }\n\n  _startRequest(params) {\n    const action = this._getAction();\n    const deferred = action(params);\n\n    this._startRequestHook(deferred);\n    this._resolved = false;\n\n    return deferred.$promise;\n  }\n\n  _finishRequest(promise) {\n    return promise\n      .then(models => this._finishRequestHook(models))\n      .finally(() => this._resolved = true);\n  }\n\n  _setModels(models: T | Model<T> | Model<T>[] | T[]) {\n    this._models = [];\n    this.add(models);\n  }\n\n  _resolveAsSelf(promise) {\n    return (this._promise = promise.then(() => this));\n  }\n\n  // PUBLIC\n  // getters\n  get models() {\n    return this._models;\n  }\n\n  get promise() {\n    return this._promise;\n  }\n\n  get resolved() {\n    return this._resolved;\n  }\n\n  // methods\n  setResource(resource) {\n    this._Resource = resource;\n    return this;\n  }\n\n  size() {\n    return this.models.length;\n  }\n\n  fetch(params?) {\n    return this._resolveAsSelf(this._fetch(params).then(models => this._setModels(models)));\n  }\n\n  add(model: T | Model<T> | Model<T>[] | T[]) {\n    let modelArray: any = (model instanceof Array ? model : [model]);\n\n    if (this._Model) {\n      modelArray = modelArray.map(mdl => mdl instanceof this._Model ? mdl : new this._Model(mdl));\n    } else if (!(model instanceof Model)) {\n      modelArray = modelArray.map(item => ({data: item}));\n    }\n\n    Array.prototype.push.apply(this._models, modelArray);\n\n    return model instanceof Array ? modelArray : modelArray[0];\n  }\n\n  remove(model) {\n    return _.remove(this._models, _model_ => _model_ === model)[0];\n  }\n\n  get(id) {\n    return _.find(this.models, 'id', id);\n  }\n\n  has(id) {\n    return !!this.get(id);\n  }\n\n  filter(what, value) {\n    return _.filter(this.models, model => model.data[what] === value);\n  }\n\n  format() {\n    return this.models.map(model => model instanceof Model ? model.format() : (model as any).data);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/index.ts",
    "content": "export {PartitionedCollection} from './partitioned-collection';\nexport {BufferedCollection} from './buffered-collection';\nexport {Collection} from './collection';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/partitioned-collection.test.ts",
    "content": "'use strict';\nimport {Model} from '../model/model';\nimport {PartitionedCollection} from './partitioned-collection';\nimport * as angular from 'angular';\n\ndescribe('Collection: PartitionedCollection', function () {\n  let $httpBackend, $resource, TestModel;\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$httpBackend_, _$resource_) {\n    $httpBackend = _$httpBackend_;\n    $resource = _$resource_;\n    TestModel = createModelClass();\n  }));\n\n  function createModelClass() {\n    const resource = $resource('/:action', {}, {\n      partitionedQuery: {\n        method: 'GET',\n        isArray: true,\n        params: {\n          action: 'query'\n        }\n      }\n    });\n\n    class TestModel extends Model {\n      constructor(data) {\n        super(data, {\n          id: null\n        });\n\n        this._Resource = resource;\n      }\n\n      static Resource = resource;\n    }\n\n    return TestModel;\n  }\n\n  function createCollection(chunkSize?) {\n    const collection = new PartitionedCollection(TestModel);\n    collection.setChunkSize(chunkSize);\n\n    return collection;\n  }\n\n  function toDataArray(collection) {\n    return collection.models.map(function (model) {\n      return model.data;\n    });\n  }\n\n  describe('Collection creation', function () {\n    it('should create an empty collection', function () {\n      const collection = createCollection();\n\n      expect(collection).toBeDefined();\n      expect(collection.models.length).toBe(0);\n    });\n  });\n\n  describe('fetch() (GET)', function () {\n    it('should request more items than was defined for chunkSize (chunkSize + 1)', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200);\n      $httpBackend.flush();\n    });\n\n    it('should fetch the initial chunk', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]);\n    });\n\n    it('should fetch with optional params', function () {\n      const collection = createCollection(2);\n      collection.fetch({\n        param1: 1\n      });\n\n      $httpBackend.expectGET('/query?offset=0&param1=1&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]);\n    });\n\n    it('should reset offset if called after more()', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=2&total=3').respond(200, [{id: 3}, {id: 4}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}, {id: 3}, {id: 4}]);\n\n      collection.fetch();\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]);\n    });\n\n    it('should reset optional params if called afer more()', function () {\n      const collection = createCollection(2);\n      collection.fetch({\n        param1: 1\n      });\n\n      $httpBackend.expectGET('/query?offset=0&param1=1&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=2&param1=1&total=3').respond(200, [{id: 3}, {id: 4}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}, {id: 3}, {id: 4}]);\n\n      collection.fetch();\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}]);\n    });\n\n    it('should be resolved with self', function () {\n      const collection = createCollection(2);\n      const spy = jasmine.createSpy('then callback');\n\n      const promise = collection.fetch();\n      collection.promise.then(spy);\n      promise.then(spy);\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200);\n      $httpBackend.flush();\n\n      expect(spy.calls.allArgs()).toEqual([[collection], [collection]]);\n    });\n  });\n\n  describe('more() (GET)', function () {\n    it('should fetch the next chunk if there are more items to fetch', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=2&total=3').respond(200);\n      $httpBackend.flush();\n    });\n\n    it('should not fetch the next chunk if there are no more items to fetch', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.verifyNoOutstandingExpectation();\n    });\n\n    it('should fetch the next chunk with same optional params used with fetch()', function () {\n      const collection = createCollection(2);\n      collection.fetch({\n        param1: 1\n      });\n\n      $httpBackend.expectGET('/query?offset=0&param1=1&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=2&param1=1&total=3').respond(200);\n      $httpBackend.flush();\n    });\n\n    it('should send the correct offset', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=2&total=3').respond(200, [{id: 3}, {id: 4}, {id: 5}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=4&total=3').respond(200, [{id: 6}]);\n      $httpBackend.flush();\n    });\n\n    it('should fetch the next chunk and append it to current models', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      collection.more();\n      $httpBackend.expectGET('/query?offset=2&total=3').respond(200, [{id: 3}, {id: 4}]);\n      $httpBackend.flush();\n\n      expect(toDataArray(collection)).toEqual([{id: 1}, {id: 2}, {id: 3}, {id: 4}]);\n    });\n\n    it('should be resolved with self', function () {\n      const collection = createCollection(2);\n      const spy = jasmine.createSpy('then callback');\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      const promise = collection.more();\n      collection.promise.then(spy);\n      promise.then(spy);\n\n      $httpBackend.expectGET('/query?offset=2&total=3').respond(200);\n      $httpBackend.flush();\n\n      expect(spy.calls.allArgs()).toEqual([[collection], [collection]]);\n    });\n\n  });\n\n  describe('hasMore', function () {\n    it('should return true initially', function () {\n      const collection = createCollection(2);\n\n      expect(collection.hasMore()).toBe(true);\n    });\n\n    it('should return true if response length is equal to the total param', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}, {id: 3}]);\n      $httpBackend.flush();\n\n      expect(collection.hasMore()).toBe(true);\n    });\n\n    it('should return false if response length is less than the total param', function () {\n      const collection = createCollection(2);\n      collection.fetch();\n\n      $httpBackend.expectGET('/query?offset=0&total=3').respond(200, [{id: 1}, {id: 2}]);\n      $httpBackend.flush();\n\n      expect(collection.hasMore()).toBe(false);\n    });\n  });\n\n  describe('getChunkSize()', function () {\n    it('should return the chunk size', function () {\n      const collection = createCollection(2);\n\n      expect(collection.getChunkSize()).toBe(2);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/collections/partitioned-collection.ts",
    "content": "import {Collection, ModelCtor} from './collection';\nimport {lodash as _} from '../../utils';\nimport {injector} from '../injector';\nimport {IBaseModel} from '../model/model';\nconst inject = injector.get;\n\nexport class PartitionedCollection<T extends IBaseModel = any> extends Collection<T> {\n  _chunkSize = 50;\n  _offset = 0;\n  _hasMore ;\n  _optionalParams;\n\n  private paramsTransformer = x => x;\n  private requestStartHandler = x => x;\n  private requestFinishHandler = x => x;\n\n  static $q: ng.IQService;\n\n  constructor(Model?: ModelCtor<T>, action = 'partitionedQuery') {\n    super(Model, action);\n\n    this._hasMore = true;\n  }\n\n  // PRIVATE\n  _getParams() {\n    const params = _.defaults({}, {\n      offset: this._offset,\n      total: this._chunkSize + 1\n    }, this._optionalParams);\n\n    return this.paramsTransformer(params);\n  }\n\n  _startRequestHook(deferred) {\n    this.requestStartHandler(deferred);\n  }\n\n  _finishRequestHook(models) {\n    this._hasMore = models.length > this._chunkSize;\n\n    if (this._hasMore) {\n      models.splice(-1, 1);\n    }\n\n    this._offset += models.length;\n\n    this.requestFinishHandler(models);\n\n    return models;\n  }\n\n  _more(params?) {\n    return this._fetch(params).then(models => this.add(models));\n  }\n\n  // PUBLIC\n  // methods\n  setChunkSize(chunkSize) {\n    this._chunkSize = chunkSize;\n    return this;\n  }\n\n  getChunkSize() {\n    return this._chunkSize;\n  }\n\n  fetch(optionalParams?) {\n    this._offset = 0;\n    this._optionalParams = optionalParams;\n\n    return super.fetch(this._getParams());\n  }\n\n  more() {\n    if (!this.hasMore()) {\n      return this._resolveAsSelf(inject('$q').when());\n    }\n\n    return this._resolveAsSelf(this._more(this._getParams()));\n  }\n\n  hasMore() {\n    return this._hasMore;\n  }\n\n  transformRequestParams(transformer) {\n    this.paramsTransformer = transformer;\n    return this;\n  }\n\n  onRequestStart(handler: (x) => any) {\n    this.requestStartHandler = handler;\n    return this;\n  }\n\n  onRequestFinish(handler: (x) => any) {\n    this.requestFinishHandler = handler;\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/event-emitter/event-emitter.test.ts",
    "content": "'use strict';\nimport {EventEmitter} from './event-emitter';\nimport * as angular from 'angular';\n\ndescribe('bi.core.srv.EventeMitter', function () {\n  let $rootScope: angular.IScope;\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$rootScope_) {\n    $rootScope = _$rootScope_;\n  }));\n\n  class ChildEventEmitter extends EventEmitter {\n    constructor(private scope?) {\n      super(scope);\n    }\n\n    getScope(): angular.IScope {\n      return this.scope;\n    }\n  }\n\n  function createEventEmitter({withScope} = {withScope: false}): ChildEventEmitter {\n    const scope = withScope ? $rootScope.$new() : undefined;\n\n    return new ChildEventEmitter(scope);\n  }\n\n  describe('creation', function () {\n    it('should create with a private state member', function () {\n      const emitter = createEventEmitter();\n\n      expect(emitter['__state']).toBeDefined();\n      expect(emitter['__id']).toBeUndefined();\n    });\n\n    it('should create with a state id', function () {\n      const emitter = createEventEmitter({withScope: true});\n\n      expect(emitter['__state']).toBeUndefined();\n      expect(emitter['__id']).toBeDefined();\n    });\n  });\n\n  describe('on()', function () {\n    it('should reeturn self', function () {\n      const emitter = createEventEmitter();\n\n      expect(emitter.on('someEvent', () => true)).toBe(emitter);\n    });\n\n    it('should subscribe to event and call handler when triggered', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter\n        .on('someEvent', spy)\n        .trigger('someEvent');\n\n      expect(spy).toHaveBeenCalled();\n    });\n\n    it('should subscribe to event and call multiple handlers when triggered', function () {\n      const emitter = createEventEmitter();\n      const spy1 = jasmine.createSpy('event handler 1');\n      const spy2 = jasmine.createSpy('event handler 2');\n\n      emitter\n        .on('someEvent', spy1)\n        .on('someEvent', spy2)\n        .trigger('someEvent');\n\n      expect(spy1).toHaveBeenCalled();\n      expect(spy2).toHaveBeenCalled();\n    });\n\n    it('should subscribe to multiple events and call handlers when triggered', function () {\n      const emitter = createEventEmitter();\n      const spy1 = jasmine.createSpy('event handler 1');\n      const spy2 = jasmine.createSpy('event handler 2');\n\n      emitter\n        .on('someEvent', spy1)\n        .on('someOtherEvent', spy2)\n        .trigger('someEvent')\n        .trigger('someOtherEvent');\n\n      expect(spy1).toHaveBeenCalled();\n      expect(spy2).toHaveBeenCalled();\n    });\n\n    it('should call handler with triggered args', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter\n        .on('someEvent', spy)\n        .trigger('someEvent', 1, 2);\n\n      expect(spy).toHaveBeenCalledWith(1, 2);\n    });\n\n    it('should not call handler when subscribing to already triggered event', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter.trigger('someEvent');\n      emitter.on('someEvent', spy);\n\n      expect(spy).not.toHaveBeenCalled();\n    });\n\n    it('should call handler when subscribing to already triggered event', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter.trigger('someEvent');\n      emitter.on('someEvent', spy, true);\n\n      expect(spy).toHaveBeenCalled();\n    });\n\n    it('should call handler with original arguments when subscribing to already triggered event', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter.trigger('someEvent', 1, 2);\n      emitter.on('someEvent', spy, true);\n\n      expect(spy).toHaveBeenCalledWith(1, 2);\n    });\n\n    it('should call handler with arguments of last triggered event', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter.trigger('someEvent', 1, 2);\n      emitter.trigger('someEvent', 3, 4);\n      emitter.on('someEvent', spy, true);\n\n      expect(spy.calls.count()).toBe(1);\n      expect(spy).toHaveBeenCalledWith(3, 4);\n    });\n  });\n\n  describe('scope', function () {\n    it('should destroy state on scope destroy if created with scope', function () {\n      const emitter = createEventEmitter({withScope: true});\n\n      emitter.getScope().$destroy();\n\n      expect(emitter['$state']()).toBeUndefined();\n    });\n\n    it('should remove handler on scope destroy if subscribed with scope', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n      const scope = $rootScope.$new();\n\n      emitter\n        .on('someEvent', spy, false, scope)\n        .trigger('someEvent');\n\n      scope.$destroy();\n\n      emitter.trigger('someEvent');\n\n      expect(spy.calls.count()).toBe(1);\n    });\n  });\n\n  describe('onOnce()', function () {\n    it('should subscribe to event and call handler when triggered', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter\n        .onOnce('someEvent', spy)\n        .trigger('someEvent');\n\n      expect(spy).toHaveBeenCalled();\n    });\n\n    it('should not call the handler if triggered for a second time', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter\n        .onOnce('someEvent', spy)\n        .trigger('someEvent')\n        .trigger('someEvent');\n\n      expect(spy.calls.count()).toBe(1);\n    });\n\n    it('should call handler with original arguments when subscribing to already triggered event, but not more than once', function () {\n      const emitter = createEventEmitter();\n      const spy = jasmine.createSpy('event handler');\n\n      emitter.trigger('someEvent', 1, 2);\n      emitter.onOnce('someEvent', spy, true);\n      emitter.trigger('someEvent', 1, 2);\n\n      expect(spy).toHaveBeenCalledWith(1, 2);\n      expect(spy.calls.count()).toBe(1);\n    });\n\n    it('should not fuck up other event handlers', function () {\n      const emitter = createEventEmitter();\n      const spyOnce = jasmine.createSpy('once handler');\n      const spy = jasmine.createSpy('event handler');\n\n      emitter.onOnce('someEvent', spyOnce, true);\n      emitter.on('someEvent', spy, true);\n      emitter.trigger('someEvent', 1, 2);\n\n      expect(spyOnce.calls.count()).toBe(1);\n      expect(spy.calls.count()).toBe(1);\n    });\n  });\n\n  describe('triggerStream()', function () {\n    it('should call handler on all previous events that were triggered', function () {\n      const emitter = createEventEmitter();\n      const argsHistory = [];\n      const spy = jasmine.createSpy('event handler').and.callFake((...args) => argsHistory.push(args));\n\n      emitter\n        .triggerStream('someEvent', 'args1', 2)\n        .triggerStream('someEvent', 'args3', 4)\n        .on('someEvent', spy, true);\n\n      expect(spy.calls.count()).toBe(2);\n      expect(argsHistory).toEqual([['args1', 2], ['args3', 4]]);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/event-emitter/event-emitter.ts",
    "content": "'use strict';\n\n/**\n * Core services\n *\n * @author Our One Creator Which Flies and is Spaghetti and a Monster\n */\nimport {lodash as _} from '../../utils';\n\nfunction cloneArray(arr: any[]) {\n  return arr.slice(0);\n}\n\nconst state = {\n  state: {},\n\n  clear() {\n    this.state = {};\n  },\n\n  init(id) {\n    this.state[id] = this.state[id] || new State();\n  },\n\n  get(id) {\n    return this.state[id];\n  },\n\n  destroy(id) {\n    // tslint:disable-next-line: no-dynamic-delete\n    delete this.state[id];\n  }\n};\n\nclass State {\n  private readonly events = {};\n\n  private getEvent(eventName: string) {\n    return this.events[eventName] = this.events[eventName] || {\n      handlers: [],\n      lastArgs: null\n    };\n  }\n\n  addHandler(eventName: string, handler: (...args) => any) {\n    const event = this.getEvent(eventName);\n\n    event.handlers.push(handler);\n\n    return event;\n  }\n\n  removeHandler(eventName: string, handler: (...args) => any) {\n    _.pull(this.getEvent(eventName).handlers, handler);\n  }\n\n  setArgs(eventName, ...args) {\n    const event = this.getEvent(eventName);\n\n    event.lastArgs = [[...args]];\n\n    return event;\n  }\n\n  setArgsKeepHistory(eventName, ...args) {\n    const event = this.getEvent(eventName);\n    if (!event.lastArgs) {\n      event.lastArgs = [];\n    }\n\n    event.lastArgs.push([...args]);\n\n    return event;\n  }\n}\n\n/**\n * Adds event subscription ability to inheriting classes\n */\nexport class EventEmitter {\n  private readonly __state;\n  private readonly __id;\n\n  /**\n   * @param scope   Pass scope when the inheriting object is deep watched. This will create the internal state outside of the object.\n   */\n  constructor(scope?: angular.IScope) {\n    if (scope) {\n      this.__id = _.uniqueId();\n\n      state.init(this.__id);\n      this.setScope(scope);\n    } else {\n      this.__state = new State();\n    }\n  }\n\n  private $state() {\n    return this.__state ? this.__state : state.get(this.__id);\n  }\n\n  /**\n   * Invokes all event subscribers\n   */\n  protected fire(eventName: string, ...args): EventEmitter {\n    const event = this.$state().setArgs(eventName, ...args);\n\n    cloneArray(event.handlers).forEach(handler => handler(...args));\n\n    return this;\n  }\n\n  /**\n   * Invokes all event subscribers, and also keep event in history list.\n   */\n  protected stream(eventName: string, ...args): EventEmitter {\n    const event = this.$state().setArgsKeepHistory(eventName, ...args);\n\n    event.handlers.forEach(handler => handler(...args));\n\n    return this;\n  }\n\n  /**\n   * Subscribes to event\n   *\n   * @param invoke  Pass true to immediately invoke the handler if event was already triggered\n   * @param scope   Pass scope to automatically remove the handler when scope is destroyed\n   */\n  public on(eventName: string, handler: (...args) => any, invoke: boolean = false, scope?: angular.IScope): EventEmitter {\n    const event = this.$state().addHandler(eventName, handler);\n\n    if (invoke && event.lastArgs) {\n      event.lastArgs.forEach(args => handler(...args));\n\n    }\n\n    if (scope) {\n      scope.$on('$destroy', () => {\n        this.$state().removeHandler(eventName, handler);\n      });\n    }\n\n    return this;\n  }\n\n  /**\n   * Subscribes to event, but only for one occurrence of the event.\n   *\n   * @param invoke  Pass true to immediately invoke the handler if event was already triggered\n   */\n  onOnce(eventName: string, handler: (...args) => any, invoke: boolean = false): EventEmitter {\n    const wrappedHandler = (...args) => {\n      handler(...args);\n      this.$state().removeHandler(eventName, wrappedHandler);\n    };\n\n    const event = this.$state().addHandler(eventName, wrappedHandler);\n\n    if (invoke && event.lastArgs) {\n      wrappedHandler(...event.lastArgs[event.lastArgs.length - 1]);\n    }\n\n    return this;\n  }\n\n  /**\n   * Invokes all event subscribers. This is a public version of {@link fire}.\n   */\n  public trigger(eventName: string, ...args): EventEmitter {\n    this.fire(eventName, ...args);\n\n    return this;\n  }\n\n  /**\n   * Invokes all event subscribers, but also keep it in history. This is a public version of {@link stream}.\n   */\n  public triggerStream(eventName: string, ...args): EventEmitter {\n    this.stream(eventName, ...args);\n\n    return this;\n  }\n\n  /**\n   * Use to update scope reference\n   */\n  public setScope(scope: angular.IScope): EventEmitter {\n    if (scope) {\n      scope.$on('$destroy', () => state.destroy(this.__id));\n    }\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/event-emitter/index.ts",
    "content": "export {EventEmitter} from './event-emitter';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/injector/index.ts",
    "content": "import { EventEmitter } from '../event-emitter';\n\nlet _injector = null;\nconst eventEmitter = new EventEmitter();\n\nfunction use(realInjector): void {\n  _injector = realInjector;\n  eventEmitter.trigger('ready');\n}\n\nexport function get(dependencyName: string): any {\n  return _injector.get(dependencyName);\n}\n\nfunction on(event: string, callback: (...args: any[]) => any) {\n  eventEmitter.on(event, callback, true);\n}\n\nwindow.addEventListener('biCore.injector.ready', (e: any) => use(e.detail));\n\nexport const injector = { use, get, on };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/local-storage/index.ts",
    "content": "export {LocalStorage} from './local-storage';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/local-storage/local-storage.test.ts",
    "content": "'use strict';\nimport {LocalStorage} from './local-storage';\nimport * as angular from 'angular';\n\ndescribe('LocalStorage Wrapper', function () {\n  let localStorage: LocalStorage;\n\n  beforeEach(() => {\n    localStorage = new LocalStorage();\n    localStorage.clear();\n  });\n\n  afterEach(() => {\n    LocalStorage.setPrefix('');\n  });\n\n  it('should store values', function () {\n    localStorage.setItem('setting', 'aaaa');\n    expect(window.localStorage.getItem('setting')).toEqual('aaaa');\n  });\n\n  it('should load values', function () {\n    window.localStorage.setItem('setting', 'bbbb');\n    expect(localStorage.getItem('setting')).toEqual('bbbb');\n  });\n\n  it('should clear all values', function () {\n    localStorage.setItem('setting', 'aaaa');\n    localStorage.clear();\n    expect(localStorage.getItem('setting')).toEqual(null);\n  });\n\n  it('should add prefix to saved values when requested', () => {\n    LocalStorage.setPrefix('test_');\n    localStorage.setItem('setting', 'aaaa');\n    expect(window.localStorage.getItem('test_setting')).toEqual('aaaa');\n  });\n\n  describe('Custom storage', function () {\n    let customStorage = {\n      data: {},\n      setItem(name, _data) {\n        this.data[name] = _data;\n      },\n      getItem(name) {\n        return this.data[name];\n      },\n      clear() {\n        this.data = {};\n      }\n    };\n\n    beforeEach(() => {\n      localStorage.setStorage(customStorage as any);\n      customStorage.clear();\n    });\n\n    it('should store values', function () {\n      localStorage.setItem('setting', 'aaaa');\n      expect(customStorage.data['setting']).toEqual('aaaa');\n    });\n\n    it('should load values', function () {\n      customStorage.data['setting'] = 'bbbb';\n      expect(localStorage.getItem('setting')).toEqual('bbbb');\n    });\n\n    it('should clear all values', function () {\n      localStorage.setItem('setting', 'aaaa');\n      localStorage.clear();\n      expect(customStorage.data['setting']).toEqual(undefined);\n    });\n\n  });\n\n});\n\ndescribe('LocalStorageWrapper angular provider', () => {\n  let lsProvider;\n\n  beforeEach(() => {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(function () {\n    angular.mock.module(['biLocalStorageProvider', function (biLocalStorageProvider) {\n      lsProvider = biLocalStorageProvider;\n    }]);\n    angular.mock.inject();\n  });\n\n  it('should call set prefix', function () {\n    spyOn(LocalStorage, 'setPrefix');\n    lsProvider.setPrefix('bla');\n    expect(LocalStorage.setPrefix).toHaveBeenCalledWith('bla');\n  });\n\n  it('should create a LocalStorage instance', function () {\n    // spyOn(bi.core.srv.localStorage, 'LocalStorage');\n    // lsProvider.$get();\n    // expect(bi.core.srv.localStorage.LocalStorage).toHaveBeenCalled();\n    // TODO TODO TODO : restore this test\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/local-storage/local-storage.ts",
    "content": "'use strict';\n\nexport class LocalStorage {\n  static prefix: string = '';\n  private storage: Storage;\n\n  constructor(storage?: Storage) {\n    this.storage = storage || window.localStorage;\n  }\n\n  static setPrefix(prefix: string) {\n    LocalStorage.prefix = prefix;\n  }\n\n  setStorage(storage: Storage) {\n    this.storage = storage;\n  }\n\n  setItem(name: string, data: string) {\n    name = LocalStorage.prefix + name;\n    this.storage.setItem(name, data);\n  }\n\n  getItem(name: string) {\n    name = LocalStorage.prefix + name;\n    return this.storage.getItem(name);\n  }\n\n  clear() {\n    this.storage.clear();\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/model/model.test.ts",
    "content": "import {Collection} from '../collections';\nimport {Model} from './model';\nimport * as angular from 'angular';\nimport * as Uuid from 'uuid';\n\ndescribe('Model: Model', function () {\n  let $rootScope, $httpBackend, $resource, mocks, v4Orig;\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n\n    v4Orig = Uuid.v4;\n    Uuid.v4 = function () {\n      return 'MOCK-UUID';\n    };\n\n    mocks = {\n      user: {\n        data: {\n          email: 'mock-user@wix.com'\n        }\n      },\n      TestCollection: Collection,\n      TestModel: Model\n    };\n\n    angular.mock.module({\n      user: mocks.user,\n      TestCollection: mocks.TestCollection,\n      TestModel: mocks.TestModel\n    });\n  });\n\n  beforeEach(inject(function (_$rootScope_, _$httpBackend_, _$resource_) {\n    $rootScope = _$rootScope_;\n    $httpBackend = _$httpBackend_;\n    $resource = _$resource_;\n  }));\n\n  afterEach(() => {\n    Uuid.v4 = v4Orig;\n  });\n\n  function createModel(data?, template?, options?, responseHook?) {\n    class TestModel extends Model {\n      constructor(data) {\n        super(data, template, options);\n\n        this._Resource = $resource('/:action/:id', {}, {\n          save: {\n            method: 'POST',\n            params: {\n              action: 'save'\n            }\n          },\n          get: {\n            method: 'GET',\n            params: {\n              action: 'get'\n            }\n          }\n        });\n\n        this._responseHook = responseHook;\n      }\n    }\n\n    let model = new TestModel(data);\n\n    spyOn(model, 'parse').and.callThrough();\n    spyOn(model, 'format').and.callThrough();\n\n    return model;\n  }\n\n  describe('instantiation', function () {\n    it('should create an empty new model', function () {\n      const model = createModel();\n\n      expect(model).toBeDefined();\n      expect(model.data).toEqual({});\n    });\n\n    it('should create a model with provided data', function () {\n      const data = {name: 'John'};\n      const model = createModel(data);\n\n      expect(model.data).toEqual(data);\n    });\n\n    it('should parse the provided data', function () {\n      const data = {name: 'John'};\n      const model = createModel(data, data);\n\n      expect(model.data).toEqual(data);\n    });\n  });\n\n  describe('id', function () {\n    it('should return a generatad id with a \"new\" prefix', function () {\n      const model = createModel();\n\n      expect(model.id.indexOf('new')).toBe(0);\n    });\n\n    it('should return the actual model id', function () {\n      const model = createModel({id: 1});\n\n      expect(model.id).toBe(1);\n    });\n\n    it('should set id', function () {\n      const model = createModel();\n      model.id = 2;\n\n      expect(model.id).toBe(2);\n    });\n  });\n\n  describe('isNew()', function () {\n    it('should be new', function () {\n      const model = createModel();\n\n      expect(model.isNew()).toBe(true);\n    });\n\n    it('should not be new', function () {\n      const model = createModel({id: 1});\n\n      expect(model.isNew()).toBe(false);\n    });\n  });\n\n  describe('save() (POST)', function () {\n    it('should call resource.save and update the data', function () {\n      const data = {name: 'John'};\n      const model = createModel(data, data);\n      model.save();\n\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(model.id).toEqual(1);\n    });\n\n    it('should call resource.save, parse and update the data', function () {\n      const data = {};\n      const model = createModel(data, data);\n      model.save();\n\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'John'});\n      $httpBackend.flush();\n\n      expect((model.parse as any).calls.mostRecent().args[0].id).toBe(1);\n      expect((model.parse as any).calls.mostRecent().args[0].name).toBe('John');\n      expect(model.data.id).toBe(1);\n      expect(model.data.name).toBe('John');\n    });\n\n    it('should not be new', function () {\n      const model = createModel();\n      model.save();\n\n      $httpBackend.expectPOST('/save', {}).respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(model.isNew()).toBe(false);\n    });\n\n    it('should be resolved with self', function () {\n      const model = createModel();\n      const promise = model.save();\n      const spy = jasmine.createSpy('then callback');\n      promise.then(spy);\n\n      $httpBackend.expectPOST('/save', {}).respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith(model);\n    });\n  });\n\n  describe('fetch() (GET)', function () {\n    it('should call resource.get and update the data', function () {\n      const model = createModel();\n      model.fetch(1);\n\n      $httpBackend.expectGET('/get/1').respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(model.data.id).toBe(1);\n    });\n\n    it('should call resource.get, parse and update the data', function () {\n      const model = createModel({}, {});\n      model.fetch(1);\n\n      $httpBackend.expectGET('/get/1').respond(200, {id: 1, name: 'John'});\n      $httpBackend.flush();\n\n      expect((model.parse as any).calls.mostRecent().args[0].id).toBe(1);\n      expect((model.parse as any).calls.mostRecent().args[0].name).toBe('John');\n      expect(model.data.id).toBe(1);\n      expect(model.data.name).toBe('John');\n    });\n\n    it('should not be new', function () {\n      const model = createModel();\n      model.fetch(2);\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2});\n      $httpBackend.flush();\n\n      expect(model.isNew()).toBe(false);\n    });\n\n    it('should be resolved with self', function () {\n      const model = createModel();\n      const promise = model.fetch(2);\n      const spy = jasmine.createSpy('then callback');\n      promise.then(spy);\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2});\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith(model);\n    });\n  });\n\n  describe('destroy()', function () {\n    it('should call resource.delete and update the data', function () {\n      const data = {id: 2};\n      const model = createModel(data, data);\n      model.destroy();\n\n      $httpBackend.expectDELETE('/2').respond(200, {id: 2});\n      $httpBackend.flush();\n    });\n\n    it('should not call resource.delete if the model is new', function () {\n      const model = createModel();\n      model.destroy();\n\n      $httpBackend.verifyNoOutstandingExpectation();\n    });\n  });\n\n  describe('resolved', function () {\n    it('should not be resolved until theres a response from server', function () {\n      const model = createModel();\n      model.fetch(2);\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2});\n\n      expect(model.resolved).toBe(false);\n    });\n\n    it('should be resolved after a server response', function () {\n      const model = createModel();\n      model.fetch(2);\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2});\n      $httpBackend.flush();\n\n      expect(model.resolved).toBe(true);\n    });\n  });\n\n  describe('promise', function () {\n    it('should be set to the latest resource.$promise', function () {\n      const model = createModel();\n      model.fetch(2);\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2});\n      $httpBackend.flush();\n\n      expect(model.promise).toBeDefined();\n    });\n\n    it('should be resolved with self', function () {\n      const model = createModel();\n      const spy = jasmine.createSpy('then callback');\n      model.fetch(2);\n      model.promise.then(spy);\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2});\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith(model);\n    });\n  });\n\n  describe('parse()', function () {\n    describe('defaults', function () {\n      it('should assign defaults for properties with undefined values', function () {\n        const data = {};\n        const template = {name: 'John'};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          name: 'John'\n        });\n      });\n\n      it('should not assign defaults for properties with defined values', function () {\n        const data = {name: 'John'};\n        const template = {name: 'Sam'};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          name: 'John'\n        });\n      });\n\n      it('should support nesting', function () {\n        const data = {nested: {}};\n        const template = {nested: {name: 'John'}};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          nested: {\n            name: 'John'\n          }\n        });\n      });\n    });\n\n    describe('@optional', function () {\n      it('should assing null value to optional properties if they are undefined', function () {\n        const data = {name: 'John'};\n        const template = {name: 'John', lastname: '@optional'};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          name: 'John',\n          lastname: null\n        });\n      });\n\n      it('should not assign null value to optional properties if they are defined', function () {\n        const data = {name: 'John', lastname: 'Doe'};\n        const template = {name: 'John', lastname: '@optional'};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          name: 'John',\n          lastname: 'Doe'\n        });\n      });\n    });\n\n    describe('@flat', function () {\n      it('should unflatten the keys', function () {\n        const data = {value: {'a.b': 1, 'a.c': 2}};\n        const template = {value: '@flat'};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          value: {\n            a: {\n              b: 1,\n              c: 2\n            }\n          }\n        });\n      });\n\n      it('should unflatten the keys (more complex example)', function () {\n        const data = {value: {'a.b': 1, 'a.c': 2, 'c.d.e': 3}};\n        const template = {value: '@flat'};\n        const model = createModel(data, template);\n\n        expect(model.data).toEqual({\n          value: {\n            a: {\n              b: 1,\n              c: 2\n            },\n            c: {\n              d: {\n                e: 3\n              }\n            }\n          }\n        });\n      });\n    });\n\n    describe('@collection', function () {\n      it('should convert array to collection', function () {\n        const data = {name: 'John', lastnames: [1]};\n        const template = {name: 'John', lastnames: '@collection:TestCollection'};\n        const model = createModel(data, template);\n\n        expect(model.data.lastnames instanceof mocks.TestCollection).toBe(true);\n      });\n\n      it('should create empty collection if array is empty', function () {\n        const data = {name: 'John', lastnames: []};\n        const template = {name: 'John', lastnames: '@collection:TestCollection'};\n        const model = createModel(data, template);\n\n        expect(model.data.lastnames instanceof mocks.TestCollection).toBe(true);\n        expect(model.data.lastnames.models.length).toBe(0);\n      });\n\n      it('should create empty collection if array is undefined', function () {\n        const data = {name: 'John', lastnames: undefined};\n        const template = {name: 'John', lastnames: '@collection:TestCollection'};\n        const model = createModel(data, template);\n\n        expect(model.data.lastnames instanceof mocks.TestCollection).toBe(true);\n        expect(model.data.lastnames.models.length).toBe(0);\n      });\n\n      it('should support nesting', function () {\n        const data = {name: 'John', nested: {lastnames: []}};\n        const template = {name: 'John', nested: {lastnames: '@collection:TestCollection'}};\n        const model = createModel(data, template);\n\n        expect(model.data.nested.lastnames instanceof mocks.TestCollection).toBe(true);\n      });\n\n      describe('keep model references in existing collections after fetching fresh data', function () {\n        it('should copy new models into old models', function () {\n          const data = {values: [{id: 1}, {id: 2}]};\n          const template = {values: '@collection:TestCollection'};\n          const model = createModel(data, template);\n\n          const value1 = model.data.values.models[0];\n          const value2 = model.data.values.models[1];\n          model.save();\n\n          $httpBackend.expectPOST('/save', data).respond(200, {values: [{id: 10}, {id: 20}]});\n          $httpBackend.flush();\n\n          expect(model.data.values instanceof mocks.TestCollection).toBe(true);\n          expect(model.data.values.models.length).toBe(2);\n          expect(model.data.values.models[0].data).toEqual({id: 10});\n          expect(model.data.values.models[1].data).toEqual({id: 20});\n\n          expect(model.data.values.models[0]).toBe(value1);\n          expect(model.data.values.models[1]).toBe(value2);\n        });\n\n        it('should add new models to an empty collection', function () {\n          const data = {values: []};\n          const template = {values: '@collection:TestCollection'};\n          const model = createModel(data, template);\n          model.fetch(1);\n\n          $httpBackend.expectGET('/get/1').respond(200, {values: [{id: 10}, {id: 20}]});\n          $httpBackend.flush();\n\n          expect(model.data.values instanceof mocks.TestCollection).toBe(true);\n          expect(model.data.values.models.length).toBe(2);\n          expect(model.data.values.models[0].data).toEqual({id: 10});\n          expect(model.data.values.models[1].data).toEqual({id: 20});\n        });\n      });\n    });\n\n    describe('@model', function () {\n      it('should create a model object based on template', function () {\n        const data = {name: 'John', lastnames: {lastname: 'Smith'}};\n        const template = {name: 'John', lastnames: '@model:TestModel'};\n        const model = createModel(data, template);\n\n        expect(model.data.lastnames.data.lastname).toEqual('Smith');\n        expect(model.data.lastnames instanceof mocks.TestModel).toBe(true);\n      });\n\n    });\n  });\n\n describe('format()', function () {\n    describe('defaults', function () {\n      it('should remove properties not defined in the template', function () {\n        const data = {prop1: true, prop2: true};\n        const model = createModel(data, {prop1: null});\n        const formatted = model.format();\n\n        expect(formatted).toEqual({\n          prop1: true\n        });\n      });\n\n      it('should strip keys starting with $', function () {\n        const data = {$prop: 1};\n        const model = createModel(data, {$prop: null});\n        const formatted = model.format();\n\n        expect(formatted).toEqual({});\n      });\n\n      it('should strip keys starting with $ (nested objects)', function () {\n        const data = {prop: {$prop: 1}};\n        const model = createModel(data, {prop: null});\n        const formatted = model.format();\n\n        expect(formatted).toEqual({prop: {}});\n      });\n\n      it('should strip keys starting with $ (arrays)', function () {\n        const data = {prop: [{$prop: 1}]};\n        const model = createModel(data, {prop: null});\n        const formatted = model.format();\n\n        expect(formatted).toEqual({prop: [{}]});\n      });\n    });\n\n    describe('@optional', function () {\n      it('should remove optional properties that are null', function () {\n        const data = {name: 'John', lastname: null};\n        const template = {name: null, lastname: '@optional'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({\n          name: 'John'\n        });\n      });\n\n      it('should not remove optional properties that are primitive values', function () {\n        const data = {name: 'John', lastname: 'Doe'};\n        const template = {name: null, lastname: '@optional'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({\n          name: 'John',\n          lastname: 'Doe'\n        });\n      });\n\n      it('should not remove optional properties that are objects', function () {\n        const data = {name: {first: 'John', last: 'Doe'}};\n        const template = {name: '@optional'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({name: {first: 'John', last: 'Doe'}});\n      });\n\n      it('should send optional properties that are arrays', function () {\n        const data = {prop: []};\n        const template = {prop: '@optional'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({prop: []});\n      });\n    });\n\n    describe('@collection', function () {\n      it('should format the collection', function () {\n        const data = {values: [1, 2]};\n        const template = {values: '@collection:TestCollection'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({values: [1, 2]});\n      });\n    });\n\n    describe('@flat', function () {\n      it('should flatten the keys', function () {\n        const data = {\n          values: {\n            a: {\n              b: 1,\n              c: 2\n            }\n          }\n        };\n        const template = {values: '@flat'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({values: {'a.b': 1, 'a.c': 2}});\n      });\n\n      it('should flatten the keys (more complex example)', function () {\n        const data = {\n          values: {\n            a: {\n              b: 1,\n              c: 2\n            },\n            c: {\n              d: {\n                e: 3\n              }\n            }\n          }\n        };\n\n        const template = {values: '@flat'};\n        const model = createModel(data, template);\n        const formatted = model.format();\n\n        expect(formatted).toEqual({values: {'a.b': 1, 'a.c': 2, 'c.d.e': 3}});\n      });\n\n      // it('should remove keys starting with $', function () {\n      //   const data = {\n      //     values: {\n      //       a: {\n      //         $b: 1\n      //       }\n      //     }\n      //   };\n\n      //   const template = {values: '@flat'};\n      //   const model = createModel(data, template);\n      //   const formatted = model.format();\n\n      //   expect(formatted).toEqual({values: {'a.b': 1}});\n      // });\n    });\n  });\n\n  describe('clone()', function () {\n    it('should fetch event by current id and return a new instance', function () {\n      const model = createModel({id: 1});\n      const cloned = model.clone(true);\n\n      $httpBackend.expectGET('/get/1').respond(200, {id: 1, name: 'test'});\n      $httpBackend.flush();\n\n      expect(cloned).not.toBe(model);\n      expect(cloned.data.name).toBe('test');\n    });\n\n    it('should fetch event with provided params', function () {\n      const model = createModel({id: 1});\n      const cloned = model.clone(true, {id: 2});\n\n      $httpBackend.expectGET('/get/2').respond(200, {id: 2, name: 'test'});\n      $httpBackend.flush();\n\n      expect(cloned).not.toBe(model);\n      expect(cloned.data.name).toBe('test');\n    });\n\n    it('should fetch event by current id and return a new instance without id', function () {\n      const data = {id: 1, name: 'test'};\n      const model = createModel(data, {id: '@optional'});\n      const cloned = model.clone(true);\n\n      $httpBackend.expectGET('/get/1').respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(cloned.data.id).toBe(null);\n      expect(cloned.isNew()).toBe(true);\n    });\n\n    it('should copy the data and return a new instance', function () {\n      const data = {name: 'test'};\n      const model = createModel(data, {name: ''});\n      const cloned = model.clone();\n\n      $rootScope.$digest();\n\n      expect(cloned).not.toBe(model);\n      expect(cloned.data.name).toBe('test');\n      expect(cloned.isNew()).toBe(true);\n    });\n\n    it('should copy the data and return a new instance without id', function () {\n      const data = {id: 1};\n      const model = createModel(data, {id: '@optional'});\n      const cloned = model.clone();\n\n      $rootScope.$digest();\n\n      expect(cloned.data.id).toBe(null);\n      expect(cloned.isNew()).toBe(true);\n    });\n\n    it('should set a promise that resolves to self', function () {\n      const data = {a: 1};\n      const model = createModel(data, data);\n      const cloned = model.clone();\n\n      const spy = jasmine.createSpy('cloned.promise');\n      cloned.promise.then(spy);\n\n      $rootScope.$digest();\n\n      expect(spy).toHaveBeenCalledWith(cloned);\n    });\n  });\n\n  describe('meta()', function () {\n    it('should set and get a meta property', function () {\n      const model = createModel();\n      model.meta('test', 1);\n\n      expect(model.meta('test')).toBe(1);\n    });\n\n    it('should return undefined for unset values', function () {\n      const model = createModel();\n\n      expect(model.meta('test')).toBeUndefined();\n    });\n\n    it('should set a value that exists only until first read ', function () {\n      const model = createModel();\n      model.meta('test', 1, true);\n\n      expect(model.meta('test')).toBe(1);\n      expect(model.meta('test')).toBeUndefined();\n    });\n  });\n\n  describe('isValid()', function () {\n    it('should be valid by default', function () {\n      const model = createModel();\n\n      expect(model.isValid()).toBe(true);\n    });\n\n    it('should set the validity status', function () {\n      const model = createModel();\n      model.setValidity(false);\n\n      expect(model.isValid()).toBe(false);\n    });\n  });\n\n  describe('promise.noSync()', function () {\n    it('should not update model with next server response if called', function () {\n      const data = {name: 'John'};\n      const model = createModel(data, data);\n      model.save().noSync();\n\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'});\n      $httpBackend.flush();\n\n      expect(model.data.name).toEqual('John');\n    });\n\n    it('should return a promise resolved with self', function () {\n      const data = {name: 'John'};\n      const model = createModel(data, data);\n      const promise = model.save().noSync();\n\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'});\n      $httpBackend.flush();\n\n      const spy = jasmine.createSpy('promise');\n      promise.then(spy);\n\n      $rootScope.$digest();\n\n      expect(spy).toHaveBeenCalledWith(model);\n    });\n\n    it('should apply only once per call', function () {\n      const data = {name: 'John'};\n      const model = createModel(data, data);\n\n      model.save().noSync();\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'});\n      $httpBackend.flush();\n\n      model.save();\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1, name: 'Jack'});\n      $httpBackend.flush();\n\n      expect(model.data.name).toEqual('Jack');\n    });\n  });\n\n  describe('responseHook', function () {\n    it('should call hook with \"get\" action and processed model', function () {\n      const spy = jasmine.createSpy('responseHook');\n      const model = createModel(undefined, undefined, {}, spy);\n      model.fetch(1);\n\n      $httpBackend.expectGET('/get/1').respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith({id: 1}, 'get', {noSync: false});\n    });\n\n    it('should call hook with \"save\" action and processed model', function () {\n      const spy = jasmine.createSpy('responseHook');\n      const data = {name: 'John'};\n      const model = createModel(data, data, {}, spy);\n      model.save();\n\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith({id: 1, name: 'John'}, 'save', {noSync: false});\n    });\n\n    it('should call hook with \"clone\" action and processed model', function () {\n      const spy = jasmine.createSpy('responseHook');\n      const data = {name: 'John'};\n      const model = createModel(data, {name: ''}, {}, spy);\n\n      model.clone();\n\n      $rootScope.$digest();\n\n      expect(spy).toHaveBeenCalledWith({id: null, name: 'John'}, 'clone', {noSync: false});\n    });\n\n    it('should call hook with \"save\" action and noSync=true', function () {\n      const spy = jasmine.createSpy('responseHook');\n      const data = {name: 'John'};\n      const model = createModel(data, data, {}, spy);\n      model.save().noSync();\n\n      $httpBackend.expectPOST('/save', data).respond(200, {id: 1});\n      $httpBackend.flush();\n\n      expect(spy).toHaveBeenCalledWith({id: 1, name: 'John'}, 'save', {noSync: true});\n    });\n  });\n\n  describe('options', function () {\n    describe('autoId', function () {\n      it('should generate id when data has no id param', function () {\n        const model = createModel(undefined, undefined, {autoId: true});\n\n        expect(model.id).toBe('MOCK-UUID');\n      });\n\n      it('should not generate id when data has id param', function () {\n        const model = createModel({id: 1}, undefined, {autoId: true});\n\n        expect(model.id).not.toBe('MOCK-UUID');\n      });\n\n      it('should be considered new', function () {\n        const model = createModel(undefined, undefined, {autoId: true});\n\n        expect(model.isNew()).toBe(true);\n      });\n\n      it('should not be considered new after fetching a model', function () {\n        const model = createModel(undefined, undefined, {autoId: true});\n        model.fetch('MOCK-UUID');\n\n        $httpBackend.expectGET('/get/MOCK-UUID').respond(200, {id: 'MOCK-UUID'});\n        $httpBackend.flush();\n\n        expect(model.id).toBe('MOCK-UUID');\n        expect(model.isNew()).toBe(false);\n      });\n\n      it('should not be considered new after saving a new model', function () {\n        const data = {};\n        const model = createModel(data, data, {autoId: true});\n        model.save();\n\n        $httpBackend.expectPOST('/save', data).respond(200, {id: 'MOCK-UUID'});\n        $httpBackend.flush();\n\n        expect(model.id).toBe('MOCK-UUID');\n        expect(model.isNew()).toBe(false);\n      });\n\n      it('should generate id for cloned model', function () {\n        const data = {id: 1};\n        const model = createModel(data, data, {autoId: true});\n        const clonedModel = model.clone();\n\n        $rootScope.$digest();\n\n        expect(clonedModel.id).toBe('MOCK-UUID');\n      });\n\n      it('should consider cloned model new', function () {\n        const data = {id: 1};\n        const model = createModel(data, data, {autoId: true});\n        const clonedModel = model.clone();\n\n        $rootScope.$digest();\n\n        expect(clonedModel.isNew()).toBe(true);\n      });\n    });\n\n    describe('autoOwner', function () {\n      it('should assign current user as owner', function () {\n        const model = createModel(undefined, undefined, {autoOwner: true});\n\n        expect(model.data.owner).toEqual(mocks.user.data);\n      });\n\n      it('should duplicate the user object', function () {\n        const model = createModel(undefined, undefined, {autoOwner: true});\n\n        expect(model.data.owner).toEqual(mocks.user.data);\n        expect(model.data.owner).not.toBe(mocks.user.data);\n      });\n\n      it('should assign current user if owner object is defined without email', function () {\n        const model = createModel({owner: {}}, {owner: {}}, {autoOwner: true});\n\n        expect(model.data.owner).toEqual(mocks.user.data);\n      });\n\n      it('should not assign current user if owner email is defined', function () {\n        const owner = {email: 'some-user@wix.com'};\n        const model = createModel({owner: owner}, {owner: {}}, {autoOwner: true});\n\n        expect(model.data.owner).toEqual(owner);\n      });\n\n      it('should assign id for cloned model', function () {\n        const data = {id: 1};\n        const model = createModel(data, data, {autoOwner: true});\n        const clonedModel = model.clone();\n\n        $rootScope.$digest();\n\n        expect(clonedModel.data.owner).toEqual(mocks.user.data);\n      });\n    });\n  });\n\n  describe('data', function () {\n    it('data property should be assignable', function () {\n      const model = createModel();\n\n      model.data = {test: true};\n      expect(model.data).toEqual({test: true});\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/model/model.ts",
    "content": "'use strict';\nimport {Collection} from '../collections/collection';\nimport {lodash as _, uuid} from '../../utils';\nimport {injector} from '../injector';\nconst inject = injector.get;\n\nfunction flatten(data, keys = [], res = {}) {\n  _.forEach(data, (value, key) => {\n    keys.push(key);\n\n    if (_.isObject(value)) {\n      flatten(value, keys, res);\n    } else {\n      res[keys.join('.')] = value;\n    }\n\n    keys.pop();\n  });\n\n  return res;\n}\n\nfunction unflatten(data, keys = []) {\n  const res = {};\n\n  _.forEach(data, (value, key) => {\n    unflattenKey(key.split('.'), value, res);\n  });\n\n  return res;\n}\n\nfunction unflattenKey(keys, value, res = {}) {\n  const key = keys.shift();\n\n  if (!keys.length) {\n    res[key] = value;\n  } else {\n    res[key] = res[key] || {};\n    unflattenKey(keys, value, res[key]);\n  }\n}\n\nexport interface IBaseModel {\n  id?: string;\n  owner?: {\n    email: string;\n  };\n}\nexport class Model<T extends IBaseModel = any> {\n  _template;\n  _resolved;\n  _valid;\n  _meta;\n  _options;\n\n  _cid;\n  _data: T;\n  _promise;\n  _permission;\n  _Resource;\n\n  constructor(model?, template?, options = {autoId: false, autoOwner: null}) {\n    this._template = template || {};\n    this._resolved = !!model;\n    this._valid = true;\n    this._meta = {};\n    this._options = options;\n\n    this._data = this.parse(model);\n    this._promise = inject('$q').when(this);\n\n    if (options.autoId && !this.data.id) {\n      this._assignId();\n    } else {\n      this._cid = _.uniqueId('new');\n    }\n\n    if (options.autoOwner && !(this.data.owner && this.data.owner.email)) {\n      this._assignAutoOwner();\n    }\n  }\n\n  // PRIVATE\n  _responseHook(data, action, options) {\n    return data;\n  }\n\n  _assignId() {\n    this._cid = this.data.id = uuid();\n\n    return this;\n  }\n\n  _doRequest(action, data) {\n    this._resolved = false;\n    return this._Resource[action](data).$promise;\n  }\n\n  _processResponse(promise, action) {\n    return (this._promise = promise.then((data) => {\n      if (!this._promise._noSync) {\n        data = this._smartMerge(this._data, this.parse(data));\n        data = typeof this._responseHook === 'function' ? this._responseHook(data, action, {noSync: false}) : data;\n\n        this._data = data;\n\n        if (action === 'clone') {\n          if (this._options.autoId) {\n            this._assignId();\n          }\n\n          if (this._options.autoOwner) {\n            this._assignAutoOwner();\n          }\n        }\n      } else if (typeof this._responseHook === 'function') {\n        this._responseHook(this.parse(data), action, {noSync: true});\n      }\n\n      if ((action === 'get' || action === 'save') && this._options.autoId) {\n        this._cid = _.uniqueId('new');\n      }\n\n      return this;\n    }).finally(() => {\n      this._resolved = true;\n    }));\n  }\n\n  _action(action, data?) {\n    if (!data) {\n      data = this.format();\n    }\n\n    const promise = this._processResponse(this._doRequest(action, data), action);\n    this._initPromise(promise);\n\n    return promise;\n  }\n\n  _initPromise(promise) {\n    promise.noSync = () => {\n      promise._noSync = true;\n      return promise;\n    };\n\n    return promise;\n  }\n\n  _assignAutoOwner() {\n    const user = inject('user');\n    this._data.owner = _.clone(user.data);\n  }\n\n  _stripDollars(data: any) {\n    if (_.isPlainObject(data)) {\n      // tslint:disable-next-line: restrict-plus-operands\n      data = _.omit(data, (value, key) => ('' + key).charAt(0) === '$');\n      data = _.mapValues(data, value => this._stripDollars(value));\n    }\n\n    if (_.isArray(data)) {\n      data = data.map(item => this._stripDollars(item));\n    }\n\n    return data;\n  }\n\n  _parseCollection(collectionString, data) {\n    const collectionClassName = collectionString.replace('@collection:', '');\n    const CollectionClass = inject(collectionClassName);\n\n    const collection = new CollectionClass();\n\n    if (data instanceof Array && data.length) {\n      collection.add(data);\n    }\n\n    return collection;\n  }\n\n  _parseModel(modelString, data) {\n    const modelClassName = modelString.replace('@model:', '');\n    const ModelClass = inject(modelClassName);\n\n    return new ModelClass(data);\n  }\n\n  /**\n   * Merges current with source while preserving collection item references\n   *\n   * @param current\n   * @param source\n   * @returns {object}\n   * @private\n   */\n  _smartMerge(current, source) {\n    return _.merge(current, source, function (currentValue, sourceValue) {\n      if (currentValue instanceof Collection) {\n        sourceValue.models.forEach((sourceModel, index) => {\n          if (currentValue.models[index]) {\n            _.assign(currentValue.models[index], sourceModel);\n          } else {\n            currentValue.models[index] = sourceModel;\n          }\n        });\n        return currentValue;\n      }  if (_.isPlainObject(sourceValue)) {\n        return; // let _.merge do the recursion\n      }\n\n      return sourceValue;\n    });\n  }\n\n  /**\n   * Parses the data according to defaults definition.\n   * Removes properties starting with \"$\"\n   *\n   * The parsed data is used for internal model representation.\n   *\n   * @param data\n   * @param defaults\n   * @returns {object}\n   * @private\n   */\n  _parse(data, defaults) {\n    data = _.cloneDeep(data || {});\n    data = this._stripDollars(data);\n\n    return _.merge(data, defaults, (dataValue, defaultValue) => {\n      if (defaultValue === '@optional') {\n        return typeof dataValue === 'undefined' ? null : dataValue;\n      } \n      \n      if (defaultValue === '@flat') {\n        return unflatten(dataValue);\n      } \n      \n      if (/^@collection:/.test(defaultValue)) {\n        return this._parseCollection(defaultValue, dataValue);\n      } \n      \n      if (/^@model:/.test(defaultValue)) {\n        return this._parseModel(defaultValue, dataValue);\n      }\n      \n      if (_.isPlainObject(defaultValue)) {\n        return; // let _.merge do the recursion\n      }\n      \n      return typeof dataValue === 'undefined' ? _.cloneDeep(defaultValue) : dataValue;\n    });\n  }\n\n  /**\n   * Formats the data according to filter definition.\n   * The formatted data is used for server request payloads.\n   *\n   * @param data\n   * @param filter\n   * @returns {object}\n   * @private\n   */\n  _format(data, filter) {\n    if (typeof filter === 'undefined') {\n      return;\n    }\n\n    if (filter === '@optional') {\n      return data === null ? undefined : data;\n    }\n\n    if (filter === '@flat') {\n      return flatten(data);\n    }\n\n    if (/^@collection:/.test(filter)) {\n      return data.format();\n    }\n\n    if (filter === null || data === null || typeof data === 'undefined' || typeof data !== 'object' || data instanceof Array) {\n      return data;\n    }\n\n    const res = {};\n\n    _.forOwn(data, (value, key) => {\n      value = this._format(value, filter[key]);\n\n      if (!_.isUndefined(value)) {\n        res[key] = value;\n      }\n    });\n\n    return res;\n  }\n\n  // PUBLIC\n  // static\n  static Resource;\n\n  // getters/setters\n  get id() {\n    return this.data.id || this._cid;\n  }\n\n  set id(value) {\n    this.data.id = value;\n  }\n\n  get data() {\n    return this._data;\n  }\n\n  set data(data) {\n    this._data = data;\n  }\n\n  get promise() {\n    return this._promise;\n  }\n\n  get resolved() {\n    return this._resolved;\n  }\n\n  get permission() {\n    return this._permission;\n  }\n\n  // methods\n  isNew() {\n    return this.id === this._cid;\n  }\n\n  isValid() {\n    return this._valid;\n  }\n\n  setPermission(Permission) {\n    this._permission = new Permission(this);\n    return this;\n  }\n\n  setValidity(valid) {\n    this._valid = valid;\n  }\n\n  format() {\n    return this._stripDollars(this._format(this.data, this._template));\n  }\n\n  parse(data) {\n    return this._parse(data, this._template);\n  }\n\n  fetch(id, ...rest) {\n    return this._action('get', {id});\n  }\n\n  /**\n   * Clones current model and returns a new instance.\n   * New model will be considered new (isNew() === true).\n   *\n   * @params fetch {boolean} - if true will fetch model data from server before cloning\n   * @returns {Model} - new model\n   */\n  clone(fetch = false, params?) {\n    let model, promise;\n\n    if (fetch) {\n      promise = this._Resource.get(params || {id: this.id}).$promise;\n    } else {\n      promise = inject('$q').when(this.format());\n    }\n\n    promise = promise.then(data => {\n      data.id = null;\n      return data;\n    });\n\n    model = new (this.constructor as any);\n    model._processResponse(promise, 'clone');\n\n    return model;\n  }\n\n  save() {\n    return this._action('save');\n  }\n\n  /**\n   * Deletes the model on server.\n   * Does nothing for new models.\n   *\n   * @returns {Promise} - promise resolved with self\n   */\n  destroy() {\n    if (!this.isNew()) {\n      return this._action('delete', {id: this.data.id});\n    } \n      return this._initPromise(inject('$q').when(this));\n    \n  }\n\n  meta(key, value?, once = false) {\n    if (typeof value === 'undefined') {\n      return typeof this._meta[key] === 'function' ? this._meta[key]() : this._meta[key];\n    } \n      this._meta[key] = once ? () => {\n        this._meta[key] = undefined;\n        return value;\n      } : value;\n      return this;\n    \n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/socket/socket.ts",
    "content": "'use strict';\nimport {EventEmitter} from '../event-emitter/event-emitter';\n\nfunction createSocket(self: Socket, url: string): any {\n  const socket = new WebSocket(url);\n\n  socket.onmessage = (message) => {\n    const data = JSON.parse(message.data || '{}');\n\n    self.trigger('event', self, data.event, data);\n  };\n\n  socket.onopen = () => {\n    self.trigger('open', self);\n  };\n\n  socket.onclose = () => {\n    self.trigger('close', self);\n  };\n\n  return socket;\n}\n\nexport class Socket extends EventEmitter {\n  private readonly socket: any;\n\n  constructor (private readonly url: string) {\n    super();\n\n    this.socket = createSocket(this, url);\n  }\n\n  send(payload): Socket {\n    this.socket.send(JSON.stringify(payload));\n    return this;\n  }\n\n  close(): Socket {\n    this.socket.close();\n    return this;\n  }\n\n  getUrl() {\n    return this.url;\n  }\n\n  getWebSocket() {\n    return this.socket;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/localstorage-state-provider.test.ts",
    "content": "'use strict';\nimport * as angular from 'angular';\nimport {localStorageStateProvider} from './localstorage-state-provider';\n\ndescribe('LocalStorageStateProvider', function () {\n  const demoData = {\n    param1: 'aaa',\n    param2: 4\n  };\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(function () {\n    window.localStorage.clear();\n  });\n\n  // beforeEach(inject(function () {\n  //   localStorageStateProvider = bi.core.srv.state.localStorageStateProvider;\n  // }));\n\n  describe('Save', () => {\n    it('should correctly save data', function () {\n      let data = JSON.stringify(demoData);\n      localStorageStateProvider.setStateData('test', data);\n      expect(window.localStorage['test']).toEqual(data);\n    });\n  });\n\n  describe('Load', () => {\n    it('should correctly load data', function () {\n      window.localStorage['test'] = JSON.stringify(demoData);\n      expect(localStorageStateProvider.getStateData('test')).toEqual(JSON.stringify(demoData));\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/localstorage-state-provider.ts",
    "content": "import {LocalStorage} from '../local-storage';\nimport {IStateProvider} from './types';\n\nexport const localStorageStateProvider: IStateProvider =\n  new class LocalStorageStateProvider implements IStateProvider {\n    private readonly storage = new LocalStorage();\n\n    getStateData(stateName: string): string {\n      return this.storage.getItem(stateName);\n    }\n\n    setStateData(stateName: string, data: string): void {\n      this.storage.setItem(stateName, data);\n    }\n  };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/state-wrapper.test.ts",
    "content": "import * as angular from 'angular';\nimport {StateWrapper} from './state-wrapper';\nimport {ViewModel, create as createViewModel} from '../view-model/view-model';\ntype Dictionary<T> = _.Dictionary<T>;\n\nfunction createDefaultExportImport(obj, paramList: string[]) {\n  obj.$export = function(stateName) {\n    const res = {};\n    paramList.forEach(paramName => {\n      res[paramName] = obj[paramName];\n    });\n    return res;\n  };\n\n  obj.$import = function(data: Dictionary<any>) {\n    paramList.forEach(paramName => {\n      obj[paramName] = data[paramName];\n    });\n  };\n}\n\ndescribe('LocalStorageStateProvider', function () {\n\n  let $location, $browser,\n    $q: ng.IQService,\n    $rootScope: ng.IRootScopeService;\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$location_, _$browser_, _$q_, _$rootScope_) {\n    $location = _$location_;\n    $browser = _$browser_;\n    $q = _$q_;\n    $rootScope = _$rootScope_;\n  }));\n\n  beforeEach(() => {\n    window.localStorage.clear();\n  });\n\n  function updateURL(url) {\n    $location.url(url);\n    $browser.poll();\n  }\n\n  describe('check mandatory parameters', function () {\n    const demoObject = {};\n    it('should throw error when no Object is passed', function () {\n      expect(() =>  StateWrapper.build().end()).toThrow(new Error('StateWrapperBuilder::build: You must provide an object'));\n\n      expect(() => {\n        StateWrapper.build()\n          .useObject(demoObject)\n          .end();\n      }).toThrow(new Error('StateWrapperBuilder::build: You must provide a clientName'));\n\n      expect(() => {\n        StateWrapper.build()\n          .useObject(demoObject)\n          .setClientName('test')\n          .end();\n      }).toThrow(new Error('StateWrapperBuilder::build: You must provide a state'));\n\n    });\n  });\n\n  describe('Basic Load\\\\Save', function () {\n    let demoObject;\n    beforeEach(function () {\n      demoObject = {\n        a: 'aaa',\n        b: {bb: 'bbb'}\n      };\n      createDefaultExportImport(demoObject, ['a']);\n      createDefaultExportImport(demoObject.b, ['bb']);\n    });\n\n    it('should save values local storage', function () {\n      const stateWrapper = StateWrapper.build()\n        .useObject(demoObject)\n        .withNewState('demoState')\n        .setClientName('test')\n        .end();\n      stateWrapper.save();\n      expect(window.localStorage.getItem('demoState')).toBe('{\"test\":{\"a\":\"aaa\",\"bb\":\"bbb\"}}');\n    });\n\n    it('should load values local storage', function () {\n      window.localStorage['demoState'] = '{\"test\":{\"a\":\"bbb\",\"bb\":\"ccc\"}}';\n      StateWrapper.build()\n        .useObject(demoObject)\n        .withNewState('demoState')\n        .setClientName('test')\n        .end();\n      expect(demoObject.a).toBe('bbb');\n      expect(demoObject.b.bb).toBe('ccc');\n    });\n\n    it('should load values from local storage and then by url', function () {\n      window.localStorage['demoState'] = '{\"test\":{\"a\":\"bbb\"}}';\n      updateURL('/loc1?demoState-data=test-a:ccc');\n      StateWrapper.build()\n        .useObject(demoObject)\n        .withNewState('demoState')\n        .setClientName('test')\n        .end();\n      expect(demoObject.a).toBe('ccc');\n    });\n\n    it('should load values ONLY from local storage if requested', function () {\n      window.localStorage['demoState'] = '{\"test\":{\"a\":\"bbb\"}}';\n      updateURL('/loc1?demoState-data=test-a:ccc');\n      StateWrapper.build()\n        .useObject(demoObject)\n        .withNewState('demoState')\n        .setClientName('test')\n        .withProviders(['localStorage'])\n        .end();\n      expect(demoObject.a).toBe('bbb');\n    });\n  });\n\n  describe('use custom traverse', function () {\n    let vm;\n    beforeEach(function () {\n      vm = createViewModel({\n        a: 'aaa',\n        b: {\n          bb: 'bbb'\n        }\n      });\n      createDefaultExportImport(vm, ['a']);\n      createDefaultExportImport(vm.b, ['bb']);\n    });\n\n    it('should save values local storage', function () {\n      const stateWrapper = StateWrapper.build()\n        .useObject(vm)\n        .withNewState('demoState')\n        .setClientName('test')\n        .withCustomTraverse(function (vm: ViewModel, callback, args) {\n          vm.forEach(function (vm) {\n            callback(vm, args);\n          });\n        })\n        .end();\n      stateWrapper.save();\n      expect(window.localStorage.getItem('demoState')).toBe('{\"test\":{\"a\":\"aaa\",\"bb\":\"bbb\"}}');\n    });\n\n    it('should load values local storage', function () {\n      window.localStorage['demoState'] = '{\"test\":{\"a\":\"bbb\"}}';\n      StateWrapper.build()\n        .useObject(vm)\n        .withNewState('demoState')\n        .setClientName('test')\n        .withCustomTraverse(function (vm: ViewModel, callback, args) {\n          vm.forEach(function (vm) {\n            callback(vm, args);\n          });\n        })\n        .end();\n      expect(vm.a).toBe('bbb');\n    });\n\n  });\n\n  describe('various options', function () {\n    let demoObject1, demoObject2, deepObject;\n    beforeEach(function () {\n      demoObject1 = {\n        a: 'aaa',\n        b: 'bbb'\n      };\n      demoObject2 = {\n        c: 'ccc',\n        d: 'ddd'\n      };\n      deepObject = {\n        a: 'aaa',\n        b: {bb: 'bbb'}\n      };\n\n      createDefaultExportImport(demoObject1, ['a', 'b']);\n      createDefaultExportImport(demoObject2, ['c', 'd']);\n      createDefaultExportImport(deepObject, ['a']);\n      createDefaultExportImport(deepObject.b, ['bb']);\n\n    });\n\n    it('should load only once when oneTimeLoad = true', function () {\n      window.localStorage['demoState'] = '{\"test1\":{\"a\":\"bbb\"},\"test2\":{\"c\":\"ddd\"}}';\n      const stateWrapper1 = StateWrapper.build()\n        .useObject(demoObject1)\n        .withNewState('demoState')\n        .setClientName('test1')\n        .withOptions({oneTimeLoad: true})\n        .end();\n      StateWrapper.build()\n        .useObject(demoObject2)\n        .withState(stateWrapper1)\n        .setClientName('test2')\n        .end();\n      expect(demoObject1.a).toBe('bbb');\n      expect(demoObject2.c).toBe('ddd');\n      demoObject1.a = 'aaa';\n      demoObject2.c = 'ccc';\n      stateWrapper1.loadAll(); /* loading again, demoObject2 should load again, demoObject1 should not */\n      expect(demoObject1.a).toBe('aaa');\n      expect(demoObject2.c).toBe('ddd');\n    });\n\n    it('should load\\\\save only one level of Object when deep = false ', function () {\n      window.localStorage['demoState'] = '{\"test\":{\"a\":\"bbb\",\"b\":\"ccc\"}}';\n      const stateWrapper = StateWrapper.build()\n        .useObject(deepObject)\n        .withNewState('demoState')\n        .setClientName('test')\n        .withOptions({deep: false})\n        .end();\n      stateWrapper.load();\n      expect(deepObject.a).toBe('bbb');\n      expect(deepObject.b.bb).toBe('bbb');\n      window.localStorage['demoState'] = '';\n      stateWrapper.save();\n      expect(window.localStorage['demoState']).toBe('{\"test\":{\"a\":\"bbb\"}}');\n    });\n\n    it('should not load automatically when doClientLoad = false', function () {\n      window.localStorage['demoState'] = '{\"test1\":{\"a\":\"bbb\"}}';\n      const stateWrapper1 = StateWrapper.build()\n        .useObject(demoObject1)\n        .withNewState('demoState')\n        .setClientName('test1')\n        .withOptions({doClientLoad: false})\n        .end();\n      expect(demoObject1.a).toBe('aaa');\n      stateWrapper1.load();\n      expect(demoObject1.a).toBe('bbb');\n    });\n\n    it('should not load automatically when doClientLoad = false, and load when promised is resolved', function (done) {\n      window.localStorage['demoState'] = '{\"test1\":{\"a\":\"bbb\"}}';\n      const deferred = $q.defer<any>();\n      StateWrapper.build()\n        .useObject(demoObject1)\n        .withNewState('demoState')\n        .setClientName('test1')\n        .withOptions({doClientLoad: deferred.promise})\n        .end();\n\n      expect(demoObject1.a).toBe('aaa');\n      deferred.resolve(true);\n      deferred.promise.then(() => {\n        setTimeout(() => {\n          expect(demoObject1.a).toBe('bbb');\n          done();\n        });\n      });\n      $rootScope.$apply();\n    });\n\n    it('should not load automatically when doGlobalLoad = false', function () {\n      window.localStorage['demoState'] = '{\"test1\":{\"a\":\"bbb\"}}';\n      const stateWrapper1 = StateWrapper.build()\n        .useObject(demoObject1)\n        .withNewState('demoState')\n        .setClientName('test1')\n        .withOptions({doGlobalLoad: false})\n        .end();\n\n      expect(demoObject1.a).toBe('aaa');\n      stateWrapper1.load(); /* even though we load, globalLoad is turned off */\n      expect(demoObject1.a).toBe('aaa');\n    });\n\n    it('should not load automatically when doGlobalLoad = false, and but should allow load when promised is resolved', function (done) {\n      window.localStorage['demoState'] = '{\"test1\":{\"a\":\"bbb\"}}';\n      const deferred = $q.defer();\n      const stateWrapper1 = StateWrapper.build()\n        .useObject(demoObject1)\n        .withNewState('demoState')\n        .setClientName('test1')\n        .withOptions({doGlobalLoad: deferred.promise as any})\n        .end();\n\n      expect(demoObject1.a).toBe('aaa');\n      stateWrapper1.load();\n      expect(demoObject1.a).toBe('aaa');\n\n      deferred.resolve(true);\n      deferred.promise.then(() => {\n        setTimeout(() => {\n          stateWrapper1.load();\n          expect(demoObject1.a).toBe('bbb');\n          done();\n        });\n      });\n      $rootScope.$apply();\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/state-wrapper.ts",
    "content": "'use strict';\nimport {State} from './state';\nimport {IStateClient, IStateProvider} from './types';\nimport {urlStateProvider} from './url-state-provider';\nimport {localStorageStateProvider} from './localstorage-state-provider';\nimport {lodash as _, isPromise} from '../../utils';\n\n/**\n * Core services\n *\n * @author Our One Creator Which Flies and is Spaghetti and a Monster\n */\n\nconst IOProviders = {\n  localStorage: {\n    provider: localStorageStateProvider,\n    dataType: 'JSON'\n  },\n  url: {\n    provider: urlStateProvider,\n    dataType: 'URL'\n  }\n};\n\nexport type traverseFunction = (obj: any, callback: (obj: any, args: any[]) => void, args: any[], deep?: boolean) => void;\nfunction defaultTraverse(obj: any, callback, args: any[] = [], deep = true) {\n  callback(obj, args);\n  if (deep) {\n    _.forOwn(obj, (child, childName) => {\n      if (_.isObject(child) && child !== obj) {\n        defaultTraverse(child, callback, args, deep);\n      }\n    });\n  }\n}\n\nfunction createLoadFunction(obj: any, deep = true, oneTimeLoad = false, customTraverse?) {\n  const traverse = customTraverse ? customTraverse : defaultTraverse;\n\n  const loadFunction = function (ob: any, args: any[] = []) {\n    if (oneTimeLoad && ob.$stateLoaded) {\n      return;\n    }\n    if (_.isFunction(ob.$import)) {\n      ob.$import(...args);\n    }\n    if (oneTimeLoad) {\n      ob.$stateLoaded = true;\n    }\n  };\n  return function (params) {\n    traverse(obj, loadFunction, [params], deep);\n  };\n}\n\nfunction createSaveFunction(obj: Object, deep = true, customTraverse?): (providerName: string, stateName: any) => any {\n  const traverse = customTraverse ? customTraverse : defaultTraverse;\n\n  const saveFunction = function (providerName: string, accumulator, ob: any, args: any[] = []) {\n    if (_.isFunction(ob.$export)) {\n      _.assign(accumulator, ob.$export(providerName, ...args));\n    }\n  };\n\n  return function (providerName: string, stateName) {\n    const accumulator = {};\n    traverse(obj, saveFunction.bind(null, providerName, accumulator), [stateName], deep);\n    return accumulator;\n  };\n}\n\nexport interface StateWrapperOptions {\n  doClientLoad?: PromiseLike<boolean> | boolean;\n  doGlobalLoad?: PromiseLike<boolean> | boolean;\n  deep?: boolean;\n  oneTimeLoad?: boolean;\n}\n\nexport class StateWrapperBuilder {\n  private object: Object;\n  private clientName: string;\n  private state: StateWrapper;\n  private options: StateWrapperOptions = {\n    doClientLoad: true,\n    doGlobalLoad: true,\n    deep: true,\n    oneTimeLoad: false\n  };\n  private providers: string[];\n  private newStateName: string;\n  private traverse: traverseFunction;\n\n  useObject(object) {\n    this.object = object;\n    return this;\n  }\n\n  setClientName(name) {\n    this.clientName = name;\n    return this;\n  }\n\n  withOptions(options: StateWrapperOptions) {\n    this.options = _.assign(this.options, options);\n    return this;\n  }\n\n  withState(state: StateWrapper) {\n    this.state = state;\n    return this;\n  }\n\n  withNewState(name: string) {\n    this.newStateName = name;\n    return this;\n  }\n\n  withProviders(providers: string[]) {\n    this.providers = providers;\n    return this;\n  }\n\n  withCustomTraverse(traverseFunc: traverseFunction) {\n    this.traverse = traverseFunc;\n    return this;\n  }\n\n  private verifyMandatoryParametrs() {\n    if (!this.object) {\n      throw new Error('StateWrapperBuilder::build: You must provide an object');\n    }\n    if (!this.clientName) {\n      throw new Error('StateWrapperBuilder::build: You must provide a clientName');\n    }\n    if (!this.state && !this.newStateName) {\n      throw new Error('StateWrapperBuilder::build: You must provide a state');\n    }\n  }\n\n  public end() {\n    this.verifyMandatoryParametrs();\n\n    const {doClientLoad, doGlobalLoad, deep, oneTimeLoad} = this.options;\n    let baseState;\n\n    if (!this.providers) {\n      this.providers = ['localStorage', 'url'];\n    }\n\n    if (this.state) {\n      baseState = this.state.getBaseState();\n    } else {\n      baseState = new State(this.newStateName, doGlobalLoad);\n    }\n    const stateWrapper = new StateWrapper(baseState, this.clientName, this.providers);\n    const stateClient: IStateClient = {\n      name: this.clientName,\n      importFunc: createLoadFunction(this.object, deep, oneTimeLoad, this.traverse),\n      exportFunc: createSaveFunction(this.object, deep, this.traverse)\n    };\n\n    baseState.register(stateClient);\n\n    if (doClientLoad === true) {\n      stateWrapper.load();\n    } else if (isPromise(doClientLoad)) {\n      (doClientLoad as PromiseLike<boolean>).then(() => {\n        stateWrapper.load();\n      });\n    }\n\n    return stateWrapper;\n  }\n}\n\nexport class StateWrapper {\n  private readonly inputOutputProviders: {name: string; provider: IStateProvider; dataType: string}[] = [];\n\n  static build() {\n    return new StateWrapperBuilder();\n  }\n\n  constructor(private readonly state: State, private readonly clientName, providers = ['localStorage', 'url']) {\n    providers.forEach((providerName) => {\n      if (IOProviders[providerName]) {\n        this.inputOutputProviders.push({name: providerName, ...IOProviders[providerName]});\n      }\n    });\n  }\n\n  getBaseState() {\n    return this.state;\n  }\n\n  private _load(clientList: string[] = []) {\n    const stateName = this.state.getName();\n    this.inputOutputProviders.forEach(providerInfo => {\n      const data = providerInfo.provider.getStateData(stateName);\n      const functionName = 'importFrom' + providerInfo.dataType;\n      this.state[functionName](data, ...clientList);\n    });\n  }\n\n  load(...clientList) {\n    if (clientList.length === 0) {\n      clientList = [this.clientName];\n    }\n    this._load(clientList);\n  }\n\n  loadAll() {\n    this._load([]);\n  }\n\n  private _save(clientList: string[] = []) {\n    const stateName = this.state.getName();\n    this.inputOutputProviders.forEach(providerInfo => {\n      const functionName = 'exportAs' + providerInfo.dataType;\n      const data = this.state[functionName](providerInfo.name, ...clientList);\n      providerInfo.provider.setStateData(stateName, data);\n    });\n  }\n\n  save(...clientList) {\n    if (clientList.length === 0) {\n      clientList = [this.clientName];\n    }\n    this._save(clientList);\n  }\n\n  saveAll() {\n    this._save([]);\n  }\n\n  unregister() {\n    this.state.unregister(this.clientName);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/state.test.ts",
    "content": "import {State} from './state';\nimport {IStateClient} from './types';\n\ndescribe('State', function () {\n\n  let state: State;\n  beforeEach(() => {\n    state = new State('test');\n  });\n\n  describe('State::register', () => {\n    beforeEach(function() {\n        spyOn(console, 'error');\n      });\n\n      const client1: IStateClient = {\n        name: 'test1',\n        exportFunc: () => ({original: true}),\n        importFunc: (params) => ({})\n      };\n      const client1Again: IStateClient = {\n        name: 'test1',\n        exportFunc: () => ({redefined: true}),\n        importFunc: (params) => ({}),\n      };\n\n      it('should not override old client with new client with same name', () => {\n        state.register(client1);\n        state.register(client1Again);\n        expect(console.error).toHaveBeenCalledWith('State:register:: trying to register same name twice - test1');\n        expect(state.exportAsJSON()).toEqual('{\"test1\":{\"original\":true}}');\n      });\n\n      it('should register waiting client when original client un-registers', () => {\n        state.register(client1);\n        state.register(client1Again);\n        state.unregister('test1');\n        expect(console.error).toHaveBeenCalledWith('State:register:: trying to register same name twice - test1');\n        expect(state.exportAsJSON()).toEqual('{\"test1\":{\"redefined\":true}}');\n      });\n  });\n\n  describe('State::export', () => {\n    let client1, client2: IStateClient;\n    beforeEach(() => {\n      client1 = {\n        name: 'test1',\n        exportFunc: () => ({param1: true, param2: 4}),\n        importFunc: (params) => ({})\n      };\n      client2 = {\n        name: 'test2',\n        exportFunc: () => ({param2: 'aaaa', param1: 'bbbb'}),\n        importFunc: (params) => ({})\n      };\n    });\n\n    it('should successfully call export function with the provider name and stateName', function () {\n      spyOn(client1, 'exportFunc');\n      state.register(client1);\n      state.exportAsJSON('testProvider');\n\n      expect(client1.exportFunc).toHaveBeenCalledWith('testProvider', 'test');\n    });\n\n    it('should successfully call export function with the provider name and stateName', function () {\n      spyOn(client1, 'exportFunc');\n      state.register(client1);\n      state.exportAsURL('testProvider');\n\n      expect(client1.exportFunc).toHaveBeenCalledWith('testProvider', 'test');\n    });\n\n    it('successfully export all clients to JSON\\\\URL', function () {\n      state.register(client1);\n      state.register(client2);\n      expect(state.exportAsJSON())\n        .toBe('{\"test1\":{\"param1\":true,\"param2\":4},\"test2\":{\"param2\":\"aaaa\",\"param1\":\"bbbb\"}}');\n      expect(state.exportAsURL())\n        .toBe('&test-data=test1-param1:true;test1-param2:4;test2-param2:aaaa;test2-param1:bbbb;');\n    });\n\n    it('successfully export specific client to JSON\\\\URL', function () {\n      state.register(client1);\n      state.register(client2);\n      expect(state.exportAsURL('provider', 'test1'))\n        .toBe('&test-data=test1-param1:true;test1-param2:4;');\n      expect(state.exportAsJSON('provider', 'test1'))\n        .toBe('{\"test1\":{\"param1\":true,\"param2\":4}}');\n    });\n  });\n\n  describe('State::import', () => {\n    let client1, client2: IStateClient;\n    let results1, results2;\n    beforeEach(() => {\n      client1 = {\n        name: 'test1',\n        exportFunc: () => ({param1: true, param2: 4}),\n        importFunc: (params: any) => {\n          results1.param1 = params.param1;\n          results1.param2 = params.param2;\n        }\n      };\n      client2 = {\n        name: 'test2',\n        exportFunc: () => ({param2: 'aaaa', param1: 'bbbb'}),\n        importFunc: (params: any) => {\n          results2.param2 = params.param2;\n          results2.param1 = params.param1;\n        }\n      };\n      results1 = {};\n      results2 = {};\n\n      state.register(client1);\n      state.register(client2);\n    });\n\n    it('should successfully import all clients from JSON', function () {\n      state.importFromJSON('{\"test1\":{\"param1\":true,\"param2\":4},\"test2\":{\"param2\":\"aaaa\",\"param1\":\"bbbb\"}}');\n      expect(results1).toEqual({param1: true, param2: 4});\n      expect(results2).toEqual({param2: 'aaaa', param1: 'bbbb'});\n    });\n\n    it('should successfully import to all clients from URL', function () {\n      state.importFromURL('test1-param1:true;test1-param2:4;test2-param2:aaaa;test2-param1:bbbb;');\n      expect(results1).toEqual({param1: 'true', param2: '4'});\n      expect(results2).toEqual({param2: 'aaaa', param1: 'bbbb'});\n    });\n\n    it('should correctly process values with colons', function () {\n      state.importFromURL('test1-param1:a:b;');\n      expect(results1).toEqual({param1: 'a:b', param2: undefined});\n    });\n  });\n\n  describe('State::unregister', () => {\n    let client1, client2: IStateClient;\n    let results1, results2;\n    beforeEach(() => {\n      client1 = {\n        name: 'test1',\n        exportFunc: () => ({param1: true, param2: 4}),\n        importFunc: (params: any) => {\n          results1.param1 = params.param1;\n          results1.param2 = params.param2;\n        }\n      };\n      client2 = {\n        name: 'test2',\n        exportFunc: () => ({param2: 'aaaa', param1: 'bbbb'}),\n        importFunc: (params: any) => {\n          results2.param2 = params.param2;\n          results2.param1 = params.param1;\n        }\n      };\n      results1 = {};\n      results2 = {};\n\n      state.register(client1);\n      state.register(client2);\n    });\n\n    it('should not to do anything after client unregistered', function () {\n      state.unregister('test2');\n      state.importFromJSON('{\"test1\":{\"param1\":true,\"param2\":4},\"test2\":{\"param2\":\"aaaa\",\"param1\":\"bbbb\"}}');\n      expect(results1).toEqual({param1: true, param2: 4});\n      expect(results2).toEqual({});\n    });\n\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/state.ts",
    "content": "import {lodash as _, isPromise} from '../../utils';\ntype Dictionary<T> = Record<string, T>;\nimport {IStateClient} from './types';\n\nexport class State {\n  private readonly clients: {[key: string]: IStateClient} = {};\n  /* sometimes $destory is called only after another instance of a directive is loading\n    so we save a queue of 1 \"waiting\" client */\n  private readonly clientsOnHold: {[key: string]: IStateClient} = {};\n\n  constructor (private readonly name: string, private doLoad: boolean | PromiseLike<boolean> = true) {\n    if (isPromise(doLoad)) {\n      (doLoad as PromiseLike<boolean>).then((value) => {\n        this.doLoad = value;\n      });\n    }\n  }\n\n  getName() {\n    return this.name;\n  }\n\n  getClientByName(name: string) {\n    return this.clients[name];\n  }\n\n  /**\n   * adds a new client to this state.\n   * @param client\n   * @returns {bi.core.srv.state.State}\n   */\n  register (client: IStateClient): State {\n    const {name} = client;\n    if (this.clients[name]) {\n      console.error('State:register:: trying to register same name twice - ' + name);\n      this.clientsOnHold[name] = client;\n    } else {\n      this.clients[name] = client;\n    }\n    return this;\n  }\n\n  unregister(name: string): State {\n    if (this.clients[name]) {\n      // tslint:disable-next-line: no-dynamic-delete\n      delete this.clients[name];\n      const waitingClient = this.clientsOnHold[name];\n      if (waitingClient) {\n        this.clients[name] = waitingClient;\n        // tslint:disable-next-line: no-dynamic-delete\n        delete this.clientsOnHold[name];\n      }\n    }\n    return this;\n  }\n\n  private _export (providerName: string, clientList: string[]) {\n    const res: Dictionary<Dictionary<string>> = {};\n\n    if (clientList.length === 0) {\n      clientList = Object.keys(this.clients);\n    }\n    _.forEach(clientList, (clientName: string) => {\n      if (this.clients[clientName]) {\n        const client = this.clients[clientName];\n        res[client.name] = {};\n        _.assign(res[client.name], client.exportFunc(providerName, this.name));\n      }\n    });\n    return res;\n  }\n\n  exportAsJSON (providerName?: string, ...clientList: string[]) {\n    return JSON.stringify(this._export(providerName, clientList));\n  }\n\n  //TODO: handle objects? in paramData\n  exportAsURL (providerName?: string, ...clientList: string[]) {\n    const data = this._export(providerName, clientList);\n    const params = _.reduce(data, (outerResult, clientData, clientName) => {\n      // tslint:disable-next-line: restrict-plus-operands\n      return outerResult + _.reduce(clientData, (innerResult, paramData, paramName) => {\n          return innerResult + `${clientName}-${paramName}:${paramData};`;\n        }, '');\n    }, '');\n    return encodeURI(`&${this.name}-data=${params}`);\n  }\n\n  private _import (data: Object, clientList: string[]) {\n    if (clientList.length === 0) {\n      clientList = Object.keys(this.clients);\n    }\n\n    _.forEach(clientList, (clientName: string) => {\n      if (this.clients[clientName]) {\n        const client = this.clients[clientName];\n        if (data[client.name]) {\n          client.importFunc(data[client.name]);\n        }\n      }\n    });\n  }\n\n  importFromJSON(stringData: string, ...clientList: string[]) {\n    if (this.doLoad !== true) {\n      return;\n    }\n\n    if (stringData) {\n      this._import(JSON.parse(stringData), clientList);\n    }\n  }\n\n  importFromURL(stringData: string, ...clientList: string[]) {\n    if (this.doLoad !== true) {\n      return;\n    }\n    // let match = new RegExp(`&?${this.name}-data=(.*)&?`).exec(stringData);\n    // if (match && match[1]) {\n    //   var stringDataStripStateName = match[1];\n    // } else {\n    //   throw new Error(\"State::importFromURL: Can't parse data!\");\n    // }\n\n    if (!stringData) {\n      return;\n    }\n    const data = {};\n    const allParams = stringData.split(';');\n\n    allParams.forEach( singleParamStr => {\n      const [paramFullName, ...paramData] = singleParamStr.split(':');\n      const path = paramFullName.replace('-', '.');\n      _.set(data, path, paramData.join(':'));\n    });\n    this._import(data, clientList );\n  }\n\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/types.ts",
    "content": "export interface IStateClient {\n  name: string;\n  importFunc(params: any): void;\n  exportFunc(providerName: string, stateName: string): Object;\n}\n\nexport interface IStateProvider {\n  getStateData(stateName: string): string;\n  setStateData(stateName: string, data: string): void;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/url-params.test.ts",
    "content": "'use strict';\n\nimport * as angular from 'angular';\nimport {UrlParams} from './url-params';\n\ndescribe('Service: UrlParams', function () {\n  let urlParams, $location, $browser, decodeSpy, encodeSpy;\n\n  function updateURL(url) {\n    $location.url(url);\n    $browser.poll();\n  }\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$location_, _$browser_) {\n    urlParams = new UrlParams();\n    $location = _$location_;\n    $browser = _$browser_;\n  }));\n\n  beforeEach(function () {\n    decodeSpy = jasmine.createSpy('decode');\n    encodeSpy = jasmine.createSpy('encode');\n  });\n\n  it('should return expected interface, decode + generateURL', function () {\n    updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3=true');\n\n    const urlObject = urlParams.register('fm', decodeSpy, encodeSpy);\n    expect(typeof urlObject.decode).toBe('function');\n    expect(typeof urlObject.generateURL).toBe('function');\n  });\n\n  it('should call decode function', function () {\n    updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3=true');\n\n    const urlObject = urlParams.register('fm', decodeSpy, encodeSpy);\n    urlObject.decode();\n    expect(decodeSpy).toHaveBeenCalled();\n  });\n\n  it('should call decode function, with expected parameters', function () {\n    updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3&not-param=5');\n\n    const expededObject = {\n      param1: '1',\n      param2: 'hello',\n      param3: true\n    };\n    const urlObject = urlParams.register('fm', decodeSpy, encodeSpy);\n    urlObject.decode();\n    expect(decodeSpy).toHaveBeenCalledWith(expededObject);\n  });\n\n  it('should call encode function', function () {\n    updateURL('/loc1?fm-param1=1&fm-param2=hello&fm-param3&not-param=5');\n\n    const urlObject = urlParams.register('fm', decodeSpy, encodeSpy);\n    urlObject.generateURL();\n    expect(encodeSpy).toHaveBeenCalled();\n  });\n\n  it('should return correct url for all modules', function () {\n    const encode = function () {\n      return {\n        param1: '1',\n        param2: 'hello',\n        param3: true\n      };\n    };\n    const encodeSecond = function () {\n      return {\n        param1: '2'\n      };\n    };\n\n    const decodeSpy = jasmine.createSpy('decode');\n    urlParams.register('fm', decodeSpy, encode);\n    urlParams.register('second', decodeSpy, encodeSecond);\n    const urlResult = urlParams.generateURL();\n    expect(urlResult).toBe('fm-param1=1&fm-param2=hello&fm-param3&second-param1=2');\n  });\n\n  it('should return correct url for specific module', function () {\n    const encode = function () {\n      return {\n        param1: '1',\n        param2: 'hello',\n        param3: true\n      };\n    };\n    const encodeSecond = function () {\n      return {\n        param1: '2'\n      };\n    };\n\n    urlParams.register('fm', decodeSpy, encode);\n    urlParams.register('second', decodeSpy, encodeSecond);\n    let urlResult = urlParams.generateURL(['second']);\n    expect(urlResult).toBe('second-param1=2');\n    urlResult = urlParams.generateURL(['fm']);\n    expect(urlResult).toBe('fm-param1=1&fm-param2=hello&fm-param3');\n  });\n\n  it('should unregister a module', function () {\n    const encodeSecondSpy = jasmine.createSpy('encode');\n\n    const urlObject = urlParams.register('fm', decodeSpy, encodeSpy);\n    urlParams.register('second', decodeSpy, encodeSecondSpy);\n    urlParams.generateURL();\n    expect(encodeSpy).toHaveBeenCalled();\n    expect(encodeSecondSpy).toHaveBeenCalled();\n    encodeSpy.calls.reset();\n    encodeSecondSpy.calls.reset();\n    urlObject.unregister();\n    urlParams.generateURL();\n    expect(encodeSpy).not.toHaveBeenCalled();\n    expect(encodeSecondSpy).toHaveBeenCalled();\n  });\n\n  it('should throw error when registering same prefix', function () {\n    urlParams.register('fm', decodeSpy, encodeSpy);\n    expect(function () {\n      urlParams.register('fm', decodeSpy, encodeSpy);\n    }).toThrow(new Error('urlParams: registered two modules with same prefix: fm'));\n  });\n\n  it('should throw error when registering module with dash', function () {\n    expect(function () {\n      urlParams.register('fm-2', decodeSpy, encodeSpy);\n    }).toThrow(new Error('urlParams: can\\'t register module name with a dash: fm-2'));\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/url-params.ts",
    "content": "'use strict';\n\nimport {lodash as _} from '../../utils';\nimport {injector} from '../injector';\n\nfunction processParam(moduleName: string, paramName: string, paramValue: string | boolean) {\n  let paramNameWithPrefix = moduleName + '-' + paramName;\n  if (paramValue === true) {\n    return paramNameWithPrefix + '&';\n  } else if (paramValue === false) {\n    return '';\n  } else {\n    return paramNameWithPrefix + '=' + paramValue + '&';\n  }\n}\n\nexport type decodeFunc = (input: {}) => any;\nexport type encodeFunc = () => {[key: string]: string | boolean};\n\nexport interface ModuleCallbacks {\n  encode: encodeFunc;\n  decode: decodeFunc;\n}\n\nexport class UrlParams {\n  modules = {};\n  private $location: ng.ILocationService;\n\n  constructor() {\n    this.$location = injector.get('$location');\n  }\n\n  register(moduleName: string, decode: decodeFunc, encode: encodeFunc) {\n    if (moduleName.search('\\-') !== -1) {\n      throw new Error('urlParams: can\\'t register module name with a dash: ' + moduleName);\n    }\n    if (this.modules[moduleName]) {\n      throw new Error('urlParams: registered two modules with same prefix: ' + moduleName);\n    }\n\n    this.modules[moduleName] = {decode, encode};\n    return {\n      decode: () => {\n        return this.decode([moduleName]);\n      },\n      generateURL: this.generateURL.bind(this, [moduleName]),\n      unregister: () => {\n        if (this.modules[moduleName]) {\n          delete this.modules[moduleName];\n        }\n      }\n    };\n  }\n\n  public generateURL(moduleList: Array<string> = null) {\n    let res = '';\n    _.forEach(this.modules, (cb: ModuleCallbacks, moduleName) => {\n      if (moduleList && ! _.includes(moduleList, moduleName)) {\n        return;\n      }\n      let moduleParams = cb.encode();\n      _.forEach(moduleParams, (paramValue, paramName) => {\n        res += processParam(moduleName, paramName, paramValue);\n      });\n    });\n    return res.slice(0, -1);\n  }\n\n  public decode(moduleList: Array<string> = null) {\n    let map = this._sperateParamsByModule();\n    _.forEach(this.modules, (cb: ModuleCallbacks, moduleName) => {\n      if (moduleList && ! _.includes(moduleList, moduleName)) {\n        return;\n      }\n      cb.decode(map[moduleName]);\n    });\n  }\n\n  private _sperateParamsByModule() {\n    let res = {};\n    let urlMap = this.$location.search();\n    _.forEach(urlMap, (value, key: string) => {\n      let [moduleName] = key.split('-', 1);\n      if (this.modules[moduleName]) {\n        let path = key.replace('-', '.');\n        _.set(res, path, value);\n      }\n    });\n    return res;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/url-state-provider.test.ts",
    "content": "'use strict';\nimport {urlStateProvider} from './url-state-provider';\nimport * as angular from 'angular';\n\ndescribe('UrlStateProvider', function () {\n\n  let $location, $browser;\n\n  function updateURL(url) {\n    $location.url(url);\n    $browser.poll();\n  }\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  beforeEach(inject(function (_$location_, _$browser_) {\n    $location = _$location_;\n    $browser = _$browser_;\n  }));\n\n  describe('Load', () => {\n    it('should correctly load data', function () {\n      updateURL('/loc1?test-data=param1:2;parma2=aaa');\n      expect(urlStateProvider.getStateData('test')).toEqual('param1:2;parma2=aaa');\n    });\n\n    it('should return null when no data in url', function () {\n      updateURL('/loc1?test-data=param1:2;parma2=aaa');\n      expect(urlStateProvider.getStateData('test2')).toEqual(null);\n    });\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/state/url-state-provider.ts",
    "content": "import {IStateProvider} from './types';\nimport {injector} from '../injector';\n\nexport const urlStateProvider: IStateProvider = new class UrlStateProvider implements IStateProvider {\n  private location: ng.ILocationService;\n\n  constructor() {\n    injector.on('ready', () => {\n      this.location = injector.get('$location');\n    });\n  }\n\n  getStateData(stateName: string): string {\n    const urlMap = this.location.search();\n    const result = urlMap[stateName + '-data'];\n    return result ? result : null;\n  }\n\n  setStateData(stateName: string, data: string): void {\n    //-- Nothing for now. maybe change url --\n  }\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/view-model/view-model.test.ts",
    "content": "'use strict';\nimport {ViewModel, create as createVM} from './view-model';\nimport * as angular from 'angular';\n\ndescribe('bi.core.drv.createViewModel()', function () {\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  describe('creation', function () {\n    it('should create an empty view model', function () {\n      const vm = createVM();\n\n      expect(vm).toBeDefined();\n    });\n\n    it('should create an view model from object', function () {\n      const vm = createVM({\n        test: true\n      }) as any;\n\n      expect(vm.test).toBe(true);\n    });\n\n    it('should not alter the template', function () {\n      const template = {\n        test: true\n      };\n      const templateString = JSON.stringify(template);\n\n      createVM(template);\n\n      expect(templateString).toBe(JSON.stringify(template));\n    });\n\n    it('should use the existing vm', function () {\n      const vm = (createVM() as any).vm;\n      const vm2 = (createVM(null, vm) as any).vm;\n\n      expect(vm2).toBe(vm);\n    });\n  });\n\n  describe('flags', function () {\n    it('should define basic flags with false values', function () {\n      const vm = createVM();\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(false);\n    });\n\n    it('should not override template flag values', function () {\n      const vm = createVM({\n        enabled: true\n      });\n\n      expect(vm.enabled).toBe(true);\n    });\n\n    it('should initialize nested values', function () {\n      const vm = createVM({\n        nested: {\n          enabled: true\n        }\n      }) as any;\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(false);\n      expect(vm.nested.enabled).toBe(true);\n      expect(vm.nested.visible).toBe(false);\n    });\n\n    it('should toggle enabled and visible flags', function () {\n      const vm = createVM() as any;\n\n      vm.toggle();\n\n      expect(vm.enabled).toBe(true);\n      expect(vm.visible).toBe(true);\n\n      vm.toggle(false);\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(false);\n    });\n\n    it('should set enabled and visible flags', function () {\n      const vm = createVM();\n\n      vm.toggle(true);\n\n      expect(vm.enabled).toBe(true);\n      expect(vm.visible).toBe(true);\n\n      vm.toggle(true);\n\n      expect(vm.enabled).toBe(true);\n      expect(vm.visible).toBe(true);\n    });\n\n    it('should toggle enabled flag', function () {\n      const vm = createVM() as any;\n\n      vm.toggleEnabled();\n\n      expect(vm.enabled).toBe(true);\n      expect(vm.visible).toBe(false);\n\n      vm.toggleEnabled(true);\n\n      expect(vm.enabled).toBe(true);\n      expect(vm.visible).toBe(false);\n\n      vm.toggleEnabled(false);\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(false);\n    });\n\n    it('should toggle visible flag', function () {\n      const vm = createVM() as any;\n\n      vm.toggleVisible();\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(true);\n\n      vm.toggleVisible(true);\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(true);\n\n      vm.toggleVisible(false);\n\n      expect(vm.enabled).toBe(false);\n      expect(vm.visible).toBe(false);\n    });\n  });\n\n  describe('template cloning', function () {\n    it('should deep clone the template (object)', function () {\n      const obj = {};\n      const vm = createVM({\n        test: obj\n      }) as any;\n\n      expect(vm.test).not.toBe(obj);\n    });\n\n    it('should deep clone the template (array)', function () {\n      const arr = [];\n      const vm = createVM({\n        test: arr\n      }) as any;\n\n      expect(vm.test).not.toBe(arr);\n    });\n  });\n\n  describe('init', function () {\n    it('should call $init function', function () {\n      const vm = createVM({\n        $init: jasmine.createSpy('$init')\n      }).init() as any;\n\n      expect(vm.$init).toHaveBeenCalled();\n    });\n\n    it('should call $init function (nested values)', function () {\n      const vm = createVM({\n        nested: {\n          $init: jasmine.createSpy('$init')\n        }\n      }).init() as any;\n\n      expect(vm.nested.$init).toHaveBeenCalled();\n    });\n  });\n\n  describe('$root', function () {\n    it('should define a reference to the root', function () {\n      const vm = createVM().init() as any;\n\n      expect(vm.$root).toBe(vm);\n    });\n\n    it('should define a reference to the root (nested)', function () {\n      const vm = createVM({\n        test: {}\n      }).init() as any;\n\n      expect(vm.test.$root).toBe(vm);\n    });\n  });\n\n  describe('$params', function () {\n    it('should define custom params', function () {\n      const vm = createVM().init({\n        foo: 1\n      }) as any;\n\n      expect(vm.$params.foo).toBe(1);\n    });\n\n    it('should define custom params (nested)', function () {\n      const vm = createVM({\n        goo: {}\n      }).init({\n        foo: 1\n      }) as any;\n\n      expect(vm.goo.$params.foo).toBe(1);\n    });\n  });\n\n  describe('createItemsVm()', function () {\n    it('should create an items vm object', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm();\n        }\n      }).init() as any;\n\n      expect(vm.items).toBeDefined();\n    });\n\n    it('should create and return item vm by id', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm({\n            foo: 1\n          });\n        }\n      }).init() as any;\n\n      const itemVm = vm.items.get({id: 1});\n\n      expect(itemVm instanceof ViewModel).toBe(true);\n      expect(itemVm.foo).toBe(1);\n    });\n\n    it('should return same vm for items with same identifier', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm();\n        }\n      }).init() as any;\n\n      const item1Vm = vm.items.get({id: 1});\n      const item2Vm = vm.items.get({id: 1});\n\n      expect(item1Vm).toBe(item2Vm);\n    });\n\n    it('should return different vm for items with different identifiers', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm();\n        }\n      }).init() as any;\n\n      const item1Vm = vm.items.get({id: 1});\n      const item2Vm = vm.items.get({id: 2});\n\n      expect(item1Vm).not.toBe(item2Vm);\n    });\n\n    it('should return null if identifier is not defined', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm();\n        }\n      }).init() as any;\n\n      const item1Vm = vm.items.get({});\n\n      expect(item1Vm).toBe(null);\n    });\n\n    it('should create and return vm by custom identifier', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm().identifyBy(function (item) {\n            return item.index;\n          });\n        }\n      }).init() as any;\n\n      const itemVm = vm.items.get({index: 1});\n\n      expect(itemVm instanceof ViewModel).toBe(true);\n    });\n\n    it('should delete item vm', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm({\n            foo: 1\n          });\n        }\n      }).init() as any;\n\n      const item1Vm = vm.items.get({id: 1});\n      vm.items.delete({id: 1});\n      const item2Vm = vm.items.get({id: 1});\n\n      expect(item2Vm).not.toBe(item1Vm);\n    });\n\n    it('should call $init for each new item vm', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.createItemsVm({\n            $init: jasmine.createSpy('$init')\n          });\n        }\n      }).init() as any;\n\n      const item1Vm = vm.items.get({id: 1});\n\n      expect(item1Vm.$init.calls.count()).toBe(1);\n    });\n\n    it('should call $init for each existing item vm', function () {\n      const vm = createVM({\n        $init: function () {\n          this.items = this.items || this.createItemsVm({\n            $init: jasmine.createSpy('$init')\n          });\n        }\n      }).init() as any;\n\n      const item1Vm = vm.items.get({id: 1});\n      vm.items.get({id: 2});\n\n      vm.init();\n\n      expect(item1Vm.$init.calls.count()).toBe(4);\n    });\n  });\n\n  describe('isHead()', function () {\n    it('should return true', function () {\n      const vm = createVM();\n\n      expect(vm.isHead()).toBe(true);\n    });\n\n    it('should return false', function () {\n      const vm = createVM({\n        child: {}\n      }) as any;\n\n      expect(vm.child.isHead()).toBe(false);\n    });\n  });\n\n  describe('forEach()', function () {\n    it('should apply the function to the root node', function () {\n      const vm = createVM();\n\n      const fn = jasmine.createSpy('forEach');\n      vm.forEach(fn);\n\n      expect(fn).toHaveBeenCalledWith(vm);\n    });\n\n    it('should apply the function for all nodes recursively', function () {\n      const vm = createVM({\n        child: {}\n      }) as any;\n\n      const fn = jasmine.createSpy('forEach');\n      vm.forEach(fn);\n\n      expect(fn.calls.allArgs()).toEqual([[vm], [vm.child]]);\n    });\n\n    it('should break on first iteration', function () {\n      const vm = createVM({\n        child: {}\n      });\n\n      const fn = jasmine.createSpy('forEach').and.returnValue(false);\n      vm.forEach(fn);\n\n      expect((<any>fn).calls.allArgs()).toEqual([[vm]]);\n    });\n\n    it('should not be called on a child head nodes', function () {\n      const vm = createVM() as any;\n\n      vm.childHead = createVM();\n\n      const fn = jasmine.createSpy('forEach');\n      vm.forEach(fn);\n\n      expect(vm.childHead.isHead()).toBe(true);\n      expect(fn.calls.allArgs()).toEqual([[vm]]);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/srv/view-model/view-model.ts",
    "content": "'use strict';\nimport {lodash as _} from '../../utils';\nimport {injector} from '../injector';\n/**\n * Core directive tools\n *\n * @author Our One Creator Which Flies and is Spaghetti and a Monster\n */\n\nfunction createVM(template, root) {\n  return _.cloneDeepWith(template, function (value) {\n    if (_.isPlainObject(value)) {\n      const vm = {};\n\n      _.forOwn(value, (val, key) => {\n        if (_.isPlainObject(val)) {\n          vm[key] = new ViewModel(val, root);\n        } else {\n          vm[key] = createVM(val, root);\n        }\n      });\n\n      return vm;\n    }  if (_.isArray(value)) {\n      return; // let lodash clone the value\n    }\n\n    return value;\n  });\n}\n\nexport class ItemsViewModel {\n  private items: { [id: string]: ViewModel } = {};\n  private identifier = item => item.id;\n\n  constructor(private readonly vm?) { }\n\n  get(item: Object): ViewModel {\n    const id = this.identifier(item);\n\n    if (_.isUndefined(id)) {\n      return null;\n    }\n\n    return this.items[id] = this.items[id] || new ViewModel(this.vm).init();\n  }\n\n  all(): ViewModel[] {\n    return _.values(this.items);\n  }\n\n  delete(item: Object): ItemsViewModel {\n    // tslint:disable-next-line: no-dynamic-delete\n    delete this.items[this.identifier(item)];\n    return this;\n  }\n\n  deleteAll(): ItemsViewModel {\n    this.items = {};\n    return this;\n  }\n\n  identifyBy(identifier: (item: Object) => number): ItemsViewModel {\n    this.identifier = identifier;\n\n    return this;\n  }\n\n  forEach(fn) {\n    let res;\n\n    this.all().every(item => {\n      res = item.forEach(fn);\n      return res === false ? false : true;\n    });\n\n    return res;\n  }\n}\n\nexport class ViewModel {\n  enabled: boolean;\n  visible: boolean;\n\n  constructor(vm: Object = null, protected $root = null) {\n    this.$root = this.$root || this;\n\n    try {\n      this.enabled = false;\n      this.visible = false;\n    } catch (e) {\n      //empty\n    }\n\n    if (vm) {\n      _.assign(this, createVM(vm, this.$root));\n    }\n  }\n\n  init(params?) {\n    this.forEach(vm => {\n      vm.$params = params;\n\n      if (_.isFunction(vm.$init)) {\n        vm.$init();\n      }\n    });\n\n    return this;\n  }\n\n  isHead() {\n    return this === this.$root;\n  }\n\n  /**\n   * Toggle both \"enabled\" and \"visible\" flags\n   */\n  toggle(enabled) {\n    try {\n      this.toggleEnabled(enabled);\n      this.toggleVisible(enabled);\n    } catch (e) {\n      //empty\n    }\n  }\n\n  /**\n   * Toggle the \"enabled\" flag\n   */\n  toggleEnabled(enabled) {\n    try {\n      this.enabled = typeof enabled !== 'undefined' ? enabled : !this.enabled;\n    } catch (e) {\n      //empty\n    }\n\n    return this.enabled;\n  }\n\n  /**\n   * Toggle the \"visible\" flag\n   */\n  toggleVisible(visible) {\n    try {\n      this.visible = typeof visible !== 'undefined' ? visible : !this.visible;\n    } catch (e) {\n      //empty\n    }\n\n    return this.visible;\n  }\n\n  reload() {\n    this.toggleVisible(false);\n\n    return injector.get('$timeout')(() => this.toggleEnabled(false)).then(() => injector.get('$timeout')(() => this.toggle(true)));\n  }\n\n  /**\n   * Create a view model for items. Useful for managing view state of items in a list.\n   */\n  createItemsVm(vm?) {\n    return new ItemsViewModel(vm);\n  }\n\n  forEach(fn) {\n    let res = fn(this);\n\n    if (res !== false) {\n      _.forOwn(this, (val, key) => {\n        if (val instanceof ViewModel && val.isHead()) {\n          return;\n        }\n\n        if (val instanceof ViewModel || val instanceof ItemsViewModel) {\n          return (res = val.forEach(fn));\n        }\n      });\n    }\n\n    return res;\n  }\n}\n\n/**\n * Create a view model object for use in the view layer\n *\n * @param vm  Plain object representation of the view model. Nested objects will be also converted to ViewModel instances.\n */\nexport function create(vm: Object = null, root?): ViewModel {\n  return new ViewModel(vm, root);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/types/angular-promise.d.ts",
    "content": "/// <reference types=\"angular\" />\nimport * as angular from 'angular';\n\ndeclare module 'angular' {\n  export interface IPromise<T> {\n    then<TResult = T, TResult2 = never>(successCallback: (promiseValue: T) => PromiseLike<TResult> | TResult, errorCallback?: (reason: any) => TResult2, notifyCallback?: (state: any) => any): IPromise<TResult | TResult2>;\n    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/utils/index.ts",
    "content": "'use strict';\n\nimport * as _ from 'lodash';\nimport jquery from 'jquery';\nimport * as Uuid from 'uuid';\nimport escapeHtml from 'escape-html';\n\nexport function isPromise(obj: any): boolean {\n  return (obj && typeof obj.then === 'function');\n}\n\nexport function uuid() {\n  return Uuid.v4();\n}\n\nexport const scope = {\n  safeApply(sc, fn: Function) {\n    const phase = sc.$root.$$phase;\n\n    if (phase === '$apply' || phase === '$digest') {\n      fn();\n    } else {\n      sc.$apply(fn);\n    }\n  },\n\n  safeDigest(sc, fn: Function) {\n    const phase = sc.$root.$$phase;\n\n    if (phase === '$apply' || phase === '$digest') {\n      fn();\n    } else {\n      fn();\n      sc.$digest();\n    }\n  }\n}\n\nexport const dom =  {\n  KEYS: {\n    escape: 27\n  },\n\n  onBlur(element, fn, sc?): Function {\n    const document = $(window.document);\n    const eventName = _.uniqueId('click.utils.dom.onBlur');\n\n    function off() {\n      document.off(eventName);\n    }\n\n    document.on(eventName, e => {\n      const parent = element.parent();\n      const target = $(e.target);\n\n      if (!target.closest(parent).length || target.closest(element).length) {\n        const child = target.closest(element).length && target;\n        let res;\n\n        if (sc) {\n          res = sc.$apply(() => fn(off, child));\n        } else {\n          res = fn(off, child);\n        }\n\n        if (res !== false) {\n          off();\n        }\n      }\n    });\n\n    if (sc) {\n      sc.$on('$destroy', off);\n    }\n\n    return off;\n  },\n\n  onKey(key, fn, s?): Function {\n    const document = $(window.document);\n    const eventName = _.uniqueId('keydown.utils.dom.onKey.' + key);\n    const codes = (Array.isArray(key) ? key : [key]).map(k => dom.KEYS[k] || k);\n\n    function off() {\n      document.off(eventName);\n    }\n\n    document.on(eventName, e => {\n      // tslint:disable-next-line: deprecation\n      if (codes.indexOf(e.keyCode) !== -1) {\n        e.preventDefault();\n\n        if (scope) {\n          // tslint:disable-next-line: deprecation\n          s.$apply(() => fn(off, e.keyCode));\n        } else {\n          // tslint:disable-next-line: deprecation\n          fn(off, e.keyCode);\n        }\n      }\n    });\n\n    if (s) {\n      s.$on('$destroy', off);\n    }\n\n    return off;\n  },\n\n  escape(str) {\n    return escapeHtml(str);\n  },\n\n  scrollIntoView(element, animate = false, offset = 0) {\n    const scrollParent = element.scrollParent();\n    // tslint:disable-next-line: restrict-plus-operands\n    const scrollTop = element.position().top + scrollParent.scrollTop() + offset;\n\n    scrollParent.animate({scrollTop}, animate ? 200 : 0);\n  },\n}\n\nexport function stripDollars<T extends object>(data: T): Partial<T> {\n  if (_.isPlainObject(data)) {\n    // tslint:disable-next-line: restrict-plus-operands\n    data = _.omitBy(data, (value, key) => ('' + key).charAt(0) === '$') as T;\n    data = _.mapValues(data, value => stripDollars(value as any)) as T;\n  }\n\n  if (_.isArray(data)) {\n    data = data.map(item => stripDollars(item)) as any;\n  }\n\n  return data;\n}\n\nexport function copyToClipboard(text: string) {\n  const input = jquery('<input>').val(text);\n\n  input.appendTo(window.document.body);\n  input.get(0).focus();\n  (input.get(0) as any).select();\n\n  // tslint:disable-next-line:deprecation\n  document.execCommand('Copy');\n\n  input.remove();\n}\n\nexport const lodash: any = _;\nimport './lodash4-polyfill';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/utils/lodash4-polyfill.ts",
    "content": "'use strict';\nimport {lodash} from './';\n\nif (!lodash.cloneDeepWith) {\n  lodash.cloneDeepWith = function (value, customizerFunction) {\n    return lodash.cloneDeep(value, customizerFunction);\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/utils/lodash4-polyfill.types.ts",
    "content": "declare module _ {\n  interface LoDashStatic {\n\n     cloneDeepWith: <TResult>(\n       value: any,\n       customizer: CloneDeepCustomizer<any, TResult>\n     ) => TResult;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/utils/utils.test-prepare.ts",
    "content": "'use strict';\n/* Don't include this file in index.vm' */\n\n// window['_'] = null;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/core/utils/utils.test.ts",
    "content": "import * as angular from 'angular';\nimport {scope, dom} from './';\n\ndescribe('bi.core.utils', function () {\n\n  beforeEach(function () {\n    angular.mock.module('bi.core.internal');\n  });\n\n  let safeApply, $rootScope: ng.IRootScopeService;\n  beforeEach(inject(function (_$rootScope_) {\n    $rootScope = _$rootScope_;\n    safeApply = scope.safeApply;\n  }));\n\n  describe('safeApply', () => {\n    it('should call function', function () {\n      const scope = $rootScope.$new();\n      const spy = jasmine.createSpy('scope spy');\n      safeApply(scope, spy);\n      expect(spy).toHaveBeenCalled();\n    });\n\n    it('should call function, even if inside $apply', function () {\n      const scope = $rootScope.$new();\n      const spy = jasmine.createSpy('scope spy');\n\n      expect(() => scope.$apply(() => scope.$apply(spy))).toThrow();\n      expect(spy).not.toHaveBeenCalled();\n\n      expect(() => scope.$apply(() => safeApply(scope, spy))).not.toThrow();\n      expect(spy).toHaveBeenCalled();\n    });\n  });\n\n  describe('escape', () => {\n    it('should html-escape string', function () {\n      expect(dom.escape('foo & bar')).toEqual('foo &amp; bar');\n    });\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/bootstrap.ts",
    "content": "import angular from 'angular';\n\nimport 'jquery-ui/ui/widgets/draggable';\nimport 'jquery-ui/ui/widgets/droppable';\nimport 'angular-dragdrop';\nimport '../core';\nimport '../ui';\n\nexport default angular.module('bi.fileExplorer', ['bi.core', 'bi.ui', 'ngDragDrop']);"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/directives/file-explorer-dynamic.html",
    "content": "<ul ng-if=\"::vm\" class=\"fe-folders\">\n  <li\n    ng-class=\"{'fe-folder--open': vm.folder.isOpen(folder)}\"\n    ng-repeat=\"folder in model.getFolders() | orderBy:'name' track by folder.getId()\"\n    ng-if=\"!options.hideEmptyFolders || folder.hasFileLeaf()\"\n  >\n    <div\n      class=\"fe-item bi-spread bi-fade-in bi-hover bi-muted {{::'fe-item-depth-' + depth}}\"\n      ng-class=\"{'bi-active': vm.folder.isActive(folder)}\"\n      drop=\"::!readonly\"\n      jqyoui-droppable=\"{onDrop: 'events.onItemDrop(folder)'}\"\n      jqyoui-options=\"{\n        accept: '.fe-item, .fe-item-name',\n        greedy: true\n      }\"\n      ng-model=\"vm.dropped.item\"\n    >\n      <div class=\"bi-r-h bi-align bi-grow\">\n        <i\n          class=\"fe-toggle bi-action bi-icon bi-pointer\"\n          ng-class=\"{'fe-toggle--hidden': folder.isEmpty()}\"\n          ng-click=\"events.onFolderToggle(folder);\"\n        >arrow_drop_down</i>\n\n        <span\n          class=\"fe-item-name bi-r-h bi-align bi-grow bi-pointer\"\n          ng-click=\"events.onFolderClick(folder)\"\n          drag=\"!readonly\"\n          jqyoui-draggable=\"{placeholder: 'keep', containment: 'offset'}\"\n          jqyoui-options=\"{\n            helper: 'clone',\n            distance: 5,\n            scroll: true,\n            appendTo: 'parent',\n            containment: options.draggable ? 'window' : vm.container\n          }\"\n          ng-model=\"folder\"\n          bi-html=\"renderFolder(scope)\"\n        ></span>\n      </div>\n\n      <bi-dropdown bd-options=\"::{align: 'right'}\" ng-if=\"::vm.folder.hasMenu(folder)\">\n        <bi-toggle class=\"bi-align\">\n          <i class=\"bi-action bi-icon\">more_vert</i>\n        </bi-toggle>\n\n        <div bi-html=\"renderMenu(scope, folder)\"></div>\n      </bi-dropdown>\n    </div>\n\n    <bi-file-explorer-inner\n      ng-if=\"vm.folder.isOpen(folder)\"\n      model=\"folder\"\n      fe-options=\"options\"\n      readonly=\"::readonly\"\n    ></bi-file-explorer-inner>\n  </li>\n</ul>\n\n<ul\n  ng-if=\"::vm\"\n  class=\"fe-files\"\n\n  drop=\"{{::depth === 0}}\"\n  jqyoui-droppable=\"{onDrop: 'events.onItemDrop(model)'}\"\n  jqyoui-options=\"{accept: '.fe-item', greedy: true}\"\n  ng-model=\"vm.dropped.item\"\n>\n  <li ng-if=\"model.isLazy()\">\n    <div class=\"fe-item {{::'fe-item-depth-' + depth}} bi-align bi-muted bi-fade-in\">Loading...</div>\n  </li>\n\n  <li\n    class=\"bi-hover bi-muted\"\n    ng-repeat=\"file in model.getFiles() | orderBy:vm.order.field track by file.getId()\"\n    ng-class=\"{'bi-active': vm.file.isActive(file)}\"\n    ng-click=\"events.onFileClick(file)\"\n  >\n    <div\n      class=\"fe-item {{::'fe-item-depth-' + depth}} bi-spread bi-align bi-pointer bi-fade-in\"\n      drag=\"!readonly\"\n      jqyoui-draggable=\"{placeholder: 'keep', containment: 'offset'}\"\n      jqyoui-options=\"{\n        helper: 'clone',\n        distance: 5,\n        scroll: true,\n        appendTo: 'parent',\n        containment: options.draggable ? 'window' : vm.container\n      }\"\n      ng-model=\"file\"\n      title=\"{{::file.getName()}}\"\n      bi-html=\"renderFile(scope)\"\n    ></div>\n  </li>\n</ul>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/directives/file-explorer-static.html",
    "content": "<ul ng-if=\"::vm\" class=\"fe-folders\">\n  <li\n    ng-class=\"{'fe-folder--open': vm.folder.isOpen(folder)}\"\n    ng-if=\"::!options.hideEmptyFolders || folder.hasFileLeaf()\"\n    ng-repeat=\"folder in model.getFolders() | orderBy:'name' | limitTo:model.getLimit() track by folder.getId()\"\n  >\n    <div\n      class=\"fe-item bi-spread bi-fade-in bi-hover bi-muted {{::'fe-item-depth-' + depth}}\"\n    >\n      <div class=\"bi-r-h bi-align bi-grow\">\n        <i\n          class=\"fe-toggle bi-action bi-icon bi-pointer\"\n          ng-class=\"{'fe-toggle--hidden': folder.isEmpty()}\"\n          ng-click=\"events.onFolderToggle(folder);\"\n        >arrow_drop_down</i>\n\n        <span\n          class=\"fe-item-name bi-r-h bi-align bi-grow bi-pointer\"\n          ng-click=\"events.onFolderClick(folder)\"\n          bi-html=\"renderFolder(scope)\"\n        ></span>\n      </div>\n\n      <bi-dropdown bd-options=\"::{align: 'right'}\" ng-if=\"::vm.folder.hasMenu(folder)\">\n        <bi-toggle class=\"bi-align\">\n          <i class=\"bi-action bi-icon\">more_vert</i>\n        </bi-toggle>\n\n        <div bi-html=\"renderMenu(scope, folder)\"></div>\n      </bi-dropdown>\n    </div>\n    \n    <bi-file-explorer-inner-static\n      ng-if=\"vm.folder.isOpen(folder)\"\n      model=\"folder\"\n      fe-options=\"options\"\n      readonly=\"true\"\n    ></bi-file-explorer-inner-static>\n  </li>\n</ul>\n\n<ul\n  ng-if=\"::vm\"\n  class=\"fe-files\"\n>\n  <li ng-if=\"model.isLazy()\">\n    <div class=\"fe-item {{::'fe-item-depth-' + depth}} bi-align bi-muted bi-fade-in\">Loading...</div>\n  </li>\n\n  <li\n    class=\"bi-hover bi-muted\"\n    ng-repeat=\"file in model.getFiles() | orderBy:vm.order.field track by file.getId()\"\n    ng-click=\"events.onFileClick(file)\"\n  >\n    <div\n      class=\"fe-item {{::'fe-item-depth-' + depth}} bi-spread bi-align bi-pointer bi-fade-in\"\n      title=\"{{::file.getName()}}\"\n      bi-html=\"renderFile(scope)\"\n    ></div>\n  </li>\n</ul>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/directives/file-explorer-vm.ts",
    "content": "import {Item, File, Folder} from '../services/file-explorer-models';\n\nexport default {\n  order: {\n    field: 'name',\n    setField(field: string, reversed = false) {\n      this.field = reversed ? '-' + field : field;\n    }\n  },\n  dropped: {\n    item: null as Item\n  },\n  folder: {\n    getPermissions(folder) {\n      const vm = this.$root.folders.get(folder);\n      return (vm.permissions = vm.permissions || this.$params.controller.getPermissions(folder));\n    },\n    canDelete(folder) {\n      return this.getPermissions(folder).delete;\n    },\n    canRename(folder) {\n      return this.getPermissions(folder).rename;\n    },\n    hasMenu(folder) {\n      return this.getPermissions(folder).menu;\n    },\n    toggleOpen(folder, value) {\n      this.$root.folders.get(folder).open.toggle(value);\n    },\n    toggleEdit(folder, value) {\n      this.$root.folders.get(folder).edit.toggle(value);\n    },\n    isOpen(folder) {\n      return this.$root.folders.get(folder).open.enabled;\n    },\n    setCurrent(folder: Folder) {\n      this.$params.controller.setCurrentFolder(folder);\n    },\n    getCurrent(): Folder {\n      return this.$params.controller.getCurrentFolder();\n    },\n    isActive(folder: File): boolean {\n      return folder.getId() === (this.getCurrent() && this.getCurrent().getId());\n    },\n    isEmpty(): boolean {\n      return this.$params.item.isEmpty();\n    },\n    $init() {\n      if (this.$params.item) {\n        this.$params.item.on('openToggled', (model, folder, isOpen) => {\n          this.$root.folder.toggleOpen(folder, isOpen);\n        }, true);\n\n        this.$params.item.on('editToggled', (model, folder, edit) => {\n          this.$root.folder.toggleEdit(folder, edit);\n        }, true);\n      }\n    }\n  },\n  file: {\n    setCurrent(file: File) {\n      this.$params.controller.setCurrentFile(file);\n    },\n    getCurrent(): File {\n      return this.$params.controller.getCurrentFile();\n    },\n    isActive(file: File): boolean {\n      return file.getId() === (this.getCurrent() && this.getCurrent().getId());\n    }\n  },\n  $init() {\n    if (!this.$params.controller) {\n      return;\n    }\n\n    this.folders = this.folders || this.createItemsVm({\n      menu: {},\n      edit: {},\n      open: {},\n      permissions: null\n    });\n\n    this.container = this.$params.controller.getContainer();\n  }\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/directives/file-explorer.scss",
    "content": "@import '../../ui/assets/css/def/colors.def';\n\n$item-height: 35px;\n\nquix-file-explorer,\nbi-file-explorer,\nbi-file-explorer-static,\nbi-file-explorer-static,\nbi-file-explorer-inner-static {\n  position: relative;\n  display: block;\n\n  bi-dropdown {\n    bi-toggle {\n      height: $item-height;\n    }\n  }\n\n  > ul > li {\n    user-select: none;\n    cursor: default !important;\n\n    .fe-item {\n      padding-right: 5px;\n      height: $item-height;\n    \n      > div {\n        flex-grow: 1;\n        overflow: hidden;\n        text-overflow: ellipsis;\n      }\n    }    \n\n    .fe-item-name {\n      height: $item-height;\n\n      .fe-icon-container {\n        line-height: 0;\n      }\n    \n      .fe-icon {\n        margin-right: 4px;\n        font-size: 18px;\n        vertical-align: text-bottom;\n      }\n    }\n  }\n\n  ul.fe-folders {\n    > li {\n      .fe-toggle {\n        transition: transform .2s;\n        transform: rotate(-90deg);\n        font-size: 19px;\n\n        &.fe-toggle--hidden {\n          visibility: hidden;\n        }\n      }\n\n      &.fe-folder--open {\n        > div > div > .fe-toggle {\n          transform: rotate(0);\n        }\n      }\n\n      > .fe-item {\n        @for $i from 0 through 3 {\n          &.fe-item-depth-#{$i} {\n            padding-left: $i * 12px + 4px;\n          }\n        }\n      }\n    }\n  }\n  \n  &.fe-folder-mode-select {\n    ul.fe-files > li,\n    ul.fe-folders > li > .fe-item {\n      transition: border-color .2s;\n      border-left: 2px solid transparent;\n\n      &:hover,\n      &.bi-active {\n        border-color: $primary;\n      }\n    }\n  }\n\n  ul.fe-files {\n    .fe-item {\n      @for $i from 0 through 3 {\n        &.fe-item-depth-#{$i} {\n          padding-left: $i * 12px + 29px;\n        }\n      }\n\n     > span {\n        white-space: nowrap;\n        overflow: hidden;\n        text-overflow: ellipsis;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/directives/file-explorer.ts",
    "content": "import { assign, isArray } from 'lodash';\nimport { createNgModel, initNgScope, inject } from '../../core';\nimport { toast } from '../../ui';\nimport { IItemDef } from '../services';\nimport { File, Folder } from '../services/file-explorer-models';\nimport { treeToDef, defToTree, addFile } from '../services/file-explorer-tools';\nimport Controller from '../services/file-explorer-controller';\nimport VM from './file-explorer-vm';\n\nimport templateDynamic from './file-explorer-dynamic.html';\nimport templateStatic from './file-explorer-static.html';\n\nimport './file-explorer.scss';\nimport { confirmAction } from '../../../services/dialog';\n\ntype Mode = 'static' | 'dynamic';\n\nfunction directive(mode: Mode, params) {\n  return assign(\n    {\n      template: mode === 'dynamic' ? templateDynamic : templateStatic,\n      restrict: 'E',\n    },\n    params\n  );\n}\n\nfunction initScope(scope, controller: Controller, depth: number, mode: Mode) {\n  scope.depth = depth;\n  scope.renderFolder = (s) => controller.renderFolder(s);\n  scope.renderFile = (s) => controller.renderFile(s);\n  scope.renderFolderIcon = (folder) =>\n    controller.renderFolderIcon(scope, folder);\n  scope.renderFileIcon = (file) => controller.renderFileIcon(scope, file);\n  scope.renderMenu = (s, folder) => controller.renderMenu(s, folder);\n\n  const helper = initNgScope(scope)\n    .readonly(scope.readonly)\n    .withOptions(\n      'feOptions',\n      {\n        fileAlias: 'file',\n        orderBy: 'name', // name|dateCreated|dateUpdated\n        orderReversed: false,\n        expandRootFolder: false,\n        expandAllFolders: false,\n        hideEmptyFolders: false,\n        folderMode: 'expand', // expand|select\n        draggable: false,\n      },\n      ({ orderBy, orderReversed, fileAlias }) => {\n        scope.options.fileAlias = isArray(fileAlias) ? fileAlias : [fileAlias];\n        scope.vm.order.setField(orderBy, orderReversed);\n      }\n    )\n    .withVM(VM)\n    .withEditableEvents({\n      onFileCreate(type = scope.options.fileAlias[0], folder?: Folder) {\n        const file = (folder || scope.model)\n          .toggleOpen(true)\n          .createFile(`New ${type}`, type);\n        controller.syncItem(file, 'fileCreated', type);\n      },\n      onFolderDelete(folder: Folder) {\n        const after = () => {\n          folder.destroy();\n\n          if (folder.getParent().isEmpty()) {\n            folder.getParent().toggleOpen(false);\n          }\n\n          controller.syncItem(folder, 'folderDeleted');\n\n          toast.showToast(\n            {\n              text: `Deleted folder \"${folder.getName()}\"`,\n              type: 'success',\n            },\n            3000\n          );\n        };\n\n        const action = folder.isEmpty() ? 'delete' : 'trash';\n\n        return confirmAction(action, 'folder', folder).then(after);\n      },\n      onFolderRename(folder: Folder) {\n        scope.vm.folder.toggleEdit(folder, true);\n      },\n      onFolderRenamed(folder: Folder) {\n        controller.syncItem(folder, 'folderRenamed');\n      },\n    })\n    .withEvents({\n      onItemDrop(_, __, folder: Folder) {\n        const { item }: { item: File | Folder } = scope.vm.dropped;\n\n        if (item instanceof File && !folder.getFileById(item.getId())) {\n          item.moveTo(folder);\n          controller.syncItem(item, 'fileMoved');\n        } else if (\n          item instanceof Folder &&\n          folder.getId() !== item.getId() &&\n          !folder.getFolderById(item.getId()) &&\n          !folder.getParentById(item.getId()) &&\n          folder.getDepth() + item.getLength() <= 3\n        ) {\n          item.moveTo(folder);\n          controller.syncItem(item, 'folderMoved');\n        }\n      },\n      onDrag(item: Folder | File) {\n        return item.getName();\n      },\n      onFolderBlur(folder: Folder) {\n        scope.vm.folder.toggleEdit(folder, false);\n      },\n      onFolderToggle(folder: Folder) {\n        if (scope.vm.folders.get(folder).edit.enabled) {\n          return;\n        }\n\n        scope.vm.folder.toggleOpen(folder);\n\n        if (scope.vm.folder.isOpen(folder)) {\n          folder.setLimit(20);\n\n          if (folder.isLazy()) {\n            controller.fetchLazyFolder(folder).then((items) => {\n              items.forEach((item) => addFile(folder, item));\n              folder.setLazy(false);\n\n              inject('$timeout')(() => folder.setLimit(null), 100);\n            });\n          } else {\n            inject('$timeout')(() => folder.setLimit(null), 100);\n          }\n        }\n      },\n      onFolderClick(folder: Folder) {\n        if (scope.options.folderMode === 'select') {\n          scope.vm.folder.setCurrent(folder);\n          scope.vm.file.setCurrent(null);\n          controller.clickFolder(folder);\n        } else {\n          scope.events.onFolderToggle(folder);\n        }\n      },\n      onFileClick(file: File) {\n        if (scope.options.folderMode === 'select') {\n          scope.vm.file.setCurrent(file);\n          scope.vm.folder.setCurrent(null);\n          controller.clickFile(file);\n        }\n      },\n    });\n\n  if (depth < 2) {\n    helper.withEditableEvents({\n      onFolderCreate(folder?: Folder) {\n        folder = (folder || scope.model).toggleOpen(true);\n\n        inject('$timeout')(() => {\n          folder = folder.createFolder('New folder').toggleEdit(true);\n\n          controller.syncItem(folder, 'folderCreated');\n        });\n      },\n    });\n  }\n}\n\nconst fileExplorerInnerBuilder = (mode: Mode) => () => {\n  return directive(mode, {\n    require: `^biFileExplorer${mode === 'static' ? 'Static' : ''}`,\n    scope: {\n      model: '=',\n      feOptions: '<',\n      readonly: '=',\n    },\n\n    link: {\n      pre: (scope, element, attrs, controller) => {\n        scope.$watch('model', (model) =>\n          scope.vm.init({\n            controller,\n            item: scope.model,\n            options: scope.options,\n          })\n        );\n\n        initScope(\n          scope,\n          controller,\n          (element.parents(\n            `bi-file-explorer-inner${mode === 'static' ? '-static' : ''}`\n          ).length as number) + 1,\n          mode\n        );\n      },\n    },\n  });\n};\n\nconst fileExplorerBuilder = (mode: Mode) => () => {\n  return directive(mode, {\n    require: ['ngModel', `biFileExplorer${mode === 'static' ? 'Static' : ''}`],\n    transclude: {\n      folderIcon: '?folderIcon',\n      fileIcon: '?fileIcon',\n      menu: '?menu',\n    },\n    controller: ['$scope', '$element', '$transclude', Controller],\n    scope: {\n      feOptions: '<',\n      onLazyFolderFetch: '&',\n      onFileClick: '&',\n      onFolderClick: '&',\n      onLoad: '&',\n      permissions: '&',\n      emptyText: '@',\n      readonly: '=',\n    },\n    link: {\n      pre: (\n        scope,\n        element,\n        attrs,\n        [ngModel, controller]: [ng.INgModelController, Controller]\n      ) => {\n        createNgModel(scope, ngModel)\n          .formatWith((model: IItemDef[]) => defToTree(model, scope.options))\n          .parseWith((model: Folder) => treeToDef(model))\n          .renderWith((model: Folder) => {\n            scope.vm.init({\n              controller,\n              item: model,\n              options: scope.options,\n              isRoot: true,\n            });\n          })\n          .then(() => {\n            if (\n              scope.options.expandRootFolder &&\n              scope.model.getFolders().length === 1\n            ) {\n              scope.model.getFolders()[0].toggleOpen(true);\n            }\n\n            scope.onLoad({ fileExplorer: controller.getInstance() });\n          })\n          .feedBack(false);\n\n        initScope(scope, controller, 0, mode);\n\n        element.addClass(`fe-folder-mode-${scope.options.folderMode}`);\n      },\n    },\n  });\n};\n\nexport const fileExplorer = fileExplorerBuilder('dynamic');\nexport const fileExplorerStatic = fileExplorerBuilder('static');\nexport const fileExplorerInner = fileExplorerInnerBuilder('dynamic');\nexport const fileExplorerInnerStatic = fileExplorerInnerBuilder('static');\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/directives/index.ts",
    "content": "export {\n  fileExplorer,\n  fileExplorerStatic,\n  fileExplorerInner,\n  fileExplorerInnerStatic\n} from './file-explorer';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/index.ts",
    "content": "import ngApp from './bootstrap';\nimport init from './init';\n\ninit(ngApp);\n\nexport * from './services';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/init.ts",
    "content": "import {forEach} from 'lodash';\nimport * as directives from './directives';\n\nfunction toDirectiveName(name: string) {\n  return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`;\n}\n\nexport default function init(ngApp: angular.IModule) {\n  forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any));\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/services/file-explorer-controller.ts",
    "content": "import {assign, defaults} from 'lodash';\nimport {inject} from '../../core';\nimport {Item, File, Folder} from './file-explorer-models';\nimport {itemToDef} from './file-explorer-tools';\nimport Instance from './file-explorer-instance';\n\ninterface Permissions {\n  rename: boolean;\n  delete: boolean;\n}\n\nexport default class Controller {\n  private readonly ngModel: ng.INgModelController;\n  private readonly $compile: ng.ICompileService;\n  private readonly instance: Instance;\n  private currentFolder: Folder = null;\n  private currentFile: File = null;\n\n  constructor(private readonly $scope, private readonly $element, private readonly $transclude :ng.ITranscludeFunction) {\n    this.instance = new Instance($scope);\n    this.ngModel = $element.controller('ngModel');\n    this.$compile = inject('$compile');\n  }\n\n  private render(html) {\n    return scope => ({html: this.$compile(html)(scope)});\n  }\n\n  getInstance(): Instance {\n    return this.instance;\n  }\n\n  getPermissions(folder): Permissions {\n    return defaults({}, this.$scope.permissions({folder: itemToDef(folder)}), {\n      rename: !this.$scope.readonly,\n      delete: !this.$scope.readonly,\n      menu: !this.$scope.readonly\n    });\n  }\n\n  getContainer() {\n    return this.$element;\n  }\n\n  setCurrentFolder(folder: Folder): Controller {\n    this.currentFolder = folder;\n    return this;\n  }\n\n  setCurrentFile(file: File): Controller {\n    this.currentFile = file;\n    return this;\n  }\n\n  getCurrentFolder(): Folder {\n    return this.currentFolder;\n  }\n\n  getCurrentFile(): File {\n    return this.currentFile;\n  }\n\n  fireEvent(item: Item, eventName: string, ...args): Controller {\n    this.instance.trigger(eventName, itemToDef(item), ...args);\n\n    return this;\n  }\n\n  syncItem(item: Item, eventName: string, ...args): Controller {\n    this.ngModel.$setViewValue(this.$scope.model.$clone());\n\n    this.fireEvent(item, eventName, ...args);\n\n    return this;\n  }\n\n  clickFile(file: File): Controller {\n    this.$scope.onFileClick({file: itemToDef(file)});\n    return this;\n  }\n\n  clickFolder(folder: Folder): Controller {\n    this.$scope.onFolderClick({folder: itemToDef(folder)});\n    return this;\n  }\n\n  fetchLazyFolder(folder: Folder) {\n    return this.$scope.onLazyFolderFetch({folder: itemToDef(folder)});\n  }\n\n  transclude(element, file) {\n    this.$transclude((clone, scope) => {\n      scope.bfe = {file};\n      element.append(clone);\n    });\n  }\n\n  renderFolder(scope) {\n    return this.render(`\n      <span class=\"bi-align bi-r-h\">\n        <span class=\"fe-icon-container\" bi-html=\"renderFolderIcon(folder)\"></span>\n\n        <span class=\"bi-text--ellipsis\" bi-draggable=\"events.onDrag(folder)\">\n          <span\n            ng-if=\"vm.folders.get(folder).edit.enabled\"\n            ng-model=\"folder.name\"\n            contenteditable=\"{{vm.folders.get(folder).edit.enabled}}\"\n            on-change=\"events.onFolderRenamed(folder)\"\n            on-blur=\"events.onFolderBlur(folder)\"\n            ce-options=\"::{autoEdit: true}\"\n          >{{folder.getName()}}</span>\n\n          <span ng-if=\"!vm.folders.get(folder).edit.enabled\">{{folder.getName()}}</span>\n        </span>\n      </span>\n    `)(scope);\n  }\n\n  renderFile(scope) {\n    return this.render(`\n      <span class=\"fe-item-name bi-r-h bi-align\">\n        <span class=\"fe-icon-container\" bi-html=\"renderFileIcon(file)\"></span>\n        <span class=\"bi-text--ellipsis\" bi-draggable=\"events.onDrag(file)\">{{file.getName()}}</span>\n      </span>\n    `)(scope);\n  }\n\n  renderFolderIcon(scope, folder: Folder) {\n    let html;\n\n    if (!this.$transclude.isSlotFilled('folderIcon')) {\n      html = inject('$compile')(`\n        <i class=\"fe-icon bi-icon\">folder</i>\n      `)(assign(scope.$new(true), {folder}));\n    } else {\n      html = this.$transclude((_, s) => s.folder = itemToDef(folder), null, 'folderIcon');\n    }\n  \n    return {html};\n  }\n\n  renderFileIcon(scope, file: File) {\n    let html;\n\n    if (!this.$transclude.isSlotFilled('fileIcon')) {\n      html = inject('$compile')(`\n        <i class=\"fe-icon bi-icon\">insert_drive_file</i>\n      `)(assign(scope.$new(true), {file}));\n    } else {\n      html = this.$transclude((_, s) => s.file = itemToDef(file), null, 'fileIcon');\n    }\n  \n    return {html};\n  }\n\n  renderMenu(scope, folder: Folder) {\n    let html;\n\n    if (!this.$transclude.isSlotFilled('menu')) {\n      html = inject('$compile')(`\n        <ul class=\"bi-dropdown-menu\">\n          <li \n            class=\"bi-align bi-space-h\"\n            ng-repeat=\"type in ::options.fileAlias\"\n            ng-disabled=\"::!events.onFileCreate\"\n            ng-click=\"events.onFileCreate && events.onFileCreate(type, folder)\"\n          >\n            <i class=\"bi-icon\">note_add</i>\n            <span>New {{::type}}</span>\n          </li>\n\n          <li \n            class=\"bi-align bi-space-h\"\n            ng-disabled=\"::!events.onFolderCreate\"\n            ng-click=\"events.onFolderCreate && events.onFolderCreate(folder)\"\n          >\n            <i class=\"bi-icon\">create_new_folder</i>\n            <span>New folder</span>\n          </li>\n\n          <li class=\"bi-dropdown-separator\"></li>\n\n          <li \n            class=\"bi-align bi-space-h\"\n            ng-disabled=\"::!events.onFolderRename || !vm.folder.canRename(folder)\"\n            ng-click=\"events.onFolderRename && vm.folder.canRename(folder) && events.onFolderRename(folder)\"\n          >\n            <i class=\"bi-icon\">edit</i>\n            <span>Rename</span>\n          </li>\n\n          <li \n            class=\"bi-align bi-space-h\"\n            ng-disabled=\"::!events.onFolderDelete || !vm.folder.canDelete(folder)\"\n            ng-click=\"events.onFolderDelete && vm.folder.canDelete(folder) && events.onFolderDelete(folder)\"\n          >\n            <i class=\"bi-icon\">delete</i>\n            <span>Delete</span>\n          </li>\n        </ul>\n      `)(assign(scope));\n    } else {\n      html = this.$transclude((_, s) => s.folder = itemToDef(folder), null, 'menu');\n    }\n  \n    return {html};\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/services/file-explorer-instance.ts",
    "content": "import {srv} from '../../core';\nimport {IItemDef} from './';\nimport {File} from './file-explorer-models';\nimport {goToFile} from './file-explorer-tools';\n\n/**\n *  Will be propagated using on-load\n */\nexport default class Instance extends srv.eventEmitter.EventEmitter {\n  constructor (private readonly scope) {\n    super();\n  }\n\n  createFolder() {\n    this.scope.events.onFolderCreate();\n  }\n\n  createFile(type?: string) {\n    this.scope.events.onFileCreate(type);\n  }\n\n  setActive(fileDef: IItemDef) {\n    const file: File = goToFile(fileDef, this.scope.model);\n    this.scope.vm.folder.setCurrent(file);\n    this.scope.vm.file.setCurrent(file);\n  }\n\n  clearActive() {\n    this.scope.vm.folder.setCurrent(null);\n    this.scope.vm.file.setCurrent(null);\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/services/file-explorer-models.ts",
    "content": "import {pull} from 'lodash';\nimport {utils, srv} from '../../core';\n\nconst {uuid} = utils;\nconst {EventEmitter} = srv.eventEmitter;\n\nexport class Item {\n  private parent: Folder;\n  private readonly eventEmitter;\n\n  constructor(\n    private readonly id: string,\n    private readonly name: string,\n    private readonly type: string,\n    private readonly data = {}\n  ) {\n    this.eventEmitter = new EventEmitter();\n  }\n\n  public getId(): string {\n    return this.id;\n  }\n\n  public getName(): string {\n    return this.name;\n  }\n\n  public getType(): string {\n    return this.type;\n  }\n\n  public setParent(parent: Folder): Item {\n    this.parent = parent;\n    return this;\n  }\n\n  public getParent(): Folder {\n    return this.parent;\n  }\n\n  public getDepth(): number {\n    let res = 0;\n    let parent: Item = this;\n\n    // tslint:disable-next-line: no-conditional-assignment\n    while (parent = parent.getParent()) {\n      res++;\n    }\n\n    return res;\n  }\n\n  public getData(): any {\n    return this.data;\n  }\n\n  public getParentById(id: string): Item {\n    let res: Item;\n    let parent: Item = this;\n\n    // tslint:disable-next-line: no-conditional-assignment\n    while (parent = parent.getParent()) {\n      if (parent.getId() === id) {\n        res = res || parent;\n        break;\n      }\n    }\n\n    return res;\n  }\n\n  public on(name, fn, invoke?, scope?) {\n    this.eventEmitter.on(name, fn, invoke, scope);\n  }\n\n  public trigger(name, ...args) {\n    this.eventEmitter.triggerStream(name, ...args);\n  }\n}\n\nexport class File extends Item {\n  constructor(id: string, name: string, type: string = 'file', data = {}) {\n    super(id, name, type, data);\n  }\n\n  public moveTo(folder: Folder): File {\n    folder.addFile(this.getParent().removeFile(this));\n    return this;\n  }\n}\n\nexport class Folder extends Item {\n  private pool: Record<string, Folder | File> = {};\n  private folders: Folder[] = [];\n  private files: File[] = [];\n  private lazy: boolean = false;\n  private limit: number = null;\n  private readonly status = {\n    open: false,\n    edit: false,\n    hasFileLeaf: false\n  };\n\n  constructor(id: string, name: string, data = {}) {\n    super(id, name, 'folder', data);\n  }\n\n  public setPool(pool: Record<string, Folder | File>): Folder {\n    this.pool = pool;\n\n    return this;\n  }\n\n  public setFolders(folders: Folder[]): Folder {\n    this.folders = folders;\n\n    return this;\n  }\n\n  public setFiles(files: File[]): Folder {\n    this.files = files;\n\n    return this;\n  }\n\n  public setLazy(lazy: boolean = false): Folder {\n    this.lazy = lazy;\n\n    return this;\n  }\n\n  public isLazy(): boolean {\n    return this.lazy;\n  }\n\n  public getFolderById(id: string): Folder {\n    return this.pool[id] as Folder;\n  }\n\n  public getFileById(id: string): File {\n    return this.pool[id] as File;\n  }\n\n  public getFolders(): Folder[] {\n    return this.folders;\n  }\n\n  public getFiles(): File[] {\n    return this.files;\n  }\n\n  public createFolder(name: string): Folder {\n    return this.addFolder(uuid(), name);\n  }\n\n  public createFile(name: string, type?): File {\n    return this.addFile(uuid(), name, type);\n  }\n\n  public addFolder(idOrFolder: string | Folder, name?: string, data = {}): Folder {\n    const folder = idOrFolder instanceof Folder ? idOrFolder : new Folder(idOrFolder, name, data);\n\n    folder.setParent(this);\n\n    this.folders.push(folder);\n    this.pool[folder.getId()] = folder;\n\n    return folder;\n  }\n\n  public addFile(idOrFile: string | File, name?: string, type?: string, data = {}): File {\n    const file = idOrFile instanceof File ? idOrFile : new File(idOrFile, name, type, data);\n\n    file.setParent(this);\n\n    this.files.push(file);\n    this.pool[file.getId()] = file;\n\n    return file;\n  }\n\n  public removeFile(file: File): File {\n    pull(this.files, file);\n\n    // tslint:disable-next-line: no-dynamic-delete\n    delete this.pool[file.getId()];\n\n    return file;\n  }\n\n  public removeFolder(folder: Folder): Folder {\n    pull(this.folders, folder);\n\n    // tslint:disable-next-line: no-dynamic-delete\n    delete this.pool[folder.getId()];\n\n    return folder;\n  }\n\n  public hasFiles(): boolean {\n    return !!this.files.length;\n  }\n\n  public hasFolders(): boolean {\n    return !!this.folders.length;\n  }\n\n  public isEmpty(): boolean {\n    return !this.hasFolders() && !this.hasFiles() && !this.lazy;\n  }\n\n  public hasFileLeaf(): boolean {\n    return this.status.hasFileLeaf;\n  }\n\n  public isOpen(): boolean {\n    return this.status.open;\n  }\n\n  public toggleOpen(open?: boolean): Folder {\n    this.status.open = typeof open === 'undefined' ? !this.status.open : open;\n\n    if (this.getParent()) {\n      this.getParent().trigger('openToggled', this.getParent(), this, this.isOpen());\n    }\n\n    return this;\n  }\n\n  public toggleEdit(edit?: boolean): Folder {\n    this.status.edit = typeof edit === 'undefined' ? !this.status.edit : edit;\n\n    if (this.getParent()) {\n      this.getParent().trigger('editToggled', this.getParent(), this, this.status.edit);\n    }\n\n    return this;\n  }\n\n  public toggleHasFileLeaf(hasFileLeaf: boolean): Folder {\n    this.status.hasFileLeaf = hasFileLeaf;\n    return this;\n  }\n\n  public moveTo(folder: Folder): Folder {\n    folder.addFolder(this.getParent().removeFolder(this));\n    return this;\n  }\n\n  public getLength(res = 1): number {\n    return Math.max(res, ...(this.folders.map(folder => folder.getLength(res + 1))));\n  }\n\n  public setLimit(limit: number) {\n    this.limit = limit;\n  }\n\n  public getLimit() {\n    return this.limit;\n  }\n\n  public destroy() {\n    this.getParent().removeFolder(this);\n  }\n\n  public $clone(): Folder {\n    const folder = new Folder(this.getId(), this.getName(), this.getData());\n\n    return folder\n      .setPool(this.pool)\n      .setFolders(this.getFolders())\n      .setFiles(this.getFiles())\n      .setLazy(this.lazy);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/services/file-explorer-tools.ts",
    "content": "import {IItemDef, IPathItemDef} from './';\nimport {Item, Folder, File} from './file-explorer-models';\n\nfunction getId(parent) {\n  return typeof parent === 'object' ? parent.id : parent;\n}\n\n/**\n * Opens all folders on the path to file\n */\nexport function goToFile(fileDef: IItemDef, folder: Folder): File {\n  fileDef.path.forEach(parent => {\n    folder = folder.getFolderById(getId(parent)).toggleOpen(true);\n  });\n\n  return folder.getFileById(fileDef.id) || folder.getFolderById(fileDef.id);\n}\n\nexport function addFolder(folder: Folder, {id, name, lazy, path, ...data}: IItemDef, options: any): Folder {\n  const childFolder = folder.addFolder(id, name, data)\n    .setLazy(lazy);\n\n  if (options.expandAllFolders && !lazy) {\n    childFolder.toggleOpen(true);\n  }\n\n  return childFolder;\n}\n\nexport function addFile(folder: Folder, {id, name, type, path, ...data}: IItemDef): File {\n  return folder.addFile(id, name, type, data);\n}\n\n/**\n * Creates a tree structure from a file definition array.\n */\nexport function defToTree(items: IItemDef[], options: any): Folder {\n  const root = new Folder(null, null);\n\n  const itemsMap = items.reduce((res, item: IItemDef) => {\n    res[item.id] = item;\n    return res;\n  }, {});\n\n  items.forEach(item => {\n    let folder = root;\n\n    (item.path || []).forEach((parent) => {\n      const id = getId(parent);\n\n      folder = folder.getFolderById(id) || addFolder(folder, itemsMap[id], options);\n\n      if (item.type !== 'folder') {\n        folder.toggleHasFileLeaf(true);\n      }\n    });\n\n    if (item.type === 'folder') {\n      if (!folder.getFolderById(item.id)) {\n        addFolder(folder, item, options);\n      }\n    } else {\n      addFile(folder, item);\n    }\n  });\n\n  return root;\n}\n\n/**\n * Creates a file definition array from a tree.\n */\nexport function treeToDef(item: Item, path = [], res: IItemDef[] = []): IItemDef[] {\n  if (item.getId()) {\n    if (item instanceof Folder) {\n      res.push({\n        id: item.getId(),\n        name: item.getName(),\n        type: item.getType(),\n        path,\n        lazy: item.isLazy(),\n        ...item.getData(),\n      });\n    } else {\n      res.push({\n        id: item.getId(),\n        name: item.getName(),\n        type: item.getType(),\n        path,\n        ...item.getData(),\n      });\n    }\n  }\n\n  if (item instanceof Folder) {\n    path = !item.getId() ? path : [\n      ...path,\n      ...[{\n        id: item.getId(),\n        name: item.getName()\n      }]\n    ];\n\n    (item as Folder).getFolders().forEach(folder => {\n      treeToDef(folder, path, res);\n    });\n\n    (item as Folder).getFiles().forEach(file => treeToDef(file, path, res));\n  }\n\n  return res;\n}\n\n/**\n * Creates a file definition object from file\n */\nexport function itemToDef(item: Item): IItemDef {\n  const path: IPathItemDef[] = [];\n  let folder: Folder = item.getParent();\n\n  while (folder && folder.getParent()) {\n    path.unshift({\n      id: folder.getId(),\n      name: folder.getName()\n    });\n\n    folder = folder.getParent();\n  }\n\n  return {\n    id: item.getId(),\n    name: item.getName(),\n    type: item.getType(),\n    path,\n    ...item.getData()\n  };\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/file-explorer/services/index.ts",
    "content": "export interface IPathItemDef {\n  id: string;\n  name: string;\n}\n\nexport interface IItemDef {\n  id: string;\n  name: string;\n  type: string;\n  path: IPathItemDef[];\n  lazy?: boolean;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/index.ts",
    "content": "import { SqlBaseLexer } from './lang/presto/SqlBaseLexer';\nimport { SqlBaseListener } from './lang/presto/SqlBaseListener';\nimport { SqlBaseParser } from './lang/presto/SqlBaseParser';\nimport { SqlBaseVisitor } from './lang/presto/SqlBaseVisitor';\n\nexport { SqlBaseLexer };\nexport { SqlBaseListener };\nexport { SqlBaseParser };\nexport { SqlBaseVisitor };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBase.tokens",
    "content": "T__0=1\nT__1=2\nT__2=3\nT__3=4\nT__4=5\nT__5=6\nT__6=7\nT__7=8\nT__8=9\nSELECT=10\nFROM=11\nADD=12\nAS=13\nALL=14\nSOME=15\nANY=16\nDISTINCT=17\nWHERE=18\nGROUP=19\nBY=20\nGROUPING=21\nSETS=22\nCUBE=23\nROLLUP=24\nORDER=25\nHAVING=26\nLIMIT=27\nAT=28\nOR=29\nAND=30\nIN=31\nNOT=32\nNO=33\nEXISTS=34\nBETWEEN=35\nLIKE=36\nIS=37\nNULL=38\nTRUE=39\nFALSE=40\nNULLS=41\nFIRST=42\nLAST=43\nESCAPE=44\nASC=45\nDESC=46\nSUBSTRING=47\nPOSITION=48\nFOR=49\nTINYINT=50\nSMALLINT=51\nINTEGER=52\nDATE=53\nTIME=54\nTIMESTAMP=55\nINTERVAL=56\nYEAR=57\nMONTH=58\nDAY=59\nHOUR=60\nMINUTE=61\nSECOND=62\nZONE=63\nCURRENT_DATE=64\nCURRENT_TIME=65\nCURRENT_TIMESTAMP=66\nLOCALTIME=67\nLOCALTIMESTAMP=68\nEXTRACT=69\nCASE=70\nWHEN=71\nTHEN=72\nELSE=73\nEND=74\nJOIN=75\nCROSS=76\nOUTER=77\nINNER=78\nLEFT=79\nRIGHT=80\nFULL=81\nNATURAL=82\nUSING=83\nON=84\nFILTER=85\nOVER=86\nPARTITION=87\nRANGE=88\nROWS=89\nUNBOUNDED=90\nPRECEDING=91\nFOLLOWING=92\nCURRENT=93\nROW=94\nWITH=95\nRECURSIVE=96\nVALUES=97\nCREATE=98\nSCHEMA=99\nTABLE=100\nVIEW=101\nREPLACE=102\nINSERT=103\nDELETE=104\nINTO=105\nCONSTRAINT=106\nDESCRIBE=107\nGRANT=108\nREVOKE=109\nPRIVILEGES=110\nPUBLIC=111\nOPTION=112\nEXPLAIN=113\nANALYZE=114\nFORMAT=115\nTYPE=116\nTEXT=117\nGRAPHVIZ=118\nLOGICAL=119\nDISTRIBUTED=120\nCAST=121\nTRY_CAST=122\nSHOW=123\nTABLES=124\nSCHEMAS=125\nCATALOGS=126\nCOLUMNS=127\nCOLUMN=128\nUSE=129\nPARTITIONS=130\nFUNCTIONS=131\nDROP=132\nUNION=133\nEXCEPT=134\nINTERSECT=135\nTO=136\nSYSTEM=137\nBERNOULLI=138\nPOISSONIZED=139\nTABLESAMPLE=140\nALTER=141\nRENAME=142\nUNNEST=143\nORDINALITY=144\nARRAY=145\nMAP=146\nSET=147\nRESET=148\nSESSION=149\nDATA=150\nSTART=151\nTRANSACTION=152\nCOMMIT=153\nROLLBACK=154\nWORK=155\nISOLATION=156\nLEVEL=157\nSERIALIZABLE=158\nREPEATABLE=159\nCOMMITTED=160\nUNCOMMITTED=161\nREAD=162\nWRITE=163\nONLY=164\nCALL=165\nPREPARE=166\nDEALLOCATE=167\nEXECUTE=168\nINPUT=169\nOUTPUT=170\nCASCADE=171\nRESTRICT=172\nINCLUDING=173\nEXCLUDING=174\nPROPERTIES=175\nNORMALIZE=176\nNFD=177\nNFC=178\nNFKD=179\nNFKC=180\nIF=181\nNULLIF=182\nCOALESCE=183\nEQ=184\nNEQ=185\nLT=186\nLTE=187\nGT=188\nGTE=189\nPLUS=190\nMINUS=191\nASTERISK=192\nSLASH=193\nPERCENT=194\nCONCAT=195\nSTRING=196\nBINARY_LITERAL=197\nINTEGER_VALUE=198\nDECIMAL_VALUE=199\nIDENTIFIER=200\nDIGIT_IDENTIFIER=201\nQUOTED_IDENTIFIER=202\nBACKQUOTED_IDENTIFIER=203\nTIME_WITH_TIME_ZONE=204\nTIMESTAMP_WITH_TIME_ZONE=205\nDOUBLE_PRECISION=206\nSIMPLE_COMMENT=207\nBRACKETED_COMMENT=208\nWS=209\nSEMICOLON=210\nUNRECOGNIZED=211\nDELIMITER=212\n'.'=1\n'('=2\n','=3\n')'=4\n'?'=5\n'->'=6\n'['=7\n']'=8\n'=>'=9\n'='=184\n'<'=186\n'<='=187\n'>'=188\n'>='=189\n'+'=190\n'-'=191\n'*'=192\n'/'=193\n'%'=194\n'||'=195\n';'=210\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseLexer.tokens",
    "content": "T__0=1\nT__1=2\nT__2=3\nT__3=4\nT__4=5\nT__5=6\nT__6=7\nT__7=8\nT__8=9\nSELECT=10\nFROM=11\nADD=12\nAS=13\nALL=14\nSOME=15\nANY=16\nDISTINCT=17\nWHERE=18\nGROUP=19\nBY=20\nGROUPING=21\nSETS=22\nCUBE=23\nROLLUP=24\nORDER=25\nHAVING=26\nLIMIT=27\nAT=28\nOR=29\nAND=30\nIN=31\nNOT=32\nNO=33\nEXISTS=34\nBETWEEN=35\nLIKE=36\nIS=37\nNULL=38\nTRUE=39\nFALSE=40\nNULLS=41\nFIRST=42\nLAST=43\nESCAPE=44\nASC=45\nDESC=46\nSUBSTRING=47\nPOSITION=48\nFOR=49\nTINYINT=50\nSMALLINT=51\nINTEGER=52\nDATE=53\nTIME=54\nTIMESTAMP=55\nINTERVAL=56\nYEAR=57\nMONTH=58\nDAY=59\nHOUR=60\nMINUTE=61\nSECOND=62\nZONE=63\nCURRENT_DATE=64\nCURRENT_TIME=65\nCURRENT_TIMESTAMP=66\nLOCALTIME=67\nLOCALTIMESTAMP=68\nEXTRACT=69\nCASE=70\nWHEN=71\nTHEN=72\nELSE=73\nEND=74\nJOIN=75\nCROSS=76\nOUTER=77\nINNER=78\nLEFT=79\nRIGHT=80\nFULL=81\nNATURAL=82\nUSING=83\nON=84\nFILTER=85\nOVER=86\nPARTITION=87\nRANGE=88\nROWS=89\nUNBOUNDED=90\nPRECEDING=91\nFOLLOWING=92\nCURRENT=93\nROW=94\nWITH=95\nRECURSIVE=96\nVALUES=97\nCREATE=98\nSCHEMA=99\nTABLE=100\nVIEW=101\nREPLACE=102\nINSERT=103\nDELETE=104\nINTO=105\nCONSTRAINT=106\nDESCRIBE=107\nGRANT=108\nREVOKE=109\nPRIVILEGES=110\nPUBLIC=111\nOPTION=112\nEXPLAIN=113\nANALYZE=114\nFORMAT=115\nTYPE=116\nTEXT=117\nGRAPHVIZ=118\nLOGICAL=119\nDISTRIBUTED=120\nCAST=121\nTRY_CAST=122\nSHOW=123\nTABLES=124\nSCHEMAS=125\nCATALOGS=126\nCOLUMNS=127\nCOLUMN=128\nUSE=129\nPARTITIONS=130\nFUNCTIONS=131\nDROP=132\nUNION=133\nEXCEPT=134\nINTERSECT=135\nTO=136\nSYSTEM=137\nBERNOULLI=138\nPOISSONIZED=139\nTABLESAMPLE=140\nALTER=141\nRENAME=142\nUNNEST=143\nORDINALITY=144\nARRAY=145\nMAP=146\nSET=147\nRESET=148\nSESSION=149\nDATA=150\nSTART=151\nTRANSACTION=152\nCOMMIT=153\nROLLBACK=154\nWORK=155\nISOLATION=156\nLEVEL=157\nSERIALIZABLE=158\nREPEATABLE=159\nCOMMITTED=160\nUNCOMMITTED=161\nREAD=162\nWRITE=163\nONLY=164\nCALL=165\nPREPARE=166\nDEALLOCATE=167\nEXECUTE=168\nINPUT=169\nOUTPUT=170\nCASCADE=171\nRESTRICT=172\nINCLUDING=173\nEXCLUDING=174\nPROPERTIES=175\nNORMALIZE=176\nNFD=177\nNFC=178\nNFKD=179\nNFKC=180\nIF=181\nNULLIF=182\nCOALESCE=183\nEQ=184\nNEQ=185\nLT=186\nLTE=187\nGT=188\nGTE=189\nPLUS=190\nMINUS=191\nASTERISK=192\nSLASH=193\nPERCENT=194\nCONCAT=195\nSTRING=196\nBINARY_LITERAL=197\nINTEGER_VALUE=198\nDECIMAL_VALUE=199\nIDENTIFIER=200\nDIGIT_IDENTIFIER=201\nQUOTED_IDENTIFIER=202\nBACKQUOTED_IDENTIFIER=203\nTIME_WITH_TIME_ZONE=204\nTIMESTAMP_WITH_TIME_ZONE=205\nDOUBLE_PRECISION=206\nSIMPLE_COMMENT=207\nBRACKETED_COMMENT=208\nWS=209\nSEMICOLON=210\nUNRECOGNIZED=211\n'.'=1\n'('=2\n','=3\n')'=4\n'?'=5\n'->'=6\n'['=7\n']'=8\n'=>'=9\n'='=184\n'<'=186\n'<='=187\n'>'=188\n'>='=189\n'+'=190\n'-'=191\n'*'=192\n'/'=193\n'%'=194\n'||'=195\n';'=210\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseLexer.ts",
    "content": "// Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7\n// jshint ignore: start\n\n// @ts-nocheck\n\nimport { atn as _atn, dfa, Lexer, PredictionContextCache, Token } from 'antlr4';\n\nconst serializedATN = [\n  '\\u0003\\u608b\\ua72a\\u8133\\ub9ed\\u417c\\u3be7\\u7786\\u5964',\n  '\\u0002\\u00d5\\u0c4e\\b\\u0001\\u0004\\u0002\\t\\u0002\\u0004\\u0003\\t\\u0003\\u0004',\n  '\\u0004\\t\\u0004\\u0004\\u0005\\t\\u0005\\u0004\\u0006\\t\\u0006\\u0004\\u0007\\t',\n  '\\u0007\\u0004\\b\\t\\b\\u0004\\t\\t\\t\\u0004\\n\\t\\n\\u0004\\u000b\\t\\u000b\\u0004',\n  '\\f\\t\\f\\u0004\\r\\t\\r\\u0004\\u000e\\t\\u000e\\u0004\\u000f\\t\\u000f\\u0004\\u0010',\n  '\\t\\u0010\\u0004\\u0011\\t\\u0011\\u0004\\u0012\\t\\u0012\\u0004\\u0013\\t\\u0013',\n  '\\u0004\\u0014\\t\\u0014\\u0004\\u0015\\t\\u0015\\u0004\\u0016\\t\\u0016\\u0004\\u0017',\n  '\\t\\u0017\\u0004\\u0018\\t\\u0018\\u0004\\u0019\\t\\u0019\\u0004\\u001a\\t\\u001a',\n  '\\u0004\\u001b\\t\\u001b\\u0004\\u001c\\t\\u001c\\u0004\\u001d\\t\\u001d\\u0004\\u001e',\n  '\\t\\u001e\\u0004\\u001f\\t\\u001f\\u0004 \\t \\u0004!\\t!\\u0004\"\\t\"\\u0004#',\n  \"\\t#\\u0004$\\t$\\u0004%\\t%\\u0004&\\t&\\u0004'\\t'\\u0004(\\t(\\u0004)\\t)\\u0004\",\n  '*\\t*\\u0004+\\t+\\u0004,\\t,\\u0004-\\t-\\u0004.\\t.\\u0004/\\t/\\u00040\\t0\\u0004',\n  '1\\t1\\u00042\\t2\\u00043\\t3\\u00044\\t4\\u00045\\t5\\u00046\\t6\\u00047\\t7\\u0004',\n  '8\\t8\\u00049\\t9\\u0004:\\t:\\u0004;\\t;\\u0004<\\t<\\u0004=\\t=\\u0004>\\t>\\u0004',\n  '?\\t?\\u0004@\\t@\\u0004A\\tA\\u0004B\\tB\\u0004C\\tC\\u0004D\\tD\\u0004E\\tE\\u0004',\n  'F\\tF\\u0004G\\tG\\u0004H\\tH\\u0004I\\tI\\u0004J\\tJ\\u0004K\\tK\\u0004L\\tL\\u0004',\n  'M\\tM\\u0004N\\tN\\u0004O\\tO\\u0004P\\tP\\u0004Q\\tQ\\u0004R\\tR\\u0004S\\tS\\u0004',\n  'T\\tT\\u0004U\\tU\\u0004V\\tV\\u0004W\\tW\\u0004X\\tX\\u0004Y\\tY\\u0004Z\\tZ\\u0004',\n  '[\\t[\\u0004\\\\\\t\\\\\\u0004]\\t]\\u0004^\\t^\\u0004_\\t_\\u0004`\\t`\\u0004a\\ta\\u0004',\n  'b\\tb\\u0004c\\tc\\u0004d\\td\\u0004e\\te\\u0004f\\tf\\u0004g\\tg\\u0004h\\th\\u0004',\n  'i\\ti\\u0004j\\tj\\u0004k\\tk\\u0004l\\tl\\u0004m\\tm\\u0004n\\tn\\u0004o\\to\\u0004',\n  'p\\tp\\u0004q\\tq\\u0004r\\tr\\u0004s\\ts\\u0004t\\tt\\u0004u\\tu\\u0004v\\tv\\u0004',\n  'w\\tw\\u0004x\\tx\\u0004y\\ty\\u0004z\\tz\\u0004{\\t{\\u0004|\\t|\\u0004}\\t}\\u0004',\n  '~\\t~\\u0004\\u007f\\t\\u007f\\u0004\\u0080\\t\\u0080\\u0004\\u0081\\t\\u0081\\u0004',\n  '\\u0082\\t\\u0082\\u0004\\u0083\\t\\u0083\\u0004\\u0084\\t\\u0084\\u0004\\u0085\\t',\n  '\\u0085\\u0004\\u0086\\t\\u0086\\u0004\\u0087\\t\\u0087\\u0004\\u0088\\t\\u0088\\u0004',\n  '\\u0089\\t\\u0089\\u0004\\u008a\\t\\u008a\\u0004\\u008b\\t\\u008b\\u0004\\u008c\\t',\n  '\\u008c\\u0004\\u008d\\t\\u008d\\u0004\\u008e\\t\\u008e\\u0004\\u008f\\t\\u008f\\u0004',\n  '\\u0090\\t\\u0090\\u0004\\u0091\\t\\u0091\\u0004\\u0092\\t\\u0092\\u0004\\u0093\\t',\n  '\\u0093\\u0004\\u0094\\t\\u0094\\u0004\\u0095\\t\\u0095\\u0004\\u0096\\t\\u0096\\u0004',\n  '\\u0097\\t\\u0097\\u0004\\u0098\\t\\u0098\\u0004\\u0099\\t\\u0099\\u0004\\u009a\\t',\n  '\\u009a\\u0004\\u009b\\t\\u009b\\u0004\\u009c\\t\\u009c\\u0004\\u009d\\t\\u009d\\u0004',\n  '\\u009e\\t\\u009e\\u0004\\u009f\\t\\u009f\\u0004\\u00a0\\t\\u00a0\\u0004\\u00a1\\t',\n  '\\u00a1\\u0004\\u00a2\\t\\u00a2\\u0004\\u00a3\\t\\u00a3\\u0004\\u00a4\\t\\u00a4\\u0004',\n  '\\u00a5\\t\\u00a5\\u0004\\u00a6\\t\\u00a6\\u0004\\u00a7\\t\\u00a7\\u0004\\u00a8\\t',\n  '\\u00a8\\u0004\\u00a9\\t\\u00a9\\u0004\\u00aa\\t\\u00aa\\u0004\\u00ab\\t\\u00ab\\u0004',\n  '\\u00ac\\t\\u00ac\\u0004\\u00ad\\t\\u00ad\\u0004\\u00ae\\t\\u00ae\\u0004\\u00af\\t',\n  '\\u00af\\u0004\\u00b0\\t\\u00b0\\u0004\\u00b1\\t\\u00b1\\u0004\\u00b2\\t\\u00b2\\u0004',\n  '\\u00b3\\t\\u00b3\\u0004\\u00b4\\t\\u00b4\\u0004\\u00b5\\t\\u00b5\\u0004\\u00b6\\t',\n  '\\u00b6\\u0004\\u00b7\\t\\u00b7\\u0004\\u00b8\\t\\u00b8\\u0004\\u00b9\\t\\u00b9\\u0004',\n  '\\u00ba\\t\\u00ba\\u0004\\u00bb\\t\\u00bb\\u0004\\u00bc\\t\\u00bc\\u0004\\u00bd\\t',\n  '\\u00bd\\u0004\\u00be\\t\\u00be\\u0004\\u00bf\\t\\u00bf\\u0004\\u00c0\\t\\u00c0\\u0004',\n  '\\u00c1\\t\\u00c1\\u0004\\u00c2\\t\\u00c2\\u0004\\u00c3\\t\\u00c3\\u0004\\u00c4\\t',\n  '\\u00c4\\u0004\\u00c5\\t\\u00c5\\u0004\\u00c6\\t\\u00c6\\u0004\\u00c7\\t\\u00c7\\u0004',\n  '\\u00c8\\t\\u00c8\\u0004\\u00c9\\t\\u00c9\\u0004\\u00ca\\t\\u00ca\\u0004\\u00cb\\t',\n  '\\u00cb\\u0004\\u00cc\\t\\u00cc\\u0004\\u00cd\\t\\u00cd\\u0004\\u00ce\\t\\u00ce\\u0004',\n  '\\u00cf\\t\\u00cf\\u0004\\u00d0\\t\\u00d0\\u0004\\u00d1\\t\\u00d1\\u0004\\u00d2\\t',\n  '\\u00d2\\u0004\\u00d3\\t\\u00d3\\u0004\\u00d4\\t\\u00d4\\u0004\\u00d5\\t\\u00d5\\u0004',\n  '\\u00d6\\t\\u00d6\\u0004\\u00d7\\t\\u00d7\\u0003\\u0002\\u0003\\u0002\\u0003\\u0003',\n  '\\u0003\\u0003\\u0003\\u0004\\u0003\\u0004\\u0003\\u0005\\u0003\\u0005\\u0003\\u0006',\n  '\\u0003\\u0006\\u0003\\u0007\\u0003\\u0007\\u0003\\u0007\\u0003\\b\\u0003\\b\\u0003',\n  '\\t\\u0003\\t\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b',\n  '\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b',\n  '\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b\\u0005\\u000b\\u01d0\\n\\u000b\\u0003',\n  '\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u01da',\n  '\\n\\f\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0005\\r\\u01e2\\n',\n  '\\r\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0005\\u000e\\u01e8',\n  '\\n\\u000e\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f',\n  '\\u0003\\u000f\\u0005\\u000f\\u01f0\\n\\u000f\\u0003\\u0010\\u0003\\u0010\\u0003',\n  '\\u0010\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\\u0005',\n  '\\u0010\\u01fa\\n\\u0010\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011',\n  '\\u0003\\u0011\\u0003\\u0011\\u0005\\u0011\\u0202\\n\\u0011\\u0003\\u0012\\u0003',\n  '\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003',\n  '\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003',\n  '\\u0012\\u0003\\u0012\\u0003\\u0012\\u0005\\u0012\\u0214\\n\\u0012\\u0003\\u0013',\n  '\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013',\n  '\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0005\\u0013\\u0220\\n\\u0013\\u0003',\n  '\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003',\n  '\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0005\\u0014\\u022c\\n\\u0014',\n  '\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0005\\u0015\\u0232\\n',\n  '\\u0015\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003',\n  '\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003',\n  '\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0005\\u0016\\u0244',\n  '\\n\\u0016\\u0003\\u0017\\u0003\\u0017\\u0003\\u0017\\u0003\\u0017\\u0003\\u0017',\n  '\\u0003\\u0017\\u0003\\u0017\\u0003\\u0017\\u0005\\u0017\\u024e\\n\\u0017\\u0003',\n  '\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003',\n  '\\u0018\\u0003\\u0018\\u0005\\u0018\\u0258\\n\\u0018\\u0003\\u0019\\u0003\\u0019',\n  '\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019',\n  '\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0005\\u0019\\u0266\\n',\n  '\\u0019\\u0003\\u001a\\u0003\\u001a\\u0003\\u001a\\u0003\\u001a\\u0003\\u001a\\u0003',\n  '\\u001a\\u0003\\u001a\\u0003\\u001a\\u0003\\u001a\\u0003\\u001a\\u0005\\u001a\\u0272',\n  '\\n\\u001a\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b',\n  '\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b',\n  '\\u0003\\u001b\\u0005\\u001b\\u0280\\n\\u001b\\u0003\\u001c\\u0003\\u001c\\u0003',\n  '\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003',\n  '\\u001c\\u0003\\u001c\\u0005\\u001c\\u028c\\n\\u001c\\u0003\\u001d\\u0003\\u001d',\n  '\\u0003\\u001d\\u0003\\u001d\\u0005\\u001d\\u0292\\n\\u001d\\u0003\\u001e\\u0003',\n  '\\u001e\\u0003\\u001e\\u0003\\u001e\\u0005\\u001e\\u0298\\n\\u001e\\u0003\\u001f',\n  '\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0005\\u001f',\n  '\\u02a0\\n\\u001f\\u0003 \\u0003 \\u0003 \\u0003 \\u0005 \\u02a6\\n \\u0003!\\u0003',\n  '!\\u0003!\\u0003!\\u0003!\\u0003!\\u0005!\\u02ae\\n!\\u0003\"\\u0003\"\\u0003',\n  '\"\\u0003\"\\u0005\"\\u02b4\\n\"\\u0003#\\u0003#\\u0003#\\u0003#\\u0003#\\u0003',\n  '#\\u0003#\\u0003#\\u0003#\\u0003#\\u0003#\\u0003#\\u0005#\\u02c2\\n#\\u0003$\\u0003',\n  '$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003',\n  '$\\u0003$\\u0003$\\u0005$\\u02d2\\n$\\u0003%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003',\n  '%\\u0003%\\u0003%\\u0005%\\u02dc\\n%\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u02e2',\n  \"\\n&\\u0003'\\u0003'\\u0003'\\u0003'\\u0003'\\u0003'\\u0003'\\u0003'\",\n  \"\\u0005'\\u02ec\\n'\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\",\n  '\\u0003(\\u0005(\\u02f6\\n(\\u0003)\\u0003)\\u0003)\\u0003)\\u0003)\\u0003)\\u0003',\n  ')\\u0003)\\u0003)\\u0003)\\u0005)\\u0302\\n)\\u0003*\\u0003*\\u0003*\\u0003*\\u0003',\n  '*\\u0003*\\u0003*\\u0003*\\u0003*\\u0003*\\u0005*\\u030e\\n*\\u0003+\\u0003+\\u0003',\n  '+\\u0003+\\u0003+\\u0003+\\u0003+\\u0003+\\u0003+\\u0003+\\u0005+\\u031a\\n+\\u0003',\n  ',\\u0003,\\u0003,\\u0003,\\u0003,\\u0003,\\u0003,\\u0003,\\u0005,\\u0324\\n,\\u0003',\n  '-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003',\n  '-\\u0003-\\u0005-\\u0332\\n-\\u0003.\\u0003.\\u0003.\\u0003.\\u0003.\\u0003.\\u0005',\n  '.\\u033a\\n.\\u0003/\\u0003/\\u0003/\\u0003/\\u0003/\\u0003/\\u0003/\\u0003/\\u0005',\n  '/\\u0344\\n/\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u0003',\n  '0\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u00030\\u0005',\n  '0\\u0358\\n0\\u00031\\u00031\\u00031\\u00031\\u00031\\u00031\\u00031\\u00031\\u0003',\n  '1\\u00031\\u00031\\u00031\\u00031\\u00031\\u00031\\u00031\\u00051\\u036a\\n1\\u0003',\n  '2\\u00032\\u00032\\u00032\\u00032\\u00032\\u00052\\u0372\\n2\\u00033\\u00033\\u0003',\n  '3\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u0003',\n  '3\\u00033\\u00053\\u0382\\n3\\u00034\\u00034\\u00034\\u00034\\u00034\\u00034\\u0003',\n  '4\\u00034\\u00034\\u00034\\u00034\\u00034\\u00034\\u00034\\u00034\\u00034\\u0005',\n  '4\\u0394\\n4\\u00035\\u00035\\u00035\\u00035\\u00035\\u00035\\u00035\\u00035\\u0003',\n  '5\\u00035\\u00035\\u00035\\u00035\\u00035\\u00055\\u03a4\\n5\\u00036\\u00036\\u0003',\n  '6\\u00036\\u00036\\u00036\\u00036\\u00036\\u00056\\u03ae\\n6\\u00037\\u00037\\u0003',\n  '7\\u00037\\u00037\\u00037\\u00037\\u00037\\u00057\\u03b8\\n7\\u00038\\u00038\\u0003',\n  '8\\u00038\\u00038\\u00038\\u00038\\u00038\\u00038\\u00038\\u00038\\u00038\\u0003',\n  '8\\u00038\\u00038\\u00038\\u00038\\u00038\\u00058\\u03cc\\n8\\u00039\\u00039\\u0003',\n  '9\\u00039\\u00039\\u00039\\u00039\\u00039\\u00039\\u00039\\u00039\\u00039\\u0003',\n  '9\\u00039\\u00039\\u00039\\u00059\\u03de\\n9\\u0003:\\u0003:\\u0003:\\u0003:\\u0003',\n  ':\\u0003:\\u0003:\\u0003:\\u0005:\\u03e8\\n:\\u0003;\\u0003;\\u0003;\\u0003;\\u0003',\n  ';\\u0003;\\u0003;\\u0003;\\u0003;\\u0003;\\u0005;\\u03f4\\n;\\u0003<\\u0003<\\u0003',\n  '<\\u0003<\\u0003<\\u0003<\\u0005<\\u03fc\\n<\\u0003=\\u0003=\\u0003=\\u0003=\\u0003',\n  '=\\u0003=\\u0003=\\u0003=\\u0005=\\u0406\\n=\\u0003>\\u0003>\\u0003>\\u0003>\\u0003',\n  '>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0005>\\u0414\\n>\\u0003',\n  '?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003',\n  '?\\u0003?\\u0005?\\u0422\\n?\\u0003@\\u0003@\\u0003@\\u0003@\\u0003@\\u0003@\\u0003',\n  '@\\u0003@\\u0005@\\u042c\\n@\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003',\n  'A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003',\n  'A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0003A\\u0005A\\u0446\\nA\\u0003',\n  'B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003',\n  'B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003B\\u0003',\n  'B\\u0003B\\u0003B\\u0003B\\u0005B\\u0460\\nB\\u0003C\\u0003C\\u0003C\\u0003C\\u0003',\n  'C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003',\n  'C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003',\n  'C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0003C\\u0005',\n  'C\\u0484\\nC\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003',\n  'D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0005',\n  'D\\u0498\\nD\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003',\n  'E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003',\n  'E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0003E\\u0005',\n  'E\\u04b6\\nE\\u0003F\\u0003F\\u0003F\\u0003F\\u0003F\\u0003F\\u0003F\\u0003F\\u0003',\n  'F\\u0003F\\u0003F\\u0003F\\u0003F\\u0003F\\u0005F\\u04c6\\nF\\u0003G\\u0003G\\u0003',\n  'G\\u0003G\\u0003G\\u0003G\\u0003G\\u0003G\\u0005G\\u04d0\\nG\\u0003H\\u0003H\\u0003',\n  'H\\u0003H\\u0003H\\u0003H\\u0003H\\u0003H\\u0005H\\u04da\\nH\\u0003I\\u0003I\\u0003',\n  'I\\u0003I\\u0003I\\u0003I\\u0003I\\u0003I\\u0005I\\u04e4\\nI\\u0003J\\u0003J\\u0003',\n  'J\\u0003J\\u0003J\\u0003J\\u0003J\\u0003J\\u0005J\\u04ee\\nJ\\u0003K\\u0003K\\u0003',\n  'K\\u0003K\\u0003K\\u0003K\\u0005K\\u04f6\\nK\\u0003L\\u0003L\\u0003L\\u0003L\\u0003',\n  'L\\u0003L\\u0003L\\u0003L\\u0005L\\u0500\\nL\\u0003M\\u0003M\\u0003M\\u0003M\\u0003',\n  'M\\u0003M\\u0003M\\u0003M\\u0003M\\u0003M\\u0005M\\u050c\\nM\\u0003N\\u0003N\\u0003',\n  'N\\u0003N\\u0003N\\u0003N\\u0003N\\u0003N\\u0003N\\u0003N\\u0005N\\u0518\\nN\\u0003',\n  'O\\u0003O\\u0003O\\u0003O\\u0003O\\u0003O\\u0003O\\u0003O\\u0003O\\u0003O\\u0005',\n  'O\\u0524\\nO\\u0003P\\u0003P\\u0003P\\u0003P\\u0003P\\u0003P\\u0003P\\u0003P\\u0005',\n  'P\\u052e\\nP\\u0003Q\\u0003Q\\u0003Q\\u0003Q\\u0003Q\\u0003Q\\u0003Q\\u0003Q\\u0003',\n  'Q\\u0003Q\\u0005Q\\u053a\\nQ\\u0003R\\u0003R\\u0003R\\u0003R\\u0003R\\u0003R\\u0003',\n  'R\\u0003R\\u0005R\\u0544\\nR\\u0003S\\u0003S\\u0003S\\u0003S\\u0003S\\u0003S\\u0003',\n  'S\\u0003S\\u0003S\\u0003S\\u0003S\\u0003S\\u0003S\\u0003S\\u0005S\\u0554\\nS\\u0003',\n  'T\\u0003T\\u0003T\\u0003T\\u0003T\\u0003T\\u0003T\\u0003T\\u0003T\\u0003T\\u0005',\n  'T\\u0560\\nT\\u0003U\\u0003U\\u0003U\\u0003U\\u0005U\\u0566\\nU\\u0003V\\u0003',\n  'V\\u0003V\\u0003V\\u0003V\\u0003V\\u0003V\\u0003V\\u0003V\\u0003V\\u0003V\\u0003',\n  'V\\u0005V\\u0574\\nV\\u0003W\\u0003W\\u0003W\\u0003W\\u0003W\\u0003W\\u0003W\\u0003',\n  'W\\u0005W\\u057e\\nW\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003',\n  'X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003X\\u0003',\n  'X\\u0005X\\u0592\\nX\\u0003Y\\u0003Y\\u0003Y\\u0003Y\\u0003Y\\u0003Y\\u0003Y\\u0003',\n  'Y\\u0003Y\\u0003Y\\u0005Y\\u059e\\nY\\u0003Z\\u0003Z\\u0003Z\\u0003Z\\u0003Z\\u0003',\n  'Z\\u0003Z\\u0003Z\\u0005Z\\u05a8\\nZ\\u0003[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003',\n  '[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003[\\u0003',\n  '[\\u0003[\\u0003[\\u0005[\\u05bc\\n[\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003',\n  '\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003',\n  '\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0003\\\\\\u0005\\\\\\u05d0\\n\\\\\\u0003]\\u0003]\\u0003',\n  ']\\u0003]\\u0003]\\u0003]\\u0003]\\u0003]\\u0003]\\u0003]\\u0003]\\u0003]\\u0003',\n  ']\\u0003]\\u0003]\\u0003]\\u0003]\\u0003]\\u0005]\\u05e4\\n]\\u0003^\\u0003^\\u0003',\n  '^\\u0003^\\u0003^\\u0003^\\u0003^\\u0003^\\u0003^\\u0003^\\u0003^\\u0003^\\u0003',\n  '^\\u0003^\\u0005^\\u05f4\\n^\\u0003_\\u0003_\\u0003_\\u0003_\\u0003_\\u0003_\\u0005',\n  '_\\u05fc\\n_\\u0003`\\u0003`\\u0003`\\u0003`\\u0003`\\u0003`\\u0003`\\u0003`\\u0005',\n  '`\\u0606\\n`\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003',\n  'a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0003a\\u0005',\n  'a\\u061a\\na\\u0003b\\u0003b\\u0003b\\u0003b\\u0003b\\u0003b\\u0003b\\u0003b\\u0003',\n  'b\\u0003b\\u0003b\\u0003b\\u0005b\\u0628\\nb\\u0003c\\u0003c\\u0003c\\u0003c\\u0003',\n  'c\\u0003c\\u0003c\\u0003c\\u0003c\\u0003c\\u0003c\\u0003c\\u0005c\\u0636\\nc\\u0003',\n  'd\\u0003d\\u0003d\\u0003d\\u0003d\\u0003d\\u0003d\\u0003d\\u0003d\\u0003d\\u0003',\n  'd\\u0003d\\u0005d\\u0644\\nd\\u0003e\\u0003e\\u0003e\\u0003e\\u0003e\\u0003e\\u0003',\n  'e\\u0003e\\u0003e\\u0003e\\u0005e\\u0650\\ne\\u0003f\\u0003f\\u0003f\\u0003f\\u0003',\n  'f\\u0003f\\u0003f\\u0003f\\u0005f\\u065a\\nf\\u0003g\\u0003g\\u0003g\\u0003g\\u0003',\n  'g\\u0003g\\u0003g\\u0003g\\u0003g\\u0003g\\u0003g\\u0003g\\u0003g\\u0003g\\u0005',\n  'g\\u066a\\ng\\u0003h\\u0003h\\u0003h\\u0003h\\u0003h\\u0003h\\u0003h\\u0003h\\u0003',\n  'h\\u0003h\\u0003h\\u0003h\\u0005h\\u0678\\nh\\u0003i\\u0003i\\u0003i\\u0003i\\u0003',\n  'i\\u0003i\\u0003i\\u0003i\\u0003i\\u0003i\\u0003i\\u0003i\\u0005i\\u0686\\ni\\u0003',\n  'j\\u0003j\\u0003j\\u0003j\\u0003j\\u0003j\\u0003j\\u0003j\\u0005j\\u0690\\nj\\u0003',\n  'k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003',\n  'k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0003k\\u0005',\n  'k\\u06a6\\nk\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003',\n  'l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0003l\\u0005l\\u06b8\\nl\\u0003',\n  'm\\u0003m\\u0003m\\u0003m\\u0003m\\u0003m\\u0003m\\u0003m\\u0003m\\u0003m\\u0005',\n  'm\\u06c4\\nm\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003',\n  'n\\u0003n\\u0003n\\u0003n\\u0005n\\u06d2\\nn\\u0003o\\u0003o\\u0003o\\u0003o\\u0003',\n  'o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003',\n  'o\\u0003o\\u0003o\\u0003o\\u0003o\\u0003o\\u0005o\\u06e8\\no\\u0003p\\u0003p\\u0003',\n  'p\\u0003p\\u0003p\\u0003p\\u0003p\\u0003p\\u0003p\\u0003p\\u0003p\\u0003p\\u0005',\n  'p\\u06f6\\np\\u0003q\\u0003q\\u0003q\\u0003q\\u0003q\\u0003q\\u0003q\\u0003q\\u0003',\n  'q\\u0003q\\u0003q\\u0003q\\u0005q\\u0704\\nq\\u0003r\\u0003r\\u0003r\\u0003r\\u0003',\n  'r\\u0003r\\u0003r\\u0003r\\u0003r\\u0003r\\u0003r\\u0003r\\u0003r\\u0003r\\u0005',\n  'r\\u0714\\nr\\u0003s\\u0003s\\u0003s\\u0003s\\u0003s\\u0003s\\u0003s\\u0003s\\u0003',\n  's\\u0003s\\u0003s\\u0003s\\u0003s\\u0003s\\u0005s\\u0724\\ns\\u0003t\\u0003t\\u0003',\n  't\\u0003t\\u0003t\\u0003t\\u0003t\\u0003t\\u0003t\\u0003t\\u0003t\\u0003t\\u0005',\n  't\\u0732\\nt\\u0003u\\u0003u\\u0003u\\u0003u\\u0003u\\u0003u\\u0003u\\u0003u\\u0005',\n  'u\\u073c\\nu\\u0003v\\u0003v\\u0003v\\u0003v\\u0003v\\u0003v\\u0003v\\u0003v\\u0005',\n  'v\\u0746\\nv\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003',\n  'w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0003w\\u0005w\\u0758\\nw\\u0003',\n  'x\\u0003x\\u0003x\\u0003x\\u0003x\\u0003x\\u0003x\\u0003x\\u0003x\\u0003x\\u0003',\n  'x\\u0003x\\u0003x\\u0003x\\u0005x\\u0768\\nx\\u0003y\\u0003y\\u0003y\\u0003y\\u0003',\n  'y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003',\n  'y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0003y\\u0005y\\u0780\\ny\\u0003',\n  'z\\u0003z\\u0003z\\u0003z\\u0003z\\u0003z\\u0003z\\u0003z\\u0005z\\u078a\\nz\\u0003',\n  '{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003',\n  '{\\u0003{\\u0003{\\u0003{\\u0003{\\u0003{\\u0005{\\u079c\\n{\\u0003|\\u0003|\\u0003',\n  '|\\u0003|\\u0003|\\u0003|\\u0003|\\u0003|\\u0005|\\u07a6\\n|\\u0003}\\u0003}\\u0003',\n  '}\\u0003}\\u0003}\\u0003}\\u0003}\\u0003}\\u0003}\\u0003}\\u0003}\\u0003}\\u0005',\n  '}\\u07b4\\n}\\u0003~\\u0003~\\u0003~\\u0003~\\u0003~\\u0003~\\u0003~\\u0003~\\u0003',\n  '~\\u0003~\\u0003~\\u0003~\\u0003~\\u0003~\\u0005~\\u07c4\\n~\\u0003\\u007f\\u0003',\n  '\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003',\n  '\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003\\u007f\\u0003',\n  '\\u007f\\u0003\\u007f\\u0003\\u007f\\u0005\\u007f\\u07d6\\n\\u007f\\u0003\\u0080',\n  '\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080',\n  '\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080\\u0003\\u0080',\n  '\\u0003\\u0080\\u0005\\u0080\\u07e6\\n\\u0080\\u0003\\u0081\\u0003\\u0081\\u0003',\n  '\\u0081\\u0003\\u0081\\u0003\\u0081\\u0003\\u0081\\u0003\\u0081\\u0003\\u0081\\u0003',\n  '\\u0081\\u0003\\u0081\\u0003\\u0081\\u0003\\u0081\\u0005\\u0081\\u07f4\\n\\u0081',\n  '\\u0003\\u0082\\u0003\\u0082\\u0003\\u0082\\u0003\\u0082\\u0003\\u0082\\u0003\\u0082',\n  '\\u0005\\u0082\\u07fc\\n\\u0082\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003',\n  '\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003',\n  '\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003',\n  '\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0003\\u0083\\u0005\\u0083\\u0812',\n  '\\n\\u0083\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084',\n  '\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084',\n  '\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084\\u0003\\u0084',\n  '\\u0003\\u0084\\u0005\\u0084\\u0826\\n\\u0084\\u0003\\u0085\\u0003\\u0085\\u0003',\n  '\\u0085\\u0003\\u0085\\u0003\\u0085\\u0003\\u0085\\u0003\\u0085\\u0003\\u0085\\u0005',\n  '\\u0085\\u0830\\n\\u0085\\u0003\\u0086\\u0003\\u0086\\u0003\\u0086\\u0003\\u0086',\n  '\\u0003\\u0086\\u0003\\u0086\\u0003\\u0086\\u0003\\u0086\\u0003\\u0086\\u0003\\u0086',\n  '\\u0005\\u0086\\u083c\\n\\u0086\\u0003\\u0087\\u0003\\u0087\\u0003\\u0087\\u0003',\n  '\\u0087\\u0003\\u0087\\u0003\\u0087\\u0003\\u0087\\u0003\\u0087\\u0003\\u0087\\u0003',\n  '\\u0087\\u0003\\u0087\\u0003\\u0087\\u0005\\u0087\\u084a\\n\\u0087\\u0003\\u0088',\n  '\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088',\n  '\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088',\n  '\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0003\\u0088\\u0005\\u0088',\n  '\\u085e\\n\\u0088\\u0003\\u0089\\u0003\\u0089\\u0003\\u0089\\u0003\\u0089\\u0005',\n  '\\u0089\\u0864\\n\\u0089\\u0003\\u008a\\u0003\\u008a\\u0003\\u008a\\u0003\\u008a',\n  '\\u0003\\u008a\\u0003\\u008a\\u0003\\u008a\\u0003\\u008a\\u0003\\u008a\\u0003\\u008a',\n  '\\u0003\\u008a\\u0003\\u008a\\u0005\\u008a\\u0872\\n\\u008a\\u0003\\u008b\\u0003',\n  '\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003',\n  '\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003',\n  '\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0003\\u008b\\u0005\\u008b\\u0886',\n  '\\n\\u008b\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c',\n  '\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c',\n  '\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c',\n  '\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0003\\u008c\\u0005\\u008c',\n  '\\u089e\\n\\u008c\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003',\n  '\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003',\n  '\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003',\n  '\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0003\\u008d\\u0005',\n  '\\u008d\\u08b6\\n\\u008d\\u0003\\u008e\\u0003\\u008e\\u0003\\u008e\\u0003\\u008e',\n  '\\u0003\\u008e\\u0003\\u008e\\u0003\\u008e\\u0003\\u008e\\u0003\\u008e\\u0003\\u008e',\n  '\\u0005\\u008e\\u08c2\\n\\u008e\\u0003\\u008f\\u0003\\u008f\\u0003\\u008f\\u0003',\n  '\\u008f\\u0003\\u008f\\u0003\\u008f\\u0003\\u008f\\u0003\\u008f\\u0003\\u008f\\u0003',\n  '\\u008f\\u0003\\u008f\\u0003\\u008f\\u0005\\u008f\\u08d0\\n\\u008f\\u0003\\u0090',\n  '\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090',\n  '\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090\\u0003\\u0090\\u0005\\u0090',\n  '\\u08de\\n\\u0090\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003',\n  '\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003',\n  '\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003',\n  '\\u0091\\u0003\\u0091\\u0003\\u0091\\u0003\\u0091\\u0005\\u0091\\u08f4\\n\\u0091',\n  '\\u0003\\u0092\\u0003\\u0092\\u0003\\u0092\\u0003\\u0092\\u0003\\u0092\\u0003\\u0092',\n  '\\u0003\\u0092\\u0003\\u0092\\u0003\\u0092\\u0003\\u0092\\u0005\\u0092\\u0900\\n',\n  '\\u0092\\u0003\\u0093\\u0003\\u0093\\u0003\\u0093\\u0003\\u0093\\u0003\\u0093\\u0003',\n  '\\u0093\\u0005\\u0093\\u0908\\n\\u0093\\u0003\\u0094\\u0003\\u0094\\u0003\\u0094',\n  '\\u0003\\u0094\\u0003\\u0094\\u0003\\u0094\\u0005\\u0094\\u0910\\n\\u0094\\u0003',\n  '\\u0095\\u0003\\u0095\\u0003\\u0095\\u0003\\u0095\\u0003\\u0095\\u0003\\u0095\\u0003',\n  '\\u0095\\u0003\\u0095\\u0003\\u0095\\u0003\\u0095\\u0005\\u0095\\u091c\\n\\u0095',\n  '\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096',\n  '\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096\\u0003\\u0096',\n  '\\u0003\\u0096\\u0003\\u0096\\u0005\\u0096\\u092c\\n\\u0096\\u0003\\u0097\\u0003',\n  '\\u0097\\u0003\\u0097\\u0003\\u0097\\u0003\\u0097\\u0003\\u0097\\u0003\\u0097\\u0003',\n  '\\u0097\\u0005\\u0097\\u0936\\n\\u0097\\u0003\\u0098\\u0003\\u0098\\u0003\\u0098',\n  '\\u0003\\u0098\\u0003\\u0098\\u0003\\u0098\\u0003\\u0098\\u0003\\u0098\\u0003\\u0098',\n  '\\u0003\\u0098\\u0005\\u0098\\u0942\\n\\u0098\\u0003\\u0099\\u0003\\u0099\\u0003',\n  '\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003',\n  '\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003',\n  '\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003\\u0099\\u0003',\n  '\\u0099\\u0003\\u0099\\u0005\\u0099\\u095a\\n\\u0099\\u0003\\u009a\\u0003\\u009a',\n  '\\u0003\\u009a\\u0003\\u009a\\u0003\\u009a\\u0003\\u009a\\u0003\\u009a\\u0003\\u009a',\n  '\\u0003\\u009a\\u0003\\u009a\\u0003\\u009a\\u0003\\u009a\\u0005\\u009a\\u0968\\n',\n  '\\u009a\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003',\n  '\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003',\n  '\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0003\\u009b\\u0005\\u009b\\u097a',\n  '\\n\\u009b\\u0003\\u009c\\u0003\\u009c\\u0003\\u009c\\u0003\\u009c\\u0003\\u009c',\n  '\\u0003\\u009c\\u0003\\u009c\\u0003\\u009c\\u0005\\u009c\\u0984\\n\\u009c\\u0003',\n  '\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003',\n  '\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003',\n  '\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0003\\u009d\\u0005',\n  '\\u009d\\u0998\\n\\u009d\\u0003\\u009e\\u0003\\u009e\\u0003\\u009e\\u0003\\u009e',\n  '\\u0003\\u009e\\u0003\\u009e\\u0003\\u009e\\u0003\\u009e\\u0003\\u009e\\u0003\\u009e',\n  '\\u0005\\u009e\\u09a4\\n\\u009e\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003',\n  '\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003',\n  '\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003',\n  '\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003\\u009f\\u0003',\n  '\\u009f\\u0003\\u009f\\u0003\\u009f\\u0005\\u009f\\u09be\\n\\u009f\\u0003\\u00a0',\n  '\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0',\n  '\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0',\n  '\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0\\u0003\\u00a0',\n  '\\u0003\\u00a0\\u0005\\u00a0\\u09d4\\n\\u00a0\\u0003\\u00a1\\u0003\\u00a1\\u0003',\n  '\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003',\n  '\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003',\n  '\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0003\\u00a1\\u0005\\u00a1\\u09e8\\n\\u00a1',\n  '\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2',\n  '\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2',\n  '\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2',\n  '\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0003\\u00a2\\u0005\\u00a2\\u0a00\\n',\n  '\\u00a2\\u0003\\u00a3\\u0003\\u00a3\\u0003\\u00a3\\u0003\\u00a3\\u0003\\u00a3\\u0003',\n  '\\u00a3\\u0003\\u00a3\\u0003\\u00a3\\u0005\\u00a3\\u0a0a\\n\\u00a3\\u0003\\u00a4',\n  '\\u0003\\u00a4\\u0003\\u00a4\\u0003\\u00a4\\u0003\\u00a4\\u0003\\u00a4\\u0003\\u00a4',\n  '\\u0003\\u00a4\\u0003\\u00a4\\u0003\\u00a4\\u0005\\u00a4\\u0a16\\n\\u00a4\\u0003',\n  '\\u00a5\\u0003\\u00a5\\u0003\\u00a5\\u0003\\u00a5\\u0003\\u00a5\\u0003\\u00a5\\u0003',\n  '\\u00a5\\u0003\\u00a5\\u0005\\u00a5\\u0a20\\n\\u00a5\\u0003\\u00a6\\u0003\\u00a6',\n  '\\u0003\\u00a6\\u0003\\u00a6\\u0003\\u00a6\\u0003\\u00a6\\u0003\\u00a6\\u0003\\u00a6',\n  '\\u0005\\u00a6\\u0a2a\\n\\u00a6\\u0003\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003',\n  '\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003',\n  '\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0003\\u00a7\\u0005\\u00a7\\u0a3a',\n  '\\n\\u00a7\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8',\n  '\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8',\n  '\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8',\n  '\\u0003\\u00a8\\u0003\\u00a8\\u0003\\u00a8\\u0005\\u00a8\\u0a50\\n\\u00a8\\u0003',\n  '\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003',\n  '\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003\\u00a9\\u0003',\n  '\\u00a9\\u0003\\u00a9\\u0005\\u00a9\\u0a60\\n\\u00a9\\u0003\\u00aa\\u0003\\u00aa',\n  '\\u0003\\u00aa\\u0003\\u00aa\\u0003\\u00aa\\u0003\\u00aa\\u0003\\u00aa\\u0003\\u00aa',\n  '\\u0003\\u00aa\\u0003\\u00aa\\u0005\\u00aa\\u0a6c\\n\\u00aa\\u0003\\u00ab\\u0003',\n  '\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0003',\n  '\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0003\\u00ab\\u0005\\u00ab\\u0a7a',\n  '\\n\\u00ab\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac',\n  '\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac',\n  '\\u0003\\u00ac\\u0003\\u00ac\\u0003\\u00ac\\u0005\\u00ac\\u0a8a\\n\\u00ac\\u0003',\n  '\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003',\n  '\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003',\n  '\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0003\\u00ad\\u0005\\u00ad\\u0a9c\\n\\u00ad',\n  '\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae',\n  '\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae',\n  '\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae\\u0003\\u00ae',\n  '\\u0005\\u00ae\\u0ab0\\n\\u00ae\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003',\n  '\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003',\n  '\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003\\u00af\\u0003',\n  '\\u00af\\u0003\\u00af\\u0003\\u00af\\u0005\\u00af\\u0ac4\\n\\u00af\\u0003\\u00b0',\n  '\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0',\n  '\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0',\n  '\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0\\u0003\\u00b0',\n  '\\u0003\\u00b0\\u0005\\u00b0\\u0ada\\n\\u00b0\\u0003\\u00b1\\u0003\\u00b1\\u0003',\n  '\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003',\n  '\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003',\n  '\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0003\\u00b1\\u0005\\u00b1\\u0aee\\n\\u00b1',\n  '\\u0003\\u00b2\\u0003\\u00b2\\u0003\\u00b2\\u0003\\u00b2\\u0003\\u00b2\\u0003\\u00b2',\n  '\\u0003\\u00b2\\u0003\\u00b2\\u0005\\u00b2\\u0af8\\n\\u00b2\\u0003\\u00b3\\u0003',\n  '\\u00b3\\u0003\\u00b3\\u0003\\u00b3\\u0003\\u00b3\\u0003\\u00b3\\u0003\\u00b3\\u0003',\n  '\\u00b3\\u0005\\u00b3\\u0b02\\n\\u00b3\\u0003\\u00b4\\u0003\\u00b4\\u0003\\u00b4',\n  '\\u0003\\u00b4\\u0003\\u00b4\\u0003\\u00b4\\u0003\\u00b4\\u0003\\u00b4\\u0003\\u00b4',\n  '\\u0003\\u00b4\\u0005\\u00b4\\u0b0e\\n\\u00b4\\u0003\\u00b5\\u0003\\u00b5\\u0003',\n  '\\u00b5\\u0003\\u00b5\\u0003\\u00b5\\u0003\\u00b5\\u0003\\u00b5\\u0003\\u00b5\\u0003',\n  '\\u00b5\\u0003\\u00b5\\u0005\\u00b5\\u0b1a\\n\\u00b5\\u0003\\u00b6\\u0003\\u00b6',\n  '\\u0003\\u00b6\\u0003\\u00b6\\u0005\\u00b6\\u0b20\\n\\u00b6\\u0003\\u00b7\\u0003',\n  '\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0003',\n  '\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0003\\u00b7\\u0005\\u00b7\\u0b2e',\n  '\\n\\u00b7\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8',\n  '\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8',\n  '\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0003\\u00b8\\u0005\\u00b8',\n  '\\u0b40\\n\\u00b8\\u0003\\u00b9\\u0003\\u00b9\\u0003\\u00ba\\u0003\\u00ba\\u0003',\n  '\\u00ba\\u0003\\u00ba\\u0005\\u00ba\\u0b48\\n\\u00ba\\u0003\\u00bb\\u0003\\u00bb',\n  '\\u0003\\u00bc\\u0003\\u00bc\\u0003\\u00bc\\u0003\\u00bd\\u0003\\u00bd\\u0003\\u00be',\n  '\\u0003\\u00be\\u0003\\u00be\\u0003\\u00bf\\u0003\\u00bf\\u0003\\u00c0\\u0003\\u00c0',\n  '\\u0003\\u00c1\\u0003\\u00c1\\u0003\\u00c2\\u0003\\u00c2\\u0003\\u00c3\\u0003\\u00c3',\n  '\\u0003\\u00c4\\u0003\\u00c4\\u0003\\u00c4\\u0003\\u00c5\\u0003\\u00c5\\u0003\\u00c5',\n  '\\u0003\\u00c5\\u0007\\u00c5\\u0b65\\n\\u00c5\\f\\u00c5\\u000e\\u00c5\\u0b68\\u000b',\n  '\\u00c5\\u0003\\u00c5\\u0003\\u00c5\\u0003\\u00c6\\u0003\\u00c6\\u0003\\u00c6\\u0003',\n  '\\u00c6\\u0007\\u00c6\\u0b70\\n\\u00c6\\f\\u00c6\\u000e\\u00c6\\u0b73\\u000b\\u00c6',\n  '\\u0003\\u00c6\\u0003\\u00c6\\u0003\\u00c7\\u0006\\u00c7\\u0b78\\n\\u00c7\\r\\u00c7',\n  '\\u000e\\u00c7\\u0b79\\u0003\\u00c8\\u0006\\u00c8\\u0b7d\\n\\u00c8\\r\\u00c8\\u000e',\n  '\\u00c8\\u0b7e\\u0003\\u00c8\\u0003\\u00c8\\u0007\\u00c8\\u0b83\\n\\u00c8\\f\\u00c8',\n  '\\u000e\\u00c8\\u0b86\\u000b\\u00c8\\u0003\\u00c8\\u0003\\u00c8\\u0006\\u00c8\\u0b8a',\n  '\\n\\u00c8\\r\\u00c8\\u000e\\u00c8\\u0b8b\\u0003\\u00c8\\u0006\\u00c8\\u0b8f\\n\\u00c8',\n  '\\r\\u00c8\\u000e\\u00c8\\u0b90\\u0003\\u00c8\\u0003\\u00c8\\u0007\\u00c8\\u0b95',\n  '\\n\\u00c8\\f\\u00c8\\u000e\\u00c8\\u0b98\\u000b\\u00c8\\u0005\\u00c8\\u0b9a\\n\\u00c8',\n  '\\u0003\\u00c8\\u0003\\u00c8\\u0003\\u00c8\\u0003\\u00c8\\u0006\\u00c8\\u0ba0\\n',\n  '\\u00c8\\r\\u00c8\\u000e\\u00c8\\u0ba1\\u0003\\u00c8\\u0003\\u00c8\\u0005\\u00c8',\n  '\\u0ba6\\n\\u00c8\\u0003\\u00c9\\u0003\\u00c9\\u0005\\u00c9\\u0baa\\n\\u00c9\\u0003',\n  '\\u00c9\\u0003\\u00c9\\u0003\\u00c9\\u0007\\u00c9\\u0baf\\n\\u00c9\\f\\u00c9\\u000e',\n  '\\u00c9\\u0bb2\\u000b\\u00c9\\u0003\\u00ca\\u0003\\u00ca\\u0003\\u00ca\\u0003\\u00ca',\n  '\\u0006\\u00ca\\u0bb8\\n\\u00ca\\r\\u00ca\\u000e\\u00ca\\u0bb9\\u0003\\u00cb\\u0003',\n  '\\u00cb\\u0003\\u00cb\\u0003\\u00cb\\u0007\\u00cb\\u0bc0\\n\\u00cb\\f\\u00cb\\u000e',\n  '\\u00cb\\u0bc3\\u000b\\u00cb\\u0003\\u00cb\\u0003\\u00cb\\u0003\\u00cc\\u0003\\u00cc',\n  '\\u0003\\u00cc\\u0003\\u00cc\\u0007\\u00cc\\u0bcb\\n\\u00cc\\f\\u00cc\\u000e\\u00cc',\n  '\\u0bce\\u000b\\u00cc\\u0003\\u00cc\\u0003\\u00cc\\u0003\\u00cd\\u0003\\u00cd\\u0003',\n  '\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003',\n  '\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003',\n  '\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003',\n  '\\u00cd\\u0003\\u00cd\\u0003\\u00cd\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003',\n  '\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003',\n  '\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003',\n  '\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003',\n  '\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003\\u00ce\\u0003',\n  '\\u00ce\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003',\n  '\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003',\n  '\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003\\u00cf\\u0003',\n  '\\u00cf\\u0003\\u00d0\\u0003\\u00d0\\u0005\\u00d0\\u0c19\\n\\u00d0\\u0003\\u00d0',\n  '\\u0006\\u00d0\\u0c1c\\n\\u00d0\\r\\u00d0\\u000e\\u00d0\\u0c1d\\u0003\\u00d1\\u0003',\n  '\\u00d1\\u0003\\u00d2\\u0005\\u00d2\\u0c23\\n\\u00d2\\u0003\\u00d3\\u0003\\u00d3',\n  '\\u0003\\u00d3\\u0003\\u00d3\\u0007\\u00d3\\u0c29\\n\\u00d3\\f\\u00d3\\u000e\\u00d3',\n  '\\u0c2c\\u000b\\u00d3\\u0003\\u00d3\\u0005\\u00d3\\u0c2f\\n\\u00d3\\u0003\\u00d3',\n  '\\u0005\\u00d3\\u0c32\\n\\u00d3\\u0003\\u00d3\\u0003\\u00d3\\u0003\\u00d4\\u0003',\n  '\\u00d4\\u0003\\u00d4\\u0003\\u00d4\\u0007\\u00d4\\u0c3a\\n\\u00d4\\f\\u00d4\\u000e',\n  '\\u00d4\\u0c3d\\u000b\\u00d4\\u0003\\u00d4\\u0003\\u00d4\\u0003\\u00d4\\u0003\\u00d4',\n  '\\u0003\\u00d4\\u0003\\u00d5\\u0006\\u00d5\\u0c45\\n\\u00d5\\r\\u00d5\\u000e\\u00d5',\n  '\\u0c46\\u0003\\u00d5\\u0003\\u00d5\\u0003\\u00d6\\u0003\\u00d6\\u0003\\u00d7\\u0003',\n  '\\u00d7\\u0003\\u0c3b\\u0002\\u00d8\\u0003\\u0003\\u0005\\u0004\\u0007\\u0005\\t',\n  '\\u0006\\u000b\\u0007\\r\\b\\u000f\\t\\u0011\\n\\u0013\\u000b\\u0015\\f\\u0017\\r\\u0019',\n  \"\\u000e\\u001b\\u000f\\u001d\\u0010\\u001f\\u0011!\\u0012#\\u0013%\\u0014'\\u0015\",\n  ')\\u0016+\\u0017-\\u0018/\\u00191\\u001a3\\u001b5\\u001c7\\u001d9\\u001e;\\u001f',\n  '= ?!A\"C#E$G%I&K\\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o9q:s;u<w=y>{?}',\n  '@\\u007fA\\u0081B\\u0083C\\u0085D\\u0087E\\u0089F\\u008bG\\u008dH\\u008fI\\u0091',\n  'J\\u0093K\\u0095L\\u0097M\\u0099N\\u009bO\\u009dP\\u009fQ\\u00a1R\\u00a3S\\u00a5',\n  'T\\u00a7U\\u00a9V\\u00abW\\u00adX\\u00afY\\u00b1Z\\u00b3[\\u00b5\\\\\\u00b7]\\u00b9',\n  '^\\u00bb_\\u00bd`\\u00bfa\\u00c1b\\u00c3c\\u00c5d\\u00c7e\\u00c9f\\u00cbg\\u00cd',\n  'h\\u00cfi\\u00d1j\\u00d3k\\u00d5l\\u00d7m\\u00d9n\\u00dbo\\u00ddp\\u00dfq\\u00e1',\n  'r\\u00e3s\\u00e5t\\u00e7u\\u00e9v\\u00ebw\\u00edx\\u00efy\\u00f1z\\u00f3{\\u00f5',\n  '|\\u00f7}\\u00f9~\\u00fb\\u007f\\u00fd\\u0080\\u00ff\\u0081\\u0101\\u0082\\u0103',\n  '\\u0083\\u0105\\u0084\\u0107\\u0085\\u0109\\u0086\\u010b\\u0087\\u010d\\u0088\\u010f',\n  '\\u0089\\u0111\\u008a\\u0113\\u008b\\u0115\\u008c\\u0117\\u008d\\u0119\\u008e\\u011b',\n  '\\u008f\\u011d\\u0090\\u011f\\u0091\\u0121\\u0092\\u0123\\u0093\\u0125\\u0094\\u0127',\n  '\\u0095\\u0129\\u0096\\u012b\\u0097\\u012d\\u0098\\u012f\\u0099\\u0131\\u009a\\u0133',\n  '\\u009b\\u0135\\u009c\\u0137\\u009d\\u0139\\u009e\\u013b\\u009f\\u013d\\u00a0\\u013f',\n  '\\u00a1\\u0141\\u00a2\\u0143\\u00a3\\u0145\\u00a4\\u0147\\u00a5\\u0149\\u00a6\\u014b',\n  '\\u00a7\\u014d\\u00a8\\u014f\\u00a9\\u0151\\u00aa\\u0153\\u00ab\\u0155\\u00ac\\u0157',\n  '\\u00ad\\u0159\\u00ae\\u015b\\u00af\\u015d\\u00b0\\u015f\\u00b1\\u0161\\u00b2\\u0163',\n  '\\u00b3\\u0165\\u00b4\\u0167\\u00b5\\u0169\\u00b6\\u016b\\u00b7\\u016d\\u00b8\\u016f',\n  '\\u00b9\\u0171\\u00ba\\u0173\\u00bb\\u0175\\u00bc\\u0177\\u00bd\\u0179\\u00be\\u017b',\n  '\\u00bf\\u017d\\u00c0\\u017f\\u00c1\\u0181\\u00c2\\u0183\\u00c3\\u0185\\u00c4\\u0187',\n  '\\u00c5\\u0189\\u00c6\\u018b\\u00c7\\u018d\\u00c8\\u018f\\u00c9\\u0191\\u00ca\\u0193',\n  '\\u00cb\\u0195\\u00cc\\u0197\\u00cd\\u0199\\u00ce\\u019b\\u00cf\\u019d\\u00d0\\u019f',\n  '\\u0002\\u01a1\\u0002\\u01a3\\u0002\\u01a5\\u00d1\\u01a7\\u00d2\\u01a9\\u00d3\\u01ab',\n  '\\u00d4\\u01ad\\u00d5\\u0003\\u0002\\u000b\\u0003\\u0002))\\u0005\\u0002<<BBa',\n  'a\\u0003\\u0002$$\\u0003\\u0002bb\\u0004\\u0002--//\\u0003\\u00022;\\u0004\\u0002',\n  'C\\\\c|\\u0004\\u0002\\f\\f\\u000f\\u000f\\u0005\\u0002\\u000b\\f\\u000f\\u000f\"',\n  '\"\\u0002\\u0d19\\u0002\\u0003\\u0003\\u0002\\u0002\\u0002\\u0002\\u0005\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u0007\\u0003\\u0002\\u0002\\u0002\\u0002\\t\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u000b\\u0003\\u0002\\u0002\\u0002\\u0002\\r\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u000f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0011\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u0013\\u0003\\u0002\\u0002\\u0002\\u0002\\u0015\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u0017\\u0003\\u0002\\u0002\\u0002\\u0002\\u0019\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u001b\\u0003\\u0002\\u0002\\u0002\\u0002\\u001d\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002\\u001f\\u0003\\u0002\\u0002\\u0002\\u0002!\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002#\\u0003\\u0002\\u0002\\u0002\\u0002%\\u0003\\u0002',\n  \"\\u0002\\u0002\\u0002'\\u0003\\u0002\\u0002\\u0002\\u0002)\\u0003\\u0002\\u0002\",\n  '\\u0002\\u0002+\\u0003\\u0002\\u0002\\u0002\\u0002-\\u0003\\u0002\\u0002\\u0002',\n  '\\u0002/\\u0003\\u0002\\u0002\\u0002\\u00021\\u0003\\u0002\\u0002\\u0002\\u0002',\n  '3\\u0003\\u0002\\u0002\\u0002\\u00025\\u0003\\u0002\\u0002\\u0002\\u00027\\u0003',\n  '\\u0002\\u0002\\u0002\\u00029\\u0003\\u0002\\u0002\\u0002\\u0002;\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002=\\u0003\\u0002\\u0002\\u0002\\u0002?\\u0003\\u0002\\u0002',\n  '\\u0002\\u0002A\\u0003\\u0002\\u0002\\u0002\\u0002C\\u0003\\u0002\\u0002\\u0002',\n  '\\u0002E\\u0003\\u0002\\u0002\\u0002\\u0002G\\u0003\\u0002\\u0002\\u0002\\u0002',\n  'I\\u0003\\u0002\\u0002\\u0002\\u0002K\\u0003\\u0002\\u0002\\u0002\\u0002M\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002O\\u0003\\u0002\\u0002\\u0002\\u0002Q\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002S\\u0003\\u0002\\u0002\\u0002\\u0002U\\u0003\\u0002\\u0002',\n  '\\u0002\\u0002W\\u0003\\u0002\\u0002\\u0002\\u0002Y\\u0003\\u0002\\u0002\\u0002',\n  '\\u0002[\\u0003\\u0002\\u0002\\u0002\\u0002]\\u0003\\u0002\\u0002\\u0002\\u0002',\n  '_\\u0003\\u0002\\u0002\\u0002\\u0002a\\u0003\\u0002\\u0002\\u0002\\u0002c\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002e\\u0003\\u0002\\u0002\\u0002\\u0002g\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002i\\u0003\\u0002\\u0002\\u0002\\u0002k\\u0003\\u0002\\u0002',\n  '\\u0002\\u0002m\\u0003\\u0002\\u0002\\u0002\\u0002o\\u0003\\u0002\\u0002\\u0002',\n  '\\u0002q\\u0003\\u0002\\u0002\\u0002\\u0002s\\u0003\\u0002\\u0002\\u0002\\u0002',\n  'u\\u0003\\u0002\\u0002\\u0002\\u0002w\\u0003\\u0002\\u0002\\u0002\\u0002y\\u0003',\n  '\\u0002\\u0002\\u0002\\u0002{\\u0003\\u0002\\u0002\\u0002\\u0002}\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u007f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0081\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0083\\u0003\\u0002\\u0002\\u0002\\u0002\\u0085\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0087\\u0003\\u0002\\u0002\\u0002\\u0002\\u0089\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u008b\\u0003\\u0002\\u0002\\u0002\\u0002\\u008d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u008f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0091\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0093\\u0003\\u0002\\u0002\\u0002\\u0002\\u0095\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0097\\u0003\\u0002\\u0002\\u0002\\u0002\\u0099\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u009b\\u0003\\u0002\\u0002\\u0002\\u0002\\u009d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u009f\\u0003\\u0002\\u0002\\u0002\\u0002\\u00a1\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00a3\\u0003\\u0002\\u0002\\u0002\\u0002\\u00a5\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00a7\\u0003\\u0002\\u0002\\u0002\\u0002\\u00a9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00ab\\u0003\\u0002\\u0002\\u0002\\u0002\\u00ad\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00af\\u0003\\u0002\\u0002\\u0002\\u0002\\u00b1\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00b3\\u0003\\u0002\\u0002\\u0002\\u0002\\u00b5\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00b7\\u0003\\u0002\\u0002\\u0002\\u0002\\u00b9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00bb\\u0003\\u0002\\u0002\\u0002\\u0002\\u00bd\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00bf\\u0003\\u0002\\u0002\\u0002\\u0002\\u00c1\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00c3\\u0003\\u0002\\u0002\\u0002\\u0002\\u00c5\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00c7\\u0003\\u0002\\u0002\\u0002\\u0002\\u00c9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00cb\\u0003\\u0002\\u0002\\u0002\\u0002\\u00cd\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00cf\\u0003\\u0002\\u0002\\u0002\\u0002\\u00d1\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00d3\\u0003\\u0002\\u0002\\u0002\\u0002\\u00d5\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00d7\\u0003\\u0002\\u0002\\u0002\\u0002\\u00d9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00db\\u0003\\u0002\\u0002\\u0002\\u0002\\u00dd\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00df\\u0003\\u0002\\u0002\\u0002\\u0002\\u00e1\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00e3\\u0003\\u0002\\u0002\\u0002\\u0002\\u00e5\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00e7\\u0003\\u0002\\u0002\\u0002\\u0002\\u00e9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00eb\\u0003\\u0002\\u0002\\u0002\\u0002\\u00ed\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00ef\\u0003\\u0002\\u0002\\u0002\\u0002\\u00f1\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00f3\\u0003\\u0002\\u0002\\u0002\\u0002\\u00f5\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00f7\\u0003\\u0002\\u0002\\u0002\\u0002\\u00f9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00fb\\u0003\\u0002\\u0002\\u0002\\u0002\\u00fd\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u00ff\\u0003\\u0002\\u0002\\u0002\\u0002\\u0101\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0103\\u0003\\u0002\\u0002\\u0002\\u0002\\u0105\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0107\\u0003\\u0002\\u0002\\u0002\\u0002\\u0109\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u010b\\u0003\\u0002\\u0002\\u0002\\u0002\\u010d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u010f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0111\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0113\\u0003\\u0002\\u0002\\u0002\\u0002\\u0115\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0117\\u0003\\u0002\\u0002\\u0002\\u0002\\u0119\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u011b\\u0003\\u0002\\u0002\\u0002\\u0002\\u011d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u011f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0121\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0123\\u0003\\u0002\\u0002\\u0002\\u0002\\u0125\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0127\\u0003\\u0002\\u0002\\u0002\\u0002\\u0129\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u012b\\u0003\\u0002\\u0002\\u0002\\u0002\\u012d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u012f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0131\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0133\\u0003\\u0002\\u0002\\u0002\\u0002\\u0135\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0137\\u0003\\u0002\\u0002\\u0002\\u0002\\u0139\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u013b\\u0003\\u0002\\u0002\\u0002\\u0002\\u013d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u013f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0141\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0143\\u0003\\u0002\\u0002\\u0002\\u0002\\u0145\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0147\\u0003\\u0002\\u0002\\u0002\\u0002\\u0149\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u014b\\u0003\\u0002\\u0002\\u0002\\u0002\\u014d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u014f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0151\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0153\\u0003\\u0002\\u0002\\u0002\\u0002\\u0155\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0157\\u0003\\u0002\\u0002\\u0002\\u0002\\u0159\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u015b\\u0003\\u0002\\u0002\\u0002\\u0002\\u015d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u015f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0161\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0163\\u0003\\u0002\\u0002\\u0002\\u0002\\u0165\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0167\\u0003\\u0002\\u0002\\u0002\\u0002\\u0169\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u016b\\u0003\\u0002\\u0002\\u0002\\u0002\\u016d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u016f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0171\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0173\\u0003\\u0002\\u0002\\u0002\\u0002\\u0175\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0177\\u0003\\u0002\\u0002\\u0002\\u0002\\u0179\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u017b\\u0003\\u0002\\u0002\\u0002\\u0002\\u017d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u017f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0181\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0183\\u0003\\u0002\\u0002\\u0002\\u0002\\u0185\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0187\\u0003\\u0002\\u0002\\u0002\\u0002\\u0189\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u018b\\u0003\\u0002\\u0002\\u0002\\u0002\\u018d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u018f\\u0003\\u0002\\u0002\\u0002\\u0002\\u0191\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0193\\u0003\\u0002\\u0002\\u0002\\u0002\\u0195\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u0197\\u0003\\u0002\\u0002\\u0002\\u0002\\u0199\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u019b\\u0003\\u0002\\u0002\\u0002\\u0002\\u019d\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u01a5\\u0003\\u0002\\u0002\\u0002\\u0002\\u01a7\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u01a9\\u0003\\u0002\\u0002\\u0002\\u0002\\u01ab\\u0003\\u0002',\n  '\\u0002\\u0002\\u0002\\u01ad\\u0003\\u0002\\u0002\\u0002\\u0003\\u01af\\u0003\\u0002',\n  '\\u0002\\u0002\\u0005\\u01b1\\u0003\\u0002\\u0002\\u0002\\u0007\\u01b3\\u0003\\u0002',\n  '\\u0002\\u0002\\t\\u01b5\\u0003\\u0002\\u0002\\u0002\\u000b\\u01b7\\u0003\\u0002',\n  '\\u0002\\u0002\\r\\u01b9\\u0003\\u0002\\u0002\\u0002\\u000f\\u01bc\\u0003\\u0002',\n  '\\u0002\\u0002\\u0011\\u01be\\u0003\\u0002\\u0002\\u0002\\u0013\\u01c0\\u0003\\u0002',\n  '\\u0002\\u0002\\u0015\\u01cf\\u0003\\u0002\\u0002\\u0002\\u0017\\u01d9\\u0003\\u0002',\n  '\\u0002\\u0002\\u0019\\u01e1\\u0003\\u0002\\u0002\\u0002\\u001b\\u01e7\\u0003\\u0002',\n  '\\u0002\\u0002\\u001d\\u01ef\\u0003\\u0002\\u0002\\u0002\\u001f\\u01f9\\u0003\\u0002',\n  '\\u0002\\u0002!\\u0201\\u0003\\u0002\\u0002\\u0002#\\u0213\\u0003\\u0002\\u0002',\n  \"\\u0002%\\u021f\\u0003\\u0002\\u0002\\u0002'\\u022b\\u0003\\u0002\\u0002\\u0002\",\n  ')\\u0231\\u0003\\u0002\\u0002\\u0002+\\u0243\\u0003\\u0002\\u0002\\u0002-\\u024d',\n  '\\u0003\\u0002\\u0002\\u0002/\\u0257\\u0003\\u0002\\u0002\\u00021\\u0265\\u0003',\n  '\\u0002\\u0002\\u00023\\u0271\\u0003\\u0002\\u0002\\u00025\\u027f\\u0003\\u0002',\n  '\\u0002\\u00027\\u028b\\u0003\\u0002\\u0002\\u00029\\u0291\\u0003\\u0002\\u0002',\n  '\\u0002;\\u0297\\u0003\\u0002\\u0002\\u0002=\\u029f\\u0003\\u0002\\u0002\\u0002',\n  '?\\u02a5\\u0003\\u0002\\u0002\\u0002A\\u02ad\\u0003\\u0002\\u0002\\u0002C\\u02b3',\n  '\\u0003\\u0002\\u0002\\u0002E\\u02c1\\u0003\\u0002\\u0002\\u0002G\\u02d1\\u0003',\n  '\\u0002\\u0002\\u0002I\\u02db\\u0003\\u0002\\u0002\\u0002K\\u02e1\\u0003\\u0002',\n  '\\u0002\\u0002M\\u02eb\\u0003\\u0002\\u0002\\u0002O\\u02f5\\u0003\\u0002\\u0002',\n  '\\u0002Q\\u0301\\u0003\\u0002\\u0002\\u0002S\\u030d\\u0003\\u0002\\u0002\\u0002',\n  'U\\u0319\\u0003\\u0002\\u0002\\u0002W\\u0323\\u0003\\u0002\\u0002\\u0002Y\\u0331',\n  '\\u0003\\u0002\\u0002\\u0002[\\u0339\\u0003\\u0002\\u0002\\u0002]\\u0343\\u0003',\n  '\\u0002\\u0002\\u0002_\\u0357\\u0003\\u0002\\u0002\\u0002a\\u0369\\u0003\\u0002',\n  '\\u0002\\u0002c\\u0371\\u0003\\u0002\\u0002\\u0002e\\u0381\\u0003\\u0002\\u0002',\n  '\\u0002g\\u0393\\u0003\\u0002\\u0002\\u0002i\\u03a3\\u0003\\u0002\\u0002\\u0002',\n  'k\\u03ad\\u0003\\u0002\\u0002\\u0002m\\u03b7\\u0003\\u0002\\u0002\\u0002o\\u03cb',\n  '\\u0003\\u0002\\u0002\\u0002q\\u03dd\\u0003\\u0002\\u0002\\u0002s\\u03e7\\u0003',\n  '\\u0002\\u0002\\u0002u\\u03f3\\u0003\\u0002\\u0002\\u0002w\\u03fb\\u0003\\u0002',\n  '\\u0002\\u0002y\\u0405\\u0003\\u0002\\u0002\\u0002{\\u0413\\u0003\\u0002\\u0002',\n  '\\u0002}\\u0421\\u0003\\u0002\\u0002\\u0002\\u007f\\u042b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0081\\u0445\\u0003\\u0002\\u0002\\u0002\\u0083\\u045f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0085\\u0483\\u0003\\u0002\\u0002\\u0002\\u0087\\u0497\\u0003\\u0002\\u0002',\n  '\\u0002\\u0089\\u04b5\\u0003\\u0002\\u0002\\u0002\\u008b\\u04c5\\u0003\\u0002\\u0002',\n  '\\u0002\\u008d\\u04cf\\u0003\\u0002\\u0002\\u0002\\u008f\\u04d9\\u0003\\u0002\\u0002',\n  '\\u0002\\u0091\\u04e3\\u0003\\u0002\\u0002\\u0002\\u0093\\u04ed\\u0003\\u0002\\u0002',\n  '\\u0002\\u0095\\u04f5\\u0003\\u0002\\u0002\\u0002\\u0097\\u04ff\\u0003\\u0002\\u0002',\n  '\\u0002\\u0099\\u050b\\u0003\\u0002\\u0002\\u0002\\u009b\\u0517\\u0003\\u0002\\u0002',\n  '\\u0002\\u009d\\u0523\\u0003\\u0002\\u0002\\u0002\\u009f\\u052d\\u0003\\u0002\\u0002',\n  '\\u0002\\u00a1\\u0539\\u0003\\u0002\\u0002\\u0002\\u00a3\\u0543\\u0003\\u0002\\u0002',\n  '\\u0002\\u00a5\\u0553\\u0003\\u0002\\u0002\\u0002\\u00a7\\u055f\\u0003\\u0002\\u0002',\n  '\\u0002\\u00a9\\u0565\\u0003\\u0002\\u0002\\u0002\\u00ab\\u0573\\u0003\\u0002\\u0002',\n  '\\u0002\\u00ad\\u057d\\u0003\\u0002\\u0002\\u0002\\u00af\\u0591\\u0003\\u0002\\u0002',\n  '\\u0002\\u00b1\\u059d\\u0003\\u0002\\u0002\\u0002\\u00b3\\u05a7\\u0003\\u0002\\u0002',\n  '\\u0002\\u00b5\\u05bb\\u0003\\u0002\\u0002\\u0002\\u00b7\\u05cf\\u0003\\u0002\\u0002',\n  '\\u0002\\u00b9\\u05e3\\u0003\\u0002\\u0002\\u0002\\u00bb\\u05f3\\u0003\\u0002\\u0002',\n  '\\u0002\\u00bd\\u05fb\\u0003\\u0002\\u0002\\u0002\\u00bf\\u0605\\u0003\\u0002\\u0002',\n  '\\u0002\\u00c1\\u0619\\u0003\\u0002\\u0002\\u0002\\u00c3\\u0627\\u0003\\u0002\\u0002',\n  '\\u0002\\u00c5\\u0635\\u0003\\u0002\\u0002\\u0002\\u00c7\\u0643\\u0003\\u0002\\u0002',\n  '\\u0002\\u00c9\\u064f\\u0003\\u0002\\u0002\\u0002\\u00cb\\u0659\\u0003\\u0002\\u0002',\n  '\\u0002\\u00cd\\u0669\\u0003\\u0002\\u0002\\u0002\\u00cf\\u0677\\u0003\\u0002\\u0002',\n  '\\u0002\\u00d1\\u0685\\u0003\\u0002\\u0002\\u0002\\u00d3\\u068f\\u0003\\u0002\\u0002',\n  '\\u0002\\u00d5\\u06a5\\u0003\\u0002\\u0002\\u0002\\u00d7\\u06b7\\u0003\\u0002\\u0002',\n  '\\u0002\\u00d9\\u06c3\\u0003\\u0002\\u0002\\u0002\\u00db\\u06d1\\u0003\\u0002\\u0002',\n  '\\u0002\\u00dd\\u06e7\\u0003\\u0002\\u0002\\u0002\\u00df\\u06f5\\u0003\\u0002\\u0002',\n  '\\u0002\\u00e1\\u0703\\u0003\\u0002\\u0002\\u0002\\u00e3\\u0713\\u0003\\u0002\\u0002',\n  '\\u0002\\u00e5\\u0723\\u0003\\u0002\\u0002\\u0002\\u00e7\\u0731\\u0003\\u0002\\u0002',\n  '\\u0002\\u00e9\\u073b\\u0003\\u0002\\u0002\\u0002\\u00eb\\u0745\\u0003\\u0002\\u0002',\n  '\\u0002\\u00ed\\u0757\\u0003\\u0002\\u0002\\u0002\\u00ef\\u0767\\u0003\\u0002\\u0002',\n  '\\u0002\\u00f1\\u077f\\u0003\\u0002\\u0002\\u0002\\u00f3\\u0789\\u0003\\u0002\\u0002',\n  '\\u0002\\u00f5\\u079b\\u0003\\u0002\\u0002\\u0002\\u00f7\\u07a5\\u0003\\u0002\\u0002',\n  '\\u0002\\u00f9\\u07b3\\u0003\\u0002\\u0002\\u0002\\u00fb\\u07c3\\u0003\\u0002\\u0002',\n  '\\u0002\\u00fd\\u07d5\\u0003\\u0002\\u0002\\u0002\\u00ff\\u07e5\\u0003\\u0002\\u0002',\n  '\\u0002\\u0101\\u07f3\\u0003\\u0002\\u0002\\u0002\\u0103\\u07fb\\u0003\\u0002\\u0002',\n  '\\u0002\\u0105\\u0811\\u0003\\u0002\\u0002\\u0002\\u0107\\u0825\\u0003\\u0002\\u0002',\n  '\\u0002\\u0109\\u082f\\u0003\\u0002\\u0002\\u0002\\u010b\\u083b\\u0003\\u0002\\u0002',\n  '\\u0002\\u010d\\u0849\\u0003\\u0002\\u0002\\u0002\\u010f\\u085d\\u0003\\u0002\\u0002',\n  '\\u0002\\u0111\\u0863\\u0003\\u0002\\u0002\\u0002\\u0113\\u0871\\u0003\\u0002\\u0002',\n  '\\u0002\\u0115\\u0885\\u0003\\u0002\\u0002\\u0002\\u0117\\u089d\\u0003\\u0002\\u0002',\n  '\\u0002\\u0119\\u08b5\\u0003\\u0002\\u0002\\u0002\\u011b\\u08c1\\u0003\\u0002\\u0002',\n  '\\u0002\\u011d\\u08cf\\u0003\\u0002\\u0002\\u0002\\u011f\\u08dd\\u0003\\u0002\\u0002',\n  '\\u0002\\u0121\\u08f3\\u0003\\u0002\\u0002\\u0002\\u0123\\u08ff\\u0003\\u0002\\u0002',\n  '\\u0002\\u0125\\u0907\\u0003\\u0002\\u0002\\u0002\\u0127\\u090f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0129\\u091b\\u0003\\u0002\\u0002\\u0002\\u012b\\u092b\\u0003\\u0002\\u0002',\n  '\\u0002\\u012d\\u0935\\u0003\\u0002\\u0002\\u0002\\u012f\\u0941\\u0003\\u0002\\u0002',\n  '\\u0002\\u0131\\u0959\\u0003\\u0002\\u0002\\u0002\\u0133\\u0967\\u0003\\u0002\\u0002',\n  '\\u0002\\u0135\\u0979\\u0003\\u0002\\u0002\\u0002\\u0137\\u0983\\u0003\\u0002\\u0002',\n  '\\u0002\\u0139\\u0997\\u0003\\u0002\\u0002\\u0002\\u013b\\u09a3\\u0003\\u0002\\u0002',\n  '\\u0002\\u013d\\u09bd\\u0003\\u0002\\u0002\\u0002\\u013f\\u09d3\\u0003\\u0002\\u0002',\n  '\\u0002\\u0141\\u09e7\\u0003\\u0002\\u0002\\u0002\\u0143\\u09ff\\u0003\\u0002\\u0002',\n  '\\u0002\\u0145\\u0a09\\u0003\\u0002\\u0002\\u0002\\u0147\\u0a15\\u0003\\u0002\\u0002',\n  '\\u0002\\u0149\\u0a1f\\u0003\\u0002\\u0002\\u0002\\u014b\\u0a29\\u0003\\u0002\\u0002',\n  '\\u0002\\u014d\\u0a39\\u0003\\u0002\\u0002\\u0002\\u014f\\u0a4f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0151\\u0a5f\\u0003\\u0002\\u0002\\u0002\\u0153\\u0a6b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0155\\u0a79\\u0003\\u0002\\u0002\\u0002\\u0157\\u0a89\\u0003\\u0002\\u0002',\n  '\\u0002\\u0159\\u0a9b\\u0003\\u0002\\u0002\\u0002\\u015b\\u0aaf\\u0003\\u0002\\u0002',\n  '\\u0002\\u015d\\u0ac3\\u0003\\u0002\\u0002\\u0002\\u015f\\u0ad9\\u0003\\u0002\\u0002',\n  '\\u0002\\u0161\\u0aed\\u0003\\u0002\\u0002\\u0002\\u0163\\u0af7\\u0003\\u0002\\u0002',\n  '\\u0002\\u0165\\u0b01\\u0003\\u0002\\u0002\\u0002\\u0167\\u0b0d\\u0003\\u0002\\u0002',\n  '\\u0002\\u0169\\u0b19\\u0003\\u0002\\u0002\\u0002\\u016b\\u0b1f\\u0003\\u0002\\u0002',\n  '\\u0002\\u016d\\u0b2d\\u0003\\u0002\\u0002\\u0002\\u016f\\u0b3f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0171\\u0b41\\u0003\\u0002\\u0002\\u0002\\u0173\\u0b47\\u0003\\u0002\\u0002',\n  '\\u0002\\u0175\\u0b49\\u0003\\u0002\\u0002\\u0002\\u0177\\u0b4b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0179\\u0b4e\\u0003\\u0002\\u0002\\u0002\\u017b\\u0b50\\u0003\\u0002\\u0002',\n  '\\u0002\\u017d\\u0b53\\u0003\\u0002\\u0002\\u0002\\u017f\\u0b55\\u0003\\u0002\\u0002',\n  '\\u0002\\u0181\\u0b57\\u0003\\u0002\\u0002\\u0002\\u0183\\u0b59\\u0003\\u0002\\u0002',\n  '\\u0002\\u0185\\u0b5b\\u0003\\u0002\\u0002\\u0002\\u0187\\u0b5d\\u0003\\u0002\\u0002',\n  '\\u0002\\u0189\\u0b60\\u0003\\u0002\\u0002\\u0002\\u018b\\u0b6b\\u0003\\u0002\\u0002',\n  '\\u0002\\u018d\\u0b77\\u0003\\u0002\\u0002\\u0002\\u018f\\u0ba5\\u0003\\u0002\\u0002',\n  '\\u0002\\u0191\\u0ba9\\u0003\\u0002\\u0002\\u0002\\u0193\\u0bb3\\u0003\\u0002\\u0002',\n  '\\u0002\\u0195\\u0bbb\\u0003\\u0002\\u0002\\u0002\\u0197\\u0bc6\\u0003\\u0002\\u0002',\n  '\\u0002\\u0199\\u0bd1\\u0003\\u0002\\u0002\\u0002\\u019b\\u0be8\\u0003\\u0002\\u0002',\n  '\\u0002\\u019d\\u0c04\\u0003\\u0002\\u0002\\u0002\\u019f\\u0c16\\u0003\\u0002\\u0002',\n  '\\u0002\\u01a1\\u0c1f\\u0003\\u0002\\u0002\\u0002\\u01a3\\u0c22\\u0003\\u0002\\u0002',\n  '\\u0002\\u01a5\\u0c24\\u0003\\u0002\\u0002\\u0002\\u01a7\\u0c35\\u0003\\u0002\\u0002',\n  '\\u0002\\u01a9\\u0c44\\u0003\\u0002\\u0002\\u0002\\u01ab\\u0c4a\\u0003\\u0002\\u0002',\n  '\\u0002\\u01ad\\u0c4c\\u0003\\u0002\\u0002\\u0002\\u01af\\u01b0\\u00070\\u0002',\n  '\\u0002\\u01b0\\u0004\\u0003\\u0002\\u0002\\u0002\\u01b1\\u01b2\\u0007*\\u0002',\n  '\\u0002\\u01b2\\u0006\\u0003\\u0002\\u0002\\u0002\\u01b3\\u01b4\\u0007.\\u0002',\n  '\\u0002\\u01b4\\b\\u0003\\u0002\\u0002\\u0002\\u01b5\\u01b6\\u0007+\\u0002\\u0002',\n  '\\u01b6\\n\\u0003\\u0002\\u0002\\u0002\\u01b7\\u01b8\\u0007A\\u0002\\u0002\\u01b8',\n  '\\f\\u0003\\u0002\\u0002\\u0002\\u01b9\\u01ba\\u0007/\\u0002\\u0002\\u01ba\\u01bb',\n  '\\u0007@\\u0002\\u0002\\u01bb\\u000e\\u0003\\u0002\\u0002\\u0002\\u01bc\\u01bd',\n  '\\u0007]\\u0002\\u0002\\u01bd\\u0010\\u0003\\u0002\\u0002\\u0002\\u01be\\u01bf',\n  '\\u0007_\\u0002\\u0002\\u01bf\\u0012\\u0003\\u0002\\u0002\\u0002\\u01c0\\u01c1',\n  '\\u0007?\\u0002\\u0002\\u01c1\\u01c2\\u0007@\\u0002\\u0002\\u01c2\\u0014\\u0003',\n  '\\u0002\\u0002\\u0002\\u01c3\\u01c4\\u0007U\\u0002\\u0002\\u01c4\\u01c5\\u0007',\n  'G\\u0002\\u0002\\u01c5\\u01c6\\u0007N\\u0002\\u0002\\u01c6\\u01c7\\u0007G\\u0002',\n  '\\u0002\\u01c7\\u01c8\\u0007E\\u0002\\u0002\\u01c8\\u01d0\\u0007V\\u0002\\u0002',\n  '\\u01c9\\u01ca\\u0007u\\u0002\\u0002\\u01ca\\u01cb\\u0007g\\u0002\\u0002\\u01cb',\n  '\\u01cc\\u0007n\\u0002\\u0002\\u01cc\\u01cd\\u0007g\\u0002\\u0002\\u01cd\\u01ce',\n  '\\u0007e\\u0002\\u0002\\u01ce\\u01d0\\u0007v\\u0002\\u0002\\u01cf\\u01c3\\u0003',\n  '\\u0002\\u0002\\u0002\\u01cf\\u01c9\\u0003\\u0002\\u0002\\u0002\\u01d0\\u0016\\u0003',\n  '\\u0002\\u0002\\u0002\\u01d1\\u01d2\\u0007H\\u0002\\u0002\\u01d2\\u01d3\\u0007',\n  'T\\u0002\\u0002\\u01d3\\u01d4\\u0007Q\\u0002\\u0002\\u01d4\\u01da\\u0007O\\u0002',\n  '\\u0002\\u01d5\\u01d6\\u0007h\\u0002\\u0002\\u01d6\\u01d7\\u0007t\\u0002\\u0002',\n  '\\u01d7\\u01d8\\u0007q\\u0002\\u0002\\u01d8\\u01da\\u0007o\\u0002\\u0002\\u01d9',\n  '\\u01d1\\u0003\\u0002\\u0002\\u0002\\u01d9\\u01d5\\u0003\\u0002\\u0002\\u0002\\u01da',\n  '\\u0018\\u0003\\u0002\\u0002\\u0002\\u01db\\u01dc\\u0007C\\u0002\\u0002\\u01dc',\n  '\\u01dd\\u0007F\\u0002\\u0002\\u01dd\\u01e2\\u0007F\\u0002\\u0002\\u01de\\u01df',\n  '\\u0007c\\u0002\\u0002\\u01df\\u01e0\\u0007f\\u0002\\u0002\\u01e0\\u01e2\\u0007',\n  'f\\u0002\\u0002\\u01e1\\u01db\\u0003\\u0002\\u0002\\u0002\\u01e1\\u01de\\u0003',\n  '\\u0002\\u0002\\u0002\\u01e2\\u001a\\u0003\\u0002\\u0002\\u0002\\u01e3\\u01e4\\u0007',\n  'C\\u0002\\u0002\\u01e4\\u01e8\\u0007U\\u0002\\u0002\\u01e5\\u01e6\\u0007c\\u0002',\n  '\\u0002\\u01e6\\u01e8\\u0007u\\u0002\\u0002\\u01e7\\u01e3\\u0003\\u0002\\u0002',\n  '\\u0002\\u01e7\\u01e5\\u0003\\u0002\\u0002\\u0002\\u01e8\\u001c\\u0003\\u0002\\u0002',\n  '\\u0002\\u01e9\\u01ea\\u0007C\\u0002\\u0002\\u01ea\\u01eb\\u0007N\\u0002\\u0002',\n  '\\u01eb\\u01f0\\u0007N\\u0002\\u0002\\u01ec\\u01ed\\u0007c\\u0002\\u0002\\u01ed',\n  '\\u01ee\\u0007n\\u0002\\u0002\\u01ee\\u01f0\\u0007n\\u0002\\u0002\\u01ef\\u01e9',\n  '\\u0003\\u0002\\u0002\\u0002\\u01ef\\u01ec\\u0003\\u0002\\u0002\\u0002\\u01f0\\u001e',\n  '\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01f2\\u0007U\\u0002\\u0002\\u01f2\\u01f3',\n  '\\u0007Q\\u0002\\u0002\\u01f3\\u01f4\\u0007O\\u0002\\u0002\\u01f4\\u01fa\\u0007',\n  'G\\u0002\\u0002\\u01f5\\u01f6\\u0007u\\u0002\\u0002\\u01f6\\u01f7\\u0007q\\u0002',\n  '\\u0002\\u01f7\\u01f8\\u0007o\\u0002\\u0002\\u01f8\\u01fa\\u0007g\\u0002\\u0002',\n  '\\u01f9\\u01f1\\u0003\\u0002\\u0002\\u0002\\u01f9\\u01f5\\u0003\\u0002\\u0002\\u0002',\n  '\\u01fa \\u0003\\u0002\\u0002\\u0002\\u01fb\\u01fc\\u0007C\\u0002\\u0002\\u01fc',\n  '\\u01fd\\u0007P\\u0002\\u0002\\u01fd\\u0202\\u0007[\\u0002\\u0002\\u01fe\\u01ff',\n  '\\u0007c\\u0002\\u0002\\u01ff\\u0200\\u0007p\\u0002\\u0002\\u0200\\u0202\\u0007',\n  '{\\u0002\\u0002\\u0201\\u01fb\\u0003\\u0002\\u0002\\u0002\\u0201\\u01fe\\u0003',\n  '\\u0002\\u0002\\u0002\\u0202\"\\u0003\\u0002\\u0002\\u0002\\u0203\\u0204\\u0007',\n  'F\\u0002\\u0002\\u0204\\u0205\\u0007K\\u0002\\u0002\\u0205\\u0206\\u0007U\\u0002',\n  '\\u0002\\u0206\\u0207\\u0007V\\u0002\\u0002\\u0207\\u0208\\u0007K\\u0002\\u0002',\n  '\\u0208\\u0209\\u0007P\\u0002\\u0002\\u0209\\u020a\\u0007E\\u0002\\u0002\\u020a',\n  '\\u0214\\u0007V\\u0002\\u0002\\u020b\\u020c\\u0007f\\u0002\\u0002\\u020c\\u020d',\n  '\\u0007k\\u0002\\u0002\\u020d\\u020e\\u0007u\\u0002\\u0002\\u020e\\u020f\\u0007',\n  'v\\u0002\\u0002\\u020f\\u0210\\u0007k\\u0002\\u0002\\u0210\\u0211\\u0007p\\u0002',\n  '\\u0002\\u0211\\u0212\\u0007e\\u0002\\u0002\\u0212\\u0214\\u0007v\\u0002\\u0002',\n  '\\u0213\\u0203\\u0003\\u0002\\u0002\\u0002\\u0213\\u020b\\u0003\\u0002\\u0002\\u0002',\n  '\\u0214$\\u0003\\u0002\\u0002\\u0002\\u0215\\u0216\\u0007Y\\u0002\\u0002\\u0216',\n  '\\u0217\\u0007J\\u0002\\u0002\\u0217\\u0218\\u0007G\\u0002\\u0002\\u0218\\u0219',\n  '\\u0007T\\u0002\\u0002\\u0219\\u0220\\u0007G\\u0002\\u0002\\u021a\\u021b\\u0007',\n  'y\\u0002\\u0002\\u021b\\u021c\\u0007j\\u0002\\u0002\\u021c\\u021d\\u0007g\\u0002',\n  '\\u0002\\u021d\\u021e\\u0007t\\u0002\\u0002\\u021e\\u0220\\u0007g\\u0002\\u0002',\n  '\\u021f\\u0215\\u0003\\u0002\\u0002\\u0002\\u021f\\u021a\\u0003\\u0002\\u0002\\u0002',\n  '\\u0220&\\u0003\\u0002\\u0002\\u0002\\u0221\\u0222\\u0007I\\u0002\\u0002\\u0222',\n  '\\u0223\\u0007T\\u0002\\u0002\\u0223\\u0224\\u0007Q\\u0002\\u0002\\u0224\\u0225',\n  '\\u0007W\\u0002\\u0002\\u0225\\u022c\\u0007R\\u0002\\u0002\\u0226\\u0227\\u0007',\n  'i\\u0002\\u0002\\u0227\\u0228\\u0007t\\u0002\\u0002\\u0228\\u0229\\u0007q\\u0002',\n  '\\u0002\\u0229\\u022a\\u0007w\\u0002\\u0002\\u022a\\u022c\\u0007r\\u0002\\u0002',\n  '\\u022b\\u0221\\u0003\\u0002\\u0002\\u0002\\u022b\\u0226\\u0003\\u0002\\u0002\\u0002',\n  '\\u022c(\\u0003\\u0002\\u0002\\u0002\\u022d\\u022e\\u0007D\\u0002\\u0002\\u022e',\n  '\\u0232\\u0007[\\u0002\\u0002\\u022f\\u0230\\u0007d\\u0002\\u0002\\u0230\\u0232',\n  '\\u0007{\\u0002\\u0002\\u0231\\u022d\\u0003\\u0002\\u0002\\u0002\\u0231\\u022f',\n  '\\u0003\\u0002\\u0002\\u0002\\u0232*\\u0003\\u0002\\u0002\\u0002\\u0233\\u0234',\n  '\\u0007I\\u0002\\u0002\\u0234\\u0235\\u0007T\\u0002\\u0002\\u0235\\u0236\\u0007',\n  'Q\\u0002\\u0002\\u0236\\u0237\\u0007W\\u0002\\u0002\\u0237\\u0238\\u0007R\\u0002',\n  '\\u0002\\u0238\\u0239\\u0007K\\u0002\\u0002\\u0239\\u023a\\u0007P\\u0002\\u0002',\n  '\\u023a\\u0244\\u0007I\\u0002\\u0002\\u023b\\u023c\\u0007i\\u0002\\u0002\\u023c',\n  '\\u023d\\u0007t\\u0002\\u0002\\u023d\\u023e\\u0007q\\u0002\\u0002\\u023e\\u023f',\n  '\\u0007w\\u0002\\u0002\\u023f\\u0240\\u0007r\\u0002\\u0002\\u0240\\u0241\\u0007',\n  'k\\u0002\\u0002\\u0241\\u0242\\u0007p\\u0002\\u0002\\u0242\\u0244\\u0007i\\u0002',\n  '\\u0002\\u0243\\u0233\\u0003\\u0002\\u0002\\u0002\\u0243\\u023b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0244,\\u0003\\u0002\\u0002\\u0002\\u0245\\u0246\\u0007U\\u0002\\u0002',\n  '\\u0246\\u0247\\u0007G\\u0002\\u0002\\u0247\\u0248\\u0007V\\u0002\\u0002\\u0248',\n  '\\u024e\\u0007U\\u0002\\u0002\\u0249\\u024a\\u0007u\\u0002\\u0002\\u024a\\u024b',\n  '\\u0007g\\u0002\\u0002\\u024b\\u024c\\u0007v\\u0002\\u0002\\u024c\\u024e\\u0007',\n  'u\\u0002\\u0002\\u024d\\u0245\\u0003\\u0002\\u0002\\u0002\\u024d\\u0249\\u0003',\n  '\\u0002\\u0002\\u0002\\u024e.\\u0003\\u0002\\u0002\\u0002\\u024f\\u0250\\u0007',\n  'E\\u0002\\u0002\\u0250\\u0251\\u0007W\\u0002\\u0002\\u0251\\u0252\\u0007D\\u0002',\n  '\\u0002\\u0252\\u0258\\u0007G\\u0002\\u0002\\u0253\\u0254\\u0007e\\u0002\\u0002',\n  '\\u0254\\u0255\\u0007w\\u0002\\u0002\\u0255\\u0256\\u0007d\\u0002\\u0002\\u0256',\n  '\\u0258\\u0007g\\u0002\\u0002\\u0257\\u024f\\u0003\\u0002\\u0002\\u0002\\u0257',\n  '\\u0253\\u0003\\u0002\\u0002\\u0002\\u02580\\u0003\\u0002\\u0002\\u0002\\u0259',\n  '\\u025a\\u0007T\\u0002\\u0002\\u025a\\u025b\\u0007Q\\u0002\\u0002\\u025b\\u025c',\n  '\\u0007N\\u0002\\u0002\\u025c\\u025d\\u0007N\\u0002\\u0002\\u025d\\u025e\\u0007',\n  'W\\u0002\\u0002\\u025e\\u0266\\u0007R\\u0002\\u0002\\u025f\\u0260\\u0007t\\u0002',\n  '\\u0002\\u0260\\u0261\\u0007q\\u0002\\u0002\\u0261\\u0262\\u0007n\\u0002\\u0002',\n  '\\u0262\\u0263\\u0007n\\u0002\\u0002\\u0263\\u0264\\u0007w\\u0002\\u0002\\u0264',\n  '\\u0266\\u0007r\\u0002\\u0002\\u0265\\u0259\\u0003\\u0002\\u0002\\u0002\\u0265',\n  '\\u025f\\u0003\\u0002\\u0002\\u0002\\u02662\\u0003\\u0002\\u0002\\u0002\\u0267',\n  '\\u0268\\u0007Q\\u0002\\u0002\\u0268\\u0269\\u0007T\\u0002\\u0002\\u0269\\u026a',\n  '\\u0007F\\u0002\\u0002\\u026a\\u026b\\u0007G\\u0002\\u0002\\u026b\\u0272\\u0007',\n  'T\\u0002\\u0002\\u026c\\u026d\\u0007q\\u0002\\u0002\\u026d\\u026e\\u0007t\\u0002',\n  '\\u0002\\u026e\\u026f\\u0007f\\u0002\\u0002\\u026f\\u0270\\u0007g\\u0002\\u0002',\n  '\\u0270\\u0272\\u0007t\\u0002\\u0002\\u0271\\u0267\\u0003\\u0002\\u0002\\u0002',\n  '\\u0271\\u026c\\u0003\\u0002\\u0002\\u0002\\u02724\\u0003\\u0002\\u0002\\u0002',\n  '\\u0273\\u0274\\u0007J\\u0002\\u0002\\u0274\\u0275\\u0007C\\u0002\\u0002\\u0275',\n  '\\u0276\\u0007X\\u0002\\u0002\\u0276\\u0277\\u0007K\\u0002\\u0002\\u0277\\u0278',\n  '\\u0007P\\u0002\\u0002\\u0278\\u0280\\u0007I\\u0002\\u0002\\u0279\\u027a\\u0007',\n  'j\\u0002\\u0002\\u027a\\u027b\\u0007c\\u0002\\u0002\\u027b\\u027c\\u0007x\\u0002',\n  '\\u0002\\u027c\\u027d\\u0007k\\u0002\\u0002\\u027d\\u027e\\u0007p\\u0002\\u0002',\n  '\\u027e\\u0280\\u0007i\\u0002\\u0002\\u027f\\u0273\\u0003\\u0002\\u0002\\u0002',\n  '\\u027f\\u0279\\u0003\\u0002\\u0002\\u0002\\u02806\\u0003\\u0002\\u0002\\u0002',\n  '\\u0281\\u0282\\u0007N\\u0002\\u0002\\u0282\\u0283\\u0007K\\u0002\\u0002\\u0283',\n  '\\u0284\\u0007O\\u0002\\u0002\\u0284\\u0285\\u0007K\\u0002\\u0002\\u0285\\u028c',\n  '\\u0007V\\u0002\\u0002\\u0286\\u0287\\u0007n\\u0002\\u0002\\u0287\\u0288\\u0007',\n  'k\\u0002\\u0002\\u0288\\u0289\\u0007o\\u0002\\u0002\\u0289\\u028a\\u0007k\\u0002',\n  '\\u0002\\u028a\\u028c\\u0007v\\u0002\\u0002\\u028b\\u0281\\u0003\\u0002\\u0002',\n  '\\u0002\\u028b\\u0286\\u0003\\u0002\\u0002\\u0002\\u028c8\\u0003\\u0002\\u0002',\n  '\\u0002\\u028d\\u028e\\u0007C\\u0002\\u0002\\u028e\\u0292\\u0007V\\u0002\\u0002',\n  '\\u028f\\u0290\\u0007c\\u0002\\u0002\\u0290\\u0292\\u0007v\\u0002\\u0002\\u0291',\n  '\\u028d\\u0003\\u0002\\u0002\\u0002\\u0291\\u028f\\u0003\\u0002\\u0002\\u0002\\u0292',\n  ':\\u0003\\u0002\\u0002\\u0002\\u0293\\u0294\\u0007Q\\u0002\\u0002\\u0294\\u0298',\n  '\\u0007T\\u0002\\u0002\\u0295\\u0296\\u0007q\\u0002\\u0002\\u0296\\u0298\\u0007',\n  't\\u0002\\u0002\\u0297\\u0293\\u0003\\u0002\\u0002\\u0002\\u0297\\u0295\\u0003',\n  '\\u0002\\u0002\\u0002\\u0298<\\u0003\\u0002\\u0002\\u0002\\u0299\\u029a\\u0007',\n  'C\\u0002\\u0002\\u029a\\u029b\\u0007P\\u0002\\u0002\\u029b\\u02a0\\u0007F\\u0002',\n  '\\u0002\\u029c\\u029d\\u0007c\\u0002\\u0002\\u029d\\u029e\\u0007p\\u0002\\u0002',\n  '\\u029e\\u02a0\\u0007f\\u0002\\u0002\\u029f\\u0299\\u0003\\u0002\\u0002\\u0002',\n  '\\u029f\\u029c\\u0003\\u0002\\u0002\\u0002\\u02a0>\\u0003\\u0002\\u0002\\u0002',\n  '\\u02a1\\u02a2\\u0007K\\u0002\\u0002\\u02a2\\u02a6\\u0007P\\u0002\\u0002\\u02a3',\n  '\\u02a4\\u0007k\\u0002\\u0002\\u02a4\\u02a6\\u0007p\\u0002\\u0002\\u02a5\\u02a1',\n  '\\u0003\\u0002\\u0002\\u0002\\u02a5\\u02a3\\u0003\\u0002\\u0002\\u0002\\u02a6@',\n  '\\u0003\\u0002\\u0002\\u0002\\u02a7\\u02a8\\u0007P\\u0002\\u0002\\u02a8\\u02a9',\n  '\\u0007Q\\u0002\\u0002\\u02a9\\u02ae\\u0007V\\u0002\\u0002\\u02aa\\u02ab\\u0007',\n  'p\\u0002\\u0002\\u02ab\\u02ac\\u0007q\\u0002\\u0002\\u02ac\\u02ae\\u0007v\\u0002',\n  '\\u0002\\u02ad\\u02a7\\u0003\\u0002\\u0002\\u0002\\u02ad\\u02aa\\u0003\\u0002\\u0002',\n  '\\u0002\\u02aeB\\u0003\\u0002\\u0002\\u0002\\u02af\\u02b0\\u0007P\\u0002\\u0002',\n  '\\u02b0\\u02b4\\u0007Q\\u0002\\u0002\\u02b1\\u02b2\\u0007p\\u0002\\u0002\\u02b2',\n  '\\u02b4\\u0007q\\u0002\\u0002\\u02b3\\u02af\\u0003\\u0002\\u0002\\u0002\\u02b3',\n  '\\u02b1\\u0003\\u0002\\u0002\\u0002\\u02b4D\\u0003\\u0002\\u0002\\u0002\\u02b5',\n  '\\u02b6\\u0007G\\u0002\\u0002\\u02b6\\u02b7\\u0007Z\\u0002\\u0002\\u02b7\\u02b8',\n  '\\u0007K\\u0002\\u0002\\u02b8\\u02b9\\u0007U\\u0002\\u0002\\u02b9\\u02ba\\u0007',\n  'V\\u0002\\u0002\\u02ba\\u02c2\\u0007U\\u0002\\u0002\\u02bb\\u02bc\\u0007g\\u0002',\n  '\\u0002\\u02bc\\u02bd\\u0007z\\u0002\\u0002\\u02bd\\u02be\\u0007k\\u0002\\u0002',\n  '\\u02be\\u02bf\\u0007u\\u0002\\u0002\\u02bf\\u02c0\\u0007v\\u0002\\u0002\\u02c0',\n  '\\u02c2\\u0007u\\u0002\\u0002\\u02c1\\u02b5\\u0003\\u0002\\u0002\\u0002\\u02c1',\n  '\\u02bb\\u0003\\u0002\\u0002\\u0002\\u02c2F\\u0003\\u0002\\u0002\\u0002\\u02c3',\n  '\\u02c4\\u0007D\\u0002\\u0002\\u02c4\\u02c5\\u0007G\\u0002\\u0002\\u02c5\\u02c6',\n  '\\u0007V\\u0002\\u0002\\u02c6\\u02c7\\u0007Y\\u0002\\u0002\\u02c7\\u02c8\\u0007',\n  'G\\u0002\\u0002\\u02c8\\u02c9\\u0007G\\u0002\\u0002\\u02c9\\u02d2\\u0007P\\u0002',\n  '\\u0002\\u02ca\\u02cb\\u0007d\\u0002\\u0002\\u02cb\\u02cc\\u0007g\\u0002\\u0002',\n  '\\u02cc\\u02cd\\u0007v\\u0002\\u0002\\u02cd\\u02ce\\u0007y\\u0002\\u0002\\u02ce',\n  '\\u02cf\\u0007g\\u0002\\u0002\\u02cf\\u02d0\\u0007g\\u0002\\u0002\\u02d0\\u02d2',\n  '\\u0007p\\u0002\\u0002\\u02d1\\u02c3\\u0003\\u0002\\u0002\\u0002\\u02d1\\u02ca',\n  '\\u0003\\u0002\\u0002\\u0002\\u02d2H\\u0003\\u0002\\u0002\\u0002\\u02d3\\u02d4',\n  '\\u0007N\\u0002\\u0002\\u02d4\\u02d5\\u0007K\\u0002\\u0002\\u02d5\\u02d6\\u0007',\n  'M\\u0002\\u0002\\u02d6\\u02dc\\u0007G\\u0002\\u0002\\u02d7\\u02d8\\u0007n\\u0002',\n  '\\u0002\\u02d8\\u02d9\\u0007k\\u0002\\u0002\\u02d9\\u02da\\u0007m\\u0002\\u0002',\n  '\\u02da\\u02dc\\u0007g\\u0002\\u0002\\u02db\\u02d3\\u0003\\u0002\\u0002\\u0002',\n  '\\u02db\\u02d7\\u0003\\u0002\\u0002\\u0002\\u02dcJ\\u0003\\u0002\\u0002\\u0002',\n  '\\u02dd\\u02de\\u0007K\\u0002\\u0002\\u02de\\u02e2\\u0007U\\u0002\\u0002\\u02df',\n  '\\u02e0\\u0007k\\u0002\\u0002\\u02e0\\u02e2\\u0007u\\u0002\\u0002\\u02e1\\u02dd',\n  '\\u0003\\u0002\\u0002\\u0002\\u02e1\\u02df\\u0003\\u0002\\u0002\\u0002\\u02e2L',\n  '\\u0003\\u0002\\u0002\\u0002\\u02e3\\u02e4\\u0007P\\u0002\\u0002\\u02e4\\u02e5',\n  '\\u0007W\\u0002\\u0002\\u02e5\\u02e6\\u0007N\\u0002\\u0002\\u02e6\\u02ec\\u0007',\n  'N\\u0002\\u0002\\u02e7\\u02e8\\u0007p\\u0002\\u0002\\u02e8\\u02e9\\u0007w\\u0002',\n  '\\u0002\\u02e9\\u02ea\\u0007n\\u0002\\u0002\\u02ea\\u02ec\\u0007n\\u0002\\u0002',\n  '\\u02eb\\u02e3\\u0003\\u0002\\u0002\\u0002\\u02eb\\u02e7\\u0003\\u0002\\u0002\\u0002',\n  '\\u02ecN\\u0003\\u0002\\u0002\\u0002\\u02ed\\u02ee\\u0007V\\u0002\\u0002\\u02ee',\n  '\\u02ef\\u0007T\\u0002\\u0002\\u02ef\\u02f0\\u0007W\\u0002\\u0002\\u02f0\\u02f6',\n  '\\u0007G\\u0002\\u0002\\u02f1\\u02f2\\u0007v\\u0002\\u0002\\u02f2\\u02f3\\u0007',\n  't\\u0002\\u0002\\u02f3\\u02f4\\u0007w\\u0002\\u0002\\u02f4\\u02f6\\u0007g\\u0002',\n  '\\u0002\\u02f5\\u02ed\\u0003\\u0002\\u0002\\u0002\\u02f5\\u02f1\\u0003\\u0002\\u0002',\n  '\\u0002\\u02f6P\\u0003\\u0002\\u0002\\u0002\\u02f7\\u02f8\\u0007H\\u0002\\u0002',\n  '\\u02f8\\u02f9\\u0007C\\u0002\\u0002\\u02f9\\u02fa\\u0007N\\u0002\\u0002\\u02fa',\n  '\\u02fb\\u0007U\\u0002\\u0002\\u02fb\\u0302\\u0007G\\u0002\\u0002\\u02fc\\u02fd',\n  '\\u0007h\\u0002\\u0002\\u02fd\\u02fe\\u0007c\\u0002\\u0002\\u02fe\\u02ff\\u0007',\n  'n\\u0002\\u0002\\u02ff\\u0300\\u0007u\\u0002\\u0002\\u0300\\u0302\\u0007g\\u0002',\n  '\\u0002\\u0301\\u02f7\\u0003\\u0002\\u0002\\u0002\\u0301\\u02fc\\u0003\\u0002\\u0002',\n  '\\u0002\\u0302R\\u0003\\u0002\\u0002\\u0002\\u0303\\u0304\\u0007P\\u0002\\u0002',\n  '\\u0304\\u0305\\u0007W\\u0002\\u0002\\u0305\\u0306\\u0007N\\u0002\\u0002\\u0306',\n  '\\u0307\\u0007N\\u0002\\u0002\\u0307\\u030e\\u0007U\\u0002\\u0002\\u0308\\u0309',\n  '\\u0007p\\u0002\\u0002\\u0309\\u030a\\u0007w\\u0002\\u0002\\u030a\\u030b\\u0007',\n  'n\\u0002\\u0002\\u030b\\u030c\\u0007n\\u0002\\u0002\\u030c\\u030e\\u0007u\\u0002',\n  '\\u0002\\u030d\\u0303\\u0003\\u0002\\u0002\\u0002\\u030d\\u0308\\u0003\\u0002\\u0002',\n  '\\u0002\\u030eT\\u0003\\u0002\\u0002\\u0002\\u030f\\u0310\\u0007H\\u0002\\u0002',\n  '\\u0310\\u0311\\u0007K\\u0002\\u0002\\u0311\\u0312\\u0007T\\u0002\\u0002\\u0312',\n  '\\u0313\\u0007U\\u0002\\u0002\\u0313\\u031a\\u0007V\\u0002\\u0002\\u0314\\u0315',\n  '\\u0007h\\u0002\\u0002\\u0315\\u0316\\u0007k\\u0002\\u0002\\u0316\\u0317\\u0007',\n  't\\u0002\\u0002\\u0317\\u0318\\u0007u\\u0002\\u0002\\u0318\\u031a\\u0007v\\u0002',\n  '\\u0002\\u0319\\u030f\\u0003\\u0002\\u0002\\u0002\\u0319\\u0314\\u0003\\u0002\\u0002',\n  '\\u0002\\u031aV\\u0003\\u0002\\u0002\\u0002\\u031b\\u031c\\u0007N\\u0002\\u0002',\n  '\\u031c\\u031d\\u0007C\\u0002\\u0002\\u031d\\u031e\\u0007U\\u0002\\u0002\\u031e',\n  '\\u0324\\u0007V\\u0002\\u0002\\u031f\\u0320\\u0007n\\u0002\\u0002\\u0320\\u0321',\n  '\\u0007c\\u0002\\u0002\\u0321\\u0322\\u0007u\\u0002\\u0002\\u0322\\u0324\\u0007',\n  'v\\u0002\\u0002\\u0323\\u031b\\u0003\\u0002\\u0002\\u0002\\u0323\\u031f\\u0003',\n  '\\u0002\\u0002\\u0002\\u0324X\\u0003\\u0002\\u0002\\u0002\\u0325\\u0326\\u0007',\n  'G\\u0002\\u0002\\u0326\\u0327\\u0007U\\u0002\\u0002\\u0327\\u0328\\u0007E\\u0002',\n  '\\u0002\\u0328\\u0329\\u0007C\\u0002\\u0002\\u0329\\u032a\\u0007R\\u0002\\u0002',\n  '\\u032a\\u0332\\u0007G\\u0002\\u0002\\u032b\\u032c\\u0007g\\u0002\\u0002\\u032c',\n  '\\u032d\\u0007u\\u0002\\u0002\\u032d\\u032e\\u0007e\\u0002\\u0002\\u032e\\u032f',\n  '\\u0007c\\u0002\\u0002\\u032f\\u0330\\u0007r\\u0002\\u0002\\u0330\\u0332\\u0007',\n  'g\\u0002\\u0002\\u0331\\u0325\\u0003\\u0002\\u0002\\u0002\\u0331\\u032b\\u0003',\n  '\\u0002\\u0002\\u0002\\u0332Z\\u0003\\u0002\\u0002\\u0002\\u0333\\u0334\\u0007',\n  'C\\u0002\\u0002\\u0334\\u0335\\u0007U\\u0002\\u0002\\u0335\\u033a\\u0007E\\u0002',\n  '\\u0002\\u0336\\u0337\\u0007c\\u0002\\u0002\\u0337\\u0338\\u0007u\\u0002\\u0002',\n  '\\u0338\\u033a\\u0007e\\u0002\\u0002\\u0339\\u0333\\u0003\\u0002\\u0002\\u0002',\n  '\\u0339\\u0336\\u0003\\u0002\\u0002\\u0002\\u033a\\\\\\u0003\\u0002\\u0002\\u0002',\n  '\\u033b\\u033c\\u0007F\\u0002\\u0002\\u033c\\u033d\\u0007G\\u0002\\u0002\\u033d',\n  '\\u033e\\u0007U\\u0002\\u0002\\u033e\\u0344\\u0007E\\u0002\\u0002\\u033f\\u0340',\n  '\\u0007f\\u0002\\u0002\\u0340\\u0341\\u0007g\\u0002\\u0002\\u0341\\u0342\\u0007',\n  'u\\u0002\\u0002\\u0342\\u0344\\u0007e\\u0002\\u0002\\u0343\\u033b\\u0003\\u0002',\n  '\\u0002\\u0002\\u0343\\u033f\\u0003\\u0002\\u0002\\u0002\\u0344^\\u0003\\u0002',\n  '\\u0002\\u0002\\u0345\\u0346\\u0007U\\u0002\\u0002\\u0346\\u0347\\u0007W\\u0002',\n  '\\u0002\\u0347\\u0348\\u0007D\\u0002\\u0002\\u0348\\u0349\\u0007U\\u0002\\u0002',\n  '\\u0349\\u034a\\u0007V\\u0002\\u0002\\u034a\\u034b\\u0007T\\u0002\\u0002\\u034b',\n  '\\u034c\\u0007K\\u0002\\u0002\\u034c\\u034d\\u0007P\\u0002\\u0002\\u034d\\u0358',\n  '\\u0007I\\u0002\\u0002\\u034e\\u034f\\u0007u\\u0002\\u0002\\u034f\\u0350\\u0007',\n  'w\\u0002\\u0002\\u0350\\u0351\\u0007d\\u0002\\u0002\\u0351\\u0352\\u0007u\\u0002',\n  '\\u0002\\u0352\\u0353\\u0007v\\u0002\\u0002\\u0353\\u0354\\u0007t\\u0002\\u0002',\n  '\\u0354\\u0355\\u0007k\\u0002\\u0002\\u0355\\u0356\\u0007p\\u0002\\u0002\\u0356',\n  '\\u0358\\u0007i\\u0002\\u0002\\u0357\\u0345\\u0003\\u0002\\u0002\\u0002\\u0357',\n  '\\u034e\\u0003\\u0002\\u0002\\u0002\\u0358`\\u0003\\u0002\\u0002\\u0002\\u0359',\n  '\\u035a\\u0007R\\u0002\\u0002\\u035a\\u035b\\u0007Q\\u0002\\u0002\\u035b\\u035c',\n  '\\u0007U\\u0002\\u0002\\u035c\\u035d\\u0007K\\u0002\\u0002\\u035d\\u035e\\u0007',\n  'V\\u0002\\u0002\\u035e\\u035f\\u0007K\\u0002\\u0002\\u035f\\u0360\\u0007Q\\u0002',\n  '\\u0002\\u0360\\u036a\\u0007P\\u0002\\u0002\\u0361\\u0362\\u0007r\\u0002\\u0002',\n  '\\u0362\\u0363\\u0007q\\u0002\\u0002\\u0363\\u0364\\u0007u\\u0002\\u0002\\u0364',\n  '\\u0365\\u0007k\\u0002\\u0002\\u0365\\u0366\\u0007v\\u0002\\u0002\\u0366\\u0367',\n  '\\u0007k\\u0002\\u0002\\u0367\\u0368\\u0007q\\u0002\\u0002\\u0368\\u036a\\u0007',\n  'p\\u0002\\u0002\\u0369\\u0359\\u0003\\u0002\\u0002\\u0002\\u0369\\u0361\\u0003',\n  '\\u0002\\u0002\\u0002\\u036ab\\u0003\\u0002\\u0002\\u0002\\u036b\\u036c\\u0007',\n  'H\\u0002\\u0002\\u036c\\u036d\\u0007Q\\u0002\\u0002\\u036d\\u0372\\u0007T\\u0002',\n  '\\u0002\\u036e\\u036f\\u0007h\\u0002\\u0002\\u036f\\u0370\\u0007q\\u0002\\u0002',\n  '\\u0370\\u0372\\u0007t\\u0002\\u0002\\u0371\\u036b\\u0003\\u0002\\u0002\\u0002',\n  '\\u0371\\u036e\\u0003\\u0002\\u0002\\u0002\\u0372d\\u0003\\u0002\\u0002\\u0002',\n  '\\u0373\\u0374\\u0007V\\u0002\\u0002\\u0374\\u0375\\u0007K\\u0002\\u0002\\u0375',\n  '\\u0376\\u0007P\\u0002\\u0002\\u0376\\u0377\\u0007[\\u0002\\u0002\\u0377\\u0378',\n  '\\u0007K\\u0002\\u0002\\u0378\\u0379\\u0007P\\u0002\\u0002\\u0379\\u0382\\u0007',\n  'V\\u0002\\u0002\\u037a\\u037b\\u0007v\\u0002\\u0002\\u037b\\u037c\\u0007k\\u0002',\n  '\\u0002\\u037c\\u037d\\u0007p\\u0002\\u0002\\u037d\\u037e\\u0007{\\u0002\\u0002',\n  '\\u037e\\u037f\\u0007k\\u0002\\u0002\\u037f\\u0380\\u0007p\\u0002\\u0002\\u0380',\n  '\\u0382\\u0007v\\u0002\\u0002\\u0381\\u0373\\u0003\\u0002\\u0002\\u0002\\u0381',\n  '\\u037a\\u0003\\u0002\\u0002\\u0002\\u0382f\\u0003\\u0002\\u0002\\u0002\\u0383',\n  '\\u0384\\u0007U\\u0002\\u0002\\u0384\\u0385\\u0007O\\u0002\\u0002\\u0385\\u0386',\n  '\\u0007C\\u0002\\u0002\\u0386\\u0387\\u0007N\\u0002\\u0002\\u0387\\u0388\\u0007',\n  'N\\u0002\\u0002\\u0388\\u0389\\u0007K\\u0002\\u0002\\u0389\\u038a\\u0007P\\u0002',\n  '\\u0002\\u038a\\u0394\\u0007V\\u0002\\u0002\\u038b\\u038c\\u0007u\\u0002\\u0002',\n  '\\u038c\\u038d\\u0007o\\u0002\\u0002\\u038d\\u038e\\u0007c\\u0002\\u0002\\u038e',\n  '\\u038f\\u0007n\\u0002\\u0002\\u038f\\u0390\\u0007n\\u0002\\u0002\\u0390\\u0391',\n  '\\u0007k\\u0002\\u0002\\u0391\\u0392\\u0007p\\u0002\\u0002\\u0392\\u0394\\u0007',\n  'v\\u0002\\u0002\\u0393\\u0383\\u0003\\u0002\\u0002\\u0002\\u0393\\u038b\\u0003',\n  '\\u0002\\u0002\\u0002\\u0394h\\u0003\\u0002\\u0002\\u0002\\u0395\\u0396\\u0007',\n  'K\\u0002\\u0002\\u0396\\u0397\\u0007P\\u0002\\u0002\\u0397\\u0398\\u0007V\\u0002',\n  '\\u0002\\u0398\\u0399\\u0007G\\u0002\\u0002\\u0399\\u039a\\u0007I\\u0002\\u0002',\n  '\\u039a\\u039b\\u0007G\\u0002\\u0002\\u039b\\u03a4\\u0007T\\u0002\\u0002\\u039c',\n  '\\u039d\\u0007k\\u0002\\u0002\\u039d\\u039e\\u0007p\\u0002\\u0002\\u039e\\u039f',\n  '\\u0007v\\u0002\\u0002\\u039f\\u03a0\\u0007g\\u0002\\u0002\\u03a0\\u03a1\\u0007',\n  'i\\u0002\\u0002\\u03a1\\u03a2\\u0007g\\u0002\\u0002\\u03a2\\u03a4\\u0007t\\u0002',\n  '\\u0002\\u03a3\\u0395\\u0003\\u0002\\u0002\\u0002\\u03a3\\u039c\\u0003\\u0002\\u0002',\n  '\\u0002\\u03a4j\\u0003\\u0002\\u0002\\u0002\\u03a5\\u03a6\\u0007F\\u0002\\u0002',\n  '\\u03a6\\u03a7\\u0007C\\u0002\\u0002\\u03a7\\u03a8\\u0007V\\u0002\\u0002\\u03a8',\n  '\\u03ae\\u0007G\\u0002\\u0002\\u03a9\\u03aa\\u0007f\\u0002\\u0002\\u03aa\\u03ab',\n  '\\u0007c\\u0002\\u0002\\u03ab\\u03ac\\u0007v\\u0002\\u0002\\u03ac\\u03ae\\u0007',\n  'g\\u0002\\u0002\\u03ad\\u03a5\\u0003\\u0002\\u0002\\u0002\\u03ad\\u03a9\\u0003',\n  '\\u0002\\u0002\\u0002\\u03ael\\u0003\\u0002\\u0002\\u0002\\u03af\\u03b0\\u0007',\n  'V\\u0002\\u0002\\u03b0\\u03b1\\u0007K\\u0002\\u0002\\u03b1\\u03b2\\u0007O\\u0002',\n  '\\u0002\\u03b2\\u03b8\\u0007G\\u0002\\u0002\\u03b3\\u03b4\\u0007v\\u0002\\u0002',\n  '\\u03b4\\u03b5\\u0007k\\u0002\\u0002\\u03b5\\u03b6\\u0007o\\u0002\\u0002\\u03b6',\n  '\\u03b8\\u0007g\\u0002\\u0002\\u03b7\\u03af\\u0003\\u0002\\u0002\\u0002\\u03b7',\n  '\\u03b3\\u0003\\u0002\\u0002\\u0002\\u03b8n\\u0003\\u0002\\u0002\\u0002\\u03b9',\n  '\\u03ba\\u0007V\\u0002\\u0002\\u03ba\\u03bb\\u0007K\\u0002\\u0002\\u03bb\\u03bc',\n  '\\u0007O\\u0002\\u0002\\u03bc\\u03bd\\u0007G\\u0002\\u0002\\u03bd\\u03be\\u0007',\n  'U\\u0002\\u0002\\u03be\\u03bf\\u0007V\\u0002\\u0002\\u03bf\\u03c0\\u0007C\\u0002',\n  '\\u0002\\u03c0\\u03c1\\u0007O\\u0002\\u0002\\u03c1\\u03cc\\u0007R\\u0002\\u0002',\n  '\\u03c2\\u03c3\\u0007v\\u0002\\u0002\\u03c3\\u03c4\\u0007k\\u0002\\u0002\\u03c4',\n  '\\u03c5\\u0007o\\u0002\\u0002\\u03c5\\u03c6\\u0007g\\u0002\\u0002\\u03c6\\u03c7',\n  '\\u0007u\\u0002\\u0002\\u03c7\\u03c8\\u0007v\\u0002\\u0002\\u03c8\\u03c9\\u0007',\n  'c\\u0002\\u0002\\u03c9\\u03ca\\u0007o\\u0002\\u0002\\u03ca\\u03cc\\u0007r\\u0002',\n  '\\u0002\\u03cb\\u03b9\\u0003\\u0002\\u0002\\u0002\\u03cb\\u03c2\\u0003\\u0002\\u0002',\n  '\\u0002\\u03ccp\\u0003\\u0002\\u0002\\u0002\\u03cd\\u03ce\\u0007K\\u0002\\u0002',\n  '\\u03ce\\u03cf\\u0007P\\u0002\\u0002\\u03cf\\u03d0\\u0007V\\u0002\\u0002\\u03d0',\n  '\\u03d1\\u0007G\\u0002\\u0002\\u03d1\\u03d2\\u0007T\\u0002\\u0002\\u03d2\\u03d3',\n  '\\u0007X\\u0002\\u0002\\u03d3\\u03d4\\u0007C\\u0002\\u0002\\u03d4\\u03de\\u0007',\n  'N\\u0002\\u0002\\u03d5\\u03d6\\u0007k\\u0002\\u0002\\u03d6\\u03d7\\u0007p\\u0002',\n  '\\u0002\\u03d7\\u03d8\\u0007v\\u0002\\u0002\\u03d8\\u03d9\\u0007g\\u0002\\u0002',\n  '\\u03d9\\u03da\\u0007t\\u0002\\u0002\\u03da\\u03db\\u0007x\\u0002\\u0002\\u03db',\n  '\\u03dc\\u0007c\\u0002\\u0002\\u03dc\\u03de\\u0007n\\u0002\\u0002\\u03dd\\u03cd',\n  '\\u0003\\u0002\\u0002\\u0002\\u03dd\\u03d5\\u0003\\u0002\\u0002\\u0002\\u03der',\n  '\\u0003\\u0002\\u0002\\u0002\\u03df\\u03e0\\u0007[\\u0002\\u0002\\u03e0\\u03e1',\n  '\\u0007G\\u0002\\u0002\\u03e1\\u03e2\\u0007C\\u0002\\u0002\\u03e2\\u03e8\\u0007',\n  'T\\u0002\\u0002\\u03e3\\u03e4\\u0007{\\u0002\\u0002\\u03e4\\u03e5\\u0007g\\u0002',\n  '\\u0002\\u03e5\\u03e6\\u0007c\\u0002\\u0002\\u03e6\\u03e8\\u0007t\\u0002\\u0002',\n  '\\u03e7\\u03df\\u0003\\u0002\\u0002\\u0002\\u03e7\\u03e3\\u0003\\u0002\\u0002\\u0002',\n  '\\u03e8t\\u0003\\u0002\\u0002\\u0002\\u03e9\\u03ea\\u0007O\\u0002\\u0002\\u03ea',\n  '\\u03eb\\u0007Q\\u0002\\u0002\\u03eb\\u03ec\\u0007P\\u0002\\u0002\\u03ec\\u03ed',\n  '\\u0007V\\u0002\\u0002\\u03ed\\u03f4\\u0007J\\u0002\\u0002\\u03ee\\u03ef\\u0007',\n  'o\\u0002\\u0002\\u03ef\\u03f0\\u0007q\\u0002\\u0002\\u03f0\\u03f1\\u0007p\\u0002',\n  '\\u0002\\u03f1\\u03f2\\u0007v\\u0002\\u0002\\u03f2\\u03f4\\u0007j\\u0002\\u0002',\n  '\\u03f3\\u03e9\\u0003\\u0002\\u0002\\u0002\\u03f3\\u03ee\\u0003\\u0002\\u0002\\u0002',\n  '\\u03f4v\\u0003\\u0002\\u0002\\u0002\\u03f5\\u03f6\\u0007F\\u0002\\u0002\\u03f6',\n  '\\u03f7\\u0007C\\u0002\\u0002\\u03f7\\u03fc\\u0007[\\u0002\\u0002\\u03f8\\u03f9',\n  '\\u0007f\\u0002\\u0002\\u03f9\\u03fa\\u0007c\\u0002\\u0002\\u03fa\\u03fc\\u0007',\n  '{\\u0002\\u0002\\u03fb\\u03f5\\u0003\\u0002\\u0002\\u0002\\u03fb\\u03f8\\u0003',\n  '\\u0002\\u0002\\u0002\\u03fcx\\u0003\\u0002\\u0002\\u0002\\u03fd\\u03fe\\u0007',\n  'J\\u0002\\u0002\\u03fe\\u03ff\\u0007Q\\u0002\\u0002\\u03ff\\u0400\\u0007W\\u0002',\n  '\\u0002\\u0400\\u0406\\u0007T\\u0002\\u0002\\u0401\\u0402\\u0007j\\u0002\\u0002',\n  '\\u0402\\u0403\\u0007q\\u0002\\u0002\\u0403\\u0404\\u0007w\\u0002\\u0002\\u0404',\n  '\\u0406\\u0007t\\u0002\\u0002\\u0405\\u03fd\\u0003\\u0002\\u0002\\u0002\\u0405',\n  '\\u0401\\u0003\\u0002\\u0002\\u0002\\u0406z\\u0003\\u0002\\u0002\\u0002\\u0407',\n  '\\u0408\\u0007O\\u0002\\u0002\\u0408\\u0409\\u0007K\\u0002\\u0002\\u0409\\u040a',\n  '\\u0007P\\u0002\\u0002\\u040a\\u040b\\u0007W\\u0002\\u0002\\u040b\\u040c\\u0007',\n  'V\\u0002\\u0002\\u040c\\u0414\\u0007G\\u0002\\u0002\\u040d\\u040e\\u0007o\\u0002',\n  '\\u0002\\u040e\\u040f\\u0007k\\u0002\\u0002\\u040f\\u0410\\u0007p\\u0002\\u0002',\n  '\\u0410\\u0411\\u0007w\\u0002\\u0002\\u0411\\u0412\\u0007v\\u0002\\u0002\\u0412',\n  '\\u0414\\u0007g\\u0002\\u0002\\u0413\\u0407\\u0003\\u0002\\u0002\\u0002\\u0413',\n  '\\u040d\\u0003\\u0002\\u0002\\u0002\\u0414|\\u0003\\u0002\\u0002\\u0002\\u0415',\n  '\\u0416\\u0007U\\u0002\\u0002\\u0416\\u0417\\u0007G\\u0002\\u0002\\u0417\\u0418',\n  '\\u0007E\\u0002\\u0002\\u0418\\u0419\\u0007Q\\u0002\\u0002\\u0419\\u041a\\u0007',\n  'P\\u0002\\u0002\\u041a\\u0422\\u0007F\\u0002\\u0002\\u041b\\u041c\\u0007u\\u0002',\n  '\\u0002\\u041c\\u041d\\u0007g\\u0002\\u0002\\u041d\\u041e\\u0007e\\u0002\\u0002',\n  '\\u041e\\u041f\\u0007q\\u0002\\u0002\\u041f\\u0420\\u0007p\\u0002\\u0002\\u0420',\n  '\\u0422\\u0007f\\u0002\\u0002\\u0421\\u0415\\u0003\\u0002\\u0002\\u0002\\u0421',\n  '\\u041b\\u0003\\u0002\\u0002\\u0002\\u0422~\\u0003\\u0002\\u0002\\u0002\\u0423',\n  '\\u0424\\u0007\\\\\\u0002\\u0002\\u0424\\u0425\\u0007Q\\u0002\\u0002\\u0425\\u0426',\n  '\\u0007P\\u0002\\u0002\\u0426\\u042c\\u0007G\\u0002\\u0002\\u0427\\u0428\\u0007',\n  '|\\u0002\\u0002\\u0428\\u0429\\u0007q\\u0002\\u0002\\u0429\\u042a\\u0007p\\u0002',\n  '\\u0002\\u042a\\u042c\\u0007g\\u0002\\u0002\\u042b\\u0423\\u0003\\u0002\\u0002',\n  '\\u0002\\u042b\\u0427\\u0003\\u0002\\u0002\\u0002\\u042c\\u0080\\u0003\\u0002\\u0002',\n  '\\u0002\\u042d\\u042e\\u0007E\\u0002\\u0002\\u042e\\u042f\\u0007W\\u0002\\u0002',\n  '\\u042f\\u0430\\u0007T\\u0002\\u0002\\u0430\\u0431\\u0007T\\u0002\\u0002\\u0431',\n  '\\u0432\\u0007G\\u0002\\u0002\\u0432\\u0433\\u0007P\\u0002\\u0002\\u0433\\u0434',\n  '\\u0007V\\u0002\\u0002\\u0434\\u0435\\u0007a\\u0002\\u0002\\u0435\\u0436\\u0007',\n  'F\\u0002\\u0002\\u0436\\u0437\\u0007C\\u0002\\u0002\\u0437\\u0438\\u0007V\\u0002',\n  '\\u0002\\u0438\\u0446\\u0007G\\u0002\\u0002\\u0439\\u043a\\u0007e\\u0002\\u0002',\n  '\\u043a\\u043b\\u0007w\\u0002\\u0002\\u043b\\u043c\\u0007t\\u0002\\u0002\\u043c',\n  '\\u043d\\u0007t\\u0002\\u0002\\u043d\\u043e\\u0007g\\u0002\\u0002\\u043e\\u043f',\n  '\\u0007p\\u0002\\u0002\\u043f\\u0440\\u0007v\\u0002\\u0002\\u0440\\u0441\\u0007',\n  'a\\u0002\\u0002\\u0441\\u0442\\u0007f\\u0002\\u0002\\u0442\\u0443\\u0007c\\u0002',\n  '\\u0002\\u0443\\u0444\\u0007v\\u0002\\u0002\\u0444\\u0446\\u0007g\\u0002\\u0002',\n  '\\u0445\\u042d\\u0003\\u0002\\u0002\\u0002\\u0445\\u0439\\u0003\\u0002\\u0002\\u0002',\n  '\\u0446\\u0082\\u0003\\u0002\\u0002\\u0002\\u0447\\u0448\\u0007E\\u0002\\u0002',\n  '\\u0448\\u0449\\u0007W\\u0002\\u0002\\u0449\\u044a\\u0007T\\u0002\\u0002\\u044a',\n  '\\u044b\\u0007T\\u0002\\u0002\\u044b\\u044c\\u0007G\\u0002\\u0002\\u044c\\u044d',\n  '\\u0007P\\u0002\\u0002\\u044d\\u044e\\u0007V\\u0002\\u0002\\u044e\\u044f\\u0007',\n  'a\\u0002\\u0002\\u044f\\u0450\\u0007V\\u0002\\u0002\\u0450\\u0451\\u0007K\\u0002',\n  '\\u0002\\u0451\\u0452\\u0007O\\u0002\\u0002\\u0452\\u0460\\u0007G\\u0002\\u0002',\n  '\\u0453\\u0454\\u0007e\\u0002\\u0002\\u0454\\u0455\\u0007w\\u0002\\u0002\\u0455',\n  '\\u0456\\u0007t\\u0002\\u0002\\u0456\\u0457\\u0007t\\u0002\\u0002\\u0457\\u0458',\n  '\\u0007g\\u0002\\u0002\\u0458\\u0459\\u0007p\\u0002\\u0002\\u0459\\u045a\\u0007',\n  'v\\u0002\\u0002\\u045a\\u045b\\u0007a\\u0002\\u0002\\u045b\\u045c\\u0007v\\u0002',\n  '\\u0002\\u045c\\u045d\\u0007k\\u0002\\u0002\\u045d\\u045e\\u0007o\\u0002\\u0002',\n  '\\u045e\\u0460\\u0007g\\u0002\\u0002\\u045f\\u0447\\u0003\\u0002\\u0002\\u0002',\n  '\\u045f\\u0453\\u0003\\u0002\\u0002\\u0002\\u0460\\u0084\\u0003\\u0002\\u0002\\u0002',\n  '\\u0461\\u0462\\u0007E\\u0002\\u0002\\u0462\\u0463\\u0007W\\u0002\\u0002\\u0463',\n  '\\u0464\\u0007T\\u0002\\u0002\\u0464\\u0465\\u0007T\\u0002\\u0002\\u0465\\u0466',\n  '\\u0007G\\u0002\\u0002\\u0466\\u0467\\u0007P\\u0002\\u0002\\u0467\\u0468\\u0007',\n  'V\\u0002\\u0002\\u0468\\u0469\\u0007a\\u0002\\u0002\\u0469\\u046a\\u0007V\\u0002',\n  '\\u0002\\u046a\\u046b\\u0007K\\u0002\\u0002\\u046b\\u046c\\u0007O\\u0002\\u0002',\n  '\\u046c\\u046d\\u0007G\\u0002\\u0002\\u046d\\u046e\\u0007U\\u0002\\u0002\\u046e',\n  '\\u046f\\u0007V\\u0002\\u0002\\u046f\\u0470\\u0007C\\u0002\\u0002\\u0470\\u0471',\n  '\\u0007O\\u0002\\u0002\\u0471\\u0484\\u0007R\\u0002\\u0002\\u0472\\u0473\\u0007',\n  'e\\u0002\\u0002\\u0473\\u0474\\u0007w\\u0002\\u0002\\u0474\\u0475\\u0007t\\u0002',\n  '\\u0002\\u0475\\u0476\\u0007t\\u0002\\u0002\\u0476\\u0477\\u0007g\\u0002\\u0002',\n  '\\u0477\\u0478\\u0007p\\u0002\\u0002\\u0478\\u0479\\u0007v\\u0002\\u0002\\u0479',\n  '\\u047a\\u0007a\\u0002\\u0002\\u047a\\u047b\\u0007v\\u0002\\u0002\\u047b\\u047c',\n  '\\u0007k\\u0002\\u0002\\u047c\\u047d\\u0007o\\u0002\\u0002\\u047d\\u047e\\u0007',\n  'g\\u0002\\u0002\\u047e\\u047f\\u0007u\\u0002\\u0002\\u047f\\u0480\\u0007v\\u0002',\n  '\\u0002\\u0480\\u0481\\u0007c\\u0002\\u0002\\u0481\\u0482\\u0007o\\u0002\\u0002',\n  '\\u0482\\u0484\\u0007r\\u0002\\u0002\\u0483\\u0461\\u0003\\u0002\\u0002\\u0002',\n  '\\u0483\\u0472\\u0003\\u0002\\u0002\\u0002\\u0484\\u0086\\u0003\\u0002\\u0002\\u0002',\n  '\\u0485\\u0486\\u0007N\\u0002\\u0002\\u0486\\u0487\\u0007Q\\u0002\\u0002\\u0487',\n  '\\u0488\\u0007E\\u0002\\u0002\\u0488\\u0489\\u0007C\\u0002\\u0002\\u0489\\u048a',\n  '\\u0007N\\u0002\\u0002\\u048a\\u048b\\u0007V\\u0002\\u0002\\u048b\\u048c\\u0007',\n  'K\\u0002\\u0002\\u048c\\u048d\\u0007O\\u0002\\u0002\\u048d\\u0498\\u0007G\\u0002',\n  '\\u0002\\u048e\\u048f\\u0007n\\u0002\\u0002\\u048f\\u0490\\u0007q\\u0002\\u0002',\n  '\\u0490\\u0491\\u0007e\\u0002\\u0002\\u0491\\u0492\\u0007c\\u0002\\u0002\\u0492',\n  '\\u0493\\u0007n\\u0002\\u0002\\u0493\\u0494\\u0007v\\u0002\\u0002\\u0494\\u0495',\n  '\\u0007k\\u0002\\u0002\\u0495\\u0496\\u0007o\\u0002\\u0002\\u0496\\u0498\\u0007',\n  'g\\u0002\\u0002\\u0497\\u0485\\u0003\\u0002\\u0002\\u0002\\u0497\\u048e\\u0003',\n  '\\u0002\\u0002\\u0002\\u0498\\u0088\\u0003\\u0002\\u0002\\u0002\\u0499\\u049a\\u0007',\n  'N\\u0002\\u0002\\u049a\\u049b\\u0007Q\\u0002\\u0002\\u049b\\u049c\\u0007E\\u0002',\n  '\\u0002\\u049c\\u049d\\u0007C\\u0002\\u0002\\u049d\\u049e\\u0007N\\u0002\\u0002',\n  '\\u049e\\u049f\\u0007V\\u0002\\u0002\\u049f\\u04a0\\u0007K\\u0002\\u0002\\u04a0',\n  '\\u04a1\\u0007O\\u0002\\u0002\\u04a1\\u04a2\\u0007G\\u0002\\u0002\\u04a2\\u04a3',\n  '\\u0007U\\u0002\\u0002\\u04a3\\u04a4\\u0007V\\u0002\\u0002\\u04a4\\u04a5\\u0007',\n  'C\\u0002\\u0002\\u04a5\\u04a6\\u0007O\\u0002\\u0002\\u04a6\\u04b6\\u0007R\\u0002',\n  '\\u0002\\u04a7\\u04a8\\u0007n\\u0002\\u0002\\u04a8\\u04a9\\u0007q\\u0002\\u0002',\n  '\\u04a9\\u04aa\\u0007e\\u0002\\u0002\\u04aa\\u04ab\\u0007c\\u0002\\u0002\\u04ab',\n  '\\u04ac\\u0007n\\u0002\\u0002\\u04ac\\u04ad\\u0007v\\u0002\\u0002\\u04ad\\u04ae',\n  '\\u0007k\\u0002\\u0002\\u04ae\\u04af\\u0007o\\u0002\\u0002\\u04af\\u04b0\\u0007',\n  'g\\u0002\\u0002\\u04b0\\u04b1\\u0007u\\u0002\\u0002\\u04b1\\u04b2\\u0007v\\u0002',\n  '\\u0002\\u04b2\\u04b3\\u0007c\\u0002\\u0002\\u04b3\\u04b4\\u0007o\\u0002\\u0002',\n  '\\u04b4\\u04b6\\u0007r\\u0002\\u0002\\u04b5\\u0499\\u0003\\u0002\\u0002\\u0002',\n  '\\u04b5\\u04a7\\u0003\\u0002\\u0002\\u0002\\u04b6\\u008a\\u0003\\u0002\\u0002\\u0002',\n  '\\u04b7\\u04b8\\u0007G\\u0002\\u0002\\u04b8\\u04b9\\u0007Z\\u0002\\u0002\\u04b9',\n  '\\u04ba\\u0007V\\u0002\\u0002\\u04ba\\u04bb\\u0007T\\u0002\\u0002\\u04bb\\u04bc',\n  '\\u0007C\\u0002\\u0002\\u04bc\\u04bd\\u0007E\\u0002\\u0002\\u04bd\\u04c6\\u0007',\n  'V\\u0002\\u0002\\u04be\\u04bf\\u0007g\\u0002\\u0002\\u04bf\\u04c0\\u0007z\\u0002',\n  '\\u0002\\u04c0\\u04c1\\u0007v\\u0002\\u0002\\u04c1\\u04c2\\u0007t\\u0002\\u0002',\n  '\\u04c2\\u04c3\\u0007c\\u0002\\u0002\\u04c3\\u04c4\\u0007e\\u0002\\u0002\\u04c4',\n  '\\u04c6\\u0007v\\u0002\\u0002\\u04c5\\u04b7\\u0003\\u0002\\u0002\\u0002\\u04c5',\n  '\\u04be\\u0003\\u0002\\u0002\\u0002\\u04c6\\u008c\\u0003\\u0002\\u0002\\u0002\\u04c7',\n  '\\u04c8\\u0007E\\u0002\\u0002\\u04c8\\u04c9\\u0007C\\u0002\\u0002\\u04c9\\u04ca',\n  '\\u0007U\\u0002\\u0002\\u04ca\\u04d0\\u0007G\\u0002\\u0002\\u04cb\\u04cc\\u0007',\n  'e\\u0002\\u0002\\u04cc\\u04cd\\u0007c\\u0002\\u0002\\u04cd\\u04ce\\u0007u\\u0002',\n  '\\u0002\\u04ce\\u04d0\\u0007g\\u0002\\u0002\\u04cf\\u04c7\\u0003\\u0002\\u0002',\n  '\\u0002\\u04cf\\u04cb\\u0003\\u0002\\u0002\\u0002\\u04d0\\u008e\\u0003\\u0002\\u0002',\n  '\\u0002\\u04d1\\u04d2\\u0007Y\\u0002\\u0002\\u04d2\\u04d3\\u0007J\\u0002\\u0002',\n  '\\u04d3\\u04d4\\u0007G\\u0002\\u0002\\u04d4\\u04da\\u0007P\\u0002\\u0002\\u04d5',\n  '\\u04d6\\u0007y\\u0002\\u0002\\u04d6\\u04d7\\u0007j\\u0002\\u0002\\u04d7\\u04d8',\n  '\\u0007g\\u0002\\u0002\\u04d8\\u04da\\u0007p\\u0002\\u0002\\u04d9\\u04d1\\u0003',\n  '\\u0002\\u0002\\u0002\\u04d9\\u04d5\\u0003\\u0002\\u0002\\u0002\\u04da\\u0090\\u0003',\n  '\\u0002\\u0002\\u0002\\u04db\\u04dc\\u0007V\\u0002\\u0002\\u04dc\\u04dd\\u0007',\n  'J\\u0002\\u0002\\u04dd\\u04de\\u0007G\\u0002\\u0002\\u04de\\u04e4\\u0007P\\u0002',\n  '\\u0002\\u04df\\u04e0\\u0007v\\u0002\\u0002\\u04e0\\u04e1\\u0007j\\u0002\\u0002',\n  '\\u04e1\\u04e2\\u0007g\\u0002\\u0002\\u04e2\\u04e4\\u0007p\\u0002\\u0002\\u04e3',\n  '\\u04db\\u0003\\u0002\\u0002\\u0002\\u04e3\\u04df\\u0003\\u0002\\u0002\\u0002\\u04e4',\n  '\\u0092\\u0003\\u0002\\u0002\\u0002\\u04e5\\u04e6\\u0007G\\u0002\\u0002\\u04e6',\n  '\\u04e7\\u0007N\\u0002\\u0002\\u04e7\\u04e8\\u0007U\\u0002\\u0002\\u04e8\\u04ee',\n  '\\u0007G\\u0002\\u0002\\u04e9\\u04ea\\u0007g\\u0002\\u0002\\u04ea\\u04eb\\u0007',\n  'n\\u0002\\u0002\\u04eb\\u04ec\\u0007u\\u0002\\u0002\\u04ec\\u04ee\\u0007g\\u0002',\n  '\\u0002\\u04ed\\u04e5\\u0003\\u0002\\u0002\\u0002\\u04ed\\u04e9\\u0003\\u0002\\u0002',\n  '\\u0002\\u04ee\\u0094\\u0003\\u0002\\u0002\\u0002\\u04ef\\u04f0\\u0007G\\u0002',\n  '\\u0002\\u04f0\\u04f1\\u0007P\\u0002\\u0002\\u04f1\\u04f6\\u0007F\\u0002\\u0002',\n  '\\u04f2\\u04f3\\u0007g\\u0002\\u0002\\u04f3\\u04f4\\u0007p\\u0002\\u0002\\u04f4',\n  '\\u04f6\\u0007f\\u0002\\u0002\\u04f5\\u04ef\\u0003\\u0002\\u0002\\u0002\\u04f5',\n  '\\u04f2\\u0003\\u0002\\u0002\\u0002\\u04f6\\u0096\\u0003\\u0002\\u0002\\u0002\\u04f7',\n  '\\u04f8\\u0007L\\u0002\\u0002\\u04f8\\u04f9\\u0007Q\\u0002\\u0002\\u04f9\\u04fa',\n  '\\u0007K\\u0002\\u0002\\u04fa\\u0500\\u0007P\\u0002\\u0002\\u04fb\\u04fc\\u0007',\n  'l\\u0002\\u0002\\u04fc\\u04fd\\u0007q\\u0002\\u0002\\u04fd\\u04fe\\u0007k\\u0002',\n  '\\u0002\\u04fe\\u0500\\u0007p\\u0002\\u0002\\u04ff\\u04f7\\u0003\\u0002\\u0002',\n  '\\u0002\\u04ff\\u04fb\\u0003\\u0002\\u0002\\u0002\\u0500\\u0098\\u0003\\u0002\\u0002',\n  '\\u0002\\u0501\\u0502\\u0007E\\u0002\\u0002\\u0502\\u0503\\u0007T\\u0002\\u0002',\n  '\\u0503\\u0504\\u0007Q\\u0002\\u0002\\u0504\\u0505\\u0007U\\u0002\\u0002\\u0505',\n  '\\u050c\\u0007U\\u0002\\u0002\\u0506\\u0507\\u0007e\\u0002\\u0002\\u0507\\u0508',\n  '\\u0007t\\u0002\\u0002\\u0508\\u0509\\u0007q\\u0002\\u0002\\u0509\\u050a\\u0007',\n  'u\\u0002\\u0002\\u050a\\u050c\\u0007u\\u0002\\u0002\\u050b\\u0501\\u0003\\u0002',\n  '\\u0002\\u0002\\u050b\\u0506\\u0003\\u0002\\u0002\\u0002\\u050c\\u009a\\u0003\\u0002',\n  '\\u0002\\u0002\\u050d\\u050e\\u0007Q\\u0002\\u0002\\u050e\\u050f\\u0007W\\u0002',\n  '\\u0002\\u050f\\u0510\\u0007V\\u0002\\u0002\\u0510\\u0511\\u0007G\\u0002\\u0002',\n  '\\u0511\\u0518\\u0007T\\u0002\\u0002\\u0512\\u0513\\u0007q\\u0002\\u0002\\u0513',\n  '\\u0514\\u0007w\\u0002\\u0002\\u0514\\u0515\\u0007v\\u0002\\u0002\\u0515\\u0516',\n  '\\u0007g\\u0002\\u0002\\u0516\\u0518\\u0007t\\u0002\\u0002\\u0517\\u050d\\u0003',\n  '\\u0002\\u0002\\u0002\\u0517\\u0512\\u0003\\u0002\\u0002\\u0002\\u0518\\u009c\\u0003',\n  '\\u0002\\u0002\\u0002\\u0519\\u051a\\u0007K\\u0002\\u0002\\u051a\\u051b\\u0007',\n  'P\\u0002\\u0002\\u051b\\u051c\\u0007P\\u0002\\u0002\\u051c\\u051d\\u0007G\\u0002',\n  '\\u0002\\u051d\\u0524\\u0007T\\u0002\\u0002\\u051e\\u051f\\u0007k\\u0002\\u0002',\n  '\\u051f\\u0520\\u0007p\\u0002\\u0002\\u0520\\u0521\\u0007p\\u0002\\u0002\\u0521',\n  '\\u0522\\u0007g\\u0002\\u0002\\u0522\\u0524\\u0007t\\u0002\\u0002\\u0523\\u0519',\n  '\\u0003\\u0002\\u0002\\u0002\\u0523\\u051e\\u0003\\u0002\\u0002\\u0002\\u0524\\u009e',\n  '\\u0003\\u0002\\u0002\\u0002\\u0525\\u0526\\u0007N\\u0002\\u0002\\u0526\\u0527',\n  '\\u0007G\\u0002\\u0002\\u0527\\u0528\\u0007H\\u0002\\u0002\\u0528\\u052e\\u0007',\n  'V\\u0002\\u0002\\u0529\\u052a\\u0007n\\u0002\\u0002\\u052a\\u052b\\u0007g\\u0002',\n  '\\u0002\\u052b\\u052c\\u0007h\\u0002\\u0002\\u052c\\u052e\\u0007v\\u0002\\u0002',\n  '\\u052d\\u0525\\u0003\\u0002\\u0002\\u0002\\u052d\\u0529\\u0003\\u0002\\u0002\\u0002',\n  '\\u052e\\u00a0\\u0003\\u0002\\u0002\\u0002\\u052f\\u0530\\u0007T\\u0002\\u0002',\n  '\\u0530\\u0531\\u0007K\\u0002\\u0002\\u0531\\u0532\\u0007I\\u0002\\u0002\\u0532',\n  '\\u0533\\u0007J\\u0002\\u0002\\u0533\\u053a\\u0007V\\u0002\\u0002\\u0534\\u0535',\n  '\\u0007t\\u0002\\u0002\\u0535\\u0536\\u0007k\\u0002\\u0002\\u0536\\u0537\\u0007',\n  'i\\u0002\\u0002\\u0537\\u0538\\u0007j\\u0002\\u0002\\u0538\\u053a\\u0007v\\u0002',\n  '\\u0002\\u0539\\u052f\\u0003\\u0002\\u0002\\u0002\\u0539\\u0534\\u0003\\u0002\\u0002',\n  '\\u0002\\u053a\\u00a2\\u0003\\u0002\\u0002\\u0002\\u053b\\u053c\\u0007H\\u0002',\n  '\\u0002\\u053c\\u053d\\u0007W\\u0002\\u0002\\u053d\\u053e\\u0007N\\u0002\\u0002',\n  '\\u053e\\u0544\\u0007N\\u0002\\u0002\\u053f\\u0540\\u0007h\\u0002\\u0002\\u0540',\n  '\\u0541\\u0007w\\u0002\\u0002\\u0541\\u0542\\u0007n\\u0002\\u0002\\u0542\\u0544',\n  '\\u0007n\\u0002\\u0002\\u0543\\u053b\\u0003\\u0002\\u0002\\u0002\\u0543\\u053f',\n  '\\u0003\\u0002\\u0002\\u0002\\u0544\\u00a4\\u0003\\u0002\\u0002\\u0002\\u0545\\u0546',\n  '\\u0007P\\u0002\\u0002\\u0546\\u0547\\u0007C\\u0002\\u0002\\u0547\\u0548\\u0007',\n  'V\\u0002\\u0002\\u0548\\u0549\\u0007W\\u0002\\u0002\\u0549\\u054a\\u0007T\\u0002',\n  '\\u0002\\u054a\\u054b\\u0007C\\u0002\\u0002\\u054b\\u0554\\u0007N\\u0002\\u0002',\n  '\\u054c\\u054d\\u0007p\\u0002\\u0002\\u054d\\u054e\\u0007c\\u0002\\u0002\\u054e',\n  '\\u054f\\u0007v\\u0002\\u0002\\u054f\\u0550\\u0007w\\u0002\\u0002\\u0550\\u0551',\n  '\\u0007t\\u0002\\u0002\\u0551\\u0552\\u0007c\\u0002\\u0002\\u0552\\u0554\\u0007',\n  'n\\u0002\\u0002\\u0553\\u0545\\u0003\\u0002\\u0002\\u0002\\u0553\\u054c\\u0003',\n  '\\u0002\\u0002\\u0002\\u0554\\u00a6\\u0003\\u0002\\u0002\\u0002\\u0555\\u0556\\u0007',\n  'W\\u0002\\u0002\\u0556\\u0557\\u0007U\\u0002\\u0002\\u0557\\u0558\\u0007K\\u0002',\n  '\\u0002\\u0558\\u0559\\u0007P\\u0002\\u0002\\u0559\\u0560\\u0007I\\u0002\\u0002',\n  '\\u055a\\u055b\\u0007w\\u0002\\u0002\\u055b\\u055c\\u0007u\\u0002\\u0002\\u055c',\n  '\\u055d\\u0007k\\u0002\\u0002\\u055d\\u055e\\u0007p\\u0002\\u0002\\u055e\\u0560',\n  '\\u0007i\\u0002\\u0002\\u055f\\u0555\\u0003\\u0002\\u0002\\u0002\\u055f\\u055a',\n  '\\u0003\\u0002\\u0002\\u0002\\u0560\\u00a8\\u0003\\u0002\\u0002\\u0002\\u0561\\u0562',\n  '\\u0007Q\\u0002\\u0002\\u0562\\u0566\\u0007P\\u0002\\u0002\\u0563\\u0564\\u0007',\n  'q\\u0002\\u0002\\u0564\\u0566\\u0007p\\u0002\\u0002\\u0565\\u0561\\u0003\\u0002',\n  '\\u0002\\u0002\\u0565\\u0563\\u0003\\u0002\\u0002\\u0002\\u0566\\u00aa\\u0003\\u0002',\n  '\\u0002\\u0002\\u0567\\u0568\\u0007H\\u0002\\u0002\\u0568\\u0569\\u0007K\\u0002',\n  '\\u0002\\u0569\\u056a\\u0007N\\u0002\\u0002\\u056a\\u056b\\u0007V\\u0002\\u0002',\n  '\\u056b\\u056c\\u0007G\\u0002\\u0002\\u056c\\u0574\\u0007T\\u0002\\u0002\\u056d',\n  '\\u056e\\u0007h\\u0002\\u0002\\u056e\\u056f\\u0007k\\u0002\\u0002\\u056f\\u0570',\n  '\\u0007n\\u0002\\u0002\\u0570\\u0571\\u0007v\\u0002\\u0002\\u0571\\u0572\\u0007',\n  'g\\u0002\\u0002\\u0572\\u0574\\u0007t\\u0002\\u0002\\u0573\\u0567\\u0003\\u0002',\n  '\\u0002\\u0002\\u0573\\u056d\\u0003\\u0002\\u0002\\u0002\\u0574\\u00ac\\u0003\\u0002',\n  '\\u0002\\u0002\\u0575\\u0576\\u0007Q\\u0002\\u0002\\u0576\\u0577\\u0007X\\u0002',\n  '\\u0002\\u0577\\u0578\\u0007G\\u0002\\u0002\\u0578\\u057e\\u0007T\\u0002\\u0002',\n  '\\u0579\\u057a\\u0007q\\u0002\\u0002\\u057a\\u057b\\u0007x\\u0002\\u0002\\u057b',\n  '\\u057c\\u0007g\\u0002\\u0002\\u057c\\u057e\\u0007t\\u0002\\u0002\\u057d\\u0575',\n  '\\u0003\\u0002\\u0002\\u0002\\u057d\\u0579\\u0003\\u0002\\u0002\\u0002\\u057e\\u00ae',\n  '\\u0003\\u0002\\u0002\\u0002\\u057f\\u0580\\u0007R\\u0002\\u0002\\u0580\\u0581',\n  '\\u0007C\\u0002\\u0002\\u0581\\u0582\\u0007T\\u0002\\u0002\\u0582\\u0583\\u0007',\n  'V\\u0002\\u0002\\u0583\\u0584\\u0007K\\u0002\\u0002\\u0584\\u0585\\u0007V\\u0002',\n  '\\u0002\\u0585\\u0586\\u0007K\\u0002\\u0002\\u0586\\u0587\\u0007Q\\u0002\\u0002',\n  '\\u0587\\u0592\\u0007P\\u0002\\u0002\\u0588\\u0589\\u0007r\\u0002\\u0002\\u0589',\n  '\\u058a\\u0007c\\u0002\\u0002\\u058a\\u058b\\u0007t\\u0002\\u0002\\u058b\\u058c',\n  '\\u0007v\\u0002\\u0002\\u058c\\u058d\\u0007k\\u0002\\u0002\\u058d\\u058e\\u0007',\n  'v\\u0002\\u0002\\u058e\\u058f\\u0007k\\u0002\\u0002\\u058f\\u0590\\u0007q\\u0002',\n  '\\u0002\\u0590\\u0592\\u0007p\\u0002\\u0002\\u0591\\u057f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0591\\u0588\\u0003\\u0002\\u0002\\u0002\\u0592\\u00b0\\u0003\\u0002\\u0002',\n  '\\u0002\\u0593\\u0594\\u0007T\\u0002\\u0002\\u0594\\u0595\\u0007C\\u0002\\u0002',\n  '\\u0595\\u0596\\u0007P\\u0002\\u0002\\u0596\\u0597\\u0007I\\u0002\\u0002\\u0597',\n  '\\u059e\\u0007G\\u0002\\u0002\\u0598\\u0599\\u0007t\\u0002\\u0002\\u0599\\u059a',\n  '\\u0007c\\u0002\\u0002\\u059a\\u059b\\u0007p\\u0002\\u0002\\u059b\\u059c\\u0007',\n  'i\\u0002\\u0002\\u059c\\u059e\\u0007g\\u0002\\u0002\\u059d\\u0593\\u0003\\u0002',\n  '\\u0002\\u0002\\u059d\\u0598\\u0003\\u0002\\u0002\\u0002\\u059e\\u00b2\\u0003\\u0002',\n  '\\u0002\\u0002\\u059f\\u05a0\\u0007T\\u0002\\u0002\\u05a0\\u05a1\\u0007Q\\u0002',\n  '\\u0002\\u05a1\\u05a2\\u0007Y\\u0002\\u0002\\u05a2\\u05a8\\u0007U\\u0002\\u0002',\n  '\\u05a3\\u05a4\\u0007t\\u0002\\u0002\\u05a4\\u05a5\\u0007q\\u0002\\u0002\\u05a5',\n  '\\u05a6\\u0007y\\u0002\\u0002\\u05a6\\u05a8\\u0007u\\u0002\\u0002\\u05a7\\u059f',\n  '\\u0003\\u0002\\u0002\\u0002\\u05a7\\u05a3\\u0003\\u0002\\u0002\\u0002\\u05a8\\u00b4',\n  '\\u0003\\u0002\\u0002\\u0002\\u05a9\\u05aa\\u0007W\\u0002\\u0002\\u05aa\\u05ab',\n  '\\u0007P\\u0002\\u0002\\u05ab\\u05ac\\u0007D\\u0002\\u0002\\u05ac\\u05ad\\u0007',\n  'Q\\u0002\\u0002\\u05ad\\u05ae\\u0007W\\u0002\\u0002\\u05ae\\u05af\\u0007P\\u0002',\n  '\\u0002\\u05af\\u05b0\\u0007F\\u0002\\u0002\\u05b0\\u05b1\\u0007G\\u0002\\u0002',\n  '\\u05b1\\u05bc\\u0007F\\u0002\\u0002\\u05b2\\u05b3\\u0007w\\u0002\\u0002\\u05b3',\n  '\\u05b4\\u0007p\\u0002\\u0002\\u05b4\\u05b5\\u0007d\\u0002\\u0002\\u05b5\\u05b6',\n  '\\u0007q\\u0002\\u0002\\u05b6\\u05b7\\u0007w\\u0002\\u0002\\u05b7\\u05b8\\u0007',\n  'p\\u0002\\u0002\\u05b8\\u05b9\\u0007f\\u0002\\u0002\\u05b9\\u05ba\\u0007g\\u0002',\n  '\\u0002\\u05ba\\u05bc\\u0007f\\u0002\\u0002\\u05bb\\u05a9\\u0003\\u0002\\u0002',\n  '\\u0002\\u05bb\\u05b2\\u0003\\u0002\\u0002\\u0002\\u05bc\\u00b6\\u0003\\u0002\\u0002',\n  '\\u0002\\u05bd\\u05be\\u0007R\\u0002\\u0002\\u05be\\u05bf\\u0007T\\u0002\\u0002',\n  '\\u05bf\\u05c0\\u0007G\\u0002\\u0002\\u05c0\\u05c1\\u0007E\\u0002\\u0002\\u05c1',\n  '\\u05c2\\u0007G\\u0002\\u0002\\u05c2\\u05c3\\u0007F\\u0002\\u0002\\u05c3\\u05c4',\n  '\\u0007K\\u0002\\u0002\\u05c4\\u05c5\\u0007P\\u0002\\u0002\\u05c5\\u05d0\\u0007',\n  'I\\u0002\\u0002\\u05c6\\u05c7\\u0007r\\u0002\\u0002\\u05c7\\u05c8\\u0007t\\u0002',\n  '\\u0002\\u05c8\\u05c9\\u0007g\\u0002\\u0002\\u05c9\\u05ca\\u0007e\\u0002\\u0002',\n  '\\u05ca\\u05cb\\u0007g\\u0002\\u0002\\u05cb\\u05cc\\u0007f\\u0002\\u0002\\u05cc',\n  '\\u05cd\\u0007k\\u0002\\u0002\\u05cd\\u05ce\\u0007p\\u0002\\u0002\\u05ce\\u05d0',\n  '\\u0007i\\u0002\\u0002\\u05cf\\u05bd\\u0003\\u0002\\u0002\\u0002\\u05cf\\u05c6',\n  '\\u0003\\u0002\\u0002\\u0002\\u05d0\\u00b8\\u0003\\u0002\\u0002\\u0002\\u05d1\\u05d2',\n  '\\u0007H\\u0002\\u0002\\u05d2\\u05d3\\u0007Q\\u0002\\u0002\\u05d3\\u05d4\\u0007',\n  'N\\u0002\\u0002\\u05d4\\u05d5\\u0007N\\u0002\\u0002\\u05d5\\u05d6\\u0007Q\\u0002',\n  '\\u0002\\u05d6\\u05d7\\u0007Y\\u0002\\u0002\\u05d7\\u05d8\\u0007K\\u0002\\u0002',\n  '\\u05d8\\u05d9\\u0007P\\u0002\\u0002\\u05d9\\u05e4\\u0007I\\u0002\\u0002\\u05da',\n  '\\u05db\\u0007h\\u0002\\u0002\\u05db\\u05dc\\u0007q\\u0002\\u0002\\u05dc\\u05dd',\n  '\\u0007n\\u0002\\u0002\\u05dd\\u05de\\u0007n\\u0002\\u0002\\u05de\\u05df\\u0007',\n  'q\\u0002\\u0002\\u05df\\u05e0\\u0007y\\u0002\\u0002\\u05e0\\u05e1\\u0007k\\u0002',\n  '\\u0002\\u05e1\\u05e2\\u0007p\\u0002\\u0002\\u05e2\\u05e4\\u0007i\\u0002\\u0002',\n  '\\u05e3\\u05d1\\u0003\\u0002\\u0002\\u0002\\u05e3\\u05da\\u0003\\u0002\\u0002\\u0002',\n  '\\u05e4\\u00ba\\u0003\\u0002\\u0002\\u0002\\u05e5\\u05e6\\u0007E\\u0002\\u0002',\n  '\\u05e6\\u05e7\\u0007W\\u0002\\u0002\\u05e7\\u05e8\\u0007T\\u0002\\u0002\\u05e8',\n  '\\u05e9\\u0007T\\u0002\\u0002\\u05e9\\u05ea\\u0007G\\u0002\\u0002\\u05ea\\u05eb',\n  '\\u0007P\\u0002\\u0002\\u05eb\\u05f4\\u0007V\\u0002\\u0002\\u05ec\\u05ed\\u0007',\n  'e\\u0002\\u0002\\u05ed\\u05ee\\u0007w\\u0002\\u0002\\u05ee\\u05ef\\u0007t\\u0002',\n  '\\u0002\\u05ef\\u05f0\\u0007t\\u0002\\u0002\\u05f0\\u05f1\\u0007g\\u0002\\u0002',\n  '\\u05f1\\u05f2\\u0007p\\u0002\\u0002\\u05f2\\u05f4\\u0007v\\u0002\\u0002\\u05f3',\n  '\\u05e5\\u0003\\u0002\\u0002\\u0002\\u05f3\\u05ec\\u0003\\u0002\\u0002\\u0002\\u05f4',\n  '\\u00bc\\u0003\\u0002\\u0002\\u0002\\u05f5\\u05f6\\u0007T\\u0002\\u0002\\u05f6',\n  '\\u05f7\\u0007Q\\u0002\\u0002\\u05f7\\u05fc\\u0007Y\\u0002\\u0002\\u05f8\\u05f9',\n  '\\u0007t\\u0002\\u0002\\u05f9\\u05fa\\u0007q\\u0002\\u0002\\u05fa\\u05fc\\u0007',\n  'y\\u0002\\u0002\\u05fb\\u05f5\\u0003\\u0002\\u0002\\u0002\\u05fb\\u05f8\\u0003',\n  '\\u0002\\u0002\\u0002\\u05fc\\u00be\\u0003\\u0002\\u0002\\u0002\\u05fd\\u05fe\\u0007',\n  'Y\\u0002\\u0002\\u05fe\\u05ff\\u0007K\\u0002\\u0002\\u05ff\\u0600\\u0007V\\u0002',\n  '\\u0002\\u0600\\u0606\\u0007J\\u0002\\u0002\\u0601\\u0602\\u0007y\\u0002\\u0002',\n  '\\u0602\\u0603\\u0007k\\u0002\\u0002\\u0603\\u0604\\u0007v\\u0002\\u0002\\u0604',\n  '\\u0606\\u0007j\\u0002\\u0002\\u0605\\u05fd\\u0003\\u0002\\u0002\\u0002\\u0605',\n  '\\u0601\\u0003\\u0002\\u0002\\u0002\\u0606\\u00c0\\u0003\\u0002\\u0002\\u0002\\u0607',\n  '\\u0608\\u0007T\\u0002\\u0002\\u0608\\u0609\\u0007G\\u0002\\u0002\\u0609\\u060a',\n  '\\u0007E\\u0002\\u0002\\u060a\\u060b\\u0007W\\u0002\\u0002\\u060b\\u060c\\u0007',\n  'T\\u0002\\u0002\\u060c\\u060d\\u0007U\\u0002\\u0002\\u060d\\u060e\\u0007K\\u0002',\n  '\\u0002\\u060e\\u060f\\u0007X\\u0002\\u0002\\u060f\\u061a\\u0007G\\u0002\\u0002',\n  '\\u0610\\u0611\\u0007t\\u0002\\u0002\\u0611\\u0612\\u0007g\\u0002\\u0002\\u0612',\n  '\\u0613\\u0007e\\u0002\\u0002\\u0613\\u0614\\u0007w\\u0002\\u0002\\u0614\\u0615',\n  '\\u0007t\\u0002\\u0002\\u0615\\u0616\\u0007u\\u0002\\u0002\\u0616\\u0617\\u0007',\n  'k\\u0002\\u0002\\u0617\\u0618\\u0007x\\u0002\\u0002\\u0618\\u061a\\u0007g\\u0002',\n  '\\u0002\\u0619\\u0607\\u0003\\u0002\\u0002\\u0002\\u0619\\u0610\\u0003\\u0002\\u0002',\n  '\\u0002\\u061a\\u00c2\\u0003\\u0002\\u0002\\u0002\\u061b\\u061c\\u0007X\\u0002',\n  '\\u0002\\u061c\\u061d\\u0007C\\u0002\\u0002\\u061d\\u061e\\u0007N\\u0002\\u0002',\n  '\\u061e\\u061f\\u0007W\\u0002\\u0002\\u061f\\u0620\\u0007G\\u0002\\u0002\\u0620',\n  '\\u0628\\u0007U\\u0002\\u0002\\u0621\\u0622\\u0007x\\u0002\\u0002\\u0622\\u0623',\n  '\\u0007c\\u0002\\u0002\\u0623\\u0624\\u0007n\\u0002\\u0002\\u0624\\u0625\\u0007',\n  'w\\u0002\\u0002\\u0625\\u0626\\u0007g\\u0002\\u0002\\u0626\\u0628\\u0007u\\u0002',\n  '\\u0002\\u0627\\u061b\\u0003\\u0002\\u0002\\u0002\\u0627\\u0621\\u0003\\u0002\\u0002',\n  '\\u0002\\u0628\\u00c4\\u0003\\u0002\\u0002\\u0002\\u0629\\u062a\\u0007E\\u0002',\n  '\\u0002\\u062a\\u062b\\u0007T\\u0002\\u0002\\u062b\\u062c\\u0007G\\u0002\\u0002',\n  '\\u062c\\u062d\\u0007C\\u0002\\u0002\\u062d\\u062e\\u0007V\\u0002\\u0002\\u062e',\n  '\\u0636\\u0007G\\u0002\\u0002\\u062f\\u0630\\u0007e\\u0002\\u0002\\u0630\\u0631',\n  '\\u0007t\\u0002\\u0002\\u0631\\u0632\\u0007g\\u0002\\u0002\\u0632\\u0633\\u0007',\n  'c\\u0002\\u0002\\u0633\\u0634\\u0007v\\u0002\\u0002\\u0634\\u0636\\u0007g\\u0002',\n  '\\u0002\\u0635\\u0629\\u0003\\u0002\\u0002\\u0002\\u0635\\u062f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0636\\u00c6\\u0003\\u0002\\u0002\\u0002\\u0637\\u0638\\u0007U\\u0002',\n  '\\u0002\\u0638\\u0639\\u0007E\\u0002\\u0002\\u0639\\u063a\\u0007J\\u0002\\u0002',\n  '\\u063a\\u063b\\u0007G\\u0002\\u0002\\u063b\\u063c\\u0007O\\u0002\\u0002\\u063c',\n  '\\u0644\\u0007C\\u0002\\u0002\\u063d\\u063e\\u0007u\\u0002\\u0002\\u063e\\u063f',\n  '\\u0007e\\u0002\\u0002\\u063f\\u0640\\u0007j\\u0002\\u0002\\u0640\\u0641\\u0007',\n  'g\\u0002\\u0002\\u0641\\u0642\\u0007o\\u0002\\u0002\\u0642\\u0644\\u0007c\\u0002',\n  '\\u0002\\u0643\\u0637\\u0003\\u0002\\u0002\\u0002\\u0643\\u063d\\u0003\\u0002\\u0002',\n  '\\u0002\\u0644\\u00c8\\u0003\\u0002\\u0002\\u0002\\u0645\\u0646\\u0007V\\u0002',\n  '\\u0002\\u0646\\u0647\\u0007C\\u0002\\u0002\\u0647\\u0648\\u0007D\\u0002\\u0002',\n  '\\u0648\\u0649\\u0007N\\u0002\\u0002\\u0649\\u0650\\u0007G\\u0002\\u0002\\u064a',\n  '\\u064b\\u0007v\\u0002\\u0002\\u064b\\u064c\\u0007c\\u0002\\u0002\\u064c\\u064d',\n  '\\u0007d\\u0002\\u0002\\u064d\\u064e\\u0007n\\u0002\\u0002\\u064e\\u0650\\u0007',\n  'g\\u0002\\u0002\\u064f\\u0645\\u0003\\u0002\\u0002\\u0002\\u064f\\u064a\\u0003',\n  '\\u0002\\u0002\\u0002\\u0650\\u00ca\\u0003\\u0002\\u0002\\u0002\\u0651\\u0652\\u0007',\n  'X\\u0002\\u0002\\u0652\\u0653\\u0007K\\u0002\\u0002\\u0653\\u0654\\u0007G\\u0002',\n  '\\u0002\\u0654\\u065a\\u0007Y\\u0002\\u0002\\u0655\\u0656\\u0007x\\u0002\\u0002',\n  '\\u0656\\u0657\\u0007k\\u0002\\u0002\\u0657\\u0658\\u0007g\\u0002\\u0002\\u0658',\n  '\\u065a\\u0007y\\u0002\\u0002\\u0659\\u0651\\u0003\\u0002\\u0002\\u0002\\u0659',\n  '\\u0655\\u0003\\u0002\\u0002\\u0002\\u065a\\u00cc\\u0003\\u0002\\u0002\\u0002\\u065b',\n  '\\u065c\\u0007T\\u0002\\u0002\\u065c\\u065d\\u0007G\\u0002\\u0002\\u065d\\u065e',\n  '\\u0007R\\u0002\\u0002\\u065e\\u065f\\u0007N\\u0002\\u0002\\u065f\\u0660\\u0007',\n  'C\\u0002\\u0002\\u0660\\u0661\\u0007E\\u0002\\u0002\\u0661\\u066a\\u0007G\\u0002',\n  '\\u0002\\u0662\\u0663\\u0007t\\u0002\\u0002\\u0663\\u0664\\u0007g\\u0002\\u0002',\n  '\\u0664\\u0665\\u0007r\\u0002\\u0002\\u0665\\u0666\\u0007n\\u0002\\u0002\\u0666',\n  '\\u0667\\u0007c\\u0002\\u0002\\u0667\\u0668\\u0007e\\u0002\\u0002\\u0668\\u066a',\n  '\\u0007g\\u0002\\u0002\\u0669\\u065b\\u0003\\u0002\\u0002\\u0002\\u0669\\u0662',\n  '\\u0003\\u0002\\u0002\\u0002\\u066a\\u00ce\\u0003\\u0002\\u0002\\u0002\\u066b\\u066c',\n  '\\u0007K\\u0002\\u0002\\u066c\\u066d\\u0007P\\u0002\\u0002\\u066d\\u066e\\u0007',\n  'U\\u0002\\u0002\\u066e\\u066f\\u0007G\\u0002\\u0002\\u066f\\u0670\\u0007T\\u0002',\n  '\\u0002\\u0670\\u0678\\u0007V\\u0002\\u0002\\u0671\\u0672\\u0007k\\u0002\\u0002',\n  '\\u0672\\u0673\\u0007p\\u0002\\u0002\\u0673\\u0674\\u0007u\\u0002\\u0002\\u0674',\n  '\\u0675\\u0007g\\u0002\\u0002\\u0675\\u0676\\u0007t\\u0002\\u0002\\u0676\\u0678',\n  '\\u0007v\\u0002\\u0002\\u0677\\u066b\\u0003\\u0002\\u0002\\u0002\\u0677\\u0671',\n  '\\u0003\\u0002\\u0002\\u0002\\u0678\\u00d0\\u0003\\u0002\\u0002\\u0002\\u0679\\u067a',\n  '\\u0007F\\u0002\\u0002\\u067a\\u067b\\u0007G\\u0002\\u0002\\u067b\\u067c\\u0007',\n  'N\\u0002\\u0002\\u067c\\u067d\\u0007G\\u0002\\u0002\\u067d\\u067e\\u0007V\\u0002',\n  '\\u0002\\u067e\\u0686\\u0007G\\u0002\\u0002\\u067f\\u0680\\u0007f\\u0002\\u0002',\n  '\\u0680\\u0681\\u0007g\\u0002\\u0002\\u0681\\u0682\\u0007n\\u0002\\u0002\\u0682',\n  '\\u0683\\u0007g\\u0002\\u0002\\u0683\\u0684\\u0007v\\u0002\\u0002\\u0684\\u0686',\n  '\\u0007g\\u0002\\u0002\\u0685\\u0679\\u0003\\u0002\\u0002\\u0002\\u0685\\u067f',\n  '\\u0003\\u0002\\u0002\\u0002\\u0686\\u00d2\\u0003\\u0002\\u0002\\u0002\\u0687\\u0688',\n  '\\u0007K\\u0002\\u0002\\u0688\\u0689\\u0007P\\u0002\\u0002\\u0689\\u068a\\u0007',\n  'V\\u0002\\u0002\\u068a\\u0690\\u0007Q\\u0002\\u0002\\u068b\\u068c\\u0007k\\u0002',\n  '\\u0002\\u068c\\u068d\\u0007p\\u0002\\u0002\\u068d\\u068e\\u0007v\\u0002\\u0002',\n  '\\u068e\\u0690\\u0007q\\u0002\\u0002\\u068f\\u0687\\u0003\\u0002\\u0002\\u0002',\n  '\\u068f\\u068b\\u0003\\u0002\\u0002\\u0002\\u0690\\u00d4\\u0003\\u0002\\u0002\\u0002',\n  '\\u0691\\u0692\\u0007E\\u0002\\u0002\\u0692\\u0693\\u0007Q\\u0002\\u0002\\u0693',\n  '\\u0694\\u0007P\\u0002\\u0002\\u0694\\u0695\\u0007U\\u0002\\u0002\\u0695\\u0696',\n  '\\u0007V\\u0002\\u0002\\u0696\\u0697\\u0007T\\u0002\\u0002\\u0697\\u0698\\u0007',\n  'C\\u0002\\u0002\\u0698\\u0699\\u0007K\\u0002\\u0002\\u0699\\u069a\\u0007P\\u0002',\n  '\\u0002\\u069a\\u06a6\\u0007V\\u0002\\u0002\\u069b\\u069c\\u0007e\\u0002\\u0002',\n  '\\u069c\\u069d\\u0007q\\u0002\\u0002\\u069d\\u069e\\u0007p\\u0002\\u0002\\u069e',\n  '\\u069f\\u0007u\\u0002\\u0002\\u069f\\u06a0\\u0007v\\u0002\\u0002\\u06a0\\u06a1',\n  '\\u0007t\\u0002\\u0002\\u06a1\\u06a2\\u0007c\\u0002\\u0002\\u06a2\\u06a3\\u0007',\n  'k\\u0002\\u0002\\u06a3\\u06a4\\u0007p\\u0002\\u0002\\u06a4\\u06a6\\u0007v\\u0002',\n  '\\u0002\\u06a5\\u0691\\u0003\\u0002\\u0002\\u0002\\u06a5\\u069b\\u0003\\u0002\\u0002',\n  '\\u0002\\u06a6\\u00d6\\u0003\\u0002\\u0002\\u0002\\u06a7\\u06a8\\u0007F\\u0002',\n  '\\u0002\\u06a8\\u06a9\\u0007G\\u0002\\u0002\\u06a9\\u06aa\\u0007U\\u0002\\u0002',\n  '\\u06aa\\u06ab\\u0007E\\u0002\\u0002\\u06ab\\u06ac\\u0007T\\u0002\\u0002\\u06ac',\n  '\\u06ad\\u0007K\\u0002\\u0002\\u06ad\\u06ae\\u0007D\\u0002\\u0002\\u06ae\\u06b8',\n  '\\u0007G\\u0002\\u0002\\u06af\\u06b0\\u0007f\\u0002\\u0002\\u06b0\\u06b1\\u0007',\n  'g\\u0002\\u0002\\u06b1\\u06b2\\u0007u\\u0002\\u0002\\u06b2\\u06b3\\u0007e\\u0002',\n  '\\u0002\\u06b3\\u06b4\\u0007t\\u0002\\u0002\\u06b4\\u06b5\\u0007k\\u0002\\u0002',\n  '\\u06b5\\u06b6\\u0007d\\u0002\\u0002\\u06b6\\u06b8\\u0007g\\u0002\\u0002\\u06b7',\n  '\\u06a7\\u0003\\u0002\\u0002\\u0002\\u06b7\\u06af\\u0003\\u0002\\u0002\\u0002\\u06b8',\n  '\\u00d8\\u0003\\u0002\\u0002\\u0002\\u06b9\\u06ba\\u0007I\\u0002\\u0002\\u06ba',\n  '\\u06bb\\u0007T\\u0002\\u0002\\u06bb\\u06bc\\u0007C\\u0002\\u0002\\u06bc\\u06bd',\n  '\\u0007P\\u0002\\u0002\\u06bd\\u06c4\\u0007V\\u0002\\u0002\\u06be\\u06bf\\u0007',\n  'i\\u0002\\u0002\\u06bf\\u06c0\\u0007t\\u0002\\u0002\\u06c0\\u06c1\\u0007c\\u0002',\n  '\\u0002\\u06c1\\u06c2\\u0007p\\u0002\\u0002\\u06c2\\u06c4\\u0007v\\u0002\\u0002',\n  '\\u06c3\\u06b9\\u0003\\u0002\\u0002\\u0002\\u06c3\\u06be\\u0003\\u0002\\u0002\\u0002',\n  '\\u06c4\\u00da\\u0003\\u0002\\u0002\\u0002\\u06c5\\u06c6\\u0007T\\u0002\\u0002',\n  '\\u06c6\\u06c7\\u0007G\\u0002\\u0002\\u06c7\\u06c8\\u0007X\\u0002\\u0002\\u06c8',\n  '\\u06c9\\u0007Q\\u0002\\u0002\\u06c9\\u06ca\\u0007M\\u0002\\u0002\\u06ca\\u06d2',\n  '\\u0007G\\u0002\\u0002\\u06cb\\u06cc\\u0007t\\u0002\\u0002\\u06cc\\u06cd\\u0007',\n  'g\\u0002\\u0002\\u06cd\\u06ce\\u0007x\\u0002\\u0002\\u06ce\\u06cf\\u0007q\\u0002',\n  '\\u0002\\u06cf\\u06d0\\u0007m\\u0002\\u0002\\u06d0\\u06d2\\u0007g\\u0002\\u0002',\n  '\\u06d1\\u06c5\\u0003\\u0002\\u0002\\u0002\\u06d1\\u06cb\\u0003\\u0002\\u0002\\u0002',\n  '\\u06d2\\u00dc\\u0003\\u0002\\u0002\\u0002\\u06d3\\u06d4\\u0007R\\u0002\\u0002',\n  '\\u06d4\\u06d5\\u0007T\\u0002\\u0002\\u06d5\\u06d6\\u0007K\\u0002\\u0002\\u06d6',\n  '\\u06d7\\u0007X\\u0002\\u0002\\u06d7\\u06d8\\u0007K\\u0002\\u0002\\u06d8\\u06d9',\n  '\\u0007N\\u0002\\u0002\\u06d9\\u06da\\u0007G\\u0002\\u0002\\u06da\\u06db\\u0007',\n  'I\\u0002\\u0002\\u06db\\u06dc\\u0007G\\u0002\\u0002\\u06dc\\u06e8\\u0007U\\u0002',\n  '\\u0002\\u06dd\\u06de\\u0007r\\u0002\\u0002\\u06de\\u06df\\u0007t\\u0002\\u0002',\n  '\\u06df\\u06e0\\u0007k\\u0002\\u0002\\u06e0\\u06e1\\u0007x\\u0002\\u0002\\u06e1',\n  '\\u06e2\\u0007k\\u0002\\u0002\\u06e2\\u06e3\\u0007n\\u0002\\u0002\\u06e3\\u06e4',\n  '\\u0007g\\u0002\\u0002\\u06e4\\u06e5\\u0007i\\u0002\\u0002\\u06e5\\u06e6\\u0007',\n  'g\\u0002\\u0002\\u06e6\\u06e8\\u0007u\\u0002\\u0002\\u06e7\\u06d3\\u0003\\u0002',\n  '\\u0002\\u0002\\u06e7\\u06dd\\u0003\\u0002\\u0002\\u0002\\u06e8\\u00de\\u0003\\u0002',\n  '\\u0002\\u0002\\u06e9\\u06ea\\u0007R\\u0002\\u0002\\u06ea\\u06eb\\u0007W\\u0002',\n  '\\u0002\\u06eb\\u06ec\\u0007D\\u0002\\u0002\\u06ec\\u06ed\\u0007N\\u0002\\u0002',\n  '\\u06ed\\u06ee\\u0007K\\u0002\\u0002\\u06ee\\u06f6\\u0007E\\u0002\\u0002\\u06ef',\n  '\\u06f0\\u0007r\\u0002\\u0002\\u06f0\\u06f1\\u0007w\\u0002\\u0002\\u06f1\\u06f2',\n  '\\u0007d\\u0002\\u0002\\u06f2\\u06f3\\u0007n\\u0002\\u0002\\u06f3\\u06f4\\u0007',\n  'k\\u0002\\u0002\\u06f4\\u06f6\\u0007e\\u0002\\u0002\\u06f5\\u06e9\\u0003\\u0002',\n  '\\u0002\\u0002\\u06f5\\u06ef\\u0003\\u0002\\u0002\\u0002\\u06f6\\u00e0\\u0003\\u0002',\n  '\\u0002\\u0002\\u06f7\\u06f8\\u0007Q\\u0002\\u0002\\u06f8\\u06f9\\u0007R\\u0002',\n  '\\u0002\\u06f9\\u06fa\\u0007V\\u0002\\u0002\\u06fa\\u06fb\\u0007K\\u0002\\u0002',\n  '\\u06fb\\u06fc\\u0007Q\\u0002\\u0002\\u06fc\\u0704\\u0007P\\u0002\\u0002\\u06fd',\n  '\\u06fe\\u0007q\\u0002\\u0002\\u06fe\\u06ff\\u0007r\\u0002\\u0002\\u06ff\\u0700',\n  '\\u0007v\\u0002\\u0002\\u0700\\u0701\\u0007k\\u0002\\u0002\\u0701\\u0702\\u0007',\n  'q\\u0002\\u0002\\u0702\\u0704\\u0007p\\u0002\\u0002\\u0703\\u06f7\\u0003\\u0002',\n  '\\u0002\\u0002\\u0703\\u06fd\\u0003\\u0002\\u0002\\u0002\\u0704\\u00e2\\u0003\\u0002',\n  '\\u0002\\u0002\\u0705\\u0706\\u0007G\\u0002\\u0002\\u0706\\u0707\\u0007Z\\u0002',\n  '\\u0002\\u0707\\u0708\\u0007R\\u0002\\u0002\\u0708\\u0709\\u0007N\\u0002\\u0002',\n  '\\u0709\\u070a\\u0007C\\u0002\\u0002\\u070a\\u070b\\u0007K\\u0002\\u0002\\u070b',\n  '\\u0714\\u0007P\\u0002\\u0002\\u070c\\u070d\\u0007g\\u0002\\u0002\\u070d\\u070e',\n  '\\u0007z\\u0002\\u0002\\u070e\\u070f\\u0007r\\u0002\\u0002\\u070f\\u0710\\u0007',\n  'n\\u0002\\u0002\\u0710\\u0711\\u0007c\\u0002\\u0002\\u0711\\u0712\\u0007k\\u0002',\n  '\\u0002\\u0712\\u0714\\u0007p\\u0002\\u0002\\u0713\\u0705\\u0003\\u0002\\u0002',\n  '\\u0002\\u0713\\u070c\\u0003\\u0002\\u0002\\u0002\\u0714\\u00e4\\u0003\\u0002\\u0002',\n  '\\u0002\\u0715\\u0716\\u0007C\\u0002\\u0002\\u0716\\u0717\\u0007P\\u0002\\u0002',\n  '\\u0717\\u0718\\u0007C\\u0002\\u0002\\u0718\\u0719\\u0007N\\u0002\\u0002\\u0719',\n  '\\u071a\\u0007[\\u0002\\u0002\\u071a\\u071b\\u0007\\\\\\u0002\\u0002\\u071b\\u0724',\n  '\\u0007G\\u0002\\u0002\\u071c\\u071d\\u0007c\\u0002\\u0002\\u071d\\u071e\\u0007',\n  'p\\u0002\\u0002\\u071e\\u071f\\u0007c\\u0002\\u0002\\u071f\\u0720\\u0007n\\u0002',\n  '\\u0002\\u0720\\u0721\\u0007{\\u0002\\u0002\\u0721\\u0722\\u0007|\\u0002\\u0002',\n  '\\u0722\\u0724\\u0007g\\u0002\\u0002\\u0723\\u0715\\u0003\\u0002\\u0002\\u0002',\n  '\\u0723\\u071c\\u0003\\u0002\\u0002\\u0002\\u0724\\u00e6\\u0003\\u0002\\u0002\\u0002',\n  '\\u0725\\u0726\\u0007H\\u0002\\u0002\\u0726\\u0727\\u0007Q\\u0002\\u0002\\u0727',\n  '\\u0728\\u0007T\\u0002\\u0002\\u0728\\u0729\\u0007O\\u0002\\u0002\\u0729\\u072a',\n  '\\u0007C\\u0002\\u0002\\u072a\\u0732\\u0007V\\u0002\\u0002\\u072b\\u072c\\u0007',\n  'h\\u0002\\u0002\\u072c\\u072d\\u0007q\\u0002\\u0002\\u072d\\u072e\\u0007t\\u0002',\n  '\\u0002\\u072e\\u072f\\u0007o\\u0002\\u0002\\u072f\\u0730\\u0007c\\u0002\\u0002',\n  '\\u0730\\u0732\\u0007v\\u0002\\u0002\\u0731\\u0725\\u0003\\u0002\\u0002\\u0002',\n  '\\u0731\\u072b\\u0003\\u0002\\u0002\\u0002\\u0732\\u00e8\\u0003\\u0002\\u0002\\u0002',\n  '\\u0733\\u0734\\u0007V\\u0002\\u0002\\u0734\\u0735\\u0007[\\u0002\\u0002\\u0735',\n  '\\u0736\\u0007R\\u0002\\u0002\\u0736\\u073c\\u0007G\\u0002\\u0002\\u0737\\u0738',\n  '\\u0007v\\u0002\\u0002\\u0738\\u0739\\u0007{\\u0002\\u0002\\u0739\\u073a\\u0007',\n  'r\\u0002\\u0002\\u073a\\u073c\\u0007g\\u0002\\u0002\\u073b\\u0733\\u0003\\u0002',\n  '\\u0002\\u0002\\u073b\\u0737\\u0003\\u0002\\u0002\\u0002\\u073c\\u00ea\\u0003\\u0002',\n  '\\u0002\\u0002\\u073d\\u073e\\u0007V\\u0002\\u0002\\u073e\\u073f\\u0007G\\u0002',\n  '\\u0002\\u073f\\u0740\\u0007Z\\u0002\\u0002\\u0740\\u0746\\u0007V\\u0002\\u0002',\n  '\\u0741\\u0742\\u0007v\\u0002\\u0002\\u0742\\u0743\\u0007g\\u0002\\u0002\\u0743',\n  '\\u0744\\u0007z\\u0002\\u0002\\u0744\\u0746\\u0007v\\u0002\\u0002\\u0745\\u073d',\n  '\\u0003\\u0002\\u0002\\u0002\\u0745\\u0741\\u0003\\u0002\\u0002\\u0002\\u0746\\u00ec',\n  '\\u0003\\u0002\\u0002\\u0002\\u0747\\u0748\\u0007I\\u0002\\u0002\\u0748\\u0749',\n  '\\u0007T\\u0002\\u0002\\u0749\\u074a\\u0007C\\u0002\\u0002\\u074a\\u074b\\u0007',\n  'R\\u0002\\u0002\\u074b\\u074c\\u0007J\\u0002\\u0002\\u074c\\u074d\\u0007X\\u0002',\n  '\\u0002\\u074d\\u074e\\u0007K\\u0002\\u0002\\u074e\\u0758\\u0007\\\\\\u0002\\u0002',\n  '\\u074f\\u0750\\u0007i\\u0002\\u0002\\u0750\\u0751\\u0007t\\u0002\\u0002\\u0751',\n  '\\u0752\\u0007c\\u0002\\u0002\\u0752\\u0753\\u0007r\\u0002\\u0002\\u0753\\u0754',\n  '\\u0007j\\u0002\\u0002\\u0754\\u0755\\u0007x\\u0002\\u0002\\u0755\\u0756\\u0007',\n  'k\\u0002\\u0002\\u0756\\u0758\\u0007|\\u0002\\u0002\\u0757\\u0747\\u0003\\u0002',\n  '\\u0002\\u0002\\u0757\\u074f\\u0003\\u0002\\u0002\\u0002\\u0758\\u00ee\\u0003\\u0002',\n  '\\u0002\\u0002\\u0759\\u075a\\u0007N\\u0002\\u0002\\u075a\\u075b\\u0007Q\\u0002',\n  '\\u0002\\u075b\\u075c\\u0007I\\u0002\\u0002\\u075c\\u075d\\u0007K\\u0002\\u0002',\n  '\\u075d\\u075e\\u0007E\\u0002\\u0002\\u075e\\u075f\\u0007C\\u0002\\u0002\\u075f',\n  '\\u0768\\u0007N\\u0002\\u0002\\u0760\\u0761\\u0007n\\u0002\\u0002\\u0761\\u0762',\n  '\\u0007q\\u0002\\u0002\\u0762\\u0763\\u0007i\\u0002\\u0002\\u0763\\u0764\\u0007',\n  'k\\u0002\\u0002\\u0764\\u0765\\u0007e\\u0002\\u0002\\u0765\\u0766\\u0007c\\u0002',\n  '\\u0002\\u0766\\u0768\\u0007n\\u0002\\u0002\\u0767\\u0759\\u0003\\u0002\\u0002',\n  '\\u0002\\u0767\\u0760\\u0003\\u0002\\u0002\\u0002\\u0768\\u00f0\\u0003\\u0002\\u0002',\n  '\\u0002\\u0769\\u076a\\u0007F\\u0002\\u0002\\u076a\\u076b\\u0007K\\u0002\\u0002',\n  '\\u076b\\u076c\\u0007U\\u0002\\u0002\\u076c\\u076d\\u0007V\\u0002\\u0002\\u076d',\n  '\\u076e\\u0007T\\u0002\\u0002\\u076e\\u076f\\u0007K\\u0002\\u0002\\u076f\\u0770',\n  '\\u0007D\\u0002\\u0002\\u0770\\u0771\\u0007W\\u0002\\u0002\\u0771\\u0772\\u0007',\n  'V\\u0002\\u0002\\u0772\\u0773\\u0007G\\u0002\\u0002\\u0773\\u0780\\u0007F\\u0002',\n  '\\u0002\\u0774\\u0775\\u0007f\\u0002\\u0002\\u0775\\u0776\\u0007k\\u0002\\u0002',\n  '\\u0776\\u0777\\u0007u\\u0002\\u0002\\u0777\\u0778\\u0007v\\u0002\\u0002\\u0778',\n  '\\u0779\\u0007t\\u0002\\u0002\\u0779\\u077a\\u0007k\\u0002\\u0002\\u077a\\u077b',\n  '\\u0007d\\u0002\\u0002\\u077b\\u077c\\u0007w\\u0002\\u0002\\u077c\\u077d\\u0007',\n  'v\\u0002\\u0002\\u077d\\u077e\\u0007g\\u0002\\u0002\\u077e\\u0780\\u0007f\\u0002',\n  '\\u0002\\u077f\\u0769\\u0003\\u0002\\u0002\\u0002\\u077f\\u0774\\u0003\\u0002\\u0002',\n  '\\u0002\\u0780\\u00f2\\u0003\\u0002\\u0002\\u0002\\u0781\\u0782\\u0007E\\u0002',\n  '\\u0002\\u0782\\u0783\\u0007C\\u0002\\u0002\\u0783\\u0784\\u0007U\\u0002\\u0002',\n  '\\u0784\\u078a\\u0007V\\u0002\\u0002\\u0785\\u0786\\u0007e\\u0002\\u0002\\u0786',\n  '\\u0787\\u0007c\\u0002\\u0002\\u0787\\u0788\\u0007u\\u0002\\u0002\\u0788\\u078a',\n  '\\u0007v\\u0002\\u0002\\u0789\\u0781\\u0003\\u0002\\u0002\\u0002\\u0789\\u0785',\n  '\\u0003\\u0002\\u0002\\u0002\\u078a\\u00f4\\u0003\\u0002\\u0002\\u0002\\u078b\\u078c',\n  '\\u0007V\\u0002\\u0002\\u078c\\u078d\\u0007T\\u0002\\u0002\\u078d\\u078e\\u0007',\n  '[\\u0002\\u0002\\u078e\\u078f\\u0007a\\u0002\\u0002\\u078f\\u0790\\u0007E\\u0002',\n  '\\u0002\\u0790\\u0791\\u0007C\\u0002\\u0002\\u0791\\u0792\\u0007U\\u0002\\u0002',\n  '\\u0792\\u079c\\u0007V\\u0002\\u0002\\u0793\\u0794\\u0007v\\u0002\\u0002\\u0794',\n  '\\u0795\\u0007t\\u0002\\u0002\\u0795\\u0796\\u0007{\\u0002\\u0002\\u0796\\u0797',\n  '\\u0007a\\u0002\\u0002\\u0797\\u0798\\u0007e\\u0002\\u0002\\u0798\\u0799\\u0007',\n  'c\\u0002\\u0002\\u0799\\u079a\\u0007u\\u0002\\u0002\\u079a\\u079c\\u0007v\\u0002',\n  '\\u0002\\u079b\\u078b\\u0003\\u0002\\u0002\\u0002\\u079b\\u0793\\u0003\\u0002\\u0002',\n  '\\u0002\\u079c\\u00f6\\u0003\\u0002\\u0002\\u0002\\u079d\\u079e\\u0007U\\u0002',\n  '\\u0002\\u079e\\u079f\\u0007J\\u0002\\u0002\\u079f\\u07a0\\u0007Q\\u0002\\u0002',\n  '\\u07a0\\u07a6\\u0007Y\\u0002\\u0002\\u07a1\\u07a2\\u0007u\\u0002\\u0002\\u07a2',\n  '\\u07a3\\u0007j\\u0002\\u0002\\u07a3\\u07a4\\u0007q\\u0002\\u0002\\u07a4\\u07a6',\n  '\\u0007y\\u0002\\u0002\\u07a5\\u079d\\u0003\\u0002\\u0002\\u0002\\u07a5\\u07a1',\n  '\\u0003\\u0002\\u0002\\u0002\\u07a6\\u00f8\\u0003\\u0002\\u0002\\u0002\\u07a7\\u07a8',\n  '\\u0007V\\u0002\\u0002\\u07a8\\u07a9\\u0007C\\u0002\\u0002\\u07a9\\u07aa\\u0007',\n  'D\\u0002\\u0002\\u07aa\\u07ab\\u0007N\\u0002\\u0002\\u07ab\\u07ac\\u0007G\\u0002',\n  '\\u0002\\u07ac\\u07b4\\u0007U\\u0002\\u0002\\u07ad\\u07ae\\u0007v\\u0002\\u0002',\n  '\\u07ae\\u07af\\u0007c\\u0002\\u0002\\u07af\\u07b0\\u0007d\\u0002\\u0002\\u07b0',\n  '\\u07b1\\u0007n\\u0002\\u0002\\u07b1\\u07b2\\u0007g\\u0002\\u0002\\u07b2\\u07b4',\n  '\\u0007u\\u0002\\u0002\\u07b3\\u07a7\\u0003\\u0002\\u0002\\u0002\\u07b3\\u07ad',\n  '\\u0003\\u0002\\u0002\\u0002\\u07b4\\u00fa\\u0003\\u0002\\u0002\\u0002\\u07b5\\u07b6',\n  '\\u0007U\\u0002\\u0002\\u07b6\\u07b7\\u0007E\\u0002\\u0002\\u07b7\\u07b8\\u0007',\n  'J\\u0002\\u0002\\u07b8\\u07b9\\u0007G\\u0002\\u0002\\u07b9\\u07ba\\u0007O\\u0002',\n  '\\u0002\\u07ba\\u07bb\\u0007C\\u0002\\u0002\\u07bb\\u07c4\\u0007U\\u0002\\u0002',\n  '\\u07bc\\u07bd\\u0007u\\u0002\\u0002\\u07bd\\u07be\\u0007e\\u0002\\u0002\\u07be',\n  '\\u07bf\\u0007j\\u0002\\u0002\\u07bf\\u07c0\\u0007g\\u0002\\u0002\\u07c0\\u07c1',\n  '\\u0007o\\u0002\\u0002\\u07c1\\u07c2\\u0007c\\u0002\\u0002\\u07c2\\u07c4\\u0007',\n  'u\\u0002\\u0002\\u07c3\\u07b5\\u0003\\u0002\\u0002\\u0002\\u07c3\\u07bc\\u0003',\n  '\\u0002\\u0002\\u0002\\u07c4\\u00fc\\u0003\\u0002\\u0002\\u0002\\u07c5\\u07c6\\u0007',\n  'E\\u0002\\u0002\\u07c6\\u07c7\\u0007C\\u0002\\u0002\\u07c7\\u07c8\\u0007V\\u0002',\n  '\\u0002\\u07c8\\u07c9\\u0007C\\u0002\\u0002\\u07c9\\u07ca\\u0007N\\u0002\\u0002',\n  '\\u07ca\\u07cb\\u0007Q\\u0002\\u0002\\u07cb\\u07cc\\u0007I\\u0002\\u0002\\u07cc',\n  '\\u07d6\\u0007U\\u0002\\u0002\\u07cd\\u07ce\\u0007e\\u0002\\u0002\\u07ce\\u07cf',\n  '\\u0007c\\u0002\\u0002\\u07cf\\u07d0\\u0007v\\u0002\\u0002\\u07d0\\u07d1\\u0007',\n  'c\\u0002\\u0002\\u07d1\\u07d2\\u0007n\\u0002\\u0002\\u07d2\\u07d3\\u0007q\\u0002',\n  '\\u0002\\u07d3\\u07d4\\u0007i\\u0002\\u0002\\u07d4\\u07d6\\u0007u\\u0002\\u0002',\n  '\\u07d5\\u07c5\\u0003\\u0002\\u0002\\u0002\\u07d5\\u07cd\\u0003\\u0002\\u0002\\u0002',\n  '\\u07d6\\u00fe\\u0003\\u0002\\u0002\\u0002\\u07d7\\u07d8\\u0007E\\u0002\\u0002',\n  '\\u07d8\\u07d9\\u0007Q\\u0002\\u0002\\u07d9\\u07da\\u0007N\\u0002\\u0002\\u07da',\n  '\\u07db\\u0007W\\u0002\\u0002\\u07db\\u07dc\\u0007O\\u0002\\u0002\\u07dc\\u07dd',\n  '\\u0007P\\u0002\\u0002\\u07dd\\u07e6\\u0007U\\u0002\\u0002\\u07de\\u07df\\u0007',\n  'e\\u0002\\u0002\\u07df\\u07e0\\u0007q\\u0002\\u0002\\u07e0\\u07e1\\u0007n\\u0002',\n  '\\u0002\\u07e1\\u07e2\\u0007w\\u0002\\u0002\\u07e2\\u07e3\\u0007o\\u0002\\u0002',\n  '\\u07e3\\u07e4\\u0007p\\u0002\\u0002\\u07e4\\u07e6\\u0007u\\u0002\\u0002\\u07e5',\n  '\\u07d7\\u0003\\u0002\\u0002\\u0002\\u07e5\\u07de\\u0003\\u0002\\u0002\\u0002\\u07e6',\n  '\\u0100\\u0003\\u0002\\u0002\\u0002\\u07e7\\u07e8\\u0007E\\u0002\\u0002\\u07e8',\n  '\\u07e9\\u0007Q\\u0002\\u0002\\u07e9\\u07ea\\u0007N\\u0002\\u0002\\u07ea\\u07eb',\n  '\\u0007W\\u0002\\u0002\\u07eb\\u07ec\\u0007O\\u0002\\u0002\\u07ec\\u07f4\\u0007',\n  'P\\u0002\\u0002\\u07ed\\u07ee\\u0007e\\u0002\\u0002\\u07ee\\u07ef\\u0007q\\u0002',\n  '\\u0002\\u07ef\\u07f0\\u0007n\\u0002\\u0002\\u07f0\\u07f1\\u0007w\\u0002\\u0002',\n  '\\u07f1\\u07f2\\u0007o\\u0002\\u0002\\u07f2\\u07f4\\u0007p\\u0002\\u0002\\u07f3',\n  '\\u07e7\\u0003\\u0002\\u0002\\u0002\\u07f3\\u07ed\\u0003\\u0002\\u0002\\u0002\\u07f4',\n  '\\u0102\\u0003\\u0002\\u0002\\u0002\\u07f5\\u07f6\\u0007W\\u0002\\u0002\\u07f6',\n  '\\u07f7\\u0007U\\u0002\\u0002\\u07f7\\u07fc\\u0007G\\u0002\\u0002\\u07f8\\u07f9',\n  '\\u0007w\\u0002\\u0002\\u07f9\\u07fa\\u0007u\\u0002\\u0002\\u07fa\\u07fc\\u0007',\n  'g\\u0002\\u0002\\u07fb\\u07f5\\u0003\\u0002\\u0002\\u0002\\u07fb\\u07f8\\u0003',\n  '\\u0002\\u0002\\u0002\\u07fc\\u0104\\u0003\\u0002\\u0002\\u0002\\u07fd\\u07fe\\u0007',\n  'R\\u0002\\u0002\\u07fe\\u07ff\\u0007C\\u0002\\u0002\\u07ff\\u0800\\u0007T\\u0002',\n  '\\u0002\\u0800\\u0801\\u0007V\\u0002\\u0002\\u0801\\u0802\\u0007K\\u0002\\u0002',\n  '\\u0802\\u0803\\u0007V\\u0002\\u0002\\u0803\\u0804\\u0007K\\u0002\\u0002\\u0804',\n  '\\u0805\\u0007Q\\u0002\\u0002\\u0805\\u0806\\u0007P\\u0002\\u0002\\u0806\\u0812',\n  '\\u0007U\\u0002\\u0002\\u0807\\u0808\\u0007r\\u0002\\u0002\\u0808\\u0809\\u0007',\n  'c\\u0002\\u0002\\u0809\\u080a\\u0007t\\u0002\\u0002\\u080a\\u080b\\u0007v\\u0002',\n  '\\u0002\\u080b\\u080c\\u0007k\\u0002\\u0002\\u080c\\u080d\\u0007v\\u0002\\u0002',\n  '\\u080d\\u080e\\u0007k\\u0002\\u0002\\u080e\\u080f\\u0007q\\u0002\\u0002\\u080f',\n  '\\u0810\\u0007p\\u0002\\u0002\\u0810\\u0812\\u0007u\\u0002\\u0002\\u0811\\u07fd',\n  '\\u0003\\u0002\\u0002\\u0002\\u0811\\u0807\\u0003\\u0002\\u0002\\u0002\\u0812\\u0106',\n  '\\u0003\\u0002\\u0002\\u0002\\u0813\\u0814\\u0007H\\u0002\\u0002\\u0814\\u0815',\n  '\\u0007W\\u0002\\u0002\\u0815\\u0816\\u0007P\\u0002\\u0002\\u0816\\u0817\\u0007',\n  'E\\u0002\\u0002\\u0817\\u0818\\u0007V\\u0002\\u0002\\u0818\\u0819\\u0007K\\u0002',\n  '\\u0002\\u0819\\u081a\\u0007Q\\u0002\\u0002\\u081a\\u081b\\u0007P\\u0002\\u0002',\n  '\\u081b\\u0826\\u0007U\\u0002\\u0002\\u081c\\u081d\\u0007h\\u0002\\u0002\\u081d',\n  '\\u081e\\u0007w\\u0002\\u0002\\u081e\\u081f\\u0007p\\u0002\\u0002\\u081f\\u0820',\n  '\\u0007e\\u0002\\u0002\\u0820\\u0821\\u0007v\\u0002\\u0002\\u0821\\u0822\\u0007',\n  'k\\u0002\\u0002\\u0822\\u0823\\u0007q\\u0002\\u0002\\u0823\\u0824\\u0007p\\u0002',\n  '\\u0002\\u0824\\u0826\\u0007u\\u0002\\u0002\\u0825\\u0813\\u0003\\u0002\\u0002',\n  '\\u0002\\u0825\\u081c\\u0003\\u0002\\u0002\\u0002\\u0826\\u0108\\u0003\\u0002\\u0002',\n  '\\u0002\\u0827\\u0828\\u0007F\\u0002\\u0002\\u0828\\u0829\\u0007T\\u0002\\u0002',\n  '\\u0829\\u082a\\u0007Q\\u0002\\u0002\\u082a\\u0830\\u0007R\\u0002\\u0002\\u082b',\n  '\\u082c\\u0007f\\u0002\\u0002\\u082c\\u082d\\u0007t\\u0002\\u0002\\u082d\\u082e',\n  '\\u0007q\\u0002\\u0002\\u082e\\u0830\\u0007r\\u0002\\u0002\\u082f\\u0827\\u0003',\n  '\\u0002\\u0002\\u0002\\u082f\\u082b\\u0003\\u0002\\u0002\\u0002\\u0830\\u010a\\u0003',\n  '\\u0002\\u0002\\u0002\\u0831\\u0832\\u0007W\\u0002\\u0002\\u0832\\u0833\\u0007',\n  'P\\u0002\\u0002\\u0833\\u0834\\u0007K\\u0002\\u0002\\u0834\\u0835\\u0007Q\\u0002',\n  '\\u0002\\u0835\\u083c\\u0007P\\u0002\\u0002\\u0836\\u0837\\u0007w\\u0002\\u0002',\n  '\\u0837\\u0838\\u0007p\\u0002\\u0002\\u0838\\u0839\\u0007k\\u0002\\u0002\\u0839',\n  '\\u083a\\u0007q\\u0002\\u0002\\u083a\\u083c\\u0007p\\u0002\\u0002\\u083b\\u0831',\n  '\\u0003\\u0002\\u0002\\u0002\\u083b\\u0836\\u0003\\u0002\\u0002\\u0002\\u083c\\u010c',\n  '\\u0003\\u0002\\u0002\\u0002\\u083d\\u083e\\u0007G\\u0002\\u0002\\u083e\\u083f',\n  '\\u0007Z\\u0002\\u0002\\u083f\\u0840\\u0007E\\u0002\\u0002\\u0840\\u0841\\u0007',\n  'G\\u0002\\u0002\\u0841\\u0842\\u0007R\\u0002\\u0002\\u0842\\u084a\\u0007V\\u0002',\n  '\\u0002\\u0843\\u0844\\u0007g\\u0002\\u0002\\u0844\\u0845\\u0007z\\u0002\\u0002',\n  '\\u0845\\u0846\\u0007e\\u0002\\u0002\\u0846\\u0847\\u0007g\\u0002\\u0002\\u0847',\n  '\\u0848\\u0007r\\u0002\\u0002\\u0848\\u084a\\u0007v\\u0002\\u0002\\u0849\\u083d',\n  '\\u0003\\u0002\\u0002\\u0002\\u0849\\u0843\\u0003\\u0002\\u0002\\u0002\\u084a\\u010e',\n  '\\u0003\\u0002\\u0002\\u0002\\u084b\\u084c\\u0007K\\u0002\\u0002\\u084c\\u084d',\n  '\\u0007P\\u0002\\u0002\\u084d\\u084e\\u0007V\\u0002\\u0002\\u084e\\u084f\\u0007',\n  'G\\u0002\\u0002\\u084f\\u0850\\u0007T\\u0002\\u0002\\u0850\\u0851\\u0007U\\u0002',\n  '\\u0002\\u0851\\u0852\\u0007G\\u0002\\u0002\\u0852\\u0853\\u0007E\\u0002\\u0002',\n  '\\u0853\\u085e\\u0007V\\u0002\\u0002\\u0854\\u0855\\u0007k\\u0002\\u0002\\u0855',\n  '\\u0856\\u0007p\\u0002\\u0002\\u0856\\u0857\\u0007v\\u0002\\u0002\\u0857\\u0858',\n  '\\u0007g\\u0002\\u0002\\u0858\\u0859\\u0007t\\u0002\\u0002\\u0859\\u085a\\u0007',\n  'u\\u0002\\u0002\\u085a\\u085b\\u0007g\\u0002\\u0002\\u085b\\u085c\\u0007e\\u0002',\n  '\\u0002\\u085c\\u085e\\u0007v\\u0002\\u0002\\u085d\\u084b\\u0003\\u0002\\u0002',\n  '\\u0002\\u085d\\u0854\\u0003\\u0002\\u0002\\u0002\\u085e\\u0110\\u0003\\u0002\\u0002',\n  '\\u0002\\u085f\\u0860\\u0007V\\u0002\\u0002\\u0860\\u0864\\u0007Q\\u0002\\u0002',\n  '\\u0861\\u0862\\u0007v\\u0002\\u0002\\u0862\\u0864\\u0007q\\u0002\\u0002\\u0863',\n  '\\u085f\\u0003\\u0002\\u0002\\u0002\\u0863\\u0861\\u0003\\u0002\\u0002\\u0002\\u0864',\n  '\\u0112\\u0003\\u0002\\u0002\\u0002\\u0865\\u0866\\u0007U\\u0002\\u0002\\u0866',\n  '\\u0867\\u0007[\\u0002\\u0002\\u0867\\u0868\\u0007U\\u0002\\u0002\\u0868\\u0869',\n  '\\u0007V\\u0002\\u0002\\u0869\\u086a\\u0007G\\u0002\\u0002\\u086a\\u0872\\u0007',\n  'O\\u0002\\u0002\\u086b\\u086c\\u0007u\\u0002\\u0002\\u086c\\u086d\\u0007{\\u0002',\n  '\\u0002\\u086d\\u086e\\u0007u\\u0002\\u0002\\u086e\\u086f\\u0007v\\u0002\\u0002',\n  '\\u086f\\u0870\\u0007g\\u0002\\u0002\\u0870\\u0872\\u0007o\\u0002\\u0002\\u0871',\n  '\\u0865\\u0003\\u0002\\u0002\\u0002\\u0871\\u086b\\u0003\\u0002\\u0002\\u0002\\u0872',\n  '\\u0114\\u0003\\u0002\\u0002\\u0002\\u0873\\u0874\\u0007D\\u0002\\u0002\\u0874',\n  '\\u0875\\u0007G\\u0002\\u0002\\u0875\\u0876\\u0007T\\u0002\\u0002\\u0876\\u0877',\n  '\\u0007P\\u0002\\u0002\\u0877\\u0878\\u0007Q\\u0002\\u0002\\u0878\\u0879\\u0007',\n  'W\\u0002\\u0002\\u0879\\u087a\\u0007N\\u0002\\u0002\\u087a\\u087b\\u0007N\\u0002',\n  '\\u0002\\u087b\\u0886\\u0007K\\u0002\\u0002\\u087c\\u087d\\u0007d\\u0002\\u0002',\n  '\\u087d\\u087e\\u0007g\\u0002\\u0002\\u087e\\u087f\\u0007t\\u0002\\u0002\\u087f',\n  '\\u0880\\u0007p\\u0002\\u0002\\u0880\\u0881\\u0007q\\u0002\\u0002\\u0881\\u0882',\n  '\\u0007w\\u0002\\u0002\\u0882\\u0883\\u0007n\\u0002\\u0002\\u0883\\u0884\\u0007',\n  'n\\u0002\\u0002\\u0884\\u0886\\u0007k\\u0002\\u0002\\u0885\\u0873\\u0003\\u0002',\n  '\\u0002\\u0002\\u0885\\u087c\\u0003\\u0002\\u0002\\u0002\\u0886\\u0116\\u0003\\u0002',\n  '\\u0002\\u0002\\u0887\\u0888\\u0007R\\u0002\\u0002\\u0888\\u0889\\u0007Q\\u0002',\n  '\\u0002\\u0889\\u088a\\u0007K\\u0002\\u0002\\u088a\\u088b\\u0007U\\u0002\\u0002',\n  '\\u088b\\u088c\\u0007U\\u0002\\u0002\\u088c\\u088d\\u0007Q\\u0002\\u0002\\u088d',\n  '\\u088e\\u0007P\\u0002\\u0002\\u088e\\u088f\\u0007K\\u0002\\u0002\\u088f\\u0890',\n  '\\u0007\\\\\\u0002\\u0002\\u0890\\u0891\\u0007G\\u0002\\u0002\\u0891\\u089e\\u0007',\n  'F\\u0002\\u0002\\u0892\\u0893\\u0007r\\u0002\\u0002\\u0893\\u0894\\u0007q\\u0002',\n  '\\u0002\\u0894\\u0895\\u0007k\\u0002\\u0002\\u0895\\u0896\\u0007u\\u0002\\u0002',\n  '\\u0896\\u0897\\u0007u\\u0002\\u0002\\u0897\\u0898\\u0007q\\u0002\\u0002\\u0898',\n  '\\u0899\\u0007p\\u0002\\u0002\\u0899\\u089a\\u0007k\\u0002\\u0002\\u089a\\u089b',\n  '\\u0007|\\u0002\\u0002\\u089b\\u089c\\u0007g\\u0002\\u0002\\u089c\\u089e\\u0007',\n  'f\\u0002\\u0002\\u089d\\u0887\\u0003\\u0002\\u0002\\u0002\\u089d\\u0892\\u0003',\n  '\\u0002\\u0002\\u0002\\u089e\\u0118\\u0003\\u0002\\u0002\\u0002\\u089f\\u08a0\\u0007',\n  'V\\u0002\\u0002\\u08a0\\u08a1\\u0007C\\u0002\\u0002\\u08a1\\u08a2\\u0007D\\u0002',\n  '\\u0002\\u08a2\\u08a3\\u0007N\\u0002\\u0002\\u08a3\\u08a4\\u0007G\\u0002\\u0002',\n  '\\u08a4\\u08a5\\u0007U\\u0002\\u0002\\u08a5\\u08a6\\u0007C\\u0002\\u0002\\u08a6',\n  '\\u08a7\\u0007O\\u0002\\u0002\\u08a7\\u08a8\\u0007R\\u0002\\u0002\\u08a8\\u08a9',\n  '\\u0007N\\u0002\\u0002\\u08a9\\u08b6\\u0007G\\u0002\\u0002\\u08aa\\u08ab\\u0007',\n  'v\\u0002\\u0002\\u08ab\\u08ac\\u0007c\\u0002\\u0002\\u08ac\\u08ad\\u0007d\\u0002',\n  '\\u0002\\u08ad\\u08ae\\u0007n\\u0002\\u0002\\u08ae\\u08af\\u0007g\\u0002\\u0002',\n  '\\u08af\\u08b0\\u0007u\\u0002\\u0002\\u08b0\\u08b1\\u0007c\\u0002\\u0002\\u08b1',\n  '\\u08b2\\u0007o\\u0002\\u0002\\u08b2\\u08b3\\u0007r\\u0002\\u0002\\u08b3\\u08b4',\n  '\\u0007n\\u0002\\u0002\\u08b4\\u08b6\\u0007g\\u0002\\u0002\\u08b5\\u089f\\u0003',\n  '\\u0002\\u0002\\u0002\\u08b5\\u08aa\\u0003\\u0002\\u0002\\u0002\\u08b6\\u011a\\u0003',\n  '\\u0002\\u0002\\u0002\\u08b7\\u08b8\\u0007C\\u0002\\u0002\\u08b8\\u08b9\\u0007',\n  'N\\u0002\\u0002\\u08b9\\u08ba\\u0007V\\u0002\\u0002\\u08ba\\u08bb\\u0007G\\u0002',\n  '\\u0002\\u08bb\\u08c2\\u0007T\\u0002\\u0002\\u08bc\\u08bd\\u0007c\\u0002\\u0002',\n  '\\u08bd\\u08be\\u0007n\\u0002\\u0002\\u08be\\u08bf\\u0007v\\u0002\\u0002\\u08bf',\n  '\\u08c0\\u0007g\\u0002\\u0002\\u08c0\\u08c2\\u0007t\\u0002\\u0002\\u08c1\\u08b7',\n  '\\u0003\\u0002\\u0002\\u0002\\u08c1\\u08bc\\u0003\\u0002\\u0002\\u0002\\u08c2\\u011c',\n  '\\u0003\\u0002\\u0002\\u0002\\u08c3\\u08c4\\u0007T\\u0002\\u0002\\u08c4\\u08c5',\n  '\\u0007G\\u0002\\u0002\\u08c5\\u08c6\\u0007P\\u0002\\u0002\\u08c6\\u08c7\\u0007',\n  'C\\u0002\\u0002\\u08c7\\u08c8\\u0007O\\u0002\\u0002\\u08c8\\u08d0\\u0007G\\u0002',\n  '\\u0002\\u08c9\\u08ca\\u0007t\\u0002\\u0002\\u08ca\\u08cb\\u0007g\\u0002\\u0002',\n  '\\u08cb\\u08cc\\u0007p\\u0002\\u0002\\u08cc\\u08cd\\u0007c\\u0002\\u0002\\u08cd',\n  '\\u08ce\\u0007o\\u0002\\u0002\\u08ce\\u08d0\\u0007g\\u0002\\u0002\\u08cf\\u08c3',\n  '\\u0003\\u0002\\u0002\\u0002\\u08cf\\u08c9\\u0003\\u0002\\u0002\\u0002\\u08d0\\u011e',\n  '\\u0003\\u0002\\u0002\\u0002\\u08d1\\u08d2\\u0007W\\u0002\\u0002\\u08d2\\u08d3',\n  '\\u0007P\\u0002\\u0002\\u08d3\\u08d4\\u0007P\\u0002\\u0002\\u08d4\\u08d5\\u0007',\n  'G\\u0002\\u0002\\u08d5\\u08d6\\u0007U\\u0002\\u0002\\u08d6\\u08de\\u0007V\\u0002',\n  '\\u0002\\u08d7\\u08d8\\u0007w\\u0002\\u0002\\u08d8\\u08d9\\u0007p\\u0002\\u0002',\n  '\\u08d9\\u08da\\u0007p\\u0002\\u0002\\u08da\\u08db\\u0007g\\u0002\\u0002\\u08db',\n  '\\u08dc\\u0007u\\u0002\\u0002\\u08dc\\u08de\\u0007v\\u0002\\u0002\\u08dd\\u08d1',\n  '\\u0003\\u0002\\u0002\\u0002\\u08dd\\u08d7\\u0003\\u0002\\u0002\\u0002\\u08de\\u0120',\n  '\\u0003\\u0002\\u0002\\u0002\\u08df\\u08e0\\u0007Q\\u0002\\u0002\\u08e0\\u08e1',\n  '\\u0007T\\u0002\\u0002\\u08e1\\u08e2\\u0007F\\u0002\\u0002\\u08e2\\u08e3\\u0007',\n  'K\\u0002\\u0002\\u08e3\\u08e4\\u0007P\\u0002\\u0002\\u08e4\\u08e5\\u0007C\\u0002',\n  '\\u0002\\u08e5\\u08e6\\u0007N\\u0002\\u0002\\u08e6\\u08e7\\u0007K\\u0002\\u0002',\n  '\\u08e7\\u08e8\\u0007V\\u0002\\u0002\\u08e8\\u08f4\\u0007[\\u0002\\u0002\\u08e9',\n  '\\u08ea\\u0007q\\u0002\\u0002\\u08ea\\u08eb\\u0007t\\u0002\\u0002\\u08eb\\u08ec',\n  '\\u0007f\\u0002\\u0002\\u08ec\\u08ed\\u0007k\\u0002\\u0002\\u08ed\\u08ee\\u0007',\n  'p\\u0002\\u0002\\u08ee\\u08ef\\u0007c\\u0002\\u0002\\u08ef\\u08f0\\u0007n\\u0002',\n  '\\u0002\\u08f0\\u08f1\\u0007k\\u0002\\u0002\\u08f1\\u08f2\\u0007v\\u0002\\u0002',\n  '\\u08f2\\u08f4\\u0007{\\u0002\\u0002\\u08f3\\u08df\\u0003\\u0002\\u0002\\u0002',\n  '\\u08f3\\u08e9\\u0003\\u0002\\u0002\\u0002\\u08f4\\u0122\\u0003\\u0002\\u0002\\u0002',\n  '\\u08f5\\u08f6\\u0007C\\u0002\\u0002\\u08f6\\u08f7\\u0007T\\u0002\\u0002\\u08f7',\n  '\\u08f8\\u0007T\\u0002\\u0002\\u08f8\\u08f9\\u0007C\\u0002\\u0002\\u08f9\\u0900',\n  '\\u0007[\\u0002\\u0002\\u08fa\\u08fb\\u0007c\\u0002\\u0002\\u08fb\\u08fc\\u0007',\n  't\\u0002\\u0002\\u08fc\\u08fd\\u0007t\\u0002\\u0002\\u08fd\\u08fe\\u0007c\\u0002',\n  '\\u0002\\u08fe\\u0900\\u0007{\\u0002\\u0002\\u08ff\\u08f5\\u0003\\u0002\\u0002',\n  '\\u0002\\u08ff\\u08fa\\u0003\\u0002\\u0002\\u0002\\u0900\\u0124\\u0003\\u0002\\u0002',\n  '\\u0002\\u0901\\u0902\\u0007O\\u0002\\u0002\\u0902\\u0903\\u0007C\\u0002\\u0002',\n  '\\u0903\\u0908\\u0007R\\u0002\\u0002\\u0904\\u0905\\u0007o\\u0002\\u0002\\u0905',\n  '\\u0906\\u0007c\\u0002\\u0002\\u0906\\u0908\\u0007r\\u0002\\u0002\\u0907\\u0901',\n  '\\u0003\\u0002\\u0002\\u0002\\u0907\\u0904\\u0003\\u0002\\u0002\\u0002\\u0908\\u0126',\n  '\\u0003\\u0002\\u0002\\u0002\\u0909\\u090a\\u0007U\\u0002\\u0002\\u090a\\u090b',\n  '\\u0007G\\u0002\\u0002\\u090b\\u0910\\u0007V\\u0002\\u0002\\u090c\\u090d\\u0007',\n  'u\\u0002\\u0002\\u090d\\u090e\\u0007g\\u0002\\u0002\\u090e\\u0910\\u0007v\\u0002',\n  '\\u0002\\u090f\\u0909\\u0003\\u0002\\u0002\\u0002\\u090f\\u090c\\u0003\\u0002\\u0002',\n  '\\u0002\\u0910\\u0128\\u0003\\u0002\\u0002\\u0002\\u0911\\u0912\\u0007T\\u0002',\n  '\\u0002\\u0912\\u0913\\u0007G\\u0002\\u0002\\u0913\\u0914\\u0007U\\u0002\\u0002',\n  '\\u0914\\u0915\\u0007G\\u0002\\u0002\\u0915\\u091c\\u0007V\\u0002\\u0002\\u0916',\n  '\\u0917\\u0007t\\u0002\\u0002\\u0917\\u0918\\u0007g\\u0002\\u0002\\u0918\\u0919',\n  '\\u0007u\\u0002\\u0002\\u0919\\u091a\\u0007g\\u0002\\u0002\\u091a\\u091c\\u0007',\n  'v\\u0002\\u0002\\u091b\\u0911\\u0003\\u0002\\u0002\\u0002\\u091b\\u0916\\u0003',\n  '\\u0002\\u0002\\u0002\\u091c\\u012a\\u0003\\u0002\\u0002\\u0002\\u091d\\u091e\\u0007',\n  'U\\u0002\\u0002\\u091e\\u091f\\u0007G\\u0002\\u0002\\u091f\\u0920\\u0007U\\u0002',\n  '\\u0002\\u0920\\u0921\\u0007U\\u0002\\u0002\\u0921\\u0922\\u0007K\\u0002\\u0002',\n  '\\u0922\\u0923\\u0007Q\\u0002\\u0002\\u0923\\u092c\\u0007P\\u0002\\u0002\\u0924',\n  '\\u0925\\u0007u\\u0002\\u0002\\u0925\\u0926\\u0007g\\u0002\\u0002\\u0926\\u0927',\n  '\\u0007u\\u0002\\u0002\\u0927\\u0928\\u0007u\\u0002\\u0002\\u0928\\u0929\\u0007',\n  'k\\u0002\\u0002\\u0929\\u092a\\u0007q\\u0002\\u0002\\u092a\\u092c\\u0007p\\u0002',\n  '\\u0002\\u092b\\u091d\\u0003\\u0002\\u0002\\u0002\\u092b\\u0924\\u0003\\u0002\\u0002',\n  '\\u0002\\u092c\\u012c\\u0003\\u0002\\u0002\\u0002\\u092d\\u092e\\u0007F\\u0002',\n  '\\u0002\\u092e\\u092f\\u0007C\\u0002\\u0002\\u092f\\u0930\\u0007V\\u0002\\u0002',\n  '\\u0930\\u0936\\u0007C\\u0002\\u0002\\u0931\\u0932\\u0007f\\u0002\\u0002\\u0932',\n  '\\u0933\\u0007c\\u0002\\u0002\\u0933\\u0934\\u0007v\\u0002\\u0002\\u0934\\u0936',\n  '\\u0007c\\u0002\\u0002\\u0935\\u092d\\u0003\\u0002\\u0002\\u0002\\u0935\\u0931',\n  '\\u0003\\u0002\\u0002\\u0002\\u0936\\u012e\\u0003\\u0002\\u0002\\u0002\\u0937\\u0938',\n  '\\u0007U\\u0002\\u0002\\u0938\\u0939\\u0007V\\u0002\\u0002\\u0939\\u093a\\u0007',\n  'C\\u0002\\u0002\\u093a\\u093b\\u0007T\\u0002\\u0002\\u093b\\u0942\\u0007V\\u0002',\n  '\\u0002\\u093c\\u093d\\u0007u\\u0002\\u0002\\u093d\\u093e\\u0007v\\u0002\\u0002',\n  '\\u093e\\u093f\\u0007c\\u0002\\u0002\\u093f\\u0940\\u0007t\\u0002\\u0002\\u0940',\n  '\\u0942\\u0007v\\u0002\\u0002\\u0941\\u0937\\u0003\\u0002\\u0002\\u0002\\u0941',\n  '\\u093c\\u0003\\u0002\\u0002\\u0002\\u0942\\u0130\\u0003\\u0002\\u0002\\u0002\\u0943',\n  '\\u0944\\u0007V\\u0002\\u0002\\u0944\\u0945\\u0007T\\u0002\\u0002\\u0945\\u0946',\n  '\\u0007C\\u0002\\u0002\\u0946\\u0947\\u0007P\\u0002\\u0002\\u0947\\u0948\\u0007',\n  'U\\u0002\\u0002\\u0948\\u0949\\u0007C\\u0002\\u0002\\u0949\\u094a\\u0007E\\u0002',\n  '\\u0002\\u094a\\u094b\\u0007V\\u0002\\u0002\\u094b\\u094c\\u0007K\\u0002\\u0002',\n  '\\u094c\\u094d\\u0007Q\\u0002\\u0002\\u094d\\u095a\\u0007P\\u0002\\u0002\\u094e',\n  '\\u094f\\u0007v\\u0002\\u0002\\u094f\\u0950\\u0007t\\u0002\\u0002\\u0950\\u0951',\n  '\\u0007c\\u0002\\u0002\\u0951\\u0952\\u0007p\\u0002\\u0002\\u0952\\u0953\\u0007',\n  'u\\u0002\\u0002\\u0953\\u0954\\u0007c\\u0002\\u0002\\u0954\\u0955\\u0007e\\u0002',\n  '\\u0002\\u0955\\u0956\\u0007v\\u0002\\u0002\\u0956\\u0957\\u0007k\\u0002\\u0002',\n  '\\u0957\\u0958\\u0007q\\u0002\\u0002\\u0958\\u095a\\u0007p\\u0002\\u0002\\u0959',\n  '\\u0943\\u0003\\u0002\\u0002\\u0002\\u0959\\u094e\\u0003\\u0002\\u0002\\u0002\\u095a',\n  '\\u0132\\u0003\\u0002\\u0002\\u0002\\u095b\\u095c\\u0007E\\u0002\\u0002\\u095c',\n  '\\u095d\\u0007Q\\u0002\\u0002\\u095d\\u095e\\u0007O\\u0002\\u0002\\u095e\\u095f',\n  '\\u0007O\\u0002\\u0002\\u095f\\u0960\\u0007K\\u0002\\u0002\\u0960\\u0968\\u0007',\n  'V\\u0002\\u0002\\u0961\\u0962\\u0007e\\u0002\\u0002\\u0962\\u0963\\u0007q\\u0002',\n  '\\u0002\\u0963\\u0964\\u0007o\\u0002\\u0002\\u0964\\u0965\\u0007o\\u0002\\u0002',\n  '\\u0965\\u0966\\u0007k\\u0002\\u0002\\u0966\\u0968\\u0007v\\u0002\\u0002\\u0967',\n  '\\u095b\\u0003\\u0002\\u0002\\u0002\\u0967\\u0961\\u0003\\u0002\\u0002\\u0002\\u0968',\n  '\\u0134\\u0003\\u0002\\u0002\\u0002\\u0969\\u096a\\u0007T\\u0002\\u0002\\u096a',\n  '\\u096b\\u0007Q\\u0002\\u0002\\u096b\\u096c\\u0007N\\u0002\\u0002\\u096c\\u096d',\n  '\\u0007N\\u0002\\u0002\\u096d\\u096e\\u0007D\\u0002\\u0002\\u096e\\u096f\\u0007',\n  'C\\u0002\\u0002\\u096f\\u0970\\u0007E\\u0002\\u0002\\u0970\\u097a\\u0007M\\u0002',\n  '\\u0002\\u0971\\u0972\\u0007t\\u0002\\u0002\\u0972\\u0973\\u0007q\\u0002\\u0002',\n  '\\u0973\\u0974\\u0007n\\u0002\\u0002\\u0974\\u0975\\u0007n\\u0002\\u0002\\u0975',\n  '\\u0976\\u0007d\\u0002\\u0002\\u0976\\u0977\\u0007c\\u0002\\u0002\\u0977\\u0978',\n  '\\u0007e\\u0002\\u0002\\u0978\\u097a\\u0007m\\u0002\\u0002\\u0979\\u0969\\u0003',\n  '\\u0002\\u0002\\u0002\\u0979\\u0971\\u0003\\u0002\\u0002\\u0002\\u097a\\u0136\\u0003',\n  '\\u0002\\u0002\\u0002\\u097b\\u097c\\u0007Y\\u0002\\u0002\\u097c\\u097d\\u0007',\n  'Q\\u0002\\u0002\\u097d\\u097e\\u0007T\\u0002\\u0002\\u097e\\u0984\\u0007M\\u0002',\n  '\\u0002\\u097f\\u0980\\u0007y\\u0002\\u0002\\u0980\\u0981\\u0007q\\u0002\\u0002',\n  '\\u0981\\u0982\\u0007t\\u0002\\u0002\\u0982\\u0984\\u0007m\\u0002\\u0002\\u0983',\n  '\\u097b\\u0003\\u0002\\u0002\\u0002\\u0983\\u097f\\u0003\\u0002\\u0002\\u0002\\u0984',\n  '\\u0138\\u0003\\u0002\\u0002\\u0002\\u0985\\u0986\\u0007K\\u0002\\u0002\\u0986',\n  '\\u0987\\u0007U\\u0002\\u0002\\u0987\\u0988\\u0007Q\\u0002\\u0002\\u0988\\u0989',\n  '\\u0007N\\u0002\\u0002\\u0989\\u098a\\u0007C\\u0002\\u0002\\u098a\\u098b\\u0007',\n  'V\\u0002\\u0002\\u098b\\u098c\\u0007K\\u0002\\u0002\\u098c\\u098d\\u0007Q\\u0002',\n  '\\u0002\\u098d\\u0998\\u0007P\\u0002\\u0002\\u098e\\u098f\\u0007k\\u0002\\u0002',\n  '\\u098f\\u0990\\u0007u\\u0002\\u0002\\u0990\\u0991\\u0007q\\u0002\\u0002\\u0991',\n  '\\u0992\\u0007n\\u0002\\u0002\\u0992\\u0993\\u0007c\\u0002\\u0002\\u0993\\u0994',\n  '\\u0007v\\u0002\\u0002\\u0994\\u0995\\u0007k\\u0002\\u0002\\u0995\\u0996\\u0007',\n  'q\\u0002\\u0002\\u0996\\u0998\\u0007p\\u0002\\u0002\\u0997\\u0985\\u0003\\u0002',\n  '\\u0002\\u0002\\u0997\\u098e\\u0003\\u0002\\u0002\\u0002\\u0998\\u013a\\u0003\\u0002',\n  '\\u0002\\u0002\\u0999\\u099a\\u0007N\\u0002\\u0002\\u099a\\u099b\\u0007G\\u0002',\n  '\\u0002\\u099b\\u099c\\u0007X\\u0002\\u0002\\u099c\\u099d\\u0007G\\u0002\\u0002',\n  '\\u099d\\u09a4\\u0007N\\u0002\\u0002\\u099e\\u099f\\u0007n\\u0002\\u0002\\u099f',\n  '\\u09a0\\u0007g\\u0002\\u0002\\u09a0\\u09a1\\u0007x\\u0002\\u0002\\u09a1\\u09a2',\n  '\\u0007g\\u0002\\u0002\\u09a2\\u09a4\\u0007n\\u0002\\u0002\\u09a3\\u0999\\u0003',\n  '\\u0002\\u0002\\u0002\\u09a3\\u099e\\u0003\\u0002\\u0002\\u0002\\u09a4\\u013c\\u0003',\n  '\\u0002\\u0002\\u0002\\u09a5\\u09a6\\u0007U\\u0002\\u0002\\u09a6\\u09a7\\u0007',\n  'G\\u0002\\u0002\\u09a7\\u09a8\\u0007T\\u0002\\u0002\\u09a8\\u09a9\\u0007K\\u0002',\n  '\\u0002\\u09a9\\u09aa\\u0007C\\u0002\\u0002\\u09aa\\u09ab\\u0007N\\u0002\\u0002',\n  '\\u09ab\\u09ac\\u0007K\\u0002\\u0002\\u09ac\\u09ad\\u0007\\\\\\u0002\\u0002\\u09ad',\n  '\\u09ae\\u0007C\\u0002\\u0002\\u09ae\\u09af\\u0007D\\u0002\\u0002\\u09af\\u09b0',\n  '\\u0007N\\u0002\\u0002\\u09b0\\u09be\\u0007G\\u0002\\u0002\\u09b1\\u09b2\\u0007',\n  'u\\u0002\\u0002\\u09b2\\u09b3\\u0007g\\u0002\\u0002\\u09b3\\u09b4\\u0007t\\u0002',\n  '\\u0002\\u09b4\\u09b5\\u0007k\\u0002\\u0002\\u09b5\\u09b6\\u0007c\\u0002\\u0002',\n  '\\u09b6\\u09b7\\u0007n\\u0002\\u0002\\u09b7\\u09b8\\u0007k\\u0002\\u0002\\u09b8',\n  '\\u09b9\\u0007|\\u0002\\u0002\\u09b9\\u09ba\\u0007c\\u0002\\u0002\\u09ba\\u09bb',\n  '\\u0007d\\u0002\\u0002\\u09bb\\u09bc\\u0007n\\u0002\\u0002\\u09bc\\u09be\\u0007',\n  'g\\u0002\\u0002\\u09bd\\u09a5\\u0003\\u0002\\u0002\\u0002\\u09bd\\u09b1\\u0003',\n  '\\u0002\\u0002\\u0002\\u09be\\u013e\\u0003\\u0002\\u0002\\u0002\\u09bf\\u09c0\\u0007',\n  'T\\u0002\\u0002\\u09c0\\u09c1\\u0007G\\u0002\\u0002\\u09c1\\u09c2\\u0007R\\u0002',\n  '\\u0002\\u09c2\\u09c3\\u0007G\\u0002\\u0002\\u09c3\\u09c4\\u0007C\\u0002\\u0002',\n  '\\u09c4\\u09c5\\u0007V\\u0002\\u0002\\u09c5\\u09c6\\u0007C\\u0002\\u0002\\u09c6',\n  '\\u09c7\\u0007D\\u0002\\u0002\\u09c7\\u09c8\\u0007N\\u0002\\u0002\\u09c8\\u09d4',\n  '\\u0007G\\u0002\\u0002\\u09c9\\u09ca\\u0007t\\u0002\\u0002\\u09ca\\u09cb\\u0007',\n  'g\\u0002\\u0002\\u09cb\\u09cc\\u0007r\\u0002\\u0002\\u09cc\\u09cd\\u0007g\\u0002',\n  '\\u0002\\u09cd\\u09ce\\u0007c\\u0002\\u0002\\u09ce\\u09cf\\u0007v\\u0002\\u0002',\n  '\\u09cf\\u09d0\\u0007c\\u0002\\u0002\\u09d0\\u09d1\\u0007d\\u0002\\u0002\\u09d1',\n  '\\u09d2\\u0007n\\u0002\\u0002\\u09d2\\u09d4\\u0007g\\u0002\\u0002\\u09d3\\u09bf',\n  '\\u0003\\u0002\\u0002\\u0002\\u09d3\\u09c9\\u0003\\u0002\\u0002\\u0002\\u09d4\\u0140',\n  '\\u0003\\u0002\\u0002\\u0002\\u09d5\\u09d6\\u0007E\\u0002\\u0002\\u09d6\\u09d7',\n  '\\u0007Q\\u0002\\u0002\\u09d7\\u09d8\\u0007O\\u0002\\u0002\\u09d8\\u09d9\\u0007',\n  'O\\u0002\\u0002\\u09d9\\u09da\\u0007K\\u0002\\u0002\\u09da\\u09db\\u0007V\\u0002',\n  '\\u0002\\u09db\\u09dc\\u0007V\\u0002\\u0002\\u09dc\\u09dd\\u0007G\\u0002\\u0002',\n  '\\u09dd\\u09e8\\u0007F\\u0002\\u0002\\u09de\\u09df\\u0007e\\u0002\\u0002\\u09df',\n  '\\u09e0\\u0007q\\u0002\\u0002\\u09e0\\u09e1\\u0007o\\u0002\\u0002\\u09e1\\u09e2',\n  '\\u0007o\\u0002\\u0002\\u09e2\\u09e3\\u0007k\\u0002\\u0002\\u09e3\\u09e4\\u0007',\n  'v\\u0002\\u0002\\u09e4\\u09e5\\u0007v\\u0002\\u0002\\u09e5\\u09e6\\u0007g\\u0002',\n  '\\u0002\\u09e6\\u09e8\\u0007f\\u0002\\u0002\\u09e7\\u09d5\\u0003\\u0002\\u0002',\n  '\\u0002\\u09e7\\u09de\\u0003\\u0002\\u0002\\u0002\\u09e8\\u0142\\u0003\\u0002\\u0002',\n  '\\u0002\\u09e9\\u09ea\\u0007W\\u0002\\u0002\\u09ea\\u09eb\\u0007P\\u0002\\u0002',\n  '\\u09eb\\u09ec\\u0007E\\u0002\\u0002\\u09ec\\u09ed\\u0007Q\\u0002\\u0002\\u09ed',\n  '\\u09ee\\u0007O\\u0002\\u0002\\u09ee\\u09ef\\u0007O\\u0002\\u0002\\u09ef\\u09f0',\n  '\\u0007K\\u0002\\u0002\\u09f0\\u09f1\\u0007V\\u0002\\u0002\\u09f1\\u09f2\\u0007',\n  'V\\u0002\\u0002\\u09f2\\u09f3\\u0007G\\u0002\\u0002\\u09f3\\u0a00\\u0007F\\u0002',\n  '\\u0002\\u09f4\\u09f5\\u0007w\\u0002\\u0002\\u09f5\\u09f6\\u0007p\\u0002\\u0002',\n  '\\u09f6\\u09f7\\u0007e\\u0002\\u0002\\u09f7\\u09f8\\u0007q\\u0002\\u0002\\u09f8',\n  '\\u09f9\\u0007o\\u0002\\u0002\\u09f9\\u09fa\\u0007o\\u0002\\u0002\\u09fa\\u09fb',\n  '\\u0007k\\u0002\\u0002\\u09fb\\u09fc\\u0007v\\u0002\\u0002\\u09fc\\u09fd\\u0007',\n  'v\\u0002\\u0002\\u09fd\\u09fe\\u0007g\\u0002\\u0002\\u09fe\\u0a00\\u0007f\\u0002',\n  '\\u0002\\u09ff\\u09e9\\u0003\\u0002\\u0002\\u0002\\u09ff\\u09f4\\u0003\\u0002\\u0002',\n  '\\u0002\\u0a00\\u0144\\u0003\\u0002\\u0002\\u0002\\u0a01\\u0a02\\u0007T\\u0002',\n  '\\u0002\\u0a02\\u0a03\\u0007G\\u0002\\u0002\\u0a03\\u0a04\\u0007C\\u0002\\u0002',\n  '\\u0a04\\u0a0a\\u0007F\\u0002\\u0002\\u0a05\\u0a06\\u0007t\\u0002\\u0002\\u0a06',\n  '\\u0a07\\u0007g\\u0002\\u0002\\u0a07\\u0a08\\u0007c\\u0002\\u0002\\u0a08\\u0a0a',\n  '\\u0007f\\u0002\\u0002\\u0a09\\u0a01\\u0003\\u0002\\u0002\\u0002\\u0a09\\u0a05',\n  '\\u0003\\u0002\\u0002\\u0002\\u0a0a\\u0146\\u0003\\u0002\\u0002\\u0002\\u0a0b\\u0a0c',\n  '\\u0007Y\\u0002\\u0002\\u0a0c\\u0a0d\\u0007T\\u0002\\u0002\\u0a0d\\u0a0e\\u0007',\n  'K\\u0002\\u0002\\u0a0e\\u0a0f\\u0007V\\u0002\\u0002\\u0a0f\\u0a16\\u0007G\\u0002',\n  '\\u0002\\u0a10\\u0a11\\u0007y\\u0002\\u0002\\u0a11\\u0a12\\u0007t\\u0002\\u0002',\n  '\\u0a12\\u0a13\\u0007k\\u0002\\u0002\\u0a13\\u0a14\\u0007v\\u0002\\u0002\\u0a14',\n  '\\u0a16\\u0007g\\u0002\\u0002\\u0a15\\u0a0b\\u0003\\u0002\\u0002\\u0002\\u0a15',\n  '\\u0a10\\u0003\\u0002\\u0002\\u0002\\u0a16\\u0148\\u0003\\u0002\\u0002\\u0002\\u0a17',\n  '\\u0a18\\u0007Q\\u0002\\u0002\\u0a18\\u0a19\\u0007P\\u0002\\u0002\\u0a19\\u0a1a',\n  '\\u0007N\\u0002\\u0002\\u0a1a\\u0a20\\u0007[\\u0002\\u0002\\u0a1b\\u0a1c\\u0007',\n  'q\\u0002\\u0002\\u0a1c\\u0a1d\\u0007p\\u0002\\u0002\\u0a1d\\u0a1e\\u0007n\\u0002',\n  '\\u0002\\u0a1e\\u0a20\\u0007{\\u0002\\u0002\\u0a1f\\u0a17\\u0003\\u0002\\u0002',\n  '\\u0002\\u0a1f\\u0a1b\\u0003\\u0002\\u0002\\u0002\\u0a20\\u014a\\u0003\\u0002\\u0002',\n  '\\u0002\\u0a21\\u0a22\\u0007E\\u0002\\u0002\\u0a22\\u0a23\\u0007C\\u0002\\u0002',\n  '\\u0a23\\u0a24\\u0007N\\u0002\\u0002\\u0a24\\u0a2a\\u0007N\\u0002\\u0002\\u0a25',\n  '\\u0a26\\u0007e\\u0002\\u0002\\u0a26\\u0a27\\u0007c\\u0002\\u0002\\u0a27\\u0a28',\n  '\\u0007n\\u0002\\u0002\\u0a28\\u0a2a\\u0007n\\u0002\\u0002\\u0a29\\u0a21\\u0003',\n  '\\u0002\\u0002\\u0002\\u0a29\\u0a25\\u0003\\u0002\\u0002\\u0002\\u0a2a\\u014c\\u0003',\n  '\\u0002\\u0002\\u0002\\u0a2b\\u0a2c\\u0007R\\u0002\\u0002\\u0a2c\\u0a2d\\u0007',\n  'T\\u0002\\u0002\\u0a2d\\u0a2e\\u0007G\\u0002\\u0002\\u0a2e\\u0a2f\\u0007R\\u0002',\n  '\\u0002\\u0a2f\\u0a30\\u0007C\\u0002\\u0002\\u0a30\\u0a31\\u0007T\\u0002\\u0002',\n  '\\u0a31\\u0a3a\\u0007G\\u0002\\u0002\\u0a32\\u0a33\\u0007r\\u0002\\u0002\\u0a33',\n  '\\u0a34\\u0007t\\u0002\\u0002\\u0a34\\u0a35\\u0007g\\u0002\\u0002\\u0a35\\u0a36',\n  '\\u0007r\\u0002\\u0002\\u0a36\\u0a37\\u0007c\\u0002\\u0002\\u0a37\\u0a38\\u0007',\n  't\\u0002\\u0002\\u0a38\\u0a3a\\u0007g\\u0002\\u0002\\u0a39\\u0a2b\\u0003\\u0002',\n  '\\u0002\\u0002\\u0a39\\u0a32\\u0003\\u0002\\u0002\\u0002\\u0a3a\\u014e\\u0003\\u0002',\n  '\\u0002\\u0002\\u0a3b\\u0a3c\\u0007F\\u0002\\u0002\\u0a3c\\u0a3d\\u0007G\\u0002',\n  '\\u0002\\u0a3d\\u0a3e\\u0007C\\u0002\\u0002\\u0a3e\\u0a3f\\u0007N\\u0002\\u0002',\n  '\\u0a3f\\u0a40\\u0007N\\u0002\\u0002\\u0a40\\u0a41\\u0007Q\\u0002\\u0002\\u0a41',\n  '\\u0a42\\u0007E\\u0002\\u0002\\u0a42\\u0a43\\u0007C\\u0002\\u0002\\u0a43\\u0a44',\n  '\\u0007V\\u0002\\u0002\\u0a44\\u0a50\\u0007G\\u0002\\u0002\\u0a45\\u0a46\\u0007',\n  'f\\u0002\\u0002\\u0a46\\u0a47\\u0007g\\u0002\\u0002\\u0a47\\u0a48\\u0007c\\u0002',\n  '\\u0002\\u0a48\\u0a49\\u0007n\\u0002\\u0002\\u0a49\\u0a4a\\u0007n\\u0002\\u0002',\n  '\\u0a4a\\u0a4b\\u0007q\\u0002\\u0002\\u0a4b\\u0a4c\\u0007e\\u0002\\u0002\\u0a4c',\n  '\\u0a4d\\u0007c\\u0002\\u0002\\u0a4d\\u0a4e\\u0007v\\u0002\\u0002\\u0a4e\\u0a50',\n  '\\u0007g\\u0002\\u0002\\u0a4f\\u0a3b\\u0003\\u0002\\u0002\\u0002\\u0a4f\\u0a45',\n  '\\u0003\\u0002\\u0002\\u0002\\u0a50\\u0150\\u0003\\u0002\\u0002\\u0002\\u0a51\\u0a52',\n  '\\u0007G\\u0002\\u0002\\u0a52\\u0a53\\u0007Z\\u0002\\u0002\\u0a53\\u0a54\\u0007',\n  'G\\u0002\\u0002\\u0a54\\u0a55\\u0007E\\u0002\\u0002\\u0a55\\u0a56\\u0007W\\u0002',\n  '\\u0002\\u0a56\\u0a57\\u0007V\\u0002\\u0002\\u0a57\\u0a60\\u0007G\\u0002\\u0002',\n  '\\u0a58\\u0a59\\u0007g\\u0002\\u0002\\u0a59\\u0a5a\\u0007z\\u0002\\u0002\\u0a5a',\n  '\\u0a5b\\u0007g\\u0002\\u0002\\u0a5b\\u0a5c\\u0007e\\u0002\\u0002\\u0a5c\\u0a5d',\n  '\\u0007w\\u0002\\u0002\\u0a5d\\u0a5e\\u0007v\\u0002\\u0002\\u0a5e\\u0a60\\u0007',\n  'g\\u0002\\u0002\\u0a5f\\u0a51\\u0003\\u0002\\u0002\\u0002\\u0a5f\\u0a58\\u0003',\n  '\\u0002\\u0002\\u0002\\u0a60\\u0152\\u0003\\u0002\\u0002\\u0002\\u0a61\\u0a62\\u0007',\n  'K\\u0002\\u0002\\u0a62\\u0a63\\u0007P\\u0002\\u0002\\u0a63\\u0a64\\u0007R\\u0002',\n  '\\u0002\\u0a64\\u0a65\\u0007W\\u0002\\u0002\\u0a65\\u0a6c\\u0007V\\u0002\\u0002',\n  '\\u0a66\\u0a67\\u0007k\\u0002\\u0002\\u0a67\\u0a68\\u0007p\\u0002\\u0002\\u0a68',\n  '\\u0a69\\u0007r\\u0002\\u0002\\u0a69\\u0a6a\\u0007w\\u0002\\u0002\\u0a6a\\u0a6c',\n  '\\u0007v\\u0002\\u0002\\u0a6b\\u0a61\\u0003\\u0002\\u0002\\u0002\\u0a6b\\u0a66',\n  '\\u0003\\u0002\\u0002\\u0002\\u0a6c\\u0154\\u0003\\u0002\\u0002\\u0002\\u0a6d\\u0a6e',\n  '\\u0007Q\\u0002\\u0002\\u0a6e\\u0a6f\\u0007W\\u0002\\u0002\\u0a6f\\u0a70\\u0007',\n  'V\\u0002\\u0002\\u0a70\\u0a71\\u0007R\\u0002\\u0002\\u0a71\\u0a72\\u0007W\\u0002',\n  '\\u0002\\u0a72\\u0a7a\\u0007V\\u0002\\u0002\\u0a73\\u0a74\\u0007q\\u0002\\u0002',\n  '\\u0a74\\u0a75\\u0007w\\u0002\\u0002\\u0a75\\u0a76\\u0007v\\u0002\\u0002\\u0a76',\n  '\\u0a77\\u0007r\\u0002\\u0002\\u0a77\\u0a78\\u0007w\\u0002\\u0002\\u0a78\\u0a7a',\n  '\\u0007v\\u0002\\u0002\\u0a79\\u0a6d\\u0003\\u0002\\u0002\\u0002\\u0a79\\u0a73',\n  '\\u0003\\u0002\\u0002\\u0002\\u0a7a\\u0156\\u0003\\u0002\\u0002\\u0002\\u0a7b\\u0a7c',\n  '\\u0007E\\u0002\\u0002\\u0a7c\\u0a7d\\u0007C\\u0002\\u0002\\u0a7d\\u0a7e\\u0007',\n  'U\\u0002\\u0002\\u0a7e\\u0a7f\\u0007E\\u0002\\u0002\\u0a7f\\u0a80\\u0007C\\u0002',\n  '\\u0002\\u0a80\\u0a81\\u0007F\\u0002\\u0002\\u0a81\\u0a8a\\u0007G\\u0002\\u0002',\n  '\\u0a82\\u0a83\\u0007e\\u0002\\u0002\\u0a83\\u0a84\\u0007c\\u0002\\u0002\\u0a84',\n  '\\u0a85\\u0007u\\u0002\\u0002\\u0a85\\u0a86\\u0007e\\u0002\\u0002\\u0a86\\u0a87',\n  '\\u0007c\\u0002\\u0002\\u0a87\\u0a88\\u0007f\\u0002\\u0002\\u0a88\\u0a8a\\u0007',\n  'g\\u0002\\u0002\\u0a89\\u0a7b\\u0003\\u0002\\u0002\\u0002\\u0a89\\u0a82\\u0003',\n  '\\u0002\\u0002\\u0002\\u0a8a\\u0158\\u0003\\u0002\\u0002\\u0002\\u0a8b\\u0a8c\\u0007',\n  'T\\u0002\\u0002\\u0a8c\\u0a8d\\u0007G\\u0002\\u0002\\u0a8d\\u0a8e\\u0007U\\u0002',\n  '\\u0002\\u0a8e\\u0a8f\\u0007V\\u0002\\u0002\\u0a8f\\u0a90\\u0007T\\u0002\\u0002',\n  '\\u0a90\\u0a91\\u0007K\\u0002\\u0002\\u0a91\\u0a92\\u0007E\\u0002\\u0002\\u0a92',\n  '\\u0a9c\\u0007V\\u0002\\u0002\\u0a93\\u0a94\\u0007t\\u0002\\u0002\\u0a94\\u0a95',\n  '\\u0007g\\u0002\\u0002\\u0a95\\u0a96\\u0007u\\u0002\\u0002\\u0a96\\u0a97\\u0007',\n  'v\\u0002\\u0002\\u0a97\\u0a98\\u0007t\\u0002\\u0002\\u0a98\\u0a99\\u0007k\\u0002',\n  '\\u0002\\u0a99\\u0a9a\\u0007e\\u0002\\u0002\\u0a9a\\u0a9c\\u0007v\\u0002\\u0002',\n  '\\u0a9b\\u0a8b\\u0003\\u0002\\u0002\\u0002\\u0a9b\\u0a93\\u0003\\u0002\\u0002\\u0002',\n  '\\u0a9c\\u015a\\u0003\\u0002\\u0002\\u0002\\u0a9d\\u0a9e\\u0007K\\u0002\\u0002',\n  '\\u0a9e\\u0a9f\\u0007P\\u0002\\u0002\\u0a9f\\u0aa0\\u0007E\\u0002\\u0002\\u0aa0',\n  '\\u0aa1\\u0007N\\u0002\\u0002\\u0aa1\\u0aa2\\u0007W\\u0002\\u0002\\u0aa2\\u0aa3',\n  '\\u0007F\\u0002\\u0002\\u0aa3\\u0aa4\\u0007K\\u0002\\u0002\\u0aa4\\u0aa5\\u0007',\n  'P\\u0002\\u0002\\u0aa5\\u0ab0\\u0007I\\u0002\\u0002\\u0aa6\\u0aa7\\u0007k\\u0002',\n  '\\u0002\\u0aa7\\u0aa8\\u0007p\\u0002\\u0002\\u0aa8\\u0aa9\\u0007e\\u0002\\u0002',\n  '\\u0aa9\\u0aaa\\u0007n\\u0002\\u0002\\u0aaa\\u0aab\\u0007w\\u0002\\u0002\\u0aab',\n  '\\u0aac\\u0007f\\u0002\\u0002\\u0aac\\u0aad\\u0007k\\u0002\\u0002\\u0aad\\u0aae',\n  '\\u0007p\\u0002\\u0002\\u0aae\\u0ab0\\u0007i\\u0002\\u0002\\u0aaf\\u0a9d\\u0003',\n  '\\u0002\\u0002\\u0002\\u0aaf\\u0aa6\\u0003\\u0002\\u0002\\u0002\\u0ab0\\u015c\\u0003',\n  '\\u0002\\u0002\\u0002\\u0ab1\\u0ab2\\u0007G\\u0002\\u0002\\u0ab2\\u0ab3\\u0007',\n  'Z\\u0002\\u0002\\u0ab3\\u0ab4\\u0007E\\u0002\\u0002\\u0ab4\\u0ab5\\u0007N\\u0002',\n  '\\u0002\\u0ab5\\u0ab6\\u0007W\\u0002\\u0002\\u0ab6\\u0ab7\\u0007F\\u0002\\u0002',\n  '\\u0ab7\\u0ab8\\u0007K\\u0002\\u0002\\u0ab8\\u0ab9\\u0007P\\u0002\\u0002\\u0ab9',\n  '\\u0ac4\\u0007I\\u0002\\u0002\\u0aba\\u0abb\\u0007g\\u0002\\u0002\\u0abb\\u0abc',\n  '\\u0007z\\u0002\\u0002\\u0abc\\u0abd\\u0007e\\u0002\\u0002\\u0abd\\u0abe\\u0007',\n  'n\\u0002\\u0002\\u0abe\\u0abf\\u0007w\\u0002\\u0002\\u0abf\\u0ac0\\u0007f\\u0002',\n  '\\u0002\\u0ac0\\u0ac1\\u0007k\\u0002\\u0002\\u0ac1\\u0ac2\\u0007p\\u0002\\u0002',\n  '\\u0ac2\\u0ac4\\u0007i\\u0002\\u0002\\u0ac3\\u0ab1\\u0003\\u0002\\u0002\\u0002',\n  '\\u0ac3\\u0aba\\u0003\\u0002\\u0002\\u0002\\u0ac4\\u015e\\u0003\\u0002\\u0002\\u0002',\n  '\\u0ac5\\u0ac6\\u0007R\\u0002\\u0002\\u0ac6\\u0ac7\\u0007T\\u0002\\u0002\\u0ac7',\n  '\\u0ac8\\u0007Q\\u0002\\u0002\\u0ac8\\u0ac9\\u0007R\\u0002\\u0002\\u0ac9\\u0aca',\n  '\\u0007G\\u0002\\u0002\\u0aca\\u0acb\\u0007T\\u0002\\u0002\\u0acb\\u0acc\\u0007',\n  'V\\u0002\\u0002\\u0acc\\u0acd\\u0007K\\u0002\\u0002\\u0acd\\u0ace\\u0007G\\u0002',\n  '\\u0002\\u0ace\\u0ada\\u0007U\\u0002\\u0002\\u0acf\\u0ad0\\u0007r\\u0002\\u0002',\n  '\\u0ad0\\u0ad1\\u0007t\\u0002\\u0002\\u0ad1\\u0ad2\\u0007q\\u0002\\u0002\\u0ad2',\n  '\\u0ad3\\u0007r\\u0002\\u0002\\u0ad3\\u0ad4\\u0007g\\u0002\\u0002\\u0ad4\\u0ad5',\n  '\\u0007t\\u0002\\u0002\\u0ad5\\u0ad6\\u0007v\\u0002\\u0002\\u0ad6\\u0ad7\\u0007',\n  'k\\u0002\\u0002\\u0ad7\\u0ad8\\u0007g\\u0002\\u0002\\u0ad8\\u0ada\\u0007u\\u0002',\n  '\\u0002\\u0ad9\\u0ac5\\u0003\\u0002\\u0002\\u0002\\u0ad9\\u0acf\\u0003\\u0002\\u0002',\n  '\\u0002\\u0ada\\u0160\\u0003\\u0002\\u0002\\u0002\\u0adb\\u0adc\\u0007P\\u0002',\n  '\\u0002\\u0adc\\u0add\\u0007Q\\u0002\\u0002\\u0add\\u0ade\\u0007T\\u0002\\u0002',\n  '\\u0ade\\u0adf\\u0007O\\u0002\\u0002\\u0adf\\u0ae0\\u0007C\\u0002\\u0002\\u0ae0',\n  '\\u0ae1\\u0007N\\u0002\\u0002\\u0ae1\\u0ae2\\u0007K\\u0002\\u0002\\u0ae2\\u0ae3',\n  '\\u0007\\\\\\u0002\\u0002\\u0ae3\\u0aee\\u0007G\\u0002\\u0002\\u0ae4\\u0ae5\\u0007',\n  'p\\u0002\\u0002\\u0ae5\\u0ae6\\u0007q\\u0002\\u0002\\u0ae6\\u0ae7\\u0007t\\u0002',\n  '\\u0002\\u0ae7\\u0ae8\\u0007o\\u0002\\u0002\\u0ae8\\u0ae9\\u0007c\\u0002\\u0002',\n  '\\u0ae9\\u0aea\\u0007n\\u0002\\u0002\\u0aea\\u0aeb\\u0007k\\u0002\\u0002\\u0aeb',\n  '\\u0aec\\u0007|\\u0002\\u0002\\u0aec\\u0aee\\u0007g\\u0002\\u0002\\u0aed\\u0adb',\n  '\\u0003\\u0002\\u0002\\u0002\\u0aed\\u0ae4\\u0003\\u0002\\u0002\\u0002\\u0aee\\u0162',\n  '\\u0003\\u0002\\u0002\\u0002\\u0aef\\u0af0\\u0007P\\u0002\\u0002\\u0af0\\u0af1',\n  '\\u0007H\\u0002\\u0002\\u0af1\\u0af2\\u0007F\\u0002\\u0002\\u0af2\\u0af8\\u0007',\n  '\"\\u0002\\u0002\\u0af3\\u0af4\\u0007p\\u0002\\u0002\\u0af4\\u0af5\\u0007h\\u0002',\n  '\\u0002\\u0af5\\u0af6\\u0007f\\u0002\\u0002\\u0af6\\u0af8\\u0007\"\\u0002\\u0002',\n  '\\u0af7\\u0aef\\u0003\\u0002\\u0002\\u0002\\u0af7\\u0af3\\u0003\\u0002\\u0002\\u0002',\n  '\\u0af8\\u0164\\u0003\\u0002\\u0002\\u0002\\u0af9\\u0afa\\u0007P\\u0002\\u0002',\n  '\\u0afa\\u0afb\\u0007H\\u0002\\u0002\\u0afb\\u0afc\\u0007E\\u0002\\u0002\\u0afc',\n  '\\u0b02\\u0007\"\\u0002\\u0002\\u0afd\\u0afe\\u0007p\\u0002\\u0002\\u0afe\\u0aff',\n  '\\u0007h\\u0002\\u0002\\u0aff\\u0b00\\u0007e\\u0002\\u0002\\u0b00\\u0b02\\u0007',\n  '\"\\u0002\\u0002\\u0b01\\u0af9\\u0003\\u0002\\u0002\\u0002\\u0b01\\u0afd\\u0003',\n  '\\u0002\\u0002\\u0002\\u0b02\\u0166\\u0003\\u0002\\u0002\\u0002\\u0b03\\u0b04\\u0007',\n  'P\\u0002\\u0002\\u0b04\\u0b05\\u0007H\\u0002\\u0002\\u0b05\\u0b06\\u0007M\\u0002',\n  '\\u0002\\u0b06\\u0b07\\u0007F\\u0002\\u0002\\u0b07\\u0b0e\\u0007\"\\u0002\\u0002',\n  '\\u0b08\\u0b09\\u0007p\\u0002\\u0002\\u0b09\\u0b0a\\u0007h\\u0002\\u0002\\u0b0a',\n  '\\u0b0b\\u0007m\\u0002\\u0002\\u0b0b\\u0b0c\\u0007f\\u0002\\u0002\\u0b0c\\u0b0e',\n  '\\u0007\"\\u0002\\u0002\\u0b0d\\u0b03\\u0003\\u0002\\u0002\\u0002\\u0b0d\\u0b08',\n  '\\u0003\\u0002\\u0002\\u0002\\u0b0e\\u0168\\u0003\\u0002\\u0002\\u0002\\u0b0f\\u0b10',\n  '\\u0007P\\u0002\\u0002\\u0b10\\u0b11\\u0007H\\u0002\\u0002\\u0b11\\u0b12\\u0007',\n  'M\\u0002\\u0002\\u0b12\\u0b13\\u0007E\\u0002\\u0002\\u0b13\\u0b1a\\u0007\"\\u0002',\n  '\\u0002\\u0b14\\u0b15\\u0007p\\u0002\\u0002\\u0b15\\u0b16\\u0007h\\u0002\\u0002',\n  '\\u0b16\\u0b17\\u0007m\\u0002\\u0002\\u0b17\\u0b18\\u0007e\\u0002\\u0002\\u0b18',\n  '\\u0b1a\\u0007\"\\u0002\\u0002\\u0b19\\u0b0f\\u0003\\u0002\\u0002\\u0002\\u0b19',\n  '\\u0b14\\u0003\\u0002\\u0002\\u0002\\u0b1a\\u016a\\u0003\\u0002\\u0002\\u0002\\u0b1b',\n  '\\u0b1c\\u0007K\\u0002\\u0002\\u0b1c\\u0b20\\u0007H\\u0002\\u0002\\u0b1d\\u0b1e',\n  '\\u0007k\\u0002\\u0002\\u0b1e\\u0b20\\u0007h\\u0002\\u0002\\u0b1f\\u0b1b\\u0003',\n  '\\u0002\\u0002\\u0002\\u0b1f\\u0b1d\\u0003\\u0002\\u0002\\u0002\\u0b20\\u016c\\u0003',\n  '\\u0002\\u0002\\u0002\\u0b21\\u0b22\\u0007P\\u0002\\u0002\\u0b22\\u0b23\\u0007',\n  'W\\u0002\\u0002\\u0b23\\u0b24\\u0007N\\u0002\\u0002\\u0b24\\u0b25\\u0007N\\u0002',\n  '\\u0002\\u0b25\\u0b26\\u0007K\\u0002\\u0002\\u0b26\\u0b2e\\u0007H\\u0002\\u0002',\n  '\\u0b27\\u0b28\\u0007p\\u0002\\u0002\\u0b28\\u0b29\\u0007w\\u0002\\u0002\\u0b29',\n  '\\u0b2a\\u0007n\\u0002\\u0002\\u0b2a\\u0b2b\\u0007n\\u0002\\u0002\\u0b2b\\u0b2c',\n  '\\u0007k\\u0002\\u0002\\u0b2c\\u0b2e\\u0007h\\u0002\\u0002\\u0b2d\\u0b21\\u0003',\n  '\\u0002\\u0002\\u0002\\u0b2d\\u0b27\\u0003\\u0002\\u0002\\u0002\\u0b2e\\u016e\\u0003',\n  '\\u0002\\u0002\\u0002\\u0b2f\\u0b30\\u0007E\\u0002\\u0002\\u0b30\\u0b31\\u0007',\n  'Q\\u0002\\u0002\\u0b31\\u0b32\\u0007C\\u0002\\u0002\\u0b32\\u0b33\\u0007N\\u0002',\n  '\\u0002\\u0b33\\u0b34\\u0007G\\u0002\\u0002\\u0b34\\u0b35\\u0007U\\u0002\\u0002',\n  '\\u0b35\\u0b36\\u0007E\\u0002\\u0002\\u0b36\\u0b40\\u0007G\\u0002\\u0002\\u0b37',\n  '\\u0b38\\u0007e\\u0002\\u0002\\u0b38\\u0b39\\u0007q\\u0002\\u0002\\u0b39\\u0b3a',\n  '\\u0007c\\u0002\\u0002\\u0b3a\\u0b3b\\u0007n\\u0002\\u0002\\u0b3b\\u0b3c\\u0007',\n  'g\\u0002\\u0002\\u0b3c\\u0b3d\\u0007u\\u0002\\u0002\\u0b3d\\u0b3e\\u0007e\\u0002',\n  '\\u0002\\u0b3e\\u0b40\\u0007g\\u0002\\u0002\\u0b3f\\u0b2f\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b3f\\u0b37\\u0003\\u0002\\u0002\\u0002\\u0b40\\u0170\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b41\\u0b42\\u0007?\\u0002\\u0002\\u0b42\\u0172\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b43\\u0b44\\u0007>\\u0002\\u0002\\u0b44\\u0b48\\u0007@\\u0002\\u0002',\n  '\\u0b45\\u0b46\\u0007#\\u0002\\u0002\\u0b46\\u0b48\\u0007?\\u0002\\u0002\\u0b47',\n  '\\u0b43\\u0003\\u0002\\u0002\\u0002\\u0b47\\u0b45\\u0003\\u0002\\u0002\\u0002\\u0b48',\n  '\\u0174\\u0003\\u0002\\u0002\\u0002\\u0b49\\u0b4a\\u0007>\\u0002\\u0002\\u0b4a',\n  '\\u0176\\u0003\\u0002\\u0002\\u0002\\u0b4b\\u0b4c\\u0007>\\u0002\\u0002\\u0b4c',\n  '\\u0b4d\\u0007?\\u0002\\u0002\\u0b4d\\u0178\\u0003\\u0002\\u0002\\u0002\\u0b4e',\n  '\\u0b4f\\u0007@\\u0002\\u0002\\u0b4f\\u017a\\u0003\\u0002\\u0002\\u0002\\u0b50',\n  '\\u0b51\\u0007@\\u0002\\u0002\\u0b51\\u0b52\\u0007?\\u0002\\u0002\\u0b52\\u017c',\n  '\\u0003\\u0002\\u0002\\u0002\\u0b53\\u0b54\\u0007-\\u0002\\u0002\\u0b54\\u017e',\n  '\\u0003\\u0002\\u0002\\u0002\\u0b55\\u0b56\\u0007/\\u0002\\u0002\\u0b56\\u0180',\n  '\\u0003\\u0002\\u0002\\u0002\\u0b57\\u0b58\\u0007,\\u0002\\u0002\\u0b58\\u0182',\n  '\\u0003\\u0002\\u0002\\u0002\\u0b59\\u0b5a\\u00071\\u0002\\u0002\\u0b5a\\u0184',\n  \"\\u0003\\u0002\\u0002\\u0002\\u0b5b\\u0b5c\\u0007'\\u0002\\u0002\\u0b5c\\u0186\",\n  '\\u0003\\u0002\\u0002\\u0002\\u0b5d\\u0b5e\\u0007~\\u0002\\u0002\\u0b5e\\u0b5f',\n  '\\u0007~\\u0002\\u0002\\u0b5f\\u0188\\u0003\\u0002\\u0002\\u0002\\u0b60\\u0b66',\n  '\\u0007)\\u0002\\u0002\\u0b61\\u0b65\\n\\u0002\\u0002\\u0002\\u0b62\\u0b63\\u0007',\n  ')\\u0002\\u0002\\u0b63\\u0b65\\u0007)\\u0002\\u0002\\u0b64\\u0b61\\u0003\\u0002',\n  '\\u0002\\u0002\\u0b64\\u0b62\\u0003\\u0002\\u0002\\u0002\\u0b65\\u0b68\\u0003\\u0002',\n  '\\u0002\\u0002\\u0b66\\u0b64\\u0003\\u0002\\u0002\\u0002\\u0b66\\u0b67\\u0003\\u0002',\n  '\\u0002\\u0002\\u0b67\\u0b69\\u0003\\u0002\\u0002\\u0002\\u0b68\\u0b66\\u0003\\u0002',\n  '\\u0002\\u0002\\u0b69\\u0b6a\\u0007)\\u0002\\u0002\\u0b6a\\u018a\\u0003\\u0002',\n  '\\u0002\\u0002\\u0b6b\\u0b6c\\u0007Z\\u0002\\u0002\\u0b6c\\u0b6d\\u0007)\\u0002',\n  '\\u0002\\u0b6d\\u0b71\\u0003\\u0002\\u0002\\u0002\\u0b6e\\u0b70\\n\\u0002\\u0002',\n  '\\u0002\\u0b6f\\u0b6e\\u0003\\u0002\\u0002\\u0002\\u0b70\\u0b73\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b71\\u0b6f\\u0003\\u0002\\u0002\\u0002\\u0b71\\u0b72\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b72\\u0b74\\u0003\\u0002\\u0002\\u0002\\u0b73\\u0b71\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b74\\u0b75\\u0007)\\u0002\\u0002\\u0b75\\u018c\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b76\\u0b78\\u0005\\u01a1\\u00d1\\u0002\\u0b77\\u0b76\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b78\\u0b79\\u0003\\u0002\\u0002\\u0002\\u0b79\\u0b77\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b79\\u0b7a\\u0003\\u0002\\u0002\\u0002\\u0b7a\\u018e\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b7b\\u0b7d\\u0005\\u01a1\\u00d1\\u0002\\u0b7c\\u0b7b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b7d\\u0b7e\\u0003\\u0002\\u0002\\u0002\\u0b7e\\u0b7c\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b7e\\u0b7f\\u0003\\u0002\\u0002\\u0002\\u0b7f\\u0b80\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b80\\u0b84\\u00070\\u0002\\u0002\\u0b81\\u0b83\\u0005\\u01a1\\u00d1',\n  '\\u0002\\u0b82\\u0b81\\u0003\\u0002\\u0002\\u0002\\u0b83\\u0b86\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b84\\u0b82\\u0003\\u0002\\u0002\\u0002\\u0b84\\u0b85\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b85\\u0ba6\\u0003\\u0002\\u0002\\u0002\\u0b86\\u0b84\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b87\\u0b89\\u00070\\u0002\\u0002\\u0b88\\u0b8a\\u0005\\u01a1\\u00d1',\n  '\\u0002\\u0b89\\u0b88\\u0003\\u0002\\u0002\\u0002\\u0b8a\\u0b8b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b8b\\u0b89\\u0003\\u0002\\u0002\\u0002\\u0b8b\\u0b8c\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b8c\\u0ba6\\u0003\\u0002\\u0002\\u0002\\u0b8d\\u0b8f\\u0005\\u01a1\\u00d1',\n  '\\u0002\\u0b8e\\u0b8d\\u0003\\u0002\\u0002\\u0002\\u0b8f\\u0b90\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b90\\u0b8e\\u0003\\u0002\\u0002\\u0002\\u0b90\\u0b91\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b91\\u0b99\\u0003\\u0002\\u0002\\u0002\\u0b92\\u0b96\\u00070\\u0002',\n  '\\u0002\\u0b93\\u0b95\\u0005\\u01a1\\u00d1\\u0002\\u0b94\\u0b93\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b95\\u0b98\\u0003\\u0002\\u0002\\u0002\\u0b96\\u0b94\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b96\\u0b97\\u0003\\u0002\\u0002\\u0002\\u0b97\\u0b9a\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b98\\u0b96\\u0003\\u0002\\u0002\\u0002\\u0b99\\u0b92\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b99\\u0b9a\\u0003\\u0002\\u0002\\u0002\\u0b9a\\u0b9b\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b9b\\u0b9c\\u0005\\u019f\\u00d0\\u0002\\u0b9c\\u0ba6\\u0003\\u0002\\u0002',\n  '\\u0002\\u0b9d\\u0b9f\\u00070\\u0002\\u0002\\u0b9e\\u0ba0\\u0005\\u01a1\\u00d1',\n  '\\u0002\\u0b9f\\u0b9e\\u0003\\u0002\\u0002\\u0002\\u0ba0\\u0ba1\\u0003\\u0002\\u0002',\n  '\\u0002\\u0ba1\\u0b9f\\u0003\\u0002\\u0002\\u0002\\u0ba1\\u0ba2\\u0003\\u0002\\u0002',\n  '\\u0002\\u0ba2\\u0ba3\\u0003\\u0002\\u0002\\u0002\\u0ba3\\u0ba4\\u0005\\u019f\\u00d0',\n  '\\u0002\\u0ba4\\u0ba6\\u0003\\u0002\\u0002\\u0002\\u0ba5\\u0b7c\\u0003\\u0002\\u0002',\n  '\\u0002\\u0ba5\\u0b87\\u0003\\u0002\\u0002\\u0002\\u0ba5\\u0b8e\\u0003\\u0002\\u0002',\n  '\\u0002\\u0ba5\\u0b9d\\u0003\\u0002\\u0002\\u0002\\u0ba6\\u0190\\u0003\\u0002\\u0002',\n  '\\u0002\\u0ba7\\u0baa\\u0005\\u01a3\\u00d2\\u0002\\u0ba8\\u0baa\\u0007a\\u0002',\n  '\\u0002\\u0ba9\\u0ba7\\u0003\\u0002\\u0002\\u0002\\u0ba9\\u0ba8\\u0003\\u0002\\u0002',\n  '\\u0002\\u0baa\\u0bb0\\u0003\\u0002\\u0002\\u0002\\u0bab\\u0baf\\u0005\\u01a3\\u00d2',\n  '\\u0002\\u0bac\\u0baf\\u0005\\u01a1\\u00d1\\u0002\\u0bad\\u0baf\\t\\u0003\\u0002',\n  '\\u0002\\u0bae\\u0bab\\u0003\\u0002\\u0002\\u0002\\u0bae\\u0bac\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bae\\u0bad\\u0003\\u0002\\u0002\\u0002\\u0baf\\u0bb2\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bb0\\u0bae\\u0003\\u0002\\u0002\\u0002\\u0bb0\\u0bb1\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bb1\\u0192\\u0003\\u0002\\u0002\\u0002\\u0bb2\\u0bb0\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bb3\\u0bb7\\u0005\\u01a1\\u00d1\\u0002\\u0bb4\\u0bb8\\u0005\\u01a3\\u00d2',\n  '\\u0002\\u0bb5\\u0bb8\\u0005\\u01a1\\u00d1\\u0002\\u0bb6\\u0bb8\\t\\u0003\\u0002',\n  '\\u0002\\u0bb7\\u0bb4\\u0003\\u0002\\u0002\\u0002\\u0bb7\\u0bb5\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bb7\\u0bb6\\u0003\\u0002\\u0002\\u0002\\u0bb8\\u0bb9\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bb9\\u0bb7\\u0003\\u0002\\u0002\\u0002\\u0bb9\\u0bba\\u0003\\u0002\\u0002',\n  '\\u0002\\u0bba\\u0194\\u0003\\u0002\\u0002\\u0002\\u0bbb\\u0bc1\\u0007$\\u0002',\n  '\\u0002\\u0bbc\\u0bc0\\n\\u0004\\u0002\\u0002\\u0bbd\\u0bbe\\u0007$\\u0002\\u0002',\n  '\\u0bbe\\u0bc0\\u0007$\\u0002\\u0002\\u0bbf\\u0bbc\\u0003\\u0002\\u0002\\u0002',\n  '\\u0bbf\\u0bbd\\u0003\\u0002\\u0002\\u0002\\u0bc0\\u0bc3\\u0003\\u0002\\u0002\\u0002',\n  '\\u0bc1\\u0bbf\\u0003\\u0002\\u0002\\u0002\\u0bc1\\u0bc2\\u0003\\u0002\\u0002\\u0002',\n  '\\u0bc2\\u0bc4\\u0003\\u0002\\u0002\\u0002\\u0bc3\\u0bc1\\u0003\\u0002\\u0002\\u0002',\n  '\\u0bc4\\u0bc5\\u0007$\\u0002\\u0002\\u0bc5\\u0196\\u0003\\u0002\\u0002\\u0002',\n  '\\u0bc6\\u0bcc\\u0007b\\u0002\\u0002\\u0bc7\\u0bcb\\n\\u0005\\u0002\\u0002\\u0bc8',\n  '\\u0bc9\\u0007b\\u0002\\u0002\\u0bc9\\u0bcb\\u0007b\\u0002\\u0002\\u0bca\\u0bc7',\n  '\\u0003\\u0002\\u0002\\u0002\\u0bca\\u0bc8\\u0003\\u0002\\u0002\\u0002\\u0bcb\\u0bce',\n  '\\u0003\\u0002\\u0002\\u0002\\u0bcc\\u0bca\\u0003\\u0002\\u0002\\u0002\\u0bcc\\u0bcd',\n  '\\u0003\\u0002\\u0002\\u0002\\u0bcd\\u0bcf\\u0003\\u0002\\u0002\\u0002\\u0bce\\u0bcc',\n  '\\u0003\\u0002\\u0002\\u0002\\u0bcf\\u0bd0\\u0007b\\u0002\\u0002\\u0bd0\\u0198',\n  '\\u0003\\u0002\\u0002\\u0002\\u0bd1\\u0bd2\\u0007V\\u0002\\u0002\\u0bd2\\u0bd3',\n  '\\u0007K\\u0002\\u0002\\u0bd3\\u0bd4\\u0007O\\u0002\\u0002\\u0bd4\\u0bd5\\u0007',\n  'G\\u0002\\u0002\\u0bd5\\u0bd6\\u0003\\u0002\\u0002\\u0002\\u0bd6\\u0bd7\\u0005',\n  '\\u01a9\\u00d5\\u0002\\u0bd7\\u0bd8\\u0007Y\\u0002\\u0002\\u0bd8\\u0bd9\\u0007',\n  'K\\u0002\\u0002\\u0bd9\\u0bda\\u0007V\\u0002\\u0002\\u0bda\\u0bdb\\u0007J\\u0002',\n  '\\u0002\\u0bdb\\u0bdc\\u0003\\u0002\\u0002\\u0002\\u0bdc\\u0bdd\\u0005\\u01a9\\u00d5',\n  '\\u0002\\u0bdd\\u0bde\\u0007V\\u0002\\u0002\\u0bde\\u0bdf\\u0007K\\u0002\\u0002',\n  '\\u0bdf\\u0be0\\u0007O\\u0002\\u0002\\u0be0\\u0be1\\u0007G\\u0002\\u0002\\u0be1',\n  '\\u0be2\\u0003\\u0002\\u0002\\u0002\\u0be2\\u0be3\\u0005\\u01a9\\u00d5\\u0002\\u0be3',\n  '\\u0be4\\u0007\\\\\\u0002\\u0002\\u0be4\\u0be5\\u0007Q\\u0002\\u0002\\u0be5\\u0be6',\n  '\\u0007P\\u0002\\u0002\\u0be6\\u0be7\\u0007G\\u0002\\u0002\\u0be7\\u019a\\u0003',\n  '\\u0002\\u0002\\u0002\\u0be8\\u0be9\\u0007V\\u0002\\u0002\\u0be9\\u0bea\\u0007',\n  'K\\u0002\\u0002\\u0bea\\u0beb\\u0007O\\u0002\\u0002\\u0beb\\u0bec\\u0007G\\u0002',\n  '\\u0002\\u0bec\\u0bed\\u0007U\\u0002\\u0002\\u0bed\\u0bee\\u0007V\\u0002\\u0002',\n  '\\u0bee\\u0bef\\u0007C\\u0002\\u0002\\u0bef\\u0bf0\\u0007O\\u0002\\u0002\\u0bf0',\n  '\\u0bf1\\u0007R\\u0002\\u0002\\u0bf1\\u0bf2\\u0003\\u0002\\u0002\\u0002\\u0bf2',\n  '\\u0bf3\\u0005\\u01a9\\u00d5\\u0002\\u0bf3\\u0bf4\\u0007Y\\u0002\\u0002\\u0bf4',\n  '\\u0bf5\\u0007K\\u0002\\u0002\\u0bf5\\u0bf6\\u0007V\\u0002\\u0002\\u0bf6\\u0bf7',\n  '\\u0007J\\u0002\\u0002\\u0bf7\\u0bf8\\u0003\\u0002\\u0002\\u0002\\u0bf8\\u0bf9',\n  '\\u0005\\u01a9\\u00d5\\u0002\\u0bf9\\u0bfa\\u0007V\\u0002\\u0002\\u0bfa\\u0bfb',\n  '\\u0007K\\u0002\\u0002\\u0bfb\\u0bfc\\u0007O\\u0002\\u0002\\u0bfc\\u0bfd\\u0007',\n  'G\\u0002\\u0002\\u0bfd\\u0bfe\\u0003\\u0002\\u0002\\u0002\\u0bfe\\u0bff\\u0005',\n  '\\u01a9\\u00d5\\u0002\\u0bff\\u0c00\\u0007\\\\\\u0002\\u0002\\u0c00\\u0c01\\u0007',\n  'Q\\u0002\\u0002\\u0c01\\u0c02\\u0007P\\u0002\\u0002\\u0c02\\u0c03\\u0007G\\u0002',\n  '\\u0002\\u0c03\\u019c\\u0003\\u0002\\u0002\\u0002\\u0c04\\u0c05\\u0007F\\u0002',\n  '\\u0002\\u0c05\\u0c06\\u0007Q\\u0002\\u0002\\u0c06\\u0c07\\u0007W\\u0002\\u0002',\n  '\\u0c07\\u0c08\\u0007D\\u0002\\u0002\\u0c08\\u0c09\\u0007N\\u0002\\u0002\\u0c09',\n  '\\u0c0a\\u0007G\\u0002\\u0002\\u0c0a\\u0c0b\\u0003\\u0002\\u0002\\u0002\\u0c0b',\n  '\\u0c0c\\u0005\\u01a9\\u00d5\\u0002\\u0c0c\\u0c0d\\u0007R\\u0002\\u0002\\u0c0d',\n  '\\u0c0e\\u0007T\\u0002\\u0002\\u0c0e\\u0c0f\\u0007G\\u0002\\u0002\\u0c0f\\u0c10',\n  '\\u0007E\\u0002\\u0002\\u0c10\\u0c11\\u0007K\\u0002\\u0002\\u0c11\\u0c12\\u0007',\n  'U\\u0002\\u0002\\u0c12\\u0c13\\u0007K\\u0002\\u0002\\u0c13\\u0c14\\u0007Q\\u0002',\n  '\\u0002\\u0c14\\u0c15\\u0007P\\u0002\\u0002\\u0c15\\u019e\\u0003\\u0002\\u0002',\n  '\\u0002\\u0c16\\u0c18\\u0007G\\u0002\\u0002\\u0c17\\u0c19\\t\\u0006\\u0002\\u0002',\n  '\\u0c18\\u0c17\\u0003\\u0002\\u0002\\u0002\\u0c18\\u0c19\\u0003\\u0002\\u0002\\u0002',\n  '\\u0c19\\u0c1b\\u0003\\u0002\\u0002\\u0002\\u0c1a\\u0c1c\\u0005\\u01a1\\u00d1\\u0002',\n  '\\u0c1b\\u0c1a\\u0003\\u0002\\u0002\\u0002\\u0c1c\\u0c1d\\u0003\\u0002\\u0002\\u0002',\n  '\\u0c1d\\u0c1b\\u0003\\u0002\\u0002\\u0002\\u0c1d\\u0c1e\\u0003\\u0002\\u0002\\u0002',\n  '\\u0c1e\\u01a0\\u0003\\u0002\\u0002\\u0002\\u0c1f\\u0c20\\t\\u0007\\u0002\\u0002',\n  '\\u0c20\\u01a2\\u0003\\u0002\\u0002\\u0002\\u0c21\\u0c23\\t\\b\\u0002\\u0002\\u0c22',\n  '\\u0c21\\u0003\\u0002\\u0002\\u0002\\u0c23\\u01a4\\u0003\\u0002\\u0002\\u0002\\u0c24',\n  '\\u0c25\\u0007/\\u0002\\u0002\\u0c25\\u0c26\\u0007/\\u0002\\u0002\\u0c26\\u0c2a',\n  '\\u0003\\u0002\\u0002\\u0002\\u0c27\\u0c29\\n\\t\\u0002\\u0002\\u0c28\\u0c27\\u0003',\n  '\\u0002\\u0002\\u0002\\u0c29\\u0c2c\\u0003\\u0002\\u0002\\u0002\\u0c2a\\u0c28\\u0003',\n  '\\u0002\\u0002\\u0002\\u0c2a\\u0c2b\\u0003\\u0002\\u0002\\u0002\\u0c2b\\u0c2e\\u0003',\n  '\\u0002\\u0002\\u0002\\u0c2c\\u0c2a\\u0003\\u0002\\u0002\\u0002\\u0c2d\\u0c2f\\u0007',\n  '\\u000f\\u0002\\u0002\\u0c2e\\u0c2d\\u0003\\u0002\\u0002\\u0002\\u0c2e\\u0c2f\\u0003',\n  '\\u0002\\u0002\\u0002\\u0c2f\\u0c31\\u0003\\u0002\\u0002\\u0002\\u0c30\\u0c32\\u0007',\n  '\\f\\u0002\\u0002\\u0c31\\u0c30\\u0003\\u0002\\u0002\\u0002\\u0c31\\u0c32\\u0003',\n  '\\u0002\\u0002\\u0002\\u0c32\\u0c33\\u0003\\u0002\\u0002\\u0002\\u0c33\\u0c34\\b',\n  '\\u00d3\\u0002\\u0002\\u0c34\\u01a6\\u0003\\u0002\\u0002\\u0002\\u0c35\\u0c36\\u0007',\n  '1\\u0002\\u0002\\u0c36\\u0c37\\u0007,\\u0002\\u0002\\u0c37\\u0c3b\\u0003\\u0002',\n  '\\u0002\\u0002\\u0c38\\u0c3a\\u000b\\u0002\\u0002\\u0002\\u0c39\\u0c38\\u0003\\u0002',\n  '\\u0002\\u0002\\u0c3a\\u0c3d\\u0003\\u0002\\u0002\\u0002\\u0c3b\\u0c3c\\u0003\\u0002',\n  '\\u0002\\u0002\\u0c3b\\u0c39\\u0003\\u0002\\u0002\\u0002\\u0c3c\\u0c3e\\u0003\\u0002',\n  '\\u0002\\u0002\\u0c3d\\u0c3b\\u0003\\u0002\\u0002\\u0002\\u0c3e\\u0c3f\\u0007,',\n  '\\u0002\\u0002\\u0c3f\\u0c40\\u00071\\u0002\\u0002\\u0c40\\u0c41\\u0003\\u0002',\n  '\\u0002\\u0002\\u0c41\\u0c42\\b\\u00d4\\u0002\\u0002\\u0c42\\u01a8\\u0003\\u0002',\n  '\\u0002\\u0002\\u0c43\\u0c45\\t\\n\\u0002\\u0002\\u0c44\\u0c43\\u0003\\u0002\\u0002',\n  '\\u0002\\u0c45\\u0c46\\u0003\\u0002\\u0002\\u0002\\u0c46\\u0c44\\u0003\\u0002\\u0002',\n  '\\u0002\\u0c46\\u0c47\\u0003\\u0002\\u0002\\u0002\\u0c47\\u0c48\\u0003\\u0002\\u0002',\n  '\\u0002\\u0c48\\u0c49\\b\\u00d5\\u0002\\u0002\\u0c49\\u01aa\\u0003\\u0002\\u0002',\n  '\\u0002\\u0c4a\\u0c4b\\u0007=\\u0002\\u0002\\u0c4b\\u01ac\\u0003\\u0002\\u0002',\n  '\\u0002\\u0c4c\\u0c4d\\u000b\\u0002\\u0002\\u0002\\u0c4d\\u01ae\\u0003\\u0002\\u0002',\n  '\\u0002\\u00cf\\u0002\\u01cf\\u01d9\\u01e1\\u01e7\\u01ef\\u01f9\\u0201\\u0213\\u021f',\n  '\\u022b\\u0231\\u0243\\u024d\\u0257\\u0265\\u0271\\u027f\\u028b\\u0291\\u0297\\u029f',\n  '\\u02a5\\u02ad\\u02b3\\u02c1\\u02d1\\u02db\\u02e1\\u02eb\\u02f5\\u0301\\u030d\\u0319',\n  '\\u0323\\u0331\\u0339\\u0343\\u0357\\u0369\\u0371\\u0381\\u0393\\u03a3\\u03ad\\u03b7',\n  '\\u03cb\\u03dd\\u03e7\\u03f3\\u03fb\\u0405\\u0413\\u0421\\u042b\\u0445\\u045f\\u0483',\n  '\\u0497\\u04b5\\u04c5\\u04cf\\u04d9\\u04e3\\u04ed\\u04f5\\u04ff\\u050b\\u0517\\u0523',\n  '\\u052d\\u0539\\u0543\\u0553\\u055f\\u0565\\u0573\\u057d\\u0591\\u059d\\u05a7\\u05bb',\n  '\\u05cf\\u05e3\\u05f3\\u05fb\\u0605\\u0619\\u0627\\u0635\\u0643\\u064f\\u0659\\u0669',\n  '\\u0677\\u0685\\u068f\\u06a5\\u06b7\\u06c3\\u06d1\\u06e7\\u06f5\\u0703\\u0713\\u0723',\n  '\\u0731\\u073b\\u0745\\u0757\\u0767\\u077f\\u0789\\u079b\\u07a5\\u07b3\\u07c3\\u07d5',\n  '\\u07e5\\u07f3\\u07fb\\u0811\\u0825\\u082f\\u083b\\u0849\\u085d\\u0863\\u0871\\u0885',\n  '\\u089d\\u08b5\\u08c1\\u08cf\\u08dd\\u08f3\\u08ff\\u0907\\u090f\\u091b\\u092b\\u0935',\n  '\\u0941\\u0959\\u0967\\u0979\\u0983\\u0997\\u09a3\\u09bd\\u09d3\\u09e7\\u09ff\\u0a09',\n  '\\u0a15\\u0a1f\\u0a29\\u0a39\\u0a4f\\u0a5f\\u0a6b\\u0a79\\u0a89\\u0a9b\\u0aaf\\u0ac3',\n  '\\u0ad9\\u0aed\\u0af7\\u0b01\\u0b0d\\u0b19\\u0b1f\\u0b2d\\u0b3f\\u0b47\\u0b64\\u0b66',\n  '\\u0b71\\u0b79\\u0b7e\\u0b84\\u0b8b\\u0b90\\u0b96\\u0b99\\u0ba1\\u0ba5\\u0ba9\\u0bae',\n  '\\u0bb0\\u0bb7\\u0bb9\\u0bbf\\u0bc1\\u0bca\\u0bcc\\u0c18\\u0c1d\\u0c22\\u0c2a\\u0c2e',\n  '\\u0c31\\u0c3b\\u0c46\\u0003\\u0002\\u0003\\u0002',\n].join('');\n\nconst atn = new _atn.ATNDeserializer().deserialize(serializedATN);\n\nconst decisionsToDFA = atn.decisionToState.map(function(ds, index) {\n  return new dfa.DFA(ds, index);\n});\n\nexport const SqlBaseLexer = function(input) {\n  Lexer.call(this, input);\n  this._interp = new _atn.LexerATNSimulator(\n    this,\n    atn,\n    decisionsToDFA,\n    new PredictionContextCache()\n  );\n  return this;\n} as any;\n\nSqlBaseLexer.prototype = Object.create(Lexer.prototype);\nSqlBaseLexer.prototype.constructor = SqlBaseLexer;\n\nSqlBaseLexer.EOF = Token.EOF;\nSqlBaseLexer.T__0 = 1;\nSqlBaseLexer.T__1 = 2;\nSqlBaseLexer.T__2 = 3;\nSqlBaseLexer.T__3 = 4;\nSqlBaseLexer.T__4 = 5;\nSqlBaseLexer.T__5 = 6;\nSqlBaseLexer.T__6 = 7;\nSqlBaseLexer.T__7 = 8;\nSqlBaseLexer.T__8 = 9;\nSqlBaseLexer.SELECT = 10;\nSqlBaseLexer.FROM = 11;\nSqlBaseLexer.ADD = 12;\nSqlBaseLexer.AS = 13;\nSqlBaseLexer.ALL = 14;\nSqlBaseLexer.SOME = 15;\nSqlBaseLexer.ANY = 16;\nSqlBaseLexer.DISTINCT = 17;\nSqlBaseLexer.WHERE = 18;\nSqlBaseLexer.GROUP = 19;\nSqlBaseLexer.BY = 20;\nSqlBaseLexer.GROUPING = 21;\nSqlBaseLexer.SETS = 22;\nSqlBaseLexer.CUBE = 23;\nSqlBaseLexer.ROLLUP = 24;\nSqlBaseLexer.ORDER = 25;\nSqlBaseLexer.HAVING = 26;\nSqlBaseLexer.LIMIT = 27;\nSqlBaseLexer.AT = 28;\nSqlBaseLexer.OR = 29;\nSqlBaseLexer.AND = 30;\nSqlBaseLexer.IN = 31;\nSqlBaseLexer.NOT = 32;\nSqlBaseLexer.NO = 33;\nSqlBaseLexer.EXISTS = 34;\nSqlBaseLexer.BETWEEN = 35;\nSqlBaseLexer.LIKE = 36;\nSqlBaseLexer.IS = 37;\nSqlBaseLexer.NULL = 38;\nSqlBaseLexer.TRUE = 39;\nSqlBaseLexer.FALSE = 40;\nSqlBaseLexer.NULLS = 41;\nSqlBaseLexer.FIRST = 42;\nSqlBaseLexer.LAST = 43;\nSqlBaseLexer.ESCAPE = 44;\nSqlBaseLexer.ASC = 45;\nSqlBaseLexer.DESC = 46;\nSqlBaseLexer.SUBSTRING = 47;\nSqlBaseLexer.POSITION = 48;\nSqlBaseLexer.FOR = 49;\nSqlBaseLexer.TINYINT = 50;\nSqlBaseLexer.SMALLINT = 51;\nSqlBaseLexer.INTEGER = 52;\nSqlBaseLexer.DATE = 53;\nSqlBaseLexer.TIME = 54;\nSqlBaseLexer.TIMESTAMP = 55;\nSqlBaseLexer.INTERVAL = 56;\nSqlBaseLexer.YEAR = 57;\nSqlBaseLexer.MONTH = 58;\nSqlBaseLexer.DAY = 59;\nSqlBaseLexer.HOUR = 60;\nSqlBaseLexer.MINUTE = 61;\nSqlBaseLexer.SECOND = 62;\nSqlBaseLexer.ZONE = 63;\nSqlBaseLexer.CURRENT_DATE = 64;\nSqlBaseLexer.CURRENT_TIME = 65;\nSqlBaseLexer.CURRENT_TIMESTAMP = 66;\nSqlBaseLexer.LOCALTIME = 67;\nSqlBaseLexer.LOCALTIMESTAMP = 68;\nSqlBaseLexer.EXTRACT = 69;\nSqlBaseLexer.CASE = 70;\nSqlBaseLexer.WHEN = 71;\nSqlBaseLexer.THEN = 72;\nSqlBaseLexer.ELSE = 73;\nSqlBaseLexer.END = 74;\nSqlBaseLexer.JOIN = 75;\nSqlBaseLexer.CROSS = 76;\nSqlBaseLexer.OUTER = 77;\nSqlBaseLexer.INNER = 78;\nSqlBaseLexer.LEFT = 79;\nSqlBaseLexer.RIGHT = 80;\nSqlBaseLexer.FULL = 81;\nSqlBaseLexer.NATURAL = 82;\nSqlBaseLexer.USING = 83;\nSqlBaseLexer.ON = 84;\nSqlBaseLexer.FILTER = 85;\nSqlBaseLexer.OVER = 86;\nSqlBaseLexer.PARTITION = 87;\nSqlBaseLexer.RANGE = 88;\nSqlBaseLexer.ROWS = 89;\nSqlBaseLexer.UNBOUNDED = 90;\nSqlBaseLexer.PRECEDING = 91;\nSqlBaseLexer.FOLLOWING = 92;\nSqlBaseLexer.CURRENT = 93;\nSqlBaseLexer.ROW = 94;\nSqlBaseLexer.WITH = 95;\nSqlBaseLexer.RECURSIVE = 96;\nSqlBaseLexer.VALUES = 97;\nSqlBaseLexer.CREATE = 98;\nSqlBaseLexer.SCHEMA = 99;\nSqlBaseLexer.TABLE = 100;\nSqlBaseLexer.VIEW = 101;\nSqlBaseLexer.REPLACE = 102;\nSqlBaseLexer.INSERT = 103;\nSqlBaseLexer.DELETE = 104;\nSqlBaseLexer.INTO = 105;\nSqlBaseLexer.CONSTRAINT = 106;\nSqlBaseLexer.DESCRIBE = 107;\nSqlBaseLexer.GRANT = 108;\nSqlBaseLexer.REVOKE = 109;\nSqlBaseLexer.PRIVILEGES = 110;\nSqlBaseLexer.PUBLIC = 111;\nSqlBaseLexer.OPTION = 112;\nSqlBaseLexer.EXPLAIN = 113;\nSqlBaseLexer.ANALYZE = 114;\nSqlBaseLexer.FORMAT = 115;\nSqlBaseLexer.TYPE = 116;\nSqlBaseLexer.TEXT = 117;\nSqlBaseLexer.GRAPHVIZ = 118;\nSqlBaseLexer.LOGICAL = 119;\nSqlBaseLexer.DISTRIBUTED = 120;\nSqlBaseLexer.CAST = 121;\nSqlBaseLexer.TRY_CAST = 122;\nSqlBaseLexer.SHOW = 123;\nSqlBaseLexer.TABLES = 124;\nSqlBaseLexer.SCHEMAS = 125;\nSqlBaseLexer.CATALOGS = 126;\nSqlBaseLexer.COLUMNS = 127;\nSqlBaseLexer.COLUMN = 128;\nSqlBaseLexer.USE = 129;\nSqlBaseLexer.PARTITIONS = 130;\nSqlBaseLexer.FUNCTIONS = 131;\nSqlBaseLexer.DROP = 132;\nSqlBaseLexer.UNION = 133;\nSqlBaseLexer.EXCEPT = 134;\nSqlBaseLexer.INTERSECT = 135;\nSqlBaseLexer.TO = 136;\nSqlBaseLexer.SYSTEM = 137;\nSqlBaseLexer.BERNOULLI = 138;\nSqlBaseLexer.POISSONIZED = 139;\nSqlBaseLexer.TABLESAMPLE = 140;\nSqlBaseLexer.ALTER = 141;\nSqlBaseLexer.RENAME = 142;\nSqlBaseLexer.UNNEST = 143;\nSqlBaseLexer.ORDINALITY = 144;\nSqlBaseLexer.ARRAY = 145;\nSqlBaseLexer.MAP = 146;\nSqlBaseLexer.SET = 147;\nSqlBaseLexer.RESET = 148;\nSqlBaseLexer.SESSION = 149;\nSqlBaseLexer.DATA = 150;\nSqlBaseLexer.START = 151;\nSqlBaseLexer.TRANSACTION = 152;\nSqlBaseLexer.COMMIT = 153;\nSqlBaseLexer.ROLLBACK = 154;\nSqlBaseLexer.WORK = 155;\nSqlBaseLexer.ISOLATION = 156;\nSqlBaseLexer.LEVEL = 157;\nSqlBaseLexer.SERIALIZABLE = 158;\nSqlBaseLexer.REPEATABLE = 159;\nSqlBaseLexer.COMMITTED = 160;\nSqlBaseLexer.UNCOMMITTED = 161;\nSqlBaseLexer.READ = 162;\nSqlBaseLexer.WRITE = 163;\nSqlBaseLexer.ONLY = 164;\nSqlBaseLexer.CALL = 165;\nSqlBaseLexer.PREPARE = 166;\nSqlBaseLexer.DEALLOCATE = 167;\nSqlBaseLexer.EXECUTE = 168;\nSqlBaseLexer.INPUT = 169;\nSqlBaseLexer.OUTPUT = 170;\nSqlBaseLexer.CASCADE = 171;\nSqlBaseLexer.RESTRICT = 172;\nSqlBaseLexer.INCLUDING = 173;\nSqlBaseLexer.EXCLUDING = 174;\nSqlBaseLexer.PROPERTIES = 175;\nSqlBaseLexer.NORMALIZE = 176;\nSqlBaseLexer.NFD = 177;\nSqlBaseLexer.NFC = 178;\nSqlBaseLexer.NFKD = 179;\nSqlBaseLexer.NFKC = 180;\nSqlBaseLexer.IF = 181;\nSqlBaseLexer.NULLIF = 182;\nSqlBaseLexer.COALESCE = 183;\nSqlBaseLexer.EQ = 184;\nSqlBaseLexer.NEQ = 185;\nSqlBaseLexer.LT = 186;\nSqlBaseLexer.LTE = 187;\nSqlBaseLexer.GT = 188;\nSqlBaseLexer.GTE = 189;\nSqlBaseLexer.PLUS = 190;\nSqlBaseLexer.MINUS = 191;\nSqlBaseLexer.ASTERISK = 192;\nSqlBaseLexer.SLASH = 193;\nSqlBaseLexer.PERCENT = 194;\nSqlBaseLexer.CONCAT = 195;\nSqlBaseLexer.STRING = 196;\nSqlBaseLexer.BINARY_LITERAL = 197;\nSqlBaseLexer.INTEGER_VALUE = 198;\nSqlBaseLexer.DECIMAL_VALUE = 199;\nSqlBaseLexer.IDENTIFIER = 200;\nSqlBaseLexer.DIGIT_IDENTIFIER = 201;\nSqlBaseLexer.QUOTED_IDENTIFIER = 202;\nSqlBaseLexer.BACKQUOTED_IDENTIFIER = 203;\nSqlBaseLexer.TIME_WITH_TIME_ZONE = 204;\nSqlBaseLexer.TIMESTAMP_WITH_TIME_ZONE = 205;\nSqlBaseLexer.DOUBLE_PRECISION = 206;\nSqlBaseLexer.SIMPLE_COMMENT = 207;\nSqlBaseLexer.BRACKETED_COMMENT = 208;\nSqlBaseLexer.WS = 209;\nSqlBaseLexer.SEMICOLON = 210;\nSqlBaseLexer.UNRECOGNIZED = 211;\n\nSqlBaseLexer.prototype.channelNames = ['DEFAULT_TOKEN_CHANNEL', 'HIDDEN'];\n\nSqlBaseLexer.prototype.modeNames = ['DEFAULT_MODE'];\n\nSqlBaseLexer.prototype.literalNames = [\n  null,\n  \"'.'\",\n  \"'('\",\n  \"','\",\n  \"')'\",\n  \"'?'\",\n  \"'->'\",\n  \"'['\",\n  \"']'\",\n  \"'=>'\",\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"'='\",\n  null,\n  \"'<'\",\n  \"'<='\",\n  \"'>'\",\n  \"'>='\",\n  \"'+'\",\n  \"'-'\",\n  \"'*'\",\n  \"'/'\",\n  \"'%'\",\n  \"'||'\",\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  \"';'\",\n];\n\nSqlBaseLexer.prototype.symbolicNames = [\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  null,\n  'SELECT',\n  'FROM',\n  'ADD',\n  'AS',\n  'ALL',\n  'SOME',\n  'ANY',\n  'DISTINCT',\n  'WHERE',\n  'GROUP',\n  'BY',\n  'GROUPING',\n  'SETS',\n  'CUBE',\n  'ROLLUP',\n  'ORDER',\n  'HAVING',\n  'LIMIT',\n  'AT',\n  'OR',\n  'AND',\n  'IN',\n  'NOT',\n  'NO',\n  'EXISTS',\n  'BETWEEN',\n  'LIKE',\n  'IS',\n  'NULL',\n  'TRUE',\n  'FALSE',\n  'NULLS',\n  'FIRST',\n  'LAST',\n  'ESCAPE',\n  'ASC',\n  'DESC',\n  'SUBSTRING',\n  'POSITION',\n  'FOR',\n  'TINYINT',\n  'SMALLINT',\n  'INTEGER',\n  'DATE',\n  'TIME',\n  'TIMESTAMP',\n  'INTERVAL',\n  'YEAR',\n  'MONTH',\n  'DAY',\n  'HOUR',\n  'MINUTE',\n  'SECOND',\n  'ZONE',\n  'CURRENT_DATE',\n  'CURRENT_TIME',\n  'CURRENT_TIMESTAMP',\n  'LOCALTIME',\n  'LOCALTIMESTAMP',\n  'EXTRACT',\n  'CASE',\n  'WHEN',\n  'THEN',\n  'ELSE',\n  'END',\n  'JOIN',\n  'CROSS',\n  'OUTER',\n  'INNER',\n  'LEFT',\n  'RIGHT',\n  'FULL',\n  'NATURAL',\n  'USING',\n  'ON',\n  'FILTER',\n  'OVER',\n  'PARTITION',\n  'RANGE',\n  'ROWS',\n  'UNBOUNDED',\n  'PRECEDING',\n  'FOLLOWING',\n  'CURRENT',\n  'ROW',\n  'WITH',\n  'RECURSIVE',\n  'VALUES',\n  'CREATE',\n  'SCHEMA',\n  'TABLE',\n  'VIEW',\n  'REPLACE',\n  'INSERT',\n  'DELETE',\n  'INTO',\n  'CONSTRAINT',\n  'DESCRIBE',\n  'GRANT',\n  'REVOKE',\n  'PRIVILEGES',\n  'PUBLIC',\n  'OPTION',\n  'EXPLAIN',\n  'ANALYZE',\n  'FORMAT',\n  'TYPE',\n  'TEXT',\n  'GRAPHVIZ',\n  'LOGICAL',\n  'DISTRIBUTED',\n  'CAST',\n  'TRY_CAST',\n  'SHOW',\n  'TABLES',\n  'SCHEMAS',\n  'CATALOGS',\n  'COLUMNS',\n  'COLUMN',\n  'USE',\n  'PARTITIONS',\n  'FUNCTIONS',\n  'DROP',\n  'UNION',\n  'EXCEPT',\n  'INTERSECT',\n  'TO',\n  'SYSTEM',\n  'BERNOULLI',\n  'POISSONIZED',\n  'TABLESAMPLE',\n  'ALTER',\n  'RENAME',\n  'UNNEST',\n  'ORDINALITY',\n  'ARRAY',\n  'MAP',\n  'SET',\n  'RESET',\n  'SESSION',\n  'DATA',\n  'START',\n  'TRANSACTION',\n  'COMMIT',\n  'ROLLBACK',\n  'WORK',\n  'ISOLATION',\n  'LEVEL',\n  'SERIALIZABLE',\n  'REPEATABLE',\n  'COMMITTED',\n  'UNCOMMITTED',\n  'READ',\n  'WRITE',\n  'ONLY',\n  'CALL',\n  'PREPARE',\n  'DEALLOCATE',\n  'EXECUTE',\n  'INPUT',\n  'OUTPUT',\n  'CASCADE',\n  'RESTRICT',\n  'INCLUDING',\n  'EXCLUDING',\n  'PROPERTIES',\n  'NORMALIZE',\n  'NFD',\n  'NFC',\n  'NFKD',\n  'NFKC',\n  'IF',\n  'NULLIF',\n  'COALESCE',\n  'EQ',\n  'NEQ',\n  'LT',\n  'LTE',\n  'GT',\n  'GTE',\n  'PLUS',\n  'MINUS',\n  'ASTERISK',\n  'SLASH',\n  'PERCENT',\n  'CONCAT',\n  'STRING',\n  'BINARY_LITERAL',\n  'INTEGER_VALUE',\n  'DECIMAL_VALUE',\n  'IDENTIFIER',\n  'DIGIT_IDENTIFIER',\n  'QUOTED_IDENTIFIER',\n  'BACKQUOTED_IDENTIFIER',\n  'TIME_WITH_TIME_ZONE',\n  'TIMESTAMP_WITH_TIME_ZONE',\n  'DOUBLE_PRECISION',\n  'SIMPLE_COMMENT',\n  'BRACKETED_COMMENT',\n  'WS',\n  'SEMICOLON',\n  'UNRECOGNIZED',\n];\n\nSqlBaseLexer.prototype.ruleNames = [\n  'T__0',\n  'T__1',\n  'T__2',\n  'T__3',\n  'T__4',\n  'T__5',\n  'T__6',\n  'T__7',\n  'T__8',\n  'SELECT',\n  'FROM',\n  'ADD',\n  'AS',\n  'ALL',\n  'SOME',\n  'ANY',\n  'DISTINCT',\n  'WHERE',\n  'GROUP',\n  'BY',\n  'GROUPING',\n  'SETS',\n  'CUBE',\n  'ROLLUP',\n  'ORDER',\n  'HAVING',\n  'LIMIT',\n  'AT',\n  'OR',\n  'AND',\n  'IN',\n  'NOT',\n  'NO',\n  'EXISTS',\n  'BETWEEN',\n  'LIKE',\n  'IS',\n  'NULL',\n  'TRUE',\n  'FALSE',\n  'NULLS',\n  'FIRST',\n  'LAST',\n  'ESCAPE',\n  'ASC',\n  'DESC',\n  'SUBSTRING',\n  'POSITION',\n  'FOR',\n  'TINYINT',\n  'SMALLINT',\n  'INTEGER',\n  'DATE',\n  'TIME',\n  'TIMESTAMP',\n  'INTERVAL',\n  'YEAR',\n  'MONTH',\n  'DAY',\n  'HOUR',\n  'MINUTE',\n  'SECOND',\n  'ZONE',\n  'CURRENT_DATE',\n  'CURRENT_TIME',\n  'CURRENT_TIMESTAMP',\n  'LOCALTIME',\n  'LOCALTIMESTAMP',\n  'EXTRACT',\n  'CASE',\n  'WHEN',\n  'THEN',\n  'ELSE',\n  'END',\n  'JOIN',\n  'CROSS',\n  'OUTER',\n  'INNER',\n  'LEFT',\n  'RIGHT',\n  'FULL',\n  'NATURAL',\n  'USING',\n  'ON',\n  'FILTER',\n  'OVER',\n  'PARTITION',\n  'RANGE',\n  'ROWS',\n  'UNBOUNDED',\n  'PRECEDING',\n  'FOLLOWING',\n  'CURRENT',\n  'ROW',\n  'WITH',\n  'RECURSIVE',\n  'VALUES',\n  'CREATE',\n  'SCHEMA',\n  'TABLE',\n  'VIEW',\n  'REPLACE',\n  'INSERT',\n  'DELETE',\n  'INTO',\n  'CONSTRAINT',\n  'DESCRIBE',\n  'GRANT',\n  'REVOKE',\n  'PRIVILEGES',\n  'PUBLIC',\n  'OPTION',\n  'EXPLAIN',\n  'ANALYZE',\n  'FORMAT',\n  'TYPE',\n  'TEXT',\n  'GRAPHVIZ',\n  'LOGICAL',\n  'DISTRIBUTED',\n  'CAST',\n  'TRY_CAST',\n  'SHOW',\n  'TABLES',\n  'SCHEMAS',\n  'CATALOGS',\n  'COLUMNS',\n  'COLUMN',\n  'USE',\n  'PARTITIONS',\n  'FUNCTIONS',\n  'DROP',\n  'UNION',\n  'EXCEPT',\n  'INTERSECT',\n  'TO',\n  'SYSTEM',\n  'BERNOULLI',\n  'POISSONIZED',\n  'TABLESAMPLE',\n  'ALTER',\n  'RENAME',\n  'UNNEST',\n  'ORDINALITY',\n  'ARRAY',\n  'MAP',\n  'SET',\n  'RESET',\n  'SESSION',\n  'DATA',\n  'START',\n  'TRANSACTION',\n  'COMMIT',\n  'ROLLBACK',\n  'WORK',\n  'ISOLATION',\n  'LEVEL',\n  'SERIALIZABLE',\n  'REPEATABLE',\n  'COMMITTED',\n  'UNCOMMITTED',\n  'READ',\n  'WRITE',\n  'ONLY',\n  'CALL',\n  'PREPARE',\n  'DEALLOCATE',\n  'EXECUTE',\n  'INPUT',\n  'OUTPUT',\n  'CASCADE',\n  'RESTRICT',\n  'INCLUDING',\n  'EXCLUDING',\n  'PROPERTIES',\n  'NORMALIZE',\n  'NFD',\n  'NFC',\n  'NFKD',\n  'NFKC',\n  'IF',\n  'NULLIF',\n  'COALESCE',\n  'EQ',\n  'NEQ',\n  'LT',\n  'LTE',\n  'GT',\n  'GTE',\n  'PLUS',\n  'MINUS',\n  'ASTERISK',\n  'SLASH',\n  'PERCENT',\n  'CONCAT',\n  'STRING',\n  'BINARY_LITERAL',\n  'INTEGER_VALUE',\n  'DECIMAL_VALUE',\n  'IDENTIFIER',\n  'DIGIT_IDENTIFIER',\n  'QUOTED_IDENTIFIER',\n  'BACKQUOTED_IDENTIFIER',\n  'TIME_WITH_TIME_ZONE',\n  'TIMESTAMP_WITH_TIME_ZONE',\n  'DOUBLE_PRECISION',\n  'EXPONENT',\n  'DIGIT',\n  'LETTER',\n  'SIMPLE_COMMENT',\n  'BRACKETED_COMMENT',\n  'WS',\n  'SEMICOLON',\n  'UNRECOGNIZED',\n];\n\nSqlBaseLexer.prototype.grammarFileName = 'SqlBase.g4';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseListener.ts",
    "content": "// Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7\n// jshint ignore: start\nimport { tree } from 'antlr4';\n\n// This class defines a complete listener for a parse tree produced by SqlBaseParser.\nexport const SqlBaseListener = function() {\n  tree.ParseTreeListener.call(this);\n  return this;\n} as any;\n\nSqlBaseListener.prototype = Object.create(tree.ParseTreeListener.prototype);\nSqlBaseListener.prototype.constructor = SqlBaseListener;\n\n// Enter a parse tree produced by SqlBaseParser#multiStatement.\nSqlBaseListener.prototype.enterMultiStatement = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#multiStatement.\nSqlBaseListener.prototype.exitMultiStatement = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#singleStatement.\nSqlBaseListener.prototype.enterSingleStatement = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#singleStatement.\nSqlBaseListener.prototype.exitSingleStatement = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#singleExpression.\nSqlBaseListener.prototype.enterSingleExpression = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#singleExpression.\nSqlBaseListener.prototype.exitSingleExpression = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#statementDefault.\nSqlBaseListener.prototype.enterStatementDefault = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#statementDefault.\nSqlBaseListener.prototype.exitStatementDefault = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#use.\nSqlBaseListener.prototype.enterUse = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#use.\nSqlBaseListener.prototype.exitUse = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#createSchema.\nSqlBaseListener.prototype.enterCreateSchema = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#createSchema.\nSqlBaseListener.prototype.exitCreateSchema = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#dropSchema.\nSqlBaseListener.prototype.enterDropSchema = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#dropSchema.\nSqlBaseListener.prototype.exitDropSchema = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#renameSchema.\nSqlBaseListener.prototype.enterRenameSchema = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#renameSchema.\nSqlBaseListener.prototype.exitRenameSchema = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#createTableAsSelect.\nSqlBaseListener.prototype.enterCreateTableAsSelect = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#createTableAsSelect.\nSqlBaseListener.prototype.exitCreateTableAsSelect = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#createTable.\nSqlBaseListener.prototype.enterCreateTable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#createTable.\nSqlBaseListener.prototype.exitCreateTable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#dropTable.\nSqlBaseListener.prototype.enterDropTable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#dropTable.\nSqlBaseListener.prototype.exitDropTable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#insertInto.\nSqlBaseListener.prototype.enterInsertInto = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#insertInto.\nSqlBaseListener.prototype.exitInsertInto = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#delete.\nSqlBaseListener.prototype.enterDelete = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#delete.\nSqlBaseListener.prototype.exitDelete = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#renameTable.\nSqlBaseListener.prototype.enterRenameTable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#renameTable.\nSqlBaseListener.prototype.exitRenameTable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#renameColumn.\nSqlBaseListener.prototype.enterRenameColumn = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#renameColumn.\nSqlBaseListener.prototype.exitRenameColumn = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#addColumn.\nSqlBaseListener.prototype.enterAddColumn = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#addColumn.\nSqlBaseListener.prototype.exitAddColumn = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#createView.\nSqlBaseListener.prototype.enterCreateView = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#createView.\nSqlBaseListener.prototype.exitCreateView = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#dropView.\nSqlBaseListener.prototype.enterDropView = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#dropView.\nSqlBaseListener.prototype.exitDropView = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#call.\nSqlBaseListener.prototype.enterCall = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#call.\nSqlBaseListener.prototype.exitCall = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#grant.\nSqlBaseListener.prototype.enterGrant = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#grant.\nSqlBaseListener.prototype.exitGrant = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#revoke.\nSqlBaseListener.prototype.enterRevoke = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#revoke.\nSqlBaseListener.prototype.exitRevoke = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#explain.\nSqlBaseListener.prototype.enterExplain = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#explain.\nSqlBaseListener.prototype.exitExplain = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showCreateTable.\nSqlBaseListener.prototype.enterShowCreateTable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showCreateTable.\nSqlBaseListener.prototype.exitShowCreateTable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showCreateView.\nSqlBaseListener.prototype.enterShowCreateView = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showCreateView.\nSqlBaseListener.prototype.exitShowCreateView = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showTables.\nSqlBaseListener.prototype.enterShowTables = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showTables.\nSqlBaseListener.prototype.exitShowTables = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showSchemas.\nSqlBaseListener.prototype.enterShowSchemas = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showSchemas.\nSqlBaseListener.prototype.exitShowSchemas = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showCatalogs.\nSqlBaseListener.prototype.enterShowCatalogs = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showCatalogs.\nSqlBaseListener.prototype.exitShowCatalogs = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showColumns.\nSqlBaseListener.prototype.enterShowColumns = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showColumns.\nSqlBaseListener.prototype.exitShowColumns = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showFunctions.\nSqlBaseListener.prototype.enterShowFunctions = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showFunctions.\nSqlBaseListener.prototype.exitShowFunctions = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showSession.\nSqlBaseListener.prototype.enterShowSession = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showSession.\nSqlBaseListener.prototype.exitShowSession = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#setSession.\nSqlBaseListener.prototype.enterSetSession = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#setSession.\nSqlBaseListener.prototype.exitSetSession = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#resetSession.\nSqlBaseListener.prototype.enterResetSession = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#resetSession.\nSqlBaseListener.prototype.exitResetSession = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#startTransaction.\nSqlBaseListener.prototype.enterStartTransaction = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#startTransaction.\nSqlBaseListener.prototype.exitStartTransaction = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#commit.\nSqlBaseListener.prototype.enterCommit = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#commit.\nSqlBaseListener.prototype.exitCommit = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#rollback.\nSqlBaseListener.prototype.enterRollback = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#rollback.\nSqlBaseListener.prototype.exitRollback = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#showPartitions.\nSqlBaseListener.prototype.enterShowPartitions = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#showPartitions.\nSqlBaseListener.prototype.exitShowPartitions = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#prepare.\nSqlBaseListener.prototype.enterPrepare = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#prepare.\nSqlBaseListener.prototype.exitPrepare = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#deallocate.\nSqlBaseListener.prototype.enterDeallocate = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#deallocate.\nSqlBaseListener.prototype.exitDeallocate = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#execute.\nSqlBaseListener.prototype.enterExecute = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#execute.\nSqlBaseListener.prototype.exitExecute = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#describeInput.\nSqlBaseListener.prototype.enterDescribeInput = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#describeInput.\nSqlBaseListener.prototype.exitDescribeInput = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#describeOutput.\nSqlBaseListener.prototype.enterDescribeOutput = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#describeOutput.\nSqlBaseListener.prototype.exitDescribeOutput = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#query.\nSqlBaseListener.prototype.enterQuery = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#query.\nSqlBaseListener.prototype.exitQuery = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#presto_with.\nSqlBaseListener.prototype.enterPresto_with = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#presto_with.\nSqlBaseListener.prototype.exitPresto_with = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#tableElement.\nSqlBaseListener.prototype.enterTableElement = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#tableElement.\nSqlBaseListener.prototype.exitTableElement = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#columnDefinition.\nSqlBaseListener.prototype.enterColumnDefinition = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#columnDefinition.\nSqlBaseListener.prototype.exitColumnDefinition = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#likeClause.\nSqlBaseListener.prototype.enterLikeClause = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#likeClause.\nSqlBaseListener.prototype.exitLikeClause = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#tableProperties.\nSqlBaseListener.prototype.enterTableProperties = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#tableProperties.\nSqlBaseListener.prototype.exitTableProperties = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#tableProperty.\nSqlBaseListener.prototype.enterTableProperty = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#tableProperty.\nSqlBaseListener.prototype.exitTableProperty = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#queryNoWith.\nSqlBaseListener.prototype.enterQueryNoWith = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#queryNoWith.\nSqlBaseListener.prototype.exitQueryNoWith = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#queryTermDefault.\nSqlBaseListener.prototype.enterQueryTermDefault = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#queryTermDefault.\nSqlBaseListener.prototype.exitQueryTermDefault = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#setOperation.\nSqlBaseListener.prototype.enterSetOperation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#setOperation.\nSqlBaseListener.prototype.exitSetOperation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#queryPrimaryDefault.\nSqlBaseListener.prototype.enterQueryPrimaryDefault = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#queryPrimaryDefault.\nSqlBaseListener.prototype.exitQueryPrimaryDefault = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#table.\nSqlBaseListener.prototype.enterTable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#table.\nSqlBaseListener.prototype.exitTable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#inlineTable.\nSqlBaseListener.prototype.enterInlineTable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#inlineTable.\nSqlBaseListener.prototype.exitInlineTable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#subquery.\nSqlBaseListener.prototype.enterSubquery = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#subquery.\nSqlBaseListener.prototype.exitSubquery = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#sortItem.\nSqlBaseListener.prototype.enterSortItem = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#sortItem.\nSqlBaseListener.prototype.exitSortItem = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#querySpecification.\nSqlBaseListener.prototype.enterQuerySpecification = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#querySpecification.\nSqlBaseListener.prototype.exitQuerySpecification = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#groupBy.\nSqlBaseListener.prototype.enterGroupBy = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#groupBy.\nSqlBaseListener.prototype.exitGroupBy = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#singleGroupingSet.\nSqlBaseListener.prototype.enterSingleGroupingSet = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#singleGroupingSet.\nSqlBaseListener.prototype.exitSingleGroupingSet = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#rollup.\nSqlBaseListener.prototype.enterRollup = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#rollup.\nSqlBaseListener.prototype.exitRollup = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#cube.\nSqlBaseListener.prototype.enterCube = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#cube.\nSqlBaseListener.prototype.exitCube = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#multipleGroupingSets.\nSqlBaseListener.prototype.enterMultipleGroupingSets = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#multipleGroupingSets.\nSqlBaseListener.prototype.exitMultipleGroupingSets = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#groupingExpressions.\nSqlBaseListener.prototype.enterGroupingExpressions = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#groupingExpressions.\nSqlBaseListener.prototype.exitGroupingExpressions = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#groupingSet.\nSqlBaseListener.prototype.enterGroupingSet = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#groupingSet.\nSqlBaseListener.prototype.exitGroupingSet = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#namedQuery.\nSqlBaseListener.prototype.enterNamedQuery = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#namedQuery.\nSqlBaseListener.prototype.exitNamedQuery = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#setQuantifier.\nSqlBaseListener.prototype.enterSetQuantifier = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#setQuantifier.\nSqlBaseListener.prototype.exitSetQuantifier = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#selectSingle.\nSqlBaseListener.prototype.enterSelectSingle = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#selectSingle.\nSqlBaseListener.prototype.exitSelectSingle = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#selectAll.\nSqlBaseListener.prototype.enterSelectAll = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#selectAll.\nSqlBaseListener.prototype.exitSelectAll = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#relationDefault.\nSqlBaseListener.prototype.enterRelationDefault = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#relationDefault.\nSqlBaseListener.prototype.exitRelationDefault = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#joinRelation.\nSqlBaseListener.prototype.enterJoinRelation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#joinRelation.\nSqlBaseListener.prototype.exitJoinRelation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#joinType.\nSqlBaseListener.prototype.enterJoinType = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#joinType.\nSqlBaseListener.prototype.exitJoinType = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#joinCriteria.\nSqlBaseListener.prototype.enterJoinCriteria = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#joinCriteria.\nSqlBaseListener.prototype.exitJoinCriteria = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#sampledRelation.\nSqlBaseListener.prototype.enterSampledRelation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#sampledRelation.\nSqlBaseListener.prototype.exitSampledRelation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#sampleType.\nSqlBaseListener.prototype.enterSampleType = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#sampleType.\nSqlBaseListener.prototype.exitSampleType = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#aliasedRelation.\nSqlBaseListener.prototype.enterAliasedRelation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#aliasedRelation.\nSqlBaseListener.prototype.exitAliasedRelation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#columnAliases.\nSqlBaseListener.prototype.enterColumnAliases = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#columnAliases.\nSqlBaseListener.prototype.exitColumnAliases = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#tableName.\nSqlBaseListener.prototype.enterTableName = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#tableName.\nSqlBaseListener.prototype.exitTableName = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#subqueryRelation.\nSqlBaseListener.prototype.enterSubqueryRelation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#subqueryRelation.\nSqlBaseListener.prototype.exitSubqueryRelation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#unnest.\nSqlBaseListener.prototype.enterUnnest = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#unnest.\nSqlBaseListener.prototype.exitUnnest = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#parenthesizedRelation.\nSqlBaseListener.prototype.enterParenthesizedRelation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#parenthesizedRelation.\nSqlBaseListener.prototype.exitParenthesizedRelation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#expression.\nSqlBaseListener.prototype.enterExpression = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#expression.\nSqlBaseListener.prototype.exitExpression = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#logicalNot.\nSqlBaseListener.prototype.enterLogicalNot = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#logicalNot.\nSqlBaseListener.prototype.exitLogicalNot = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#booleanDefault.\nSqlBaseListener.prototype.enterBooleanDefault = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#booleanDefault.\nSqlBaseListener.prototype.exitBooleanDefault = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#logicalBinary.\nSqlBaseListener.prototype.enterLogicalBinary = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#logicalBinary.\nSqlBaseListener.prototype.exitLogicalBinary = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#predicated.\nSqlBaseListener.prototype.enterPredicated = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#predicated.\nSqlBaseListener.prototype.exitPredicated = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#comparison.\nSqlBaseListener.prototype.enterComparison = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#comparison.\nSqlBaseListener.prototype.exitComparison = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#quantifiedComparison.\nSqlBaseListener.prototype.enterQuantifiedComparison = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#quantifiedComparison.\nSqlBaseListener.prototype.exitQuantifiedComparison = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#between.\nSqlBaseListener.prototype.enterBetween = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#between.\nSqlBaseListener.prototype.exitBetween = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#inList.\nSqlBaseListener.prototype.enterInList = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#inList.\nSqlBaseListener.prototype.exitInList = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#inSubquery.\nSqlBaseListener.prototype.enterInSubquery = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#inSubquery.\nSqlBaseListener.prototype.exitInSubquery = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#like.\nSqlBaseListener.prototype.enterLike = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#like.\nSqlBaseListener.prototype.exitLike = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#nullPredicate.\nSqlBaseListener.prototype.enterNullPredicate = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#nullPredicate.\nSqlBaseListener.prototype.exitNullPredicate = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#distinctFrom.\nSqlBaseListener.prototype.enterDistinctFrom = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#distinctFrom.\nSqlBaseListener.prototype.exitDistinctFrom = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#valueExpressionDefault.\nSqlBaseListener.prototype.enterValueExpressionDefault = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#valueExpressionDefault.\nSqlBaseListener.prototype.exitValueExpressionDefault = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#concatenation.\nSqlBaseListener.prototype.enterConcatenation = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#concatenation.\nSqlBaseListener.prototype.exitConcatenation = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#arithmeticBinary.\nSqlBaseListener.prototype.enterArithmeticBinary = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#arithmeticBinary.\nSqlBaseListener.prototype.exitArithmeticBinary = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#arithmeticUnary.\nSqlBaseListener.prototype.enterArithmeticUnary = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#arithmeticUnary.\nSqlBaseListener.prototype.exitArithmeticUnary = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#atTimeZone.\nSqlBaseListener.prototype.enterAtTimeZone = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#atTimeZone.\nSqlBaseListener.prototype.exitAtTimeZone = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#dereference.\nSqlBaseListener.prototype.enterDereference = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#dereference.\nSqlBaseListener.prototype.exitDereference = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#typeConstructor.\nSqlBaseListener.prototype.enterTypeConstructor = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#typeConstructor.\nSqlBaseListener.prototype.exitTypeConstructor = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#specialDateTimeFunction.\nSqlBaseListener.prototype.enterSpecialDateTimeFunction = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#specialDateTimeFunction.\nSqlBaseListener.prototype.exitSpecialDateTimeFunction = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#substring.\nSqlBaseListener.prototype.enterSubstring = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#substring.\nSqlBaseListener.prototype.exitSubstring = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#cast.\nSqlBaseListener.prototype.enterCast = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#cast.\nSqlBaseListener.prototype.exitCast = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#lambda.\nSqlBaseListener.prototype.enterLambda = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#lambda.\nSqlBaseListener.prototype.exitLambda = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#parameter.\nSqlBaseListener.prototype.enterParameter = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#parameter.\nSqlBaseListener.prototype.exitParameter = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#normalize.\nSqlBaseListener.prototype.enterNormalize = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#normalize.\nSqlBaseListener.prototype.exitNormalize = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#intervalLiteral.\nSqlBaseListener.prototype.enterIntervalLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#intervalLiteral.\nSqlBaseListener.prototype.exitIntervalLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#numericLiteral.\nSqlBaseListener.prototype.enterNumericLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#numericLiteral.\nSqlBaseListener.prototype.exitNumericLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#booleanLiteral.\nSqlBaseListener.prototype.enterBooleanLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#booleanLiteral.\nSqlBaseListener.prototype.exitBooleanLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#implicitRowConstructor.\nSqlBaseListener.prototype.enterImplicitRowConstructor = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#implicitRowConstructor.\nSqlBaseListener.prototype.exitImplicitRowConstructor = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#simpleCase.\nSqlBaseListener.prototype.enterSimpleCase = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#simpleCase.\nSqlBaseListener.prototype.exitSimpleCase = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#columnReference.\nSqlBaseListener.prototype.enterColumnReference = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#columnReference.\nSqlBaseListener.prototype.exitColumnReference = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#nullLiteral.\nSqlBaseListener.prototype.enterNullLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#nullLiteral.\nSqlBaseListener.prototype.exitNullLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#rowConstructor.\nSqlBaseListener.prototype.enterRowConstructor = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#rowConstructor.\nSqlBaseListener.prototype.exitRowConstructor = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#subscript.\nSqlBaseListener.prototype.enterSubscript = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#subscript.\nSqlBaseListener.prototype.exitSubscript = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#subqueryExpression.\nSqlBaseListener.prototype.enterSubqueryExpression = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#subqueryExpression.\nSqlBaseListener.prototype.exitSubqueryExpression = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#binaryLiteral.\nSqlBaseListener.prototype.enterBinaryLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#binaryLiteral.\nSqlBaseListener.prototype.exitBinaryLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#extract.\nSqlBaseListener.prototype.enterExtract = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#extract.\nSqlBaseListener.prototype.exitExtract = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#stringLiteral.\nSqlBaseListener.prototype.enterStringLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#stringLiteral.\nSqlBaseListener.prototype.exitStringLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#arrayConstructor.\nSqlBaseListener.prototype.enterArrayConstructor = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#arrayConstructor.\nSqlBaseListener.prototype.exitArrayConstructor = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#functionCall.\nSqlBaseListener.prototype.enterFunctionCall = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#functionCall.\nSqlBaseListener.prototype.exitFunctionCall = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#exists.\nSqlBaseListener.prototype.enterExists = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#exists.\nSqlBaseListener.prototype.exitExists = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#position.\nSqlBaseListener.prototype.enterPosition = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#position.\nSqlBaseListener.prototype.exitPosition = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#searchedCase.\nSqlBaseListener.prototype.enterSearchedCase = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#searchedCase.\nSqlBaseListener.prototype.exitSearchedCase = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#timeZoneInterval.\nSqlBaseListener.prototype.enterTimeZoneInterval = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#timeZoneInterval.\nSqlBaseListener.prototype.exitTimeZoneInterval = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#timeZoneString.\nSqlBaseListener.prototype.enterTimeZoneString = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#timeZoneString.\nSqlBaseListener.prototype.exitTimeZoneString = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#comparisonOperator.\nSqlBaseListener.prototype.enterComparisonOperator = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#comparisonOperator.\nSqlBaseListener.prototype.exitComparisonOperator = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#comparisonQuantifier.\nSqlBaseListener.prototype.enterComparisonQuantifier = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#comparisonQuantifier.\nSqlBaseListener.prototype.exitComparisonQuantifier = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#booleanValue.\nSqlBaseListener.prototype.enterBooleanValue = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#booleanValue.\nSqlBaseListener.prototype.exitBooleanValue = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#interval.\nSqlBaseListener.prototype.enterInterval = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#interval.\nSqlBaseListener.prototype.exitInterval = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#intervalField.\nSqlBaseListener.prototype.enterIntervalField = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#intervalField.\nSqlBaseListener.prototype.exitIntervalField = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#type.\nSqlBaseListener.prototype.enterType = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#type.\nSqlBaseListener.prototype.exitType = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#typeParameter.\nSqlBaseListener.prototype.enterTypeParameter = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#typeParameter.\nSqlBaseListener.prototype.exitTypeParameter = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#baseType.\nSqlBaseListener.prototype.enterBaseType = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#baseType.\nSqlBaseListener.prototype.exitBaseType = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#whenClause.\nSqlBaseListener.prototype.enterWhenClause = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#whenClause.\nSqlBaseListener.prototype.exitWhenClause = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#filter.\nSqlBaseListener.prototype.enterFilter = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#filter.\nSqlBaseListener.prototype.exitFilter = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#over.\nSqlBaseListener.prototype.enterOver = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#over.\nSqlBaseListener.prototype.exitOver = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#windowFrame.\nSqlBaseListener.prototype.enterWindowFrame = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#windowFrame.\nSqlBaseListener.prototype.exitWindowFrame = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#unboundedFrame.\nSqlBaseListener.prototype.enterUnboundedFrame = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#unboundedFrame.\nSqlBaseListener.prototype.exitUnboundedFrame = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#currentRowBound.\nSqlBaseListener.prototype.enterCurrentRowBound = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#currentRowBound.\nSqlBaseListener.prototype.exitCurrentRowBound = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#boundedFrame.\nSqlBaseListener.prototype.enterBoundedFrame = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#boundedFrame.\nSqlBaseListener.prototype.exitBoundedFrame = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#explainFormat.\nSqlBaseListener.prototype.enterExplainFormat = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#explainFormat.\nSqlBaseListener.prototype.exitExplainFormat = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#explainType.\nSqlBaseListener.prototype.enterExplainType = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#explainType.\nSqlBaseListener.prototype.exitExplainType = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#isolationLevel.\nSqlBaseListener.prototype.enterIsolationLevel = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#isolationLevel.\nSqlBaseListener.prototype.exitIsolationLevel = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#transactionAccessMode.\nSqlBaseListener.prototype.enterTransactionAccessMode = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#transactionAccessMode.\nSqlBaseListener.prototype.exitTransactionAccessMode = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#readUncommitted.\nSqlBaseListener.prototype.enterReadUncommitted = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#readUncommitted.\nSqlBaseListener.prototype.exitReadUncommitted = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#readCommitted.\nSqlBaseListener.prototype.enterReadCommitted = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#readCommitted.\nSqlBaseListener.prototype.exitReadCommitted = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#repeatableRead.\nSqlBaseListener.prototype.enterRepeatableRead = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#repeatableRead.\nSqlBaseListener.prototype.exitRepeatableRead = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#serializable.\nSqlBaseListener.prototype.enterSerializable = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#serializable.\nSqlBaseListener.prototype.exitSerializable = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#positionalArgument.\nSqlBaseListener.prototype.enterPositionalArgument = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#positionalArgument.\nSqlBaseListener.prototype.exitPositionalArgument = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#namedArgument.\nSqlBaseListener.prototype.enterNamedArgument = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#namedArgument.\nSqlBaseListener.prototype.exitNamedArgument = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#privilege.\nSqlBaseListener.prototype.enterPrivilege = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#privilege.\nSqlBaseListener.prototype.exitPrivilege = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#qualifiedName.\nSqlBaseListener.prototype.enterQualifiedName = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#qualifiedName.\nSqlBaseListener.prototype.exitQualifiedName = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#unquotedIdentifier.\nSqlBaseListener.prototype.enterUnquotedIdentifier = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#unquotedIdentifier.\nSqlBaseListener.prototype.exitUnquotedIdentifier = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#quotedIdentifierAlternative.\nSqlBaseListener.prototype.enterQuotedIdentifierAlternative = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#quotedIdentifierAlternative.\nSqlBaseListener.prototype.exitQuotedIdentifierAlternative = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#backQuotedIdentifier.\nSqlBaseListener.prototype.enterBackQuotedIdentifier = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#backQuotedIdentifier.\nSqlBaseListener.prototype.exitBackQuotedIdentifier = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#digitIdentifier.\nSqlBaseListener.prototype.enterDigitIdentifier = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#digitIdentifier.\nSqlBaseListener.prototype.exitDigitIdentifier = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#quotedIdentifier.\nSqlBaseListener.prototype.enterQuotedIdentifier = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#quotedIdentifier.\nSqlBaseListener.prototype.exitQuotedIdentifier = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#decimalLiteral.\nSqlBaseListener.prototype.enterDecimalLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#decimalLiteral.\nSqlBaseListener.prototype.exitDecimalLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#integerLiteral.\nSqlBaseListener.prototype.enterIntegerLiteral = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#integerLiteral.\nSqlBaseListener.prototype.exitIntegerLiteral = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#nonReserved.\nSqlBaseListener.prototype.enterNonReserved = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#nonReserved.\nSqlBaseListener.prototype.exitNonReserved = function(ctx) {};\n\n// Enter a parse tree produced by SqlBaseParser#normalForm.\nSqlBaseListener.prototype.enterNormalForm = function(ctx) {};\n\n// Exit a parse tree produced by SqlBaseParser#normalForm.\nSqlBaseListener.prototype.exitNormalForm = function(ctx) {};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseParser.ts",
    "content": "// Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7\n// jshint ignore: start\n\n// @ts-nocheck\n\nimport { atn as _atn, dfa, PredictionContextCache, Parser, Token, ParserRuleContext, error as _error } from 'antlr4';\nimport { SqlBaseListener } from './SqlBaseListener';\nimport { SqlBaseVisitor } from './SqlBaseVisitor';\n\nvar grammarFileName = \"SqlBase.g4\";\n\nvar serializedATN = [\"\\u0003\\u608b\\ua72a\\u8133\\ub9ed\\u417c\\u3be7\\u7786\\u5964\",\n    \"\\u0003\\u00d6\\u05e0\\u0004\\u0002\\t\\u0002\\u0004\\u0003\\t\\u0003\\u0004\\u0004\",\n    \"\\t\\u0004\\u0004\\u0005\\t\\u0005\\u0004\\u0006\\t\\u0006\\u0004\\u0007\\t\\u0007\",\n    \"\\u0004\\b\\t\\b\\u0004\\t\\t\\t\\u0004\\n\\t\\n\\u0004\\u000b\\t\\u000b\\u0004\\f\\t\\f\",\n    \"\\u0004\\r\\t\\r\\u0004\\u000e\\t\\u000e\\u0004\\u000f\\t\\u000f\\u0004\\u0010\\t\\u0010\",\n    \"\\u0004\\u0011\\t\\u0011\\u0004\\u0012\\t\\u0012\\u0004\\u0013\\t\\u0013\\u0004\\u0014\",\n    \"\\t\\u0014\\u0004\\u0015\\t\\u0015\\u0004\\u0016\\t\\u0016\\u0004\\u0017\\t\\u0017\",\n    \"\\u0004\\u0018\\t\\u0018\\u0004\\u0019\\t\\u0019\\u0004\\u001a\\t\\u001a\\u0004\\u001b\",\n    \"\\t\\u001b\\u0004\\u001c\\t\\u001c\\u0004\\u001d\\t\\u001d\\u0004\\u001e\\t\\u001e\",\n    \"\\u0004\\u001f\\t\\u001f\\u0004 \\t \\u0004!\\t!\\u0004\\\"\\t\\\"\\u0004#\\t#\\u0004\",\n    \"$\\t$\\u0004%\\t%\\u0004&\\t&\\u0004\\'\\t\\'\\u0004(\\t(\\u0004)\\t)\\u0004*\\t*\\u0004\",\n    \"+\\t+\\u0004,\\t,\\u0004-\\t-\\u0004.\\t.\\u0004/\\t/\\u00040\\t0\\u00041\\t1\\u0004\",\n    \"2\\t2\\u00043\\t3\\u00044\\t4\\u00045\\t5\\u00046\\t6\\u00047\\t7\\u00048\\t8\\u0004\",\n    \"9\\t9\\u0004:\\t:\\u0004;\\t;\\u0004<\\t<\\u0004=\\t=\\u0004>\\t>\\u0004?\\t?\\u0003\",\n    \"\\u0002\\u0003\\u0002\\u0003\\u0002\\u0007\\u0002\\u0082\\n\\u0002\\f\\u0002\\u000e\",\n    \"\\u0002\\u0085\\u000b\\u0002\\u0003\\u0002\\u0005\\u0002\\u0088\\n\\u0002\\u0003\",\n    \"\\u0002\\u0003\\u0002\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0004\\u0003\",\n    \"\\u0004\\u0003\\u0004\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u009f\\n\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00a4\\n\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00aa\\n\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0005\\u0005\\u00ae\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00bc\\n\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00c1\\n\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00c7\\n\\u0005\",\n    \"\\u0003\\u0005\\u0005\\u0005\\u00ca\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00d1\\n\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0007\\u0005\\u00d8\\n\",\n    \"\\u0005\\f\\u0005\\u000e\\u0005\\u00db\\u000b\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0005\\u0005\\u00e0\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0005\\u0005\\u00e6\\n\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u00ed\\n\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0005\\u0005\\u00f6\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\",\n    \"\\u0112\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u011d\",\n    \"\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0007\\u0005\\u0126\\n\\u0005\\f\\u0005\\u000e\\u0005\",\n    \"\\u0129\\u000b\\u0005\\u0005\\u0005\\u012b\\n\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0007\\u0005\\u0133\\n\",\n    \"\\u0005\\f\\u0005\\u000e\\u0005\\u0136\\u000b\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0005\\u0005\\u013a\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u013e\",\n    \"\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0005\\u0005\\u0146\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0005\\u0005\\u014c\\n\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0007\\u0005\\u0151\\n\\u0005\\f\\u0005\\u000e\\u0005\\u0154\\u000b\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u0158\\n\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0005\\u0005\\u015c\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u0164\\n\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0007\\u0005\\u016a\\n\",\n    \"\\u0005\\f\\u0005\\u000e\\u0005\\u016d\\u000b\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0005\\u0005\\u0171\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u0180\\n\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u0184\\n\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u018a\\n\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0005\\u0005\\u018e\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0005\\u0005\\u0194\\n\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0007\\u0005\\u01b0\\n\\u0005\\f\\u0005\\u000e\\u0005\\u01b3\\u000b\\u0005\\u0005\",\n    \"\\u0005\\u01b5\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u01b9\\n\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u01bd\\n\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u01c5\",\n    \"\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0007\\u0005\\u01cc\\n\\u0005\\f\\u0005\\u000e\\u0005\\u01cf\\u000b\\u0005\\u0005\",\n    \"\\u0005\\u01d1\\n\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u01d5\\n\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0007\\u0005\\u01e5\\n\\u0005\\f\\u0005\\u000e\\u0005\",\n    \"\\u01e8\\u000b\\u0005\\u0005\\u0005\\u01ea\\n\\u0005\\u0003\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\\u0005\\u01f2\\n\",\n    \"\\u0005\\u0003\\u0006\\u0005\\u0006\\u01f5\\n\\u0006\\u0003\\u0006\\u0003\\u0006\",\n    \"\\u0003\\u0007\\u0003\\u0007\\u0005\\u0007\\u01fb\\n\\u0007\\u0003\\u0007\\u0003\",\n    \"\\u0007\\u0003\\u0007\\u0007\\u0007\\u0200\\n\\u0007\\f\\u0007\\u000e\\u0007\\u0203\",\n    \"\\u000b\\u0007\\u0003\\b\\u0003\\b\\u0005\\b\\u0207\\n\\b\\u0003\\t\\u0003\\t\\u0003\",\n    \"\\t\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0005\\n\\u0210\\n\\n\\u0003\\u000b\\u0003\",\n    \"\\u000b\\u0003\\u000b\\u0003\\u000b\\u0007\\u000b\\u0216\\n\\u000b\\f\\u000b\\u000e\",\n    \"\\u000b\\u0219\\u000b\\u000b\\u0003\\u000b\\u0003\\u000b\\u0003\\f\\u0003\\f\\u0003\",\n    \"\\f\\u0003\\f\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0007\\r\\u0227\",\n    \"\\n\\r\\f\\r\\u000e\\r\\u022a\\u000b\\r\\u0005\\r\\u022c\\n\\r\\u0003\\r\\u0003\\r\\u0005\",\n    \"\\r\\u0230\\n\\r\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\",\n    \"\\u0003\\u000e\\u0005\\u000e\\u0238\\n\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\",\n    \"\\u000e\\u0003\\u000e\\u0005\\u000e\\u023e\\n\\u000e\\u0003\\u000e\\u0007\\u000e\",\n    \"\\u0241\\n\\u000e\\f\\u000e\\u000e\\u000e\\u0244\\u000b\\u000e\\u0003\\u000f\\u0003\",\n    \"\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0007\",\n    \"\\u000f\\u024d\\n\\u000f\\f\\u000f\\u000e\\u000f\\u0250\\u000b\\u000f\\u0003\\u000f\",\n    \"\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0005\\u000f\\u0256\\n\\u000f\\u0003\",\n    \"\\u0010\\u0003\\u0010\\u0005\\u0010\\u025a\\n\\u0010\\u0003\\u0010\\u0003\\u0010\",\n    \"\\u0005\\u0010\\u025e\\n\\u0010\\u0003\\u0011\\u0003\\u0011\\u0005\\u0011\\u0262\",\n    \"\\n\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0007\\u0011\\u0267\\n\\u0011\",\n    \"\\f\\u0011\\u000e\\u0011\\u026a\\u000b\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\",\n    \"\\u0011\\u0003\\u0011\\u0007\\u0011\\u0270\\n\\u0011\\f\\u0011\\u000e\\u0011\\u0273\",\n    \"\\u000b\\u0011\\u0005\\u0011\\u0275\\n\\u0011\\u0003\\u0011\\u0003\\u0011\\u0005\",\n    \"\\u0011\\u0279\\n\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0005\\u0011\",\n    \"\\u027e\\n\\u0011\\u0003\\u0011\\u0003\\u0011\\u0005\\u0011\\u0282\\n\\u0011\\u0003\",\n    \"\\u0012\\u0005\\u0012\\u0285\\n\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\",\n    \"\\u0007\\u0012\\u028a\\n\\u0012\\f\\u0012\\u000e\\u0012\\u028d\\u000b\\u0012\\u0003\",\n    \"\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0007\",\n    \"\\u0013\\u0295\\n\\u0013\\f\\u0013\\u000e\\u0013\\u0298\\u000b\\u0013\\u0005\\u0013\",\n    \"\\u029a\\n\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\",\n    \"\\u0013\\u0003\\u0013\\u0007\\u0013\\u02a2\\n\\u0013\\f\\u0013\\u000e\\u0013\\u02a5\",\n    \"\\u000b\\u0013\\u0005\\u0013\\u02a7\\n\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\",\n    \"\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0007\\u0013\\u02b0\",\n    \"\\n\\u0013\\f\\u0013\\u000e\\u0013\\u02b3\\u000b\\u0013\\u0003\\u0013\\u0003\\u0013\",\n    \"\\u0005\\u0013\\u02b7\\n\\u0013\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\",\n    \"\\u0014\\u0007\\u0014\\u02bd\\n\\u0014\\f\\u0014\\u000e\\u0014\\u02c0\\u000b\\u0014\",\n    \"\\u0005\\u0014\\u02c2\\n\\u0014\\u0003\\u0014\\u0003\\u0014\\u0005\\u0014\\u02c6\",\n    \"\\n\\u0014\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0007\\u0015\",\n    \"\\u02cc\\n\\u0015\\f\\u0015\\u000e\\u0015\\u02cf\\u000b\\u0015\\u0005\\u0015\\u02d1\",\n    \"\\n\\u0015\\u0003\\u0015\\u0003\\u0015\\u0005\\u0015\\u02d5\\n\\u0015\\u0003\\u0016\",\n    \"\\u0003\\u0016\\u0005\\u0016\\u02d9\\n\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\",\n    \"\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0017\\u0003\\u0017\\u0003\\u0018\\u0003\",\n    \"\\u0018\\u0005\\u0018\\u02e4\\n\\u0018\\u0003\\u0018\\u0005\\u0018\\u02e7\\n\\u0018\",\n    \"\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0005\\u0018\",\n    \"\\u02ee\\n\\u0018\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\",\n    \"\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\",\n    \"\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\",\n    \"\\u0019\\u0005\\u0019\\u0301\\n\\u0019\\u0007\\u0019\\u0303\\n\\u0019\\f\\u0019\\u000e\",\n    \"\\u0019\\u0306\\u000b\\u0019\\u0003\\u001a\\u0005\\u001a\\u0309\\n\\u001a\\u0003\",\n    \"\\u001a\\u0003\\u001a\\u0005\\u001a\\u030d\\n\\u001a\\u0003\\u001a\\u0003\\u001a\",\n    \"\\u0005\\u001a\\u0311\\n\\u001a\\u0003\\u001a\\u0003\\u001a\\u0005\\u001a\\u0315\",\n    \"\\n\\u001a\\u0005\\u001a\\u0317\\n\\u001a\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\",\n    \"\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0007\\u001b\\u0320\\n\",\n    \"\\u001b\\f\\u001b\\u000e\\u001b\\u0323\\u000b\\u001b\\u0003\\u001b\\u0003\\u001b\",\n    \"\\u0005\\u001b\\u0327\\n\\u001b\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\",\n    \"\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0005\\u001c\\u0330\\n\\u001c\",\n    \"\\u0003\\u001d\\u0003\\u001d\\u0003\\u001e\\u0003\\u001e\\u0005\\u001e\\u0336\\n\",\n    \"\\u001e\\u0003\\u001e\\u0003\\u001e\\u0005\\u001e\\u033a\\n\\u001e\\u0005\\u001e\",\n    \"\\u033c\\n\\u001e\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0007\",\n    \"\\u001f\\u0342\\n\\u001f\\f\\u001f\\u000e\\u001f\\u0345\\u000b\\u001f\\u0003\\u001f\",\n    \"\\u0003\\u001f\\u0003 \\u0003 \\u0003 \\u0003 \\u0003 \\u0003 \\u0003 \\u0003\",\n    \" \\u0003 \\u0003 \\u0007 \\u0353\\n \\f \\u000e \\u0356\\u000b \\u0003 \\u0003\",\n    \" \\u0003 \\u0005 \\u035b\\n \\u0003 \\u0003 \\u0003 \\u0003 \\u0005 \\u0361\\n\",\n    \" \\u0003!\\u0003!\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0005\\\"\\u0369\\n\\\"\\u0003\",\n    \"\\\"\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0007\\\"\\u0371\\n\\\"\\f\\\"\\u000e\",\n    \"\\\"\\u0374\\u000b\\\"\\u0003#\\u0003#\\u0005#\\u0378\\n#\\u0003$\\u0003$\\u0003$\",\n    \"\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0005$\\u0384\\n$\\u0003\",\n    \"$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0005$\\u038c\\n$\\u0003$\\u0003$\\u0003\",\n    \"$\\u0003$\\u0003$\\u0007$\\u0393\\n$\\f$\\u000e$\\u0396\\u000b$\\u0003$\\u0003\",\n    \"$\\u0003$\\u0005$\\u039b\\n$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0003$\\u0005\",\n    \"$\\u03a3\\n$\\u0003$\\u0003$\\u0003$\\u0003$\\u0005$\\u03a9\\n$\\u0003$\\u0003\",\n    \"$\\u0005$\\u03ad\\n$\\u0003$\\u0003$\\u0003$\\u0005$\\u03b2\\n$\\u0003$\\u0003\",\n    \"$\\u0003$\\u0005$\\u03b7\\n$\\u0003%\\u0003%\\u0003%\\u0003%\\u0005%\\u03bd\\n\",\n    \"%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003%\\u0003\",\n    \"%\\u0003%\\u0003%\\u0007%\\u03cb\\n%\\f%\\u000e%\\u03ce\\u000b%\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0007&\\u03e8\\n&\\f&\\u000e&\\u03eb\\u000b&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0007&\\u03f4\\n&\\f&\\u000e&\\u03f7\",\n    \"\\u000b&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u0400\",\n    \"\\n&\\u0003&\\u0005&\\u0403\\n&\\u0003&\\u0003&\\u0003&\\u0005&\\u0408\\n&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0007&\\u040d\\n&\\f&\\u000e&\\u0410\\u000b&\\u0005&\\u0412\",\n    \"\\n&\\u0003&\\u0003&\\u0005&\\u0416\\n&\\u0003&\\u0005&\\u0419\\n&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0007&\\u0423\\n&\\f&\\u000e\",\n    \"&\\u0426\\u000b&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0006&\\u0438\",\n    \"\\n&\\r&\\u000e&\\u0439\\u0003&\\u0003&\\u0005&\\u043e\\n&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0006&\\u0444\\n&\\r&\\u000e&\\u0445\\u0003&\\u0003&\\u0005&\\u044a\",\n    \"\\n&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0007&\\u0461\\n&\\f&\\u000e&\\u0464\\u000b&\\u0005&\\u0466\\n&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u046f\\n&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0005&\\u0475\\n&\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u047b\",\n    \"\\n&\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u0481\\n&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u048a\\n&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0005&\\u0493\\n&\\u0003&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u049e\\n&\\u0003&\\u0003&\\u0003&\\u0003\",\n    \"&\\u0003&\\u0003&\\u0003&\\u0003&\\u0007&\\u04a8\\n&\\f&\\u000e&\\u04ab\\u000b\",\n    \"&\\u0003\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0005\\'\\u04b3\\n\\'\",\n    \"\\u0003(\\u0003(\\u0003)\\u0003)\\u0003*\\u0003*\\u0003+\\u0003+\\u0005+\\u04bd\",\n    \"\\n+\\u0003+\\u0003+\\u0003+\\u0003+\\u0005+\\u04c3\\n+\\u0003,\\u0003,\\u0003\",\n    \"-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003\",\n    \"-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003-\\u0003\",\n    \"-\\u0007-\\u04dc\\n-\\f-\\u000e-\\u04df\\u000b-\\u0003-\\u0003-\\u0003-\\u0003\",\n    \"-\\u0003-\\u0003-\\u0003-\\u0007-\\u04e8\\n-\\f-\\u000e-\\u04eb\\u000b-\\u0003\",\n    \"-\\u0003-\\u0005-\\u04ef\\n-\\u0005-\\u04f1\\n-\\u0003-\\u0003-\\u0007-\\u04f5\",\n    \"\\n-\\f-\\u000e-\\u04f8\\u000b-\\u0003.\\u0003.\\u0005.\\u04fc\\n.\\u0003/\\u0003\",\n    \"/\\u0003/\\u0003/\\u0005/\\u0502\\n/\\u00030\\u00030\\u00030\\u00030\\u00030\\u0003\",\n    \"1\\u00031\\u00031\\u00031\\u00031\\u00031\\u00032\\u00032\\u00032\\u00032\\u0003\",\n    \"2\\u00032\\u00032\\u00072\\u0516\\n2\\f2\\u000e2\\u0519\\u000b2\\u00052\\u051b\",\n    \"\\n2\\u00032\\u00032\\u00032\\u00032\\u00032\\u00072\\u0522\\n2\\f2\\u000e2\\u0525\",\n    \"\\u000b2\\u00052\\u0527\\n2\\u00032\\u00052\\u052a\\n2\\u00032\\u00032\\u00033\",\n    \"\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u00033\\u0003\",\n    \"3\\u00033\\u00033\\u00033\\u00033\\u00033\\u00053\\u053e\\n3\\u00034\\u00034\\u0003\",\n    \"4\\u00034\\u00034\\u00034\\u00034\\u00034\\u00034\\u00054\\u0549\\n4\\u00035\\u0003\",\n    \"5\\u00035\\u00035\\u00055\\u054f\\n5\\u00036\\u00036\\u00036\\u00036\\u00036\\u0005\",\n    \"6\\u0556\\n6\\u00037\\u00037\\u00037\\u00037\\u00037\\u00037\\u00037\\u00057\\u055f\",\n    \"\\n7\\u00038\\u00038\\u00038\\u00038\\u00038\\u00058\\u0566\\n8\\u00039\\u0003\",\n    \"9\\u00039\\u00039\\u00059\\u056c\\n9\\u0003:\\u0003:\\u0003:\\u0007:\\u0571\\n\",\n    \":\\f:\\u000e:\\u0574\\u000b:\\u0003;\\u0003;\\u0003;\\u0003;\\u0003;\\u0005;\\u057b\",\n    \"\\n;\\u0003<\\u0003<\\u0003=\\u0003=\\u0005=\\u0581\\n=\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003\",\n    \">\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0005>\\u05dc\\n>\\u0003?\\u0003\",\n    \"?\\u0003?\\u0002\\b\\u001a0BHJX@\\u0002\\u0004\\u0006\\b\\n\\f\\u000e\\u0010\\u0012\",\n    \"\\u0014\\u0016\\u0018\\u001a\\u001c\\u001e \\\"$&(*,.02468:<>@BDFHJLNPRTVXZ\",\n    \"\\\\^`bdfhjlnprtvxz|\\u0002\\u0016\\u0003\\u0002\\u00ad\\u00ae\\u0004\\u0002\\r\",\n    \"\\r!!\\u0004\\u0002\\u0010\\u0010\\u00c8\\u00c8\\u0003\\u0002\\u00af\\u00b0\\u0003\",\n    \"\\u0002\\u0087\\u0088\\u0003\\u0002/0\\u0003\\u0002,-\\u0004\\u0002\\u0010\\u0010\",\n    \"\\u0013\\u0013\\u0003\\u0002\\u008b\\u008d\\u0003\\u0002\\u00c0\\u00c1\\u0003\\u0002\",\n    \"\\u00c2\\u00c4\\u0003\\u0002\\u00ba\\u00bf\\u0003\\u0002\\u0010\\u0012\\u0003\\u0002\",\n    \")*\\u0003\\u0002;@\\u0003\\u0002]^\\u0003\\u0002wx\\u0003\\u0002yz\\u0003\\u0002\",\n    \"\\u00a5\\u00a6\\u0003\\u0002\\u00b3\\u00b6\\u0002\\u070b\\u0002~\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0004\\u008b\\u0003\\u0002\\u0002\\u0002\\u0006\\u008e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\b\\u01f1\\u0003\\u0002\\u0002\\u0002\\n\\u01f4\\u0003\\u0002\\u0002\",\n    \"\\u0002\\f\\u01f8\\u0003\\u0002\\u0002\\u0002\\u000e\\u0206\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0010\\u0208\\u0003\\u0002\\u0002\\u0002\\u0012\\u020b\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0014\\u0211\\u0003\\u0002\\u0002\\u0002\\u0016\\u021c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0018\\u0220\\u0003\\u0002\\u0002\\u0002\\u001a\\u0231\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u001c\\u0255\\u0003\\u0002\\u0002\\u0002\\u001e\\u0257\\u0003\\u0002\\u0002\",\n    \"\\u0002 \\u025f\\u0003\\u0002\\u0002\\u0002\\\"\\u0284\\u0003\\u0002\\u0002\\u0002\",\n    \"$\\u02b6\\u0003\\u0002\\u0002\\u0002&\\u02c5\\u0003\\u0002\\u0002\\u0002(\\u02d4\",\n    \"\\u0003\\u0002\\u0002\\u0002*\\u02d6\\u0003\\u0002\\u0002\\u0002,\\u02df\\u0003\",\n    \"\\u0002\\u0002\\u0002.\\u02ed\\u0003\\u0002\\u0002\\u00020\\u02ef\\u0003\\u0002\",\n    \"\\u0002\\u00022\\u0316\\u0003\\u0002\\u0002\\u00024\\u0326\\u0003\\u0002\\u0002\",\n    \"\\u00026\\u0328\\u0003\\u0002\\u0002\\u00028\\u0331\\u0003\\u0002\\u0002\\u0002\",\n    \":\\u0333\\u0003\\u0002\\u0002\\u0002<\\u033d\\u0003\\u0002\\u0002\\u0002>\\u0360\",\n    \"\\u0003\\u0002\\u0002\\u0002@\\u0362\\u0003\\u0002\\u0002\\u0002B\\u0368\\u0003\",\n    \"\\u0002\\u0002\\u0002D\\u0375\\u0003\\u0002\\u0002\\u0002F\\u03b6\\u0003\\u0002\",\n    \"\\u0002\\u0002H\\u03bc\\u0003\\u0002\\u0002\\u0002J\\u049d\\u0003\\u0002\\u0002\",\n    \"\\u0002L\\u04b2\\u0003\\u0002\\u0002\\u0002N\\u04b4\\u0003\\u0002\\u0002\\u0002\",\n    \"P\\u04b6\\u0003\\u0002\\u0002\\u0002R\\u04b8\\u0003\\u0002\\u0002\\u0002T\\u04ba\",\n    \"\\u0003\\u0002\\u0002\\u0002V\\u04c4\\u0003\\u0002\\u0002\\u0002X\\u04f0\\u0003\",\n    \"\\u0002\\u0002\\u0002Z\\u04fb\\u0003\\u0002\\u0002\\u0002\\\\\\u0501\\u0003\\u0002\",\n    \"\\u0002\\u0002^\\u0503\\u0003\\u0002\\u0002\\u0002`\\u0508\\u0003\\u0002\\u0002\",\n    \"\\u0002b\\u050e\\u0003\\u0002\\u0002\\u0002d\\u053d\\u0003\\u0002\\u0002\\u0002\",\n    \"f\\u0548\\u0003\\u0002\\u0002\\u0002h\\u054e\\u0003\\u0002\\u0002\\u0002j\\u0555\",\n    \"\\u0003\\u0002\\u0002\\u0002l\\u055e\\u0003\\u0002\\u0002\\u0002n\\u0565\\u0003\",\n    \"\\u0002\\u0002\\u0002p\\u056b\\u0003\\u0002\\u0002\\u0002r\\u056d\\u0003\\u0002\",\n    \"\\u0002\\u0002t\\u057a\\u0003\\u0002\\u0002\\u0002v\\u057c\\u0003\\u0002\\u0002\",\n    \"\\u0002x\\u0580\\u0003\\u0002\\u0002\\u0002z\\u05db\\u0003\\u0002\\u0002\\u0002\",\n    \"|\\u05dd\\u0003\\u0002\\u0002\\u0002~\\u0083\\u0005\\b\\u0005\\u0002\\u007f\\u0080\",\n    \"\\u0007\\u00d4\\u0002\\u0002\\u0080\\u0082\\u0005\\b\\u0005\\u0002\\u0081\\u007f\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0082\\u0085\\u0003\\u0002\\u0002\\u0002\\u0083\\u0081\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0083\\u0084\\u0003\\u0002\\u0002\\u0002\\u0084\\u0087\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0085\\u0083\\u0003\\u0002\\u0002\\u0002\\u0086\\u0088\",\n    \"\\u0007\\u00d4\\u0002\\u0002\\u0087\\u0086\\u0003\\u0002\\u0002\\u0002\\u0087\\u0088\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0088\\u0089\\u0003\\u0002\\u0002\\u0002\\u0089\\u008a\",\n    \"\\u0007\\u0002\\u0002\\u0003\\u008a\\u0003\\u0003\\u0002\\u0002\\u0002\\u008b\\u008c\",\n    \"\\u0005\\b\\u0005\\u0002\\u008c\\u008d\\u0007\\u0002\\u0002\\u0003\\u008d\\u0005\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u008e\\u008f\\u0005@!\\u0002\\u008f\\u0090\\u0007\",\n    \"\\u0002\\u0002\\u0003\\u0090\\u0007\\u0003\\u0002\\u0002\\u0002\\u0091\\u01f2\\u0005\",\n    \"\\n\\u0006\\u0002\\u0092\\u0093\\u0007\\u0083\\u0002\\u0002\\u0093\\u01f2\\u0005\",\n    \"t;\\u0002\\u0094\\u0095\\u0007\\u0083\\u0002\\u0002\\u0095\\u0096\\u0005t;\\u0002\",\n    \"\\u0096\\u0097\\u0007\\u0003\\u0002\\u0002\\u0097\\u0098\\u0005t;\\u0002\\u0098\",\n    \"\\u01f2\\u0003\\u0002\\u0002\\u0002\\u0099\\u009a\\u0007d\\u0002\\u0002\\u009a\",\n    \"\\u009e\\u0007e\\u0002\\u0002\\u009b\\u009c\\u0007\\u00b7\\u0002\\u0002\\u009c\",\n    \"\\u009d\\u0007\\\"\\u0002\\u0002\\u009d\\u009f\\u0007$\\u0002\\u0002\\u009e\\u009b\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u009e\\u009f\\u0003\\u0002\\u0002\\u0002\\u009f\\u00a0\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u00a0\\u00a3\\u0005r:\\u0002\\u00a1\\u00a2\\u0007\",\n    \"a\\u0002\\u0002\\u00a2\\u00a4\\u0005\\u0014\\u000b\\u0002\\u00a3\\u00a1\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00a3\\u00a4\\u0003\\u0002\\u0002\\u0002\\u00a4\\u01f2\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00a5\\u00a6\\u0007\\u0086\\u0002\\u0002\\u00a6\\u00a9\\u0007\",\n    \"e\\u0002\\u0002\\u00a7\\u00a8\\u0007\\u00b7\\u0002\\u0002\\u00a8\\u00aa\\u0007\",\n    \"$\\u0002\\u0002\\u00a9\\u00a7\\u0003\\u0002\\u0002\\u0002\\u00a9\\u00aa\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00aa\\u00ab\\u0003\\u0002\\u0002\\u0002\\u00ab\\u00ad\\u0005\",\n    \"r:\\u0002\\u00ac\\u00ae\\t\\u0002\\u0002\\u0002\\u00ad\\u00ac\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ad\\u00ae\\u0003\\u0002\\u0002\\u0002\\u00ae\\u01f2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00af\\u00b0\\u0007\\u008f\\u0002\\u0002\\u00b0\\u00b1\\u0007e\\u0002\",\n    \"\\u0002\\u00b1\\u00b2\\u0005r:\\u0002\\u00b2\\u00b3\\u0007\\u0090\\u0002\\u0002\",\n    \"\\u00b3\\u00b4\\u0007\\u008a\\u0002\\u0002\\u00b4\\u00b5\\u0005t;\\u0002\\u00b5\",\n    \"\\u01f2\\u0003\\u0002\\u0002\\u0002\\u00b6\\u00b7\\u0007d\\u0002\\u0002\\u00b7\",\n    \"\\u00bb\\u0007f\\u0002\\u0002\\u00b8\\u00b9\\u0007\\u00b7\\u0002\\u0002\\u00b9\",\n    \"\\u00ba\\u0007\\\"\\u0002\\u0002\\u00ba\\u00bc\\u0007$\\u0002\\u0002\\u00bb\\u00b8\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u00bb\\u00bc\\u0003\\u0002\\u0002\\u0002\\u00bc\\u00bd\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u00bd\\u00c0\\u0005r:\\u0002\\u00be\\u00bf\\u0007\",\n    \"a\\u0002\\u0002\\u00bf\\u00c1\\u0005\\u0014\\u000b\\u0002\\u00c0\\u00be\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00c0\\u00c1\\u0003\\u0002\\u0002\\u0002\\u00c1\\u00c2\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00c2\\u00c3\\u0007\\u000f\\u0002\\u0002\\u00c3\\u00c9\\u0005\",\n    \"\\n\\u0006\\u0002\\u00c4\\u00c6\\u0007a\\u0002\\u0002\\u00c5\\u00c7\\u0007#\\u0002\",\n    \"\\u0002\\u00c6\\u00c5\\u0003\\u0002\\u0002\\u0002\\u00c6\\u00c7\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00c7\\u00c8\\u0003\\u0002\\u0002\\u0002\\u00c8\\u00ca\\u0007\\u0098\\u0002\",\n    \"\\u0002\\u00c9\\u00c4\\u0003\\u0002\\u0002\\u0002\\u00c9\\u00ca\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ca\\u01f2\\u0003\\u0002\\u0002\\u0002\\u00cb\\u00cc\\u0007d\\u0002\",\n    \"\\u0002\\u00cc\\u00d0\\u0007f\\u0002\\u0002\\u00cd\\u00ce\\u0007\\u00b7\\u0002\",\n    \"\\u0002\\u00ce\\u00cf\\u0007\\\"\\u0002\\u0002\\u00cf\\u00d1\\u0007$\\u0002\\u0002\",\n    \"\\u00d0\\u00cd\\u0003\\u0002\\u0002\\u0002\\u00d0\\u00d1\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00d1\\u00d2\\u0003\\u0002\\u0002\\u0002\\u00d2\\u00d3\\u0005r:\\u0002\\u00d3\",\n    \"\\u00d4\\u0007\\u0004\\u0002\\u0002\\u00d4\\u00d9\\u0005\\u000e\\b\\u0002\\u00d5\",\n    \"\\u00d6\\u0007\\u0005\\u0002\\u0002\\u00d6\\u00d8\\u0005\\u000e\\b\\u0002\\u00d7\",\n    \"\\u00d5\\u0003\\u0002\\u0002\\u0002\\u00d8\\u00db\\u0003\\u0002\\u0002\\u0002\\u00d9\",\n    \"\\u00d7\\u0003\\u0002\\u0002\\u0002\\u00d9\\u00da\\u0003\\u0002\\u0002\\u0002\\u00da\",\n    \"\\u00dc\\u0003\\u0002\\u0002\\u0002\\u00db\\u00d9\\u0003\\u0002\\u0002\\u0002\\u00dc\",\n    \"\\u00df\\u0007\\u0006\\u0002\\u0002\\u00dd\\u00de\\u0007a\\u0002\\u0002\\u00de\",\n    \"\\u00e0\\u0005\\u0014\\u000b\\u0002\\u00df\\u00dd\\u0003\\u0002\\u0002\\u0002\\u00df\",\n    \"\\u00e0\\u0003\\u0002\\u0002\\u0002\\u00e0\\u01f2\\u0003\\u0002\\u0002\\u0002\\u00e1\",\n    \"\\u00e2\\u0007\\u0086\\u0002\\u0002\\u00e2\\u00e5\\u0007f\\u0002\\u0002\\u00e3\",\n    \"\\u00e4\\u0007\\u00b7\\u0002\\u0002\\u00e4\\u00e6\\u0007$\\u0002\\u0002\\u00e5\",\n    \"\\u00e3\\u0003\\u0002\\u0002\\u0002\\u00e5\\u00e6\\u0003\\u0002\\u0002\\u0002\\u00e6\",\n    \"\\u00e7\\u0003\\u0002\\u0002\\u0002\\u00e7\\u01f2\\u0005r:\\u0002\\u00e8\\u00e9\",\n    \"\\u0007i\\u0002\\u0002\\u00e9\\u00ea\\u0007k\\u0002\\u0002\\u00ea\\u00ec\\u0005\",\n    \"r:\\u0002\\u00eb\\u00ed\\u0005<\\u001f\\u0002\\u00ec\\u00eb\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ec\\u00ed\\u0003\\u0002\\u0002\\u0002\\u00ed\\u00ee\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ee\\u00ef\\u0005\\n\\u0006\\u0002\\u00ef\\u01f2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00f0\\u00f1\\u0007j\\u0002\\u0002\\u00f1\\u00f2\\u0007\\r\\u0002\\u0002\",\n    \"\\u00f2\\u00f5\\u0005r:\\u0002\\u00f3\\u00f4\\u0007\\u0014\\u0002\\u0002\\u00f4\",\n    \"\\u00f6\\u0005B\\\"\\u0002\\u00f5\\u00f3\\u0003\\u0002\\u0002\\u0002\\u00f5\\u00f6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u00f6\\u01f2\\u0003\\u0002\\u0002\\u0002\\u00f7\\u00f8\",\n    \"\\u0007\\u008f\\u0002\\u0002\\u00f8\\u00f9\\u0007f\\u0002\\u0002\\u00f9\\u00fa\",\n    \"\\u0005r:\\u0002\\u00fa\\u00fb\\u0007\\u0090\\u0002\\u0002\\u00fb\\u00fc\\u0007\",\n    \"\\u008a\\u0002\\u0002\\u00fc\\u00fd\\u0005r:\\u0002\\u00fd\\u01f2\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u00fe\\u00ff\\u0007\\u008f\\u0002\\u0002\\u00ff\\u0100\\u0007f\",\n    \"\\u0002\\u0002\\u0100\\u0101\\u0005r:\\u0002\\u0101\\u0102\\u0007\\u0090\\u0002\",\n    \"\\u0002\\u0102\\u0103\\u0007\\u0082\\u0002\\u0002\\u0103\\u0104\\u0005t;\\u0002\",\n    \"\\u0104\\u0105\\u0007\\u008a\\u0002\\u0002\\u0105\\u0106\\u0005t;\\u0002\\u0106\",\n    \"\\u01f2\\u0003\\u0002\\u0002\\u0002\\u0107\\u0108\\u0007\\u008f\\u0002\\u0002\\u0108\",\n    \"\\u0109\\u0007f\\u0002\\u0002\\u0109\\u010a\\u0005r:\\u0002\\u010a\\u010b\\u0007\",\n    \"\\u000e\\u0002\\u0002\\u010b\\u010c\\u0007\\u0082\\u0002\\u0002\\u010c\\u010d\\u0005\",\n    \"\\u0010\\t\\u0002\\u010d\\u01f2\\u0003\\u0002\\u0002\\u0002\\u010e\\u0111\\u0007\",\n    \"d\\u0002\\u0002\\u010f\\u0110\\u0007\\u001f\\u0002\\u0002\\u0110\\u0112\\u0007\",\n    \"h\\u0002\\u0002\\u0111\\u010f\\u0003\\u0002\\u0002\\u0002\\u0111\\u0112\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0112\\u0113\\u0003\\u0002\\u0002\\u0002\\u0113\\u0114\\u0007\",\n    \"g\\u0002\\u0002\\u0114\\u0115\\u0005r:\\u0002\\u0115\\u0116\\u0007\\u000f\\u0002\",\n    \"\\u0002\\u0116\\u0117\\u0005\\n\\u0006\\u0002\\u0117\\u01f2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0118\\u0119\\u0007\\u0086\\u0002\\u0002\\u0119\\u011c\\u0007g\\u0002\",\n    \"\\u0002\\u011a\\u011b\\u0007\\u00b7\\u0002\\u0002\\u011b\\u011d\\u0007$\\u0002\",\n    \"\\u0002\\u011c\\u011a\\u0003\\u0002\\u0002\\u0002\\u011c\\u011d\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u011d\\u011e\\u0003\\u0002\\u0002\\u0002\\u011e\\u01f2\\u0005r:\\u0002\",\n    \"\\u011f\\u0120\\u0007\\u00a7\\u0002\\u0002\\u0120\\u0121\\u0005r:\\u0002\\u0121\",\n    \"\\u012a\\u0007\\u0004\\u0002\\u0002\\u0122\\u0127\\u0005n8\\u0002\\u0123\\u0124\",\n    \"\\u0007\\u0005\\u0002\\u0002\\u0124\\u0126\\u0005n8\\u0002\\u0125\\u0123\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0126\\u0129\\u0003\\u0002\\u0002\\u0002\\u0127\\u0125\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0127\\u0128\\u0003\\u0002\\u0002\\u0002\\u0128\\u012b\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0129\\u0127\\u0003\\u0002\\u0002\\u0002\\u012a\\u0122\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u012a\\u012b\\u0003\\u0002\\u0002\\u0002\\u012b\\u012c\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u012c\\u012d\\u0007\\u0006\\u0002\\u0002\\u012d\\u01f2\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u012e\\u0139\\u0007n\\u0002\\u0002\\u012f\\u0134\\u0005\",\n    \"p9\\u0002\\u0130\\u0131\\u0007\\u0005\\u0002\\u0002\\u0131\\u0133\\u0005p9\\u0002\",\n    \"\\u0132\\u0130\\u0003\\u0002\\u0002\\u0002\\u0133\\u0136\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0134\\u0132\\u0003\\u0002\\u0002\\u0002\\u0134\\u0135\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0135\\u013a\\u0003\\u0002\\u0002\\u0002\\u0136\\u0134\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0137\\u0138\\u0007\\u0010\\u0002\\u0002\\u0138\\u013a\\u0007p\\u0002\\u0002\",\n    \"\\u0139\\u012f\\u0003\\u0002\\u0002\\u0002\\u0139\\u0137\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u013a\\u013b\\u0003\\u0002\\u0002\\u0002\\u013b\\u013d\\u0007V\\u0002\\u0002\",\n    \"\\u013c\\u013e\\u0007f\\u0002\\u0002\\u013d\\u013c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u013d\\u013e\\u0003\\u0002\\u0002\\u0002\\u013e\\u013f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u013f\\u0140\\u0005r:\\u0002\\u0140\\u0141\\u0007\\u008a\\u0002\\u0002\\u0141\",\n    \"\\u0145\\u0005t;\\u0002\\u0142\\u0143\\u0007a\\u0002\\u0002\\u0143\\u0144\\u0007\",\n    \"n\\u0002\\u0002\\u0144\\u0146\\u0007r\\u0002\\u0002\\u0145\\u0142\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0145\\u0146\\u0003\\u0002\\u0002\\u0002\\u0146\\u01f2\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0147\\u014b\\u0007o\\u0002\\u0002\\u0148\\u0149\\u0007n\\u0002\",\n    \"\\u0002\\u0149\\u014a\\u0007r\\u0002\\u0002\\u014a\\u014c\\u00073\\u0002\\u0002\",\n    \"\\u014b\\u0148\\u0003\\u0002\\u0002\\u0002\\u014b\\u014c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u014c\\u0157\\u0003\\u0002\\u0002\\u0002\\u014d\\u0152\\u0005p9\\u0002\\u014e\",\n    \"\\u014f\\u0007\\u0005\\u0002\\u0002\\u014f\\u0151\\u0005p9\\u0002\\u0150\\u014e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0151\\u0154\\u0003\\u0002\\u0002\\u0002\\u0152\\u0150\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0152\\u0153\\u0003\\u0002\\u0002\\u0002\\u0153\\u0158\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0154\\u0152\\u0003\\u0002\\u0002\\u0002\\u0155\\u0156\",\n    \"\\u0007\\u0010\\u0002\\u0002\\u0156\\u0158\\u0007p\\u0002\\u0002\\u0157\\u014d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0157\\u0155\\u0003\\u0002\\u0002\\u0002\\u0158\\u0159\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0159\\u015b\\u0007V\\u0002\\u0002\\u015a\\u015c\",\n    \"\\u0007f\\u0002\\u0002\\u015b\\u015a\\u0003\\u0002\\u0002\\u0002\\u015b\\u015c\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u015c\\u015d\\u0003\\u0002\\u0002\\u0002\\u015d\\u015e\",\n    \"\\u0005r:\\u0002\\u015e\\u015f\\u0007\\r\\u0002\\u0002\\u015f\\u0160\\u0005t;\\u0002\",\n    \"\\u0160\\u01f2\\u0003\\u0002\\u0002\\u0002\\u0161\\u0163\\u0007s\\u0002\\u0002\",\n    \"\\u0162\\u0164\\u0007t\\u0002\\u0002\\u0163\\u0162\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0163\\u0164\\u0003\\u0002\\u0002\\u0002\\u0164\\u0170\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0165\\u0166\\u0007\\u0004\\u0002\\u0002\\u0166\\u016b\\u0005h5\\u0002\\u0167\",\n    \"\\u0168\\u0007\\u0005\\u0002\\u0002\\u0168\\u016a\\u0005h5\\u0002\\u0169\\u0167\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u016a\\u016d\\u0003\\u0002\\u0002\\u0002\\u016b\\u0169\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u016b\\u016c\\u0003\\u0002\\u0002\\u0002\\u016c\\u016e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u016d\\u016b\\u0003\\u0002\\u0002\\u0002\\u016e\\u016f\",\n    \"\\u0007\\u0006\\u0002\\u0002\\u016f\\u0171\\u0003\\u0002\\u0002\\u0002\\u0170\\u0165\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0170\\u0171\\u0003\\u0002\\u0002\\u0002\\u0171\\u0172\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0172\\u01f2\\u0005\\b\\u0005\\u0002\\u0173\\u0174\",\n    \"\\u0007}\\u0002\\u0002\\u0174\\u0175\\u0007d\\u0002\\u0002\\u0175\\u0176\\u0007\",\n    \"f\\u0002\\u0002\\u0176\\u01f2\\u0005r:\\u0002\\u0177\\u0178\\u0007}\\u0002\\u0002\",\n    \"\\u0178\\u0179\\u0007d\\u0002\\u0002\\u0179\\u017a\\u0007g\\u0002\\u0002\\u017a\",\n    \"\\u01f2\\u0005r:\\u0002\\u017b\\u017c\\u0007}\\u0002\\u0002\\u017c\\u017f\\u0007\",\n    \"~\\u0002\\u0002\\u017d\\u017e\\t\\u0003\\u0002\\u0002\\u017e\\u0180\\u0005r:\\u0002\",\n    \"\\u017f\\u017d\\u0003\\u0002\\u0002\\u0002\\u017f\\u0180\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0180\\u0183\\u0003\\u0002\\u0002\\u0002\\u0181\\u0182\\u0007&\\u0002\\u0002\",\n    \"\\u0182\\u0184\\u0007\\u00c6\\u0002\\u0002\\u0183\\u0181\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0183\\u0184\\u0003\\u0002\\u0002\\u0002\\u0184\\u01f2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0185\\u0186\\u0007}\\u0002\\u0002\\u0186\\u0189\\u0007\\u007f\\u0002\\u0002\",\n    \"\\u0187\\u0188\\t\\u0003\\u0002\\u0002\\u0188\\u018a\\u0005t;\\u0002\\u0189\\u0187\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0189\\u018a\\u0003\\u0002\\u0002\\u0002\\u018a\\u018d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u018b\\u018c\\u0007&\\u0002\\u0002\\u018c\\u018e\",\n    \"\\u0007\\u00c6\\u0002\\u0002\\u018d\\u018b\\u0003\\u0002\\u0002\\u0002\\u018d\\u018e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u018e\\u01f2\\u0003\\u0002\\u0002\\u0002\\u018f\\u0190\",\n    \"\\u0007}\\u0002\\u0002\\u0190\\u0193\\u0007\\u0080\\u0002\\u0002\\u0191\\u0192\",\n    \"\\u0007&\\u0002\\u0002\\u0192\\u0194\\u0007\\u00c6\\u0002\\u0002\\u0193\\u0191\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0193\\u0194\\u0003\\u0002\\u0002\\u0002\\u0194\\u01f2\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0195\\u0196\\u0007}\\u0002\\u0002\\u0196\\u0197\",\n    \"\\u0007\\u0081\\u0002\\u0002\\u0197\\u0198\\t\\u0003\\u0002\\u0002\\u0198\\u01f2\",\n    \"\\u0005r:\\u0002\\u0199\\u019a\\u0007m\\u0002\\u0002\\u019a\\u01f2\\u0005r:\\u0002\",\n    \"\\u019b\\u019c\\u00070\\u0002\\u0002\\u019c\\u01f2\\u0005r:\\u0002\\u019d\\u019e\",\n    \"\\u0007}\\u0002\\u0002\\u019e\\u01f2\\u0007\\u0085\\u0002\\u0002\\u019f\\u01a0\",\n    \"\\u0007}\\u0002\\u0002\\u01a0\\u01f2\\u0007\\u0097\\u0002\\u0002\\u01a1\\u01a2\",\n    \"\\u0007\\u0095\\u0002\\u0002\\u01a2\\u01a3\\u0007\\u0097\\u0002\\u0002\\u01a3\\u01a4\",\n    \"\\u0005r:\\u0002\\u01a4\\u01a5\\u0007\\u00ba\\u0002\\u0002\\u01a5\\u01a6\\u0005\",\n    \"@!\\u0002\\u01a6\\u01f2\\u0003\\u0002\\u0002\\u0002\\u01a7\\u01a8\\u0007\\u0096\",\n    \"\\u0002\\u0002\\u01a8\\u01a9\\u0007\\u0097\\u0002\\u0002\\u01a9\\u01f2\\u0005r\",\n    \":\\u0002\\u01aa\\u01ab\\u0007\\u0099\\u0002\\u0002\\u01ab\\u01b4\\u0007\\u009a\",\n    \"\\u0002\\u0002\\u01ac\\u01b1\\u0005j6\\u0002\\u01ad\\u01ae\\u0007\\u0005\\u0002\",\n    \"\\u0002\\u01ae\\u01b0\\u0005j6\\u0002\\u01af\\u01ad\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01b0\\u01b3\\u0003\\u0002\\u0002\\u0002\\u01b1\\u01af\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01b1\\u01b2\\u0003\\u0002\\u0002\\u0002\\u01b2\\u01b5\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01b3\\u01b1\\u0003\\u0002\\u0002\\u0002\\u01b4\\u01ac\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01b4\\u01b5\\u0003\\u0002\\u0002\\u0002\\u01b5\\u01f2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01b6\\u01b8\\u0007\\u009b\\u0002\\u0002\\u01b7\\u01b9\\u0007\\u009d\\u0002\\u0002\",\n    \"\\u01b8\\u01b7\\u0003\\u0002\\u0002\\u0002\\u01b8\\u01b9\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01b9\\u01f2\\u0003\\u0002\\u0002\\u0002\\u01ba\\u01bc\\u0007\\u009c\\u0002\\u0002\",\n    \"\\u01bb\\u01bd\\u0007\\u009d\\u0002\\u0002\\u01bc\\u01bb\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01bc\\u01bd\\u0003\\u0002\\u0002\\u0002\\u01bd\\u01f2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01be\\u01bf\\u0007}\\u0002\\u0002\\u01bf\\u01c0\\u0007\\u0084\\u0002\\u0002\",\n    \"\\u01c0\\u01c1\\t\\u0003\\u0002\\u0002\\u01c1\\u01c4\\u0005r:\\u0002\\u01c2\\u01c3\",\n    \"\\u0007\\u0014\\u0002\\u0002\\u01c3\\u01c5\\u0005B\\\"\\u0002\\u01c4\\u01c2\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01c4\\u01c5\\u0003\\u0002\\u0002\\u0002\\u01c5\\u01d0\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01c6\\u01c7\\u0007\\u001b\\u0002\\u0002\\u01c7\\u01c8\\u0007\",\n    \"\\u0016\\u0002\\u0002\\u01c8\\u01cd\\u0005\\u001e\\u0010\\u0002\\u01c9\\u01ca\\u0007\",\n    \"\\u0005\\u0002\\u0002\\u01ca\\u01cc\\u0005\\u001e\\u0010\\u0002\\u01cb\\u01c9\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01cc\\u01cf\\u0003\\u0002\\u0002\\u0002\\u01cd\\u01cb\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01cd\\u01ce\\u0003\\u0002\\u0002\\u0002\\u01ce\\u01d1\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01cf\\u01cd\\u0003\\u0002\\u0002\\u0002\\u01d0\\u01c6\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01d0\\u01d1\\u0003\\u0002\\u0002\\u0002\\u01d1\\u01d4\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01d2\\u01d3\\u0007\\u001d\\u0002\\u0002\\u01d3\\u01d5\\t\",\n    \"\\u0004\\u0002\\u0002\\u01d4\\u01d2\\u0003\\u0002\\u0002\\u0002\\u01d4\\u01d5\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01d5\\u01f2\\u0003\\u0002\\u0002\\u0002\\u01d6\\u01d7\\u0007\",\n    \"\\u00a8\\u0002\\u0002\\u01d7\\u01d8\\u0005t;\\u0002\\u01d8\\u01d9\\u0007\\r\\u0002\",\n    \"\\u0002\\u01d9\\u01da\\u0005\\b\\u0005\\u0002\\u01da\\u01f2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01db\\u01dc\\u0007\\u00a9\\u0002\\u0002\\u01dc\\u01dd\\u0007\\u00a8\\u0002\",\n    \"\\u0002\\u01dd\\u01f2\\u0005t;\\u0002\\u01de\\u01df\\u0007\\u00aa\\u0002\\u0002\",\n    \"\\u01df\\u01e9\\u0005t;\\u0002\\u01e0\\u01e1\\u0007U\\u0002\\u0002\\u01e1\\u01e6\",\n    \"\\u0005@!\\u0002\\u01e2\\u01e3\\u0007\\u0005\\u0002\\u0002\\u01e3\\u01e5\\u0005\",\n    \"@!\\u0002\\u01e4\\u01e2\\u0003\\u0002\\u0002\\u0002\\u01e5\\u01e8\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e6\\u01e4\\u0003\\u0002\\u0002\\u0002\\u01e6\\u01e7\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e7\\u01ea\\u0003\\u0002\\u0002\\u0002\\u01e8\\u01e6\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e9\\u01e0\\u0003\\u0002\\u0002\\u0002\\u01e9\\u01ea\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01ea\\u01f2\\u0003\\u0002\\u0002\\u0002\\u01eb\\u01ec\\u0007m\",\n    \"\\u0002\\u0002\\u01ec\\u01ed\\u0007\\u00ab\\u0002\\u0002\\u01ed\\u01f2\\u0005t\",\n    \";\\u0002\\u01ee\\u01ef\\u0007m\\u0002\\u0002\\u01ef\\u01f0\\u0007\\u00ac\\u0002\",\n    \"\\u0002\\u01f0\\u01f2\\u0005t;\\u0002\\u01f1\\u0091\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0092\\u0003\\u0002\\u0002\\u0002\\u01f1\\u0094\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0099\\u0003\\u0002\\u0002\\u0002\\u01f1\\u00a5\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u00af\\u0003\\u0002\\u0002\\u0002\\u01f1\\u00b6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u00cb\\u0003\\u0002\\u0002\\u0002\\u01f1\\u00e1\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u00e8\\u0003\\u0002\\u0002\\u0002\\u01f1\\u00f0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u00f7\\u0003\\u0002\\u0002\\u0002\\u01f1\\u00fe\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0107\\u0003\\u0002\\u0002\\u0002\\u01f1\\u010e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0118\\u0003\\u0002\\u0002\\u0002\\u01f1\\u011f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u012e\\u0003\\u0002\\u0002\\u0002\\u01f1\\u0147\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0161\\u0003\\u0002\\u0002\\u0002\\u01f1\\u0173\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0177\\u0003\\u0002\\u0002\\u0002\\u01f1\\u017b\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0185\\u0003\\u0002\\u0002\\u0002\\u01f1\\u018f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u0195\\u0003\\u0002\\u0002\\u0002\\u01f1\\u0199\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u019b\\u0003\\u0002\\u0002\\u0002\\u01f1\\u019d\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u019f\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01a1\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u01a7\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01aa\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u01b6\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01ba\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u01be\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01d6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u01db\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01de\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f1\\u01eb\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01ee\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f2\\t\\u0003\\u0002\\u0002\\u0002\\u01f3\\u01f5\\u0005\\f\\u0007\\u0002\\u01f4\",\n    \"\\u01f3\\u0003\\u0002\\u0002\\u0002\\u01f4\\u01f5\\u0003\\u0002\\u0002\\u0002\\u01f5\",\n    \"\\u01f6\\u0003\\u0002\\u0002\\u0002\\u01f6\\u01f7\\u0005\\u0018\\r\\u0002\\u01f7\",\n    \"\\u000b\\u0003\\u0002\\u0002\\u0002\\u01f8\\u01fa\\u0007a\\u0002\\u0002\\u01f9\",\n    \"\\u01fb\\u0007b\\u0002\\u0002\\u01fa\\u01f9\\u0003\\u0002\\u0002\\u0002\\u01fa\",\n    \"\\u01fb\\u0003\\u0002\\u0002\\u0002\\u01fb\\u01fc\\u0003\\u0002\\u0002\\u0002\\u01fc\",\n    \"\\u0201\\u0005*\\u0016\\u0002\\u01fd\\u01fe\\u0007\\u0005\\u0002\\u0002\\u01fe\",\n    \"\\u0200\\u0005*\\u0016\\u0002\\u01ff\\u01fd\\u0003\\u0002\\u0002\\u0002\\u0200\",\n    \"\\u0203\\u0003\\u0002\\u0002\\u0002\\u0201\\u01ff\\u0003\\u0002\\u0002\\u0002\\u0201\",\n    \"\\u0202\\u0003\\u0002\\u0002\\u0002\\u0202\\r\\u0003\\u0002\\u0002\\u0002\\u0203\",\n    \"\\u0201\\u0003\\u0002\\u0002\\u0002\\u0204\\u0207\\u0005\\u0010\\t\\u0002\\u0205\",\n    \"\\u0207\\u0005\\u0012\\n\\u0002\\u0206\\u0204\\u0003\\u0002\\u0002\\u0002\\u0206\",\n    \"\\u0205\\u0003\\u0002\\u0002\\u0002\\u0207\\u000f\\u0003\\u0002\\u0002\\u0002\\u0208\",\n    \"\\u0209\\u0005t;\\u0002\\u0209\\u020a\\u0005X-\\u0002\\u020a\\u0011\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u020b\\u020c\\u0007&\\u0002\\u0002\\u020c\\u020f\\u0005r:\\u0002\",\n    \"\\u020d\\u020e\\t\\u0005\\u0002\\u0002\\u020e\\u0210\\u0007\\u00b1\\u0002\\u0002\",\n    \"\\u020f\\u020d\\u0003\\u0002\\u0002\\u0002\\u020f\\u0210\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0210\\u0013\\u0003\\u0002\\u0002\\u0002\\u0211\\u0212\\u0007\\u0004\\u0002\\u0002\",\n    \"\\u0212\\u0217\\u0005\\u0016\\f\\u0002\\u0213\\u0214\\u0007\\u0005\\u0002\\u0002\",\n    \"\\u0214\\u0216\\u0005\\u0016\\f\\u0002\\u0215\\u0213\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0216\\u0219\\u0003\\u0002\\u0002\\u0002\\u0217\\u0215\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0217\\u0218\\u0003\\u0002\\u0002\\u0002\\u0218\\u021a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0219\\u0217\\u0003\\u0002\\u0002\\u0002\\u021a\\u021b\\u0007\\u0006\\u0002\\u0002\",\n    \"\\u021b\\u0015\\u0003\\u0002\\u0002\\u0002\\u021c\\u021d\\u0005t;\\u0002\\u021d\",\n    \"\\u021e\\u0007\\u00ba\\u0002\\u0002\\u021e\\u021f\\u0005@!\\u0002\\u021f\\u0017\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0220\\u022b\\u0005\\u001a\\u000e\\u0002\\u0221\\u0222\",\n    \"\\u0007\\u001b\\u0002\\u0002\\u0222\\u0223\\u0007\\u0016\\u0002\\u0002\\u0223\\u0228\",\n    \"\\u0005\\u001e\\u0010\\u0002\\u0224\\u0225\\u0007\\u0005\\u0002\\u0002\\u0225\\u0227\",\n    \"\\u0005\\u001e\\u0010\\u0002\\u0226\\u0224\\u0003\\u0002\\u0002\\u0002\\u0227\\u022a\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0228\\u0226\\u0003\\u0002\\u0002\\u0002\\u0228\\u0229\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0229\\u022c\\u0003\\u0002\\u0002\\u0002\\u022a\\u0228\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u022b\\u0221\\u0003\\u0002\\u0002\\u0002\\u022b\\u022c\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u022c\\u022f\\u0003\\u0002\\u0002\\u0002\\u022d\\u022e\",\n    \"\\u0007\\u001d\\u0002\\u0002\\u022e\\u0230\\t\\u0004\\u0002\\u0002\\u022f\\u022d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u022f\\u0230\\u0003\\u0002\\u0002\\u0002\\u0230\\u0019\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0231\\u0232\\b\\u000e\\u0001\\u0002\\u0232\\u0233\",\n    \"\\u0005\\u001c\\u000f\\u0002\\u0233\\u0242\\u0003\\u0002\\u0002\\u0002\\u0234\\u0235\",\n    \"\\f\\u0004\\u0002\\u0002\\u0235\\u0237\\u0007\\u0089\\u0002\\u0002\\u0236\\u0238\",\n    \"\\u0005,\\u0017\\u0002\\u0237\\u0236\\u0003\\u0002\\u0002\\u0002\\u0237\\u0238\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0238\\u0239\\u0003\\u0002\\u0002\\u0002\\u0239\\u0241\",\n    \"\\u0005\\u001a\\u000e\\u0005\\u023a\\u023b\\f\\u0003\\u0002\\u0002\\u023b\\u023d\",\n    \"\\t\\u0006\\u0002\\u0002\\u023c\\u023e\\u0005,\\u0017\\u0002\\u023d\\u023c\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u023d\\u023e\\u0003\\u0002\\u0002\\u0002\\u023e\\u023f\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u023f\\u0241\\u0005\\u001a\\u000e\\u0004\\u0240\\u0234\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0240\\u023a\\u0003\\u0002\\u0002\\u0002\\u0241\\u0244\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0242\\u0240\\u0003\\u0002\\u0002\\u0002\\u0242\\u0243\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0243\\u001b\\u0003\\u0002\\u0002\\u0002\\u0244\\u0242\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0245\\u0256\\u0005 \\u0011\\u0002\\u0246\\u0247\\u0007\",\n    \"f\\u0002\\u0002\\u0247\\u0256\\u0005r:\\u0002\\u0248\\u0249\\u0007c\\u0002\\u0002\",\n    \"\\u0249\\u024e\\u0005@!\\u0002\\u024a\\u024b\\u0007\\u0005\\u0002\\u0002\\u024b\",\n    \"\\u024d\\u0005@!\\u0002\\u024c\\u024a\\u0003\\u0002\\u0002\\u0002\\u024d\\u0250\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u024e\\u024c\\u0003\\u0002\\u0002\\u0002\\u024e\\u024f\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u024f\\u0256\\u0003\\u0002\\u0002\\u0002\\u0250\\u024e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0251\\u0252\\u0007\\u0004\\u0002\\u0002\\u0252\\u0253\",\n    \"\\u0005\\u0018\\r\\u0002\\u0253\\u0254\\u0007\\u0006\\u0002\\u0002\\u0254\\u0256\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0255\\u0245\\u0003\\u0002\\u0002\\u0002\\u0255\\u0246\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0255\\u0248\\u0003\\u0002\\u0002\\u0002\\u0255\\u0251\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0256\\u001d\\u0003\\u0002\\u0002\\u0002\\u0257\\u0259\",\n    \"\\u0005@!\\u0002\\u0258\\u025a\\t\\u0007\\u0002\\u0002\\u0259\\u0258\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0259\\u025a\\u0003\\u0002\\u0002\\u0002\\u025a\\u025d\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u025b\\u025c\\u0007+\\u0002\\u0002\\u025c\\u025e\\t\\b\\u0002\\u0002\",\n    \"\\u025d\\u025b\\u0003\\u0002\\u0002\\u0002\\u025d\\u025e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u025e\\u001f\\u0003\\u0002\\u0002\\u0002\\u025f\\u0261\\u0007\\f\\u0002\\u0002\",\n    \"\\u0260\\u0262\\u0005,\\u0017\\u0002\\u0261\\u0260\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0261\\u0262\\u0003\\u0002\\u0002\\u0002\\u0262\\u0263\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0263\\u0268\\u0005.\\u0018\\u0002\\u0264\\u0265\\u0007\\u0005\\u0002\\u0002\",\n    \"\\u0265\\u0267\\u0005.\\u0018\\u0002\\u0266\\u0264\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0267\\u026a\\u0003\\u0002\\u0002\\u0002\\u0268\\u0266\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0268\\u0269\\u0003\\u0002\\u0002\\u0002\\u0269\\u0274\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u026a\\u0268\\u0003\\u0002\\u0002\\u0002\\u026b\\u026c\\u0007\\r\\u0002\\u0002\",\n    \"\\u026c\\u0271\\u00050\\u0019\\u0002\\u026d\\u026e\\u0007\\u0005\\u0002\\u0002\",\n    \"\\u026e\\u0270\\u00050\\u0019\\u0002\\u026f\\u026d\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0270\\u0273\\u0003\\u0002\\u0002\\u0002\\u0271\\u026f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0271\\u0272\\u0003\\u0002\\u0002\\u0002\\u0272\\u0275\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0273\\u0271\\u0003\\u0002\\u0002\\u0002\\u0274\\u026b\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0274\\u0275\\u0003\\u0002\\u0002\\u0002\\u0275\\u0278\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0276\\u0277\\u0007\\u0014\\u0002\\u0002\\u0277\\u0279\\u0005B\\\"\\u0002\\u0278\",\n    \"\\u0276\\u0003\\u0002\\u0002\\u0002\\u0278\\u0279\\u0003\\u0002\\u0002\\u0002\\u0279\",\n    \"\\u027d\\u0003\\u0002\\u0002\\u0002\\u027a\\u027b\\u0007\\u0015\\u0002\\u0002\\u027b\",\n    \"\\u027c\\u0007\\u0016\\u0002\\u0002\\u027c\\u027e\\u0005\\\"\\u0012\\u0002\\u027d\",\n    \"\\u027a\\u0003\\u0002\\u0002\\u0002\\u027d\\u027e\\u0003\\u0002\\u0002\\u0002\\u027e\",\n    \"\\u0281\\u0003\\u0002\\u0002\\u0002\\u027f\\u0280\\u0007\\u001c\\u0002\\u0002\\u0280\",\n    \"\\u0282\\u0005B\\\"\\u0002\\u0281\\u027f\\u0003\\u0002\\u0002\\u0002\\u0281\\u0282\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0282!\\u0003\\u0002\\u0002\\u0002\\u0283\\u0285\",\n    \"\\u0005,\\u0017\\u0002\\u0284\\u0283\\u0003\\u0002\\u0002\\u0002\\u0284\\u0285\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0285\\u0286\\u0003\\u0002\\u0002\\u0002\\u0286\\u028b\",\n    \"\\u0005$\\u0013\\u0002\\u0287\\u0288\\u0007\\u0005\\u0002\\u0002\\u0288\\u028a\",\n    \"\\u0005$\\u0013\\u0002\\u0289\\u0287\\u0003\\u0002\\u0002\\u0002\\u028a\\u028d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u028b\\u0289\\u0003\\u0002\\u0002\\u0002\\u028b\\u028c\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u028c#\\u0003\\u0002\\u0002\\u0002\\u028d\\u028b\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u028e\\u02b7\\u0005&\\u0014\\u0002\\u028f\\u0290\",\n    \"\\u0007\\u001a\\u0002\\u0002\\u0290\\u0299\\u0007\\u0004\\u0002\\u0002\\u0291\\u0296\",\n    \"\\u0005r:\\u0002\\u0292\\u0293\\u0007\\u0005\\u0002\\u0002\\u0293\\u0295\\u0005\",\n    \"r:\\u0002\\u0294\\u0292\\u0003\\u0002\\u0002\\u0002\\u0295\\u0298\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0296\\u0294\\u0003\\u0002\\u0002\\u0002\\u0296\\u0297\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0297\\u029a\\u0003\\u0002\\u0002\\u0002\\u0298\\u0296\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0299\\u0291\\u0003\\u0002\\u0002\\u0002\\u0299\\u029a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u029a\\u029b\\u0003\\u0002\\u0002\\u0002\\u029b\\u02b7\\u0007\\u0006\",\n    \"\\u0002\\u0002\\u029c\\u029d\\u0007\\u0019\\u0002\\u0002\\u029d\\u02a6\\u0007\\u0004\",\n    \"\\u0002\\u0002\\u029e\\u02a3\\u0005r:\\u0002\\u029f\\u02a0\\u0007\\u0005\\u0002\",\n    \"\\u0002\\u02a0\\u02a2\\u0005r:\\u0002\\u02a1\\u029f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02a2\\u02a5\\u0003\\u0002\\u0002\\u0002\\u02a3\\u02a1\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02a3\\u02a4\\u0003\\u0002\\u0002\\u0002\\u02a4\\u02a7\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02a5\\u02a3\\u0003\\u0002\\u0002\\u0002\\u02a6\\u029e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02a6\\u02a7\\u0003\\u0002\\u0002\\u0002\\u02a7\\u02a8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02a8\\u02b7\\u0007\\u0006\\u0002\\u0002\\u02a9\\u02aa\\u0007\\u0017\\u0002\\u0002\",\n    \"\\u02aa\\u02ab\\u0007\\u0018\\u0002\\u0002\\u02ab\\u02ac\\u0007\\u0004\\u0002\\u0002\",\n    \"\\u02ac\\u02b1\\u0005(\\u0015\\u0002\\u02ad\\u02ae\\u0007\\u0005\\u0002\\u0002\",\n    \"\\u02ae\\u02b0\\u0005(\\u0015\\u0002\\u02af\\u02ad\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b0\\u02b3\\u0003\\u0002\\u0002\\u0002\\u02b1\\u02af\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b1\\u02b2\\u0003\\u0002\\u0002\\u0002\\u02b2\\u02b4\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b3\\u02b1\\u0003\\u0002\\u0002\\u0002\\u02b4\\u02b5\\u0007\\u0006\\u0002\\u0002\",\n    \"\\u02b5\\u02b7\\u0003\\u0002\\u0002\\u0002\\u02b6\\u028e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b6\\u028f\\u0003\\u0002\\u0002\\u0002\\u02b6\\u029c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b6\\u02a9\\u0003\\u0002\\u0002\\u0002\\u02b7%\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b8\\u02c1\\u0007\\u0004\\u0002\\u0002\\u02b9\\u02be\\u0005@!\\u0002\\u02ba\",\n    \"\\u02bb\\u0007\\u0005\\u0002\\u0002\\u02bb\\u02bd\\u0005@!\\u0002\\u02bc\\u02ba\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02bd\\u02c0\\u0003\\u0002\\u0002\\u0002\\u02be\\u02bc\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02be\\u02bf\\u0003\\u0002\\u0002\\u0002\\u02bf\\u02c2\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c0\\u02be\\u0003\\u0002\\u0002\\u0002\\u02c1\\u02b9\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c1\\u02c2\\u0003\\u0002\\u0002\\u0002\\u02c2\\u02c3\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c3\\u02c6\\u0007\\u0006\\u0002\\u0002\\u02c4\\u02c6\",\n    \"\\u0005@!\\u0002\\u02c5\\u02b8\\u0003\\u0002\\u0002\\u0002\\u02c5\\u02c4\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02c6\\'\\u0003\\u0002\\u0002\\u0002\\u02c7\\u02d0\\u0007\",\n    \"\\u0004\\u0002\\u0002\\u02c8\\u02cd\\u0005r:\\u0002\\u02c9\\u02ca\\u0007\\u0005\",\n    \"\\u0002\\u0002\\u02ca\\u02cc\\u0005r:\\u0002\\u02cb\\u02c9\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02cc\\u02cf\\u0003\\u0002\\u0002\\u0002\\u02cd\\u02cb\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02cd\\u02ce\\u0003\\u0002\\u0002\\u0002\\u02ce\\u02d1\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02cf\\u02cd\\u0003\\u0002\\u0002\\u0002\\u02d0\\u02c8\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02d0\\u02d1\\u0003\\u0002\\u0002\\u0002\\u02d1\\u02d2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02d2\\u02d5\\u0007\\u0006\\u0002\\u0002\\u02d3\\u02d5\\u0005r:\\u0002\",\n    \"\\u02d4\\u02c7\\u0003\\u0002\\u0002\\u0002\\u02d4\\u02d3\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02d5)\\u0003\\u0002\\u0002\\u0002\\u02d6\\u02d8\\u0005t;\\u0002\\u02d7\\u02d9\",\n    \"\\u0005<\\u001f\\u0002\\u02d8\\u02d7\\u0003\\u0002\\u0002\\u0002\\u02d8\\u02d9\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02d9\\u02da\\u0003\\u0002\\u0002\\u0002\\u02da\\u02db\",\n    \"\\u0007\\u000f\\u0002\\u0002\\u02db\\u02dc\\u0007\\u0004\\u0002\\u0002\\u02dc\\u02dd\",\n    \"\\u0005\\n\\u0006\\u0002\\u02dd\\u02de\\u0007\\u0006\\u0002\\u0002\\u02de+\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02df\\u02e0\\t\\t\\u0002\\u0002\\u02e0-\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e1\\u02e6\\u0005@!\\u0002\\u02e2\\u02e4\\u0007\\u000f\\u0002\\u0002\",\n    \"\\u02e3\\u02e2\\u0003\\u0002\\u0002\\u0002\\u02e3\\u02e4\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02e4\\u02e5\\u0003\\u0002\\u0002\\u0002\\u02e5\\u02e7\\u0005t;\\u0002\\u02e6\",\n    \"\\u02e3\\u0003\\u0002\\u0002\\u0002\\u02e6\\u02e7\\u0003\\u0002\\u0002\\u0002\\u02e7\",\n    \"\\u02ee\\u0003\\u0002\\u0002\\u0002\\u02e8\\u02e9\\u0005r:\\u0002\\u02e9\\u02ea\",\n    \"\\u0007\\u0003\\u0002\\u0002\\u02ea\\u02eb\\u0007\\u00c2\\u0002\\u0002\\u02eb\\u02ee\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02ec\\u02ee\\u0007\\u00c2\\u0002\\u0002\\u02ed\\u02e1\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02ed\\u02e8\\u0003\\u0002\\u0002\\u0002\\u02ed\\u02ec\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02ee/\\u0003\\u0002\\u0002\\u0002\\u02ef\\u02f0\",\n    \"\\b\\u0019\\u0001\\u0002\\u02f0\\u02f1\\u00056\\u001c\\u0002\\u02f1\\u0304\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02f2\\u0300\\f\\u0004\\u0002\\u0002\\u02f3\\u02f4\\u0007\",\n    \"N\\u0002\\u0002\\u02f4\\u02f5\\u0007M\\u0002\\u0002\\u02f5\\u0301\\u00056\\u001c\",\n    \"\\u0002\\u02f6\\u02f7\\u00052\\u001a\\u0002\\u02f7\\u02f8\\u0007M\\u0002\\u0002\",\n    \"\\u02f8\\u02f9\\u00050\\u0019\\u0002\\u02f9\\u02fa\\u00054\\u001b\\u0002\\u02fa\",\n    \"\\u0301\\u0003\\u0002\\u0002\\u0002\\u02fb\\u02fc\\u0007T\\u0002\\u0002\\u02fc\",\n    \"\\u02fd\\u00052\\u001a\\u0002\\u02fd\\u02fe\\u0007M\\u0002\\u0002\\u02fe\\u02ff\",\n    \"\\u00056\\u001c\\u0002\\u02ff\\u0301\\u0003\\u0002\\u0002\\u0002\\u0300\\u02f3\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0300\\u02f6\\u0003\\u0002\\u0002\\u0002\\u0300\\u02fb\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0301\\u0303\\u0003\\u0002\\u0002\\u0002\\u0302\\u02f2\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0303\\u0306\\u0003\\u0002\\u0002\\u0002\\u0304\\u0302\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0304\\u0305\\u0003\\u0002\\u0002\\u0002\\u03051\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0306\\u0304\\u0003\\u0002\\u0002\\u0002\\u0307\\u0309\",\n    \"\\u0007P\\u0002\\u0002\\u0308\\u0307\\u0003\\u0002\\u0002\\u0002\\u0308\\u0309\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0309\\u0317\\u0003\\u0002\\u0002\\u0002\\u030a\\u030c\",\n    \"\\u0007Q\\u0002\\u0002\\u030b\\u030d\\u0007O\\u0002\\u0002\\u030c\\u030b\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u030c\\u030d\\u0003\\u0002\\u0002\\u0002\\u030d\\u0317\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u030e\\u0310\\u0007R\\u0002\\u0002\\u030f\\u0311\\u0007\",\n    \"O\\u0002\\u0002\\u0310\\u030f\\u0003\\u0002\\u0002\\u0002\\u0310\\u0311\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0311\\u0317\\u0003\\u0002\\u0002\\u0002\\u0312\\u0314\\u0007\",\n    \"S\\u0002\\u0002\\u0313\\u0315\\u0007O\\u0002\\u0002\\u0314\\u0313\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0314\\u0315\\u0003\\u0002\\u0002\\u0002\\u0315\\u0317\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0316\\u0308\\u0003\\u0002\\u0002\\u0002\\u0316\\u030a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0316\\u030e\\u0003\\u0002\\u0002\\u0002\\u0316\\u0312\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03173\\u0003\\u0002\\u0002\\u0002\\u0318\\u0319\\u0007V\\u0002\",\n    \"\\u0002\\u0319\\u0327\\u0005B\\\"\\u0002\\u031a\\u031b\\u0007U\\u0002\\u0002\\u031b\",\n    \"\\u031c\\u0007\\u0004\\u0002\\u0002\\u031c\\u0321\\u0005t;\\u0002\\u031d\\u031e\",\n    \"\\u0007\\u0005\\u0002\\u0002\\u031e\\u0320\\u0005t;\\u0002\\u031f\\u031d\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0320\\u0323\\u0003\\u0002\\u0002\\u0002\\u0321\\u031f\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0321\\u0322\\u0003\\u0002\\u0002\\u0002\\u0322\\u0324\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0323\\u0321\\u0003\\u0002\\u0002\\u0002\\u0324\\u0325\\u0007\",\n    \"\\u0006\\u0002\\u0002\\u0325\\u0327\\u0003\\u0002\\u0002\\u0002\\u0326\\u0318\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0326\\u031a\\u0003\\u0002\\u0002\\u0002\\u03275\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0328\\u032f\\u0005:\\u001e\\u0002\\u0329\\u032a\\u0007\",\n    \"\\u008e\\u0002\\u0002\\u032a\\u032b\\u00058\\u001d\\u0002\\u032b\\u032c\\u0007\",\n    \"\\u0004\\u0002\\u0002\\u032c\\u032d\\u0005@!\\u0002\\u032d\\u032e\\u0007\\u0006\",\n    \"\\u0002\\u0002\\u032e\\u0330\\u0003\\u0002\\u0002\\u0002\\u032f\\u0329\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u032f\\u0330\\u0003\\u0002\\u0002\\u0002\\u03307\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0331\\u0332\\t\\n\\u0002\\u0002\\u03329\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0333\\u033b\\u0005> \\u0002\\u0334\\u0336\\u0007\\u000f\\u0002\\u0002\\u0335\",\n    \"\\u0334\\u0003\\u0002\\u0002\\u0002\\u0335\\u0336\\u0003\\u0002\\u0002\\u0002\\u0336\",\n    \"\\u0337\\u0003\\u0002\\u0002\\u0002\\u0337\\u0339\\u0005t;\\u0002\\u0338\\u033a\",\n    \"\\u0005<\\u001f\\u0002\\u0339\\u0338\\u0003\\u0002\\u0002\\u0002\\u0339\\u033a\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033a\\u033c\\u0003\\u0002\\u0002\\u0002\\u033b\\u0335\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033b\\u033c\\u0003\\u0002\\u0002\\u0002\\u033c;\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033d\\u033e\\u0007\\u0004\\u0002\\u0002\\u033e\\u0343\",\n    \"\\u0005t;\\u0002\\u033f\\u0340\\u0007\\u0005\\u0002\\u0002\\u0340\\u0342\\u0005\",\n    \"t;\\u0002\\u0341\\u033f\\u0003\\u0002\\u0002\\u0002\\u0342\\u0345\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0343\\u0341\\u0003\\u0002\\u0002\\u0002\\u0343\\u0344\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0344\\u0346\\u0003\\u0002\\u0002\\u0002\\u0345\\u0343\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0346\\u0347\\u0007\\u0006\\u0002\\u0002\\u0347=\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0348\\u0361\\u0005r:\\u0002\\u0349\\u034a\\u0007\\u0004\\u0002\",\n    \"\\u0002\\u034a\\u034b\\u0005\\n\\u0006\\u0002\\u034b\\u034c\\u0007\\u0006\\u0002\",\n    \"\\u0002\\u034c\\u0361\\u0003\\u0002\\u0002\\u0002\\u034d\\u034e\\u0007\\u0091\\u0002\",\n    \"\\u0002\\u034e\\u034f\\u0007\\u0004\\u0002\\u0002\\u034f\\u0354\\u0005@!\\u0002\",\n    \"\\u0350\\u0351\\u0007\\u0005\\u0002\\u0002\\u0351\\u0353\\u0005@!\\u0002\\u0352\",\n    \"\\u0350\\u0003\\u0002\\u0002\\u0002\\u0353\\u0356\\u0003\\u0002\\u0002\\u0002\\u0354\",\n    \"\\u0352\\u0003\\u0002\\u0002\\u0002\\u0354\\u0355\\u0003\\u0002\\u0002\\u0002\\u0355\",\n    \"\\u0357\\u0003\\u0002\\u0002\\u0002\\u0356\\u0354\\u0003\\u0002\\u0002\\u0002\\u0357\",\n    \"\\u035a\\u0007\\u0006\\u0002\\u0002\\u0358\\u0359\\u0007a\\u0002\\u0002\\u0359\",\n    \"\\u035b\\u0007\\u0092\\u0002\\u0002\\u035a\\u0358\\u0003\\u0002\\u0002\\u0002\\u035a\",\n    \"\\u035b\\u0003\\u0002\\u0002\\u0002\\u035b\\u0361\\u0003\\u0002\\u0002\\u0002\\u035c\",\n    \"\\u035d\\u0007\\u0004\\u0002\\u0002\\u035d\\u035e\\u00050\\u0019\\u0002\\u035e\",\n    \"\\u035f\\u0007\\u0006\\u0002\\u0002\\u035f\\u0361\\u0003\\u0002\\u0002\\u0002\\u0360\",\n    \"\\u0348\\u0003\\u0002\\u0002\\u0002\\u0360\\u0349\\u0003\\u0002\\u0002\\u0002\\u0360\",\n    \"\\u034d\\u0003\\u0002\\u0002\\u0002\\u0360\\u035c\\u0003\\u0002\\u0002\\u0002\\u0361\",\n    \"?\\u0003\\u0002\\u0002\\u0002\\u0362\\u0363\\u0005B\\\"\\u0002\\u0363A\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0364\\u0365\\b\\\"\\u0001\\u0002\\u0365\\u0369\\u0005D#\\u0002\\u0366\",\n    \"\\u0367\\u0007\\\"\\u0002\\u0002\\u0367\\u0369\\u0005B\\\"\\u0005\\u0368\\u0364\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0368\\u0366\\u0003\\u0002\\u0002\\u0002\\u0369\\u0372\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u036a\\u036b\\f\\u0004\\u0002\\u0002\\u036b\\u036c\\u0007\",\n    \" \\u0002\\u0002\\u036c\\u0371\\u0005B\\\"\\u0005\\u036d\\u036e\\f\\u0003\\u0002\\u0002\",\n    \"\\u036e\\u036f\\u0007\\u001f\\u0002\\u0002\\u036f\\u0371\\u0005B\\\"\\u0004\\u0370\",\n    \"\\u036a\\u0003\\u0002\\u0002\\u0002\\u0370\\u036d\\u0003\\u0002\\u0002\\u0002\\u0371\",\n    \"\\u0374\\u0003\\u0002\\u0002\\u0002\\u0372\\u0370\\u0003\\u0002\\u0002\\u0002\\u0372\",\n    \"\\u0373\\u0003\\u0002\\u0002\\u0002\\u0373C\\u0003\\u0002\\u0002\\u0002\\u0374\",\n    \"\\u0372\\u0003\\u0002\\u0002\\u0002\\u0375\\u0377\\u0005H%\\u0002\\u0376\\u0378\",\n    \"\\u0005F$\\u0002\\u0377\\u0376\\u0003\\u0002\\u0002\\u0002\\u0377\\u0378\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0378E\\u0003\\u0002\\u0002\\u0002\\u0379\\u037a\\u0005\",\n    \"N(\\u0002\\u037a\\u037b\\u0005H%\\u0002\\u037b\\u03b7\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u037c\\u037d\\u0005N(\\u0002\\u037d\\u037e\\u0005P)\\u0002\\u037e\\u037f\\u0007\",\n    \"\\u0004\\u0002\\u0002\\u037f\\u0380\\u0005\\n\\u0006\\u0002\\u0380\\u0381\\u0007\",\n    \"\\u0006\\u0002\\u0002\\u0381\\u03b7\\u0003\\u0002\\u0002\\u0002\\u0382\\u0384\\u0007\",\n    \"\\\"\\u0002\\u0002\\u0383\\u0382\\u0003\\u0002\\u0002\\u0002\\u0383\\u0384\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0384\\u0385\\u0003\\u0002\\u0002\\u0002\\u0385\\u0386\\u0007\",\n    \"%\\u0002\\u0002\\u0386\\u0387\\u0005H%\\u0002\\u0387\\u0388\\u0007 \\u0002\\u0002\",\n    \"\\u0388\\u0389\\u0005H%\\u0002\\u0389\\u03b7\\u0003\\u0002\\u0002\\u0002\\u038a\",\n    \"\\u038c\\u0007\\\"\\u0002\\u0002\\u038b\\u038a\\u0003\\u0002\\u0002\\u0002\\u038b\",\n    \"\\u038c\\u0003\\u0002\\u0002\\u0002\\u038c\\u038d\\u0003\\u0002\\u0002\\u0002\\u038d\",\n    \"\\u038e\\u0007!\\u0002\\u0002\\u038e\\u038f\\u0007\\u0004\\u0002\\u0002\\u038f\",\n    \"\\u0394\\u0005@!\\u0002\\u0390\\u0391\\u0007\\u0005\\u0002\\u0002\\u0391\\u0393\",\n    \"\\u0005@!\\u0002\\u0392\\u0390\\u0003\\u0002\\u0002\\u0002\\u0393\\u0396\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0394\\u0392\\u0003\\u0002\\u0002\\u0002\\u0394\\u0395\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0395\\u0397\\u0003\\u0002\\u0002\\u0002\\u0396\\u0394\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0397\\u0398\\u0007\\u0006\\u0002\\u0002\\u0398\\u03b7\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0399\\u039b\\u0007\\\"\\u0002\\u0002\\u039a\\u0399\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u039a\\u039b\\u0003\\u0002\\u0002\\u0002\\u039b\\u039c\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u039c\\u039d\\u0007!\\u0002\\u0002\\u039d\\u039e\\u0007\",\n    \"\\u0004\\u0002\\u0002\\u039e\\u039f\\u0005\\n\\u0006\\u0002\\u039f\\u03a0\\u0007\",\n    \"\\u0006\\u0002\\u0002\\u03a0\\u03b7\\u0003\\u0002\\u0002\\u0002\\u03a1\\u03a3\\u0007\",\n    \"\\\"\\u0002\\u0002\\u03a2\\u03a1\\u0003\\u0002\\u0002\\u0002\\u03a2\\u03a3\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03a3\\u03a4\\u0003\\u0002\\u0002\\u0002\\u03a4\\u03a5\\u0007\",\n    \"&\\u0002\\u0002\\u03a5\\u03a8\\u0005H%\\u0002\\u03a6\\u03a7\\u0007.\\u0002\\u0002\",\n    \"\\u03a7\\u03a9\\u0005H%\\u0002\\u03a8\\u03a6\\u0003\\u0002\\u0002\\u0002\\u03a8\",\n    \"\\u03a9\\u0003\\u0002\\u0002\\u0002\\u03a9\\u03b7\\u0003\\u0002\\u0002\\u0002\\u03aa\",\n    \"\\u03ac\\u0007\\'\\u0002\\u0002\\u03ab\\u03ad\\u0007\\\"\\u0002\\u0002\\u03ac\\u03ab\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03ac\\u03ad\\u0003\\u0002\\u0002\\u0002\\u03ad\\u03ae\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03ae\\u03b7\\u0007(\\u0002\\u0002\\u03af\\u03b1\",\n    \"\\u0007\\'\\u0002\\u0002\\u03b0\\u03b2\\u0007\\\"\\u0002\\u0002\\u03b1\\u03b0\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b1\\u03b2\\u0003\\u0002\\u0002\\u0002\\u03b2\\u03b3\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b3\\u03b4\\u0007\\u0013\\u0002\\u0002\\u03b4\\u03b5\\u0007\",\n    \"\\r\\u0002\\u0002\\u03b5\\u03b7\\u0005H%\\u0002\\u03b6\\u0379\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u03b6\\u037c\\u0003\\u0002\\u0002\\u0002\\u03b6\\u0383\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u03b6\\u038b\\u0003\\u0002\\u0002\\u0002\\u03b6\\u039a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u03b6\\u03a2\\u0003\\u0002\\u0002\\u0002\\u03b6\\u03aa\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u03b6\\u03af\\u0003\\u0002\\u0002\\u0002\\u03b7G\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u03b8\\u03b9\\b%\\u0001\\u0002\\u03b9\\u03bd\\u0005J&\\u0002\\u03ba\\u03bb\",\n    \"\\t\\u000b\\u0002\\u0002\\u03bb\\u03bd\\u0005H%\\u0006\\u03bc\\u03b8\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03bc\\u03ba\\u0003\\u0002\\u0002\\u0002\\u03bd\\u03cc\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03be\\u03bf\\f\\u0005\\u0002\\u0002\\u03bf\\u03c0\\t\\f\\u0002\\u0002\",\n    \"\\u03c0\\u03cb\\u0005H%\\u0006\\u03c1\\u03c2\\f\\u0004\\u0002\\u0002\\u03c2\\u03c3\",\n    \"\\t\\u000b\\u0002\\u0002\\u03c3\\u03cb\\u0005H%\\u0005\\u03c4\\u03c5\\f\\u0003\\u0002\",\n    \"\\u0002\\u03c5\\u03c6\\u0007\\u00c5\\u0002\\u0002\\u03c6\\u03cb\\u0005H%\\u0004\",\n    \"\\u03c7\\u03c8\\f\\u0007\\u0002\\u0002\\u03c8\\u03c9\\u0007\\u001e\\u0002\\u0002\",\n    \"\\u03c9\\u03cb\\u0005L\\'\\u0002\\u03ca\\u03be\\u0003\\u0002\\u0002\\u0002\\u03ca\",\n    \"\\u03c1\\u0003\\u0002\\u0002\\u0002\\u03ca\\u03c4\\u0003\\u0002\\u0002\\u0002\\u03ca\",\n    \"\\u03c7\\u0003\\u0002\\u0002\\u0002\\u03cb\\u03ce\\u0003\\u0002\\u0002\\u0002\\u03cc\",\n    \"\\u03ca\\u0003\\u0002\\u0002\\u0002\\u03cc\\u03cd\\u0003\\u0002\\u0002\\u0002\\u03cd\",\n    \"I\\u0003\\u0002\\u0002\\u0002\\u03ce\\u03cc\\u0003\\u0002\\u0002\\u0002\\u03cf\",\n    \"\\u03d0\\b&\\u0001\\u0002\\u03d0\\u049e\\u0007(\\u0002\\u0002\\u03d1\\u049e\\u0005\",\n    \"T+\\u0002\\u03d2\\u03d3\\u0005t;\\u0002\\u03d3\\u03d4\\u0007\\u00c6\\u0002\\u0002\",\n    \"\\u03d4\\u049e\\u0003\\u0002\\u0002\\u0002\\u03d5\\u03d6\\u0007\\u00d0\\u0002\\u0002\",\n    \"\\u03d6\\u049e\\u0007\\u00c6\\u0002\\u0002\\u03d7\\u049e\\u0005x=\\u0002\\u03d8\",\n    \"\\u049e\\u0005R*\\u0002\\u03d9\\u049e\\u0007\\u00c6\\u0002\\u0002\\u03da\\u049e\",\n    \"\\u0007\\u00c7\\u0002\\u0002\\u03db\\u049e\\u0007\\u0007\\u0002\\u0002\\u03dc\\u03dd\",\n    \"\\u00072\\u0002\\u0002\\u03dd\\u03de\\u0007\\u0004\\u0002\\u0002\\u03de\\u03df\",\n    \"\\u0005H%\\u0002\\u03df\\u03e0\\u0007!\\u0002\\u0002\\u03e0\\u03e1\\u0005H%\\u0002\",\n    \"\\u03e1\\u03e2\\u0007\\u0006\\u0002\\u0002\\u03e2\\u049e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u03e3\\u03e4\\u0007\\u0004\\u0002\\u0002\\u03e4\\u03e9\\u0005@!\\u0002\\u03e5\",\n    \"\\u03e6\\u0007\\u0005\\u0002\\u0002\\u03e6\\u03e8\\u0005@!\\u0002\\u03e7\\u03e5\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03e8\\u03eb\\u0003\\u0002\\u0002\\u0002\\u03e9\\u03e7\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03e9\\u03ea\\u0003\\u0002\\u0002\\u0002\\u03ea\\u03ec\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03eb\\u03e9\\u0003\\u0002\\u0002\\u0002\\u03ec\\u03ed\",\n    \"\\u0007\\u0006\\u0002\\u0002\\u03ed\\u049e\\u0003\\u0002\\u0002\\u0002\\u03ee\\u03ef\",\n    \"\\u0007`\\u0002\\u0002\\u03ef\\u03f0\\u0007\\u0004\\u0002\\u0002\\u03f0\\u03f5\",\n    \"\\u0005@!\\u0002\\u03f1\\u03f2\\u0007\\u0005\\u0002\\u0002\\u03f2\\u03f4\\u0005\",\n    \"@!\\u0002\\u03f3\\u03f1\\u0003\\u0002\\u0002\\u0002\\u03f4\\u03f7\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03f5\\u03f3\\u0003\\u0002\\u0002\\u0002\\u03f5\\u03f6\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03f6\\u03f8\\u0003\\u0002\\u0002\\u0002\\u03f7\\u03f5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03f8\\u03f9\\u0007\\u0006\\u0002\\u0002\\u03f9\\u049e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03fa\\u03fb\\u0005r:\\u0002\\u03fb\\u03fc\\u0007\\u0004\\u0002\",\n    \"\\u0002\\u03fc\\u03fd\\u0007\\u00c2\\u0002\\u0002\\u03fd\\u03ff\\u0007\\u0006\\u0002\",\n    \"\\u0002\\u03fe\\u0400\\u0005`1\\u0002\\u03ff\\u03fe\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u03ff\\u0400\\u0003\\u0002\\u0002\\u0002\\u0400\\u0402\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0401\\u0403\\u0005b2\\u0002\\u0402\\u0401\\u0003\\u0002\\u0002\\u0002\\u0402\",\n    \"\\u0403\\u0003\\u0002\\u0002\\u0002\\u0403\\u049e\\u0003\\u0002\\u0002\\u0002\\u0404\",\n    \"\\u0405\\u0005r:\\u0002\\u0405\\u0411\\u0007\\u0004\\u0002\\u0002\\u0406\\u0408\",\n    \"\\u0005,\\u0017\\u0002\\u0407\\u0406\\u0003\\u0002\\u0002\\u0002\\u0407\\u0408\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0408\\u0409\\u0003\\u0002\\u0002\\u0002\\u0409\\u040e\",\n    \"\\u0005@!\\u0002\\u040a\\u040b\\u0007\\u0005\\u0002\\u0002\\u040b\\u040d\\u0005\",\n    \"@!\\u0002\\u040c\\u040a\\u0003\\u0002\\u0002\\u0002\\u040d\\u0410\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u040e\\u040c\\u0003\\u0002\\u0002\\u0002\\u040e\\u040f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u040f\\u0412\\u0003\\u0002\\u0002\\u0002\\u0410\\u040e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0411\\u0407\\u0003\\u0002\\u0002\\u0002\\u0411\\u0412\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0412\\u0413\\u0003\\u0002\\u0002\\u0002\\u0413\\u0415\\u0007\\u0006\",\n    \"\\u0002\\u0002\\u0414\\u0416\\u0005`1\\u0002\\u0415\\u0414\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0415\\u0416\\u0003\\u0002\\u0002\\u0002\\u0416\\u0418\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0417\\u0419\\u0005b2\\u0002\\u0418\\u0417\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0418\\u0419\\u0003\\u0002\\u0002\\u0002\\u0419\\u049e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u041a\\u041b\\u0005t;\\u0002\\u041b\\u041c\\u0007\\b\\u0002\\u0002\\u041c\\u041d\",\n    \"\\u0005@!\\u0002\\u041d\\u049e\\u0003\\u0002\\u0002\\u0002\\u041e\\u041f\\u0007\",\n    \"\\u0004\\u0002\\u0002\\u041f\\u0424\\u0005t;\\u0002\\u0420\\u0421\\u0007\\u0005\",\n    \"\\u0002\\u0002\\u0421\\u0423\\u0005t;\\u0002\\u0422\\u0420\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0423\\u0426\\u0003\\u0002\\u0002\\u0002\\u0424\\u0422\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0424\\u0425\\u0003\\u0002\\u0002\\u0002\\u0425\\u0427\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0426\\u0424\\u0003\\u0002\\u0002\\u0002\\u0427\\u0428\\u0007\\u0006\\u0002\",\n    \"\\u0002\\u0428\\u0429\\u0007\\b\\u0002\\u0002\\u0429\\u042a\\u0005@!\\u0002\\u042a\",\n    \"\\u049e\\u0003\\u0002\\u0002\\u0002\\u042b\\u042c\\u0007\\u0004\\u0002\\u0002\\u042c\",\n    \"\\u042d\\u0005\\n\\u0006\\u0002\\u042d\\u042e\\u0007\\u0006\\u0002\\u0002\\u042e\",\n    \"\\u049e\\u0003\\u0002\\u0002\\u0002\\u042f\\u0430\\u0007$\\u0002\\u0002\\u0430\",\n    \"\\u0431\\u0007\\u0004\\u0002\\u0002\\u0431\\u0432\\u0005\\n\\u0006\\u0002\\u0432\",\n    \"\\u0433\\u0007\\u0006\\u0002\\u0002\\u0433\\u049e\\u0003\\u0002\\u0002\\u0002\\u0434\",\n    \"\\u0435\\u0007H\\u0002\\u0002\\u0435\\u0437\\u0005H%\\u0002\\u0436\\u0438\\u0005\",\n    \"^0\\u0002\\u0437\\u0436\\u0003\\u0002\\u0002\\u0002\\u0438\\u0439\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0439\\u0437\\u0003\\u0002\\u0002\\u0002\\u0439\\u043a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u043a\\u043d\\u0003\\u0002\\u0002\\u0002\\u043b\\u043c\\u0007K\",\n    \"\\u0002\\u0002\\u043c\\u043e\\u0005@!\\u0002\\u043d\\u043b\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u043d\\u043e\\u0003\\u0002\\u0002\\u0002\\u043e\\u043f\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u043f\\u0440\\u0007L\\u0002\\u0002\\u0440\\u049e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0441\\u0443\\u0007H\\u0002\\u0002\\u0442\\u0444\\u0005^0\\u0002\\u0443\",\n    \"\\u0442\\u0003\\u0002\\u0002\\u0002\\u0444\\u0445\\u0003\\u0002\\u0002\\u0002\\u0445\",\n    \"\\u0443\\u0003\\u0002\\u0002\\u0002\\u0445\\u0446\\u0003\\u0002\\u0002\\u0002\\u0446\",\n    \"\\u0449\\u0003\\u0002\\u0002\\u0002\\u0447\\u0448\\u0007K\\u0002\\u0002\\u0448\",\n    \"\\u044a\\u0005@!\\u0002\\u0449\\u0447\\u0003\\u0002\\u0002\\u0002\\u0449\\u044a\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u044a\\u044b\\u0003\\u0002\\u0002\\u0002\\u044b\\u044c\",\n    \"\\u0007L\\u0002\\u0002\\u044c\\u049e\\u0003\\u0002\\u0002\\u0002\\u044d\\u044e\",\n    \"\\u0007{\\u0002\\u0002\\u044e\\u044f\\u0007\\u0004\\u0002\\u0002\\u044f\\u0450\",\n    \"\\u0005@!\\u0002\\u0450\\u0451\\u0007\\u000f\\u0002\\u0002\\u0451\\u0452\\u0005\",\n    \"X-\\u0002\\u0452\\u0453\\u0007\\u0006\\u0002\\u0002\\u0453\\u049e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0454\\u0455\\u0007|\\u0002\\u0002\\u0455\\u0456\\u0007\\u0004\",\n    \"\\u0002\\u0002\\u0456\\u0457\\u0005@!\\u0002\\u0457\\u0458\\u0007\\u000f\\u0002\",\n    \"\\u0002\\u0458\\u0459\\u0005X-\\u0002\\u0459\\u045a\\u0007\\u0006\\u0002\\u0002\",\n    \"\\u045a\\u049e\\u0003\\u0002\\u0002\\u0002\\u045b\\u045c\\u0007\\u0093\\u0002\\u0002\",\n    \"\\u045c\\u0465\\u0007\\t\\u0002\\u0002\\u045d\\u0462\\u0005@!\\u0002\\u045e\\u045f\",\n    \"\\u0007\\u0005\\u0002\\u0002\\u045f\\u0461\\u0005@!\\u0002\\u0460\\u045e\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0461\\u0464\\u0003\\u0002\\u0002\\u0002\\u0462\\u0460\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0462\\u0463\\u0003\\u0002\\u0002\\u0002\\u0463\\u0466\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0464\\u0462\\u0003\\u0002\\u0002\\u0002\\u0465\\u045d\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0465\\u0466\\u0003\\u0002\\u0002\\u0002\\u0466\\u0467\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0467\\u049e\\u0007\\n\\u0002\\u0002\\u0468\\u049e\\u0005\",\n    \"t;\\u0002\\u0469\\u049e\\u0007B\\u0002\\u0002\\u046a\\u046e\\u0007C\\u0002\\u0002\",\n    \"\\u046b\\u046c\\u0007\\u0004\\u0002\\u0002\\u046c\\u046d\\u0007\\u00c8\\u0002\\u0002\",\n    \"\\u046d\\u046f\\u0007\\u0006\\u0002\\u0002\\u046e\\u046b\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u046e\\u046f\\u0003\\u0002\\u0002\\u0002\\u046f\\u049e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0470\\u0474\\u0007D\\u0002\\u0002\\u0471\\u0472\\u0007\\u0004\\u0002\\u0002\",\n    \"\\u0472\\u0473\\u0007\\u00c8\\u0002\\u0002\\u0473\\u0475\\u0007\\u0006\\u0002\\u0002\",\n    \"\\u0474\\u0471\\u0003\\u0002\\u0002\\u0002\\u0474\\u0475\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0475\\u049e\\u0003\\u0002\\u0002\\u0002\\u0476\\u047a\\u0007E\\u0002\\u0002\",\n    \"\\u0477\\u0478\\u0007\\u0004\\u0002\\u0002\\u0478\\u0479\\u0007\\u00c8\\u0002\\u0002\",\n    \"\\u0479\\u047b\\u0007\\u0006\\u0002\\u0002\\u047a\\u0477\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u047a\\u047b\\u0003\\u0002\\u0002\\u0002\\u047b\\u049e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u047c\\u0480\\u0007F\\u0002\\u0002\\u047d\\u047e\\u0007\\u0004\\u0002\\u0002\",\n    \"\\u047e\\u047f\\u0007\\u00c8\\u0002\\u0002\\u047f\\u0481\\u0007\\u0006\\u0002\\u0002\",\n    \"\\u0480\\u047d\\u0003\\u0002\\u0002\\u0002\\u0480\\u0481\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0481\\u049e\\u0003\\u0002\\u0002\\u0002\\u0482\\u0483\\u00071\\u0002\\u0002\",\n    \"\\u0483\\u0484\\u0007\\u0004\\u0002\\u0002\\u0484\\u0485\\u0005H%\\u0002\\u0485\",\n    \"\\u0486\\u0007\\r\\u0002\\u0002\\u0486\\u0489\\u0005H%\\u0002\\u0487\\u0488\\u0007\",\n    \"3\\u0002\\u0002\\u0488\\u048a\\u0005H%\\u0002\\u0489\\u0487\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0489\\u048a\\u0003\\u0002\\u0002\\u0002\\u048a\\u048b\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u048b\\u048c\\u0007\\u0006\\u0002\\u0002\\u048c\\u049e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u048d\\u048e\\u0007\\u00b2\\u0002\\u0002\\u048e\\u048f\\u0007\\u0004\\u0002\",\n    \"\\u0002\\u048f\\u0492\\u0005H%\\u0002\\u0490\\u0491\\u0007\\u0005\\u0002\\u0002\",\n    \"\\u0491\\u0493\\u0005|?\\u0002\\u0492\\u0490\\u0003\\u0002\\u0002\\u0002\\u0492\",\n    \"\\u0493\\u0003\\u0002\\u0002\\u0002\\u0493\\u0494\\u0003\\u0002\\u0002\\u0002\\u0494\",\n    \"\\u0495\\u0007\\u0006\\u0002\\u0002\\u0495\\u049e\\u0003\\u0002\\u0002\\u0002\\u0496\",\n    \"\\u0497\\u0007G\\u0002\\u0002\\u0497\\u0498\\u0007\\u0004\\u0002\\u0002\\u0498\",\n    \"\\u0499\\u0005t;\\u0002\\u0499\\u049a\\u0007\\r\\u0002\\u0002\\u049a\\u049b\\u0005\",\n    \"H%\\u0002\\u049b\\u049c\\u0007\\u0006\\u0002\\u0002\\u049c\\u049e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03cf\\u0003\\u0002\\u0002\\u0002\\u049d\\u03d1\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03d2\\u0003\\u0002\\u0002\\u0002\\u049d\\u03d5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03d7\\u0003\\u0002\\u0002\\u0002\\u049d\\u03d8\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03d9\\u0003\\u0002\\u0002\\u0002\\u049d\\u03da\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03db\\u0003\\u0002\\u0002\\u0002\\u049d\\u03dc\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03e3\\u0003\\u0002\\u0002\\u0002\\u049d\\u03ee\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u03fa\\u0003\\u0002\\u0002\\u0002\\u049d\\u0404\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u041a\\u0003\\u0002\\u0002\\u0002\\u049d\\u041e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u042b\\u0003\\u0002\\u0002\\u0002\\u049d\\u042f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u0434\\u0003\\u0002\\u0002\\u0002\\u049d\\u0441\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u044d\\u0003\\u0002\\u0002\\u0002\\u049d\\u0454\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u045b\\u0003\\u0002\\u0002\\u0002\\u049d\\u0468\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u0469\\u0003\\u0002\\u0002\\u0002\\u049d\\u046a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u0470\\u0003\\u0002\\u0002\\u0002\\u049d\\u0476\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u047c\\u0003\\u0002\\u0002\\u0002\\u049d\\u0482\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049d\\u048d\\u0003\\u0002\\u0002\\u0002\\u049d\\u0496\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u049e\\u04a9\\u0003\\u0002\\u0002\\u0002\\u049f\\u04a0\\f\\r\\u0002\",\n    \"\\u0002\\u04a0\\u04a1\\u0007\\t\\u0002\\u0002\\u04a1\\u04a2\\u0005H%\\u0002\\u04a2\",\n    \"\\u04a3\\u0007\\n\\u0002\\u0002\\u04a3\\u04a8\\u0003\\u0002\\u0002\\u0002\\u04a4\",\n    \"\\u04a5\\f\\u000b\\u0002\\u0002\\u04a5\\u04a6\\u0007\\u0003\\u0002\\u0002\\u04a6\",\n    \"\\u04a8\\u0005t;\\u0002\\u04a7\\u049f\\u0003\\u0002\\u0002\\u0002\\u04a7\\u04a4\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04a8\\u04ab\\u0003\\u0002\\u0002\\u0002\\u04a9\\u04a7\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04a9\\u04aa\\u0003\\u0002\\u0002\\u0002\\u04aaK\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04ab\\u04a9\\u0003\\u0002\\u0002\\u0002\\u04ac\\u04ad\",\n    \"\\u00078\\u0002\\u0002\\u04ad\\u04ae\\u0007A\\u0002\\u0002\\u04ae\\u04b3\\u0005\",\n    \"T+\\u0002\\u04af\\u04b0\\u00078\\u0002\\u0002\\u04b0\\u04b1\\u0007A\\u0002\\u0002\",\n    \"\\u04b1\\u04b3\\u0007\\u00c6\\u0002\\u0002\\u04b2\\u04ac\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u04b2\\u04af\\u0003\\u0002\\u0002\\u0002\\u04b3M\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u04b4\\u04b5\\t\\r\\u0002\\u0002\\u04b5O\\u0003\\u0002\\u0002\\u0002\\u04b6\\u04b7\",\n    \"\\t\\u000e\\u0002\\u0002\\u04b7Q\\u0003\\u0002\\u0002\\u0002\\u04b8\\u04b9\\t\\u000f\",\n    \"\\u0002\\u0002\\u04b9S\\u0003\\u0002\\u0002\\u0002\\u04ba\\u04bc\\u0007:\\u0002\",\n    \"\\u0002\\u04bb\\u04bd\\t\\u000b\\u0002\\u0002\\u04bc\\u04bb\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04bc\\u04bd\\u0003\\u0002\\u0002\\u0002\\u04bd\\u04be\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04be\\u04bf\\u0007\\u00c6\\u0002\\u0002\\u04bf\\u04c2\\u0005V,\\u0002\",\n    \"\\u04c0\\u04c1\\u0007\\u008a\\u0002\\u0002\\u04c1\\u04c3\\u0005V,\\u0002\\u04c2\",\n    \"\\u04c0\\u0003\\u0002\\u0002\\u0002\\u04c2\\u04c3\\u0003\\u0002\\u0002\\u0002\\u04c3\",\n    \"U\\u0003\\u0002\\u0002\\u0002\\u04c4\\u04c5\\t\\u0010\\u0002\\u0002\\u04c5W\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u04c6\\u04c7\\b-\\u0001\\u0002\\u04c7\\u04c8\\u0007\\u0093\",\n    \"\\u0002\\u0002\\u04c8\\u04c9\\u0007\\u00bc\\u0002\\u0002\\u04c9\\u04ca\\u0005X\",\n    \"-\\u0002\\u04ca\\u04cb\\u0007\\u00be\\u0002\\u0002\\u04cb\\u04f1\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u04cc\\u04cd\\u0007\\u0094\\u0002\\u0002\\u04cd\\u04ce\\u0007\\u00bc\",\n    \"\\u0002\\u0002\\u04ce\\u04cf\\u0005X-\\u0002\\u04cf\\u04d0\\u0007\\u0005\\u0002\",\n    \"\\u0002\\u04d0\\u04d1\\u0005X-\\u0002\\u04d1\\u04d2\\u0007\\u00be\\u0002\\u0002\",\n    \"\\u04d2\\u04f1\\u0003\\u0002\\u0002\\u0002\\u04d3\\u04d4\\u0007`\\u0002\\u0002\",\n    \"\\u04d4\\u04d5\\u0007\\u0004\\u0002\\u0002\\u04d5\\u04d6\\u0005t;\\u0002\\u04d6\",\n    \"\\u04dd\\u0005X-\\u0002\\u04d7\\u04d8\\u0007\\u0005\\u0002\\u0002\\u04d8\\u04d9\",\n    \"\\u0005t;\\u0002\\u04d9\\u04da\\u0005X-\\u0002\\u04da\\u04dc\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04db\\u04d7\\u0003\\u0002\\u0002\\u0002\\u04dc\\u04df\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04dd\\u04db\\u0003\\u0002\\u0002\\u0002\\u04dd\\u04de\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04de\\u04e0\\u0003\\u0002\\u0002\\u0002\\u04df\\u04dd\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04e0\\u04e1\\u0007\\u0006\\u0002\\u0002\\u04e1\\u04f1\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u04e2\\u04ee\\u0005\\\\/\\u0002\\u04e3\\u04e4\\u0007\\u0004\\u0002\\u0002\",\n    \"\\u04e4\\u04e9\\u0005Z.\\u0002\\u04e5\\u04e6\\u0007\\u0005\\u0002\\u0002\\u04e6\",\n    \"\\u04e8\\u0005Z.\\u0002\\u04e7\\u04e5\\u0003\\u0002\\u0002\\u0002\\u04e8\\u04eb\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04e9\\u04e7\\u0003\\u0002\\u0002\\u0002\\u04e9\\u04ea\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04ea\\u04ec\\u0003\\u0002\\u0002\\u0002\\u04eb\\u04e9\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04ec\\u04ed\\u0007\\u0006\\u0002\\u0002\\u04ed\\u04ef\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04ee\\u04e3\\u0003\\u0002\\u0002\\u0002\\u04ee\\u04ef\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04ef\\u04f1\\u0003\\u0002\\u0002\\u0002\\u04f0\\u04c6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04f0\\u04cc\\u0003\\u0002\\u0002\\u0002\\u04f0\\u04d3\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04f0\\u04e2\\u0003\\u0002\\u0002\\u0002\\u04f1\\u04f6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04f2\\u04f3\\f\\u0007\\u0002\\u0002\\u04f3\\u04f5\",\n    \"\\u0007\\u0093\\u0002\\u0002\\u04f4\\u04f2\\u0003\\u0002\\u0002\\u0002\\u04f5\\u04f8\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04f6\\u04f4\\u0003\\u0002\\u0002\\u0002\\u04f6\\u04f7\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04f7Y\\u0003\\u0002\\u0002\\u0002\\u04f8\\u04f6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u04f9\\u04fc\\u0007\\u00c8\\u0002\\u0002\\u04fa\\u04fc\",\n    \"\\u0005X-\\u0002\\u04fb\\u04f9\\u0003\\u0002\\u0002\\u0002\\u04fb\\u04fa\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u04fc[\\u0003\\u0002\\u0002\\u0002\\u04fd\\u0502\\u0007\",\n    \"\\u00ce\\u0002\\u0002\\u04fe\\u0502\\u0007\\u00cf\\u0002\\u0002\\u04ff\\u0502\\u0007\",\n    \"\\u00d0\\u0002\\u0002\\u0500\\u0502\\u0005t;\\u0002\\u0501\\u04fd\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0501\\u04fe\\u0003\\u0002\\u0002\\u0002\\u0501\\u04ff\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0501\\u0500\\u0003\\u0002\\u0002\\u0002\\u0502]\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0503\\u0504\\u0007I\\u0002\\u0002\\u0504\\u0505\\u0005@!\\u0002\",\n    \"\\u0505\\u0506\\u0007J\\u0002\\u0002\\u0506\\u0507\\u0005@!\\u0002\\u0507_\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0508\\u0509\\u0007W\\u0002\\u0002\\u0509\\u050a\\u0007\",\n    \"\\u0004\\u0002\\u0002\\u050a\\u050b\\u0007\\u0014\\u0002\\u0002\\u050b\\u050c\\u0005\",\n    \"B\\\"\\u0002\\u050c\\u050d\\u0007\\u0006\\u0002\\u0002\\u050da\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u050e\\u050f\\u0007X\\u0002\\u0002\\u050f\\u051a\\u0007\\u0004\\u0002\",\n    \"\\u0002\\u0510\\u0511\\u0007Y\\u0002\\u0002\\u0511\\u0512\\u0007\\u0016\\u0002\",\n    \"\\u0002\\u0512\\u0517\\u0005@!\\u0002\\u0513\\u0514\\u0007\\u0005\\u0002\\u0002\",\n    \"\\u0514\\u0516\\u0005@!\\u0002\\u0515\\u0513\\u0003\\u0002\\u0002\\u0002\\u0516\",\n    \"\\u0519\\u0003\\u0002\\u0002\\u0002\\u0517\\u0515\\u0003\\u0002\\u0002\\u0002\\u0517\",\n    \"\\u0518\\u0003\\u0002\\u0002\\u0002\\u0518\\u051b\\u0003\\u0002\\u0002\\u0002\\u0519\",\n    \"\\u0517\\u0003\\u0002\\u0002\\u0002\\u051a\\u0510\\u0003\\u0002\\u0002\\u0002\\u051a\",\n    \"\\u051b\\u0003\\u0002\\u0002\\u0002\\u051b\\u0526\\u0003\\u0002\\u0002\\u0002\\u051c\",\n    \"\\u051d\\u0007\\u001b\\u0002\\u0002\\u051d\\u051e\\u0007\\u0016\\u0002\\u0002\\u051e\",\n    \"\\u0523\\u0005\\u001e\\u0010\\u0002\\u051f\\u0520\\u0007\\u0005\\u0002\\u0002\\u0520\",\n    \"\\u0522\\u0005\\u001e\\u0010\\u0002\\u0521\\u051f\\u0003\\u0002\\u0002\\u0002\\u0522\",\n    \"\\u0525\\u0003\\u0002\\u0002\\u0002\\u0523\\u0521\\u0003\\u0002\\u0002\\u0002\\u0523\",\n    \"\\u0524\\u0003\\u0002\\u0002\\u0002\\u0524\\u0527\\u0003\\u0002\\u0002\\u0002\\u0525\",\n    \"\\u0523\\u0003\\u0002\\u0002\\u0002\\u0526\\u051c\\u0003\\u0002\\u0002\\u0002\\u0526\",\n    \"\\u0527\\u0003\\u0002\\u0002\\u0002\\u0527\\u0529\\u0003\\u0002\\u0002\\u0002\\u0528\",\n    \"\\u052a\\u0005d3\\u0002\\u0529\\u0528\\u0003\\u0002\\u0002\\u0002\\u0529\\u052a\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u052a\\u052b\\u0003\\u0002\\u0002\\u0002\\u052b\\u052c\",\n    \"\\u0007\\u0006\\u0002\\u0002\\u052cc\\u0003\\u0002\\u0002\\u0002\\u052d\\u052e\",\n    \"\\u0007Z\\u0002\\u0002\\u052e\\u053e\\u0005f4\\u0002\\u052f\\u0530\\u0007[\\u0002\",\n    \"\\u0002\\u0530\\u053e\\u0005f4\\u0002\\u0531\\u0532\\u0007Z\\u0002\\u0002\\u0532\",\n    \"\\u0533\\u0007%\\u0002\\u0002\\u0533\\u0534\\u0005f4\\u0002\\u0534\\u0535\\u0007\",\n    \" \\u0002\\u0002\\u0535\\u0536\\u0005f4\\u0002\\u0536\\u053e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0537\\u0538\\u0007[\\u0002\\u0002\\u0538\\u0539\\u0007%\\u0002\\u0002\",\n    \"\\u0539\\u053a\\u0005f4\\u0002\\u053a\\u053b\\u0007 \\u0002\\u0002\\u053b\\u053c\",\n    \"\\u0005f4\\u0002\\u053c\\u053e\\u0003\\u0002\\u0002\\u0002\\u053d\\u052d\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u053d\\u052f\\u0003\\u0002\\u0002\\u0002\\u053d\\u0531\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u053d\\u0537\\u0003\\u0002\\u0002\\u0002\\u053ee\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u053f\\u0540\\u0007\\\\\\u0002\\u0002\\u0540\\u0549\\u0007\",\n    \"]\\u0002\\u0002\\u0541\\u0542\\u0007\\\\\\u0002\\u0002\\u0542\\u0549\\u0007^\\u0002\",\n    \"\\u0002\\u0543\\u0544\\u0007_\\u0002\\u0002\\u0544\\u0549\\u0007`\\u0002\\u0002\",\n    \"\\u0545\\u0546\\u0005@!\\u0002\\u0546\\u0547\\t\\u0011\\u0002\\u0002\\u0547\\u0549\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0548\\u053f\\u0003\\u0002\\u0002\\u0002\\u0548\\u0541\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0548\\u0543\\u0003\\u0002\\u0002\\u0002\\u0548\\u0545\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0549g\\u0003\\u0002\\u0002\\u0002\\u054a\\u054b\",\n    \"\\u0007u\\u0002\\u0002\\u054b\\u054f\\t\\u0012\\u0002\\u0002\\u054c\\u054d\\u0007\",\n    \"v\\u0002\\u0002\\u054d\\u054f\\t\\u0013\\u0002\\u0002\\u054e\\u054a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u054e\\u054c\\u0003\\u0002\\u0002\\u0002\\u054fi\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0550\\u0551\\u0007\\u009e\\u0002\\u0002\\u0551\\u0552\\u0007\\u009f\",\n    \"\\u0002\\u0002\\u0552\\u0556\\u0005l7\\u0002\\u0553\\u0554\\u0007\\u00a4\\u0002\",\n    \"\\u0002\\u0554\\u0556\\t\\u0014\\u0002\\u0002\\u0555\\u0550\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0555\\u0553\\u0003\\u0002\\u0002\\u0002\\u0556k\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0557\\u0558\\u0007\\u00a4\\u0002\\u0002\\u0558\\u055f\\u0007\\u00a3\\u0002\",\n    \"\\u0002\\u0559\\u055a\\u0007\\u00a4\\u0002\\u0002\\u055a\\u055f\\u0007\\u00a2\\u0002\",\n    \"\\u0002\\u055b\\u055c\\u0007\\u00a1\\u0002\\u0002\\u055c\\u055f\\u0007\\u00a4\\u0002\",\n    \"\\u0002\\u055d\\u055f\\u0007\\u00a0\\u0002\\u0002\\u055e\\u0557\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u055e\\u0559\\u0003\\u0002\\u0002\\u0002\\u055e\\u055b\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u055e\\u055d\\u0003\\u0002\\u0002\\u0002\\u055fm\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0560\\u0566\\u0005@!\\u0002\\u0561\\u0562\\u0005t;\\u0002\\u0562\\u0563\",\n    \"\\u0007\\u000b\\u0002\\u0002\\u0563\\u0564\\u0005@!\\u0002\\u0564\\u0566\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0565\\u0560\\u0003\\u0002\\u0002\\u0002\\u0565\\u0561\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0566o\\u0003\\u0002\\u0002\\u0002\\u0567\\u056c\\u0007\",\n    \"\\f\\u0002\\u0002\\u0568\\u056c\\u0007j\\u0002\\u0002\\u0569\\u056c\\u0007i\\u0002\",\n    \"\\u0002\\u056a\\u056c\\u0005t;\\u0002\\u056b\\u0567\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u056b\\u0568\\u0003\\u0002\\u0002\\u0002\\u056b\\u0569\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u056b\\u056a\\u0003\\u0002\\u0002\\u0002\\u056cq\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u056d\\u0572\\u0005t;\\u0002\\u056e\\u056f\\u0007\\u0003\\u0002\\u0002\\u056f\",\n    \"\\u0571\\u0005t;\\u0002\\u0570\\u056e\\u0003\\u0002\\u0002\\u0002\\u0571\\u0574\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0572\\u0570\\u0003\\u0002\\u0002\\u0002\\u0572\\u0573\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0573s\\u0003\\u0002\\u0002\\u0002\\u0574\\u0572\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0575\\u057b\\u0007\\u00ca\\u0002\\u0002\\u0576\\u057b\",\n    \"\\u0005v<\\u0002\\u0577\\u057b\\u0005z>\\u0002\\u0578\\u057b\\u0007\\u00cd\\u0002\",\n    \"\\u0002\\u0579\\u057b\\u0007\\u00cb\\u0002\\u0002\\u057a\\u0575\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u057a\\u0576\\u0003\\u0002\\u0002\\u0002\\u057a\\u0577\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u057a\\u0578\\u0003\\u0002\\u0002\\u0002\\u057a\\u0579\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u057bu\\u0003\\u0002\\u0002\\u0002\\u057c\\u057d\\u0007\\u00cc\\u0002\",\n    \"\\u0002\\u057dw\\u0003\\u0002\\u0002\\u0002\\u057e\\u0581\\u0007\\u00c9\\u0002\",\n    \"\\u0002\\u057f\\u0581\\u0007\\u00c8\\u0002\\u0002\\u0580\\u057e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0580\\u057f\\u0003\\u0002\\u0002\\u0002\\u0581y\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0582\\u05dc\\u0007}\\u0002\\u0002\\u0583\\u05dc\\u0007~\\u0002\\u0002\",\n    \"\\u0584\\u05dc\\u0007\\u0081\\u0002\\u0002\\u0585\\u05dc\\u0007\\u0082\\u0002\\u0002\",\n    \"\\u0586\\u05dc\\u0007\\u0084\\u0002\\u0002\\u0587\\u05dc\\u0007\\u0085\\u0002\\u0002\",\n    \"\\u0588\\u05dc\\u0007\\u007f\\u0002\\u0002\\u0589\\u05dc\\u0007\\u0080\\u0002\\u0002\",\n    \"\\u058a\\u05dc\\u0007\\u0097\\u0002\\u0002\\u058b\\u05dc\\u0007\\u000e\\u0002\\u0002\",\n    \"\\u058c\\u05dc\\u0007W\\u0002\\u0002\\u058d\\u05dc\\u0007X\\u0002\\u0002\\u058e\",\n    \"\\u05dc\\u0007Y\\u0002\\u0002\\u058f\\u05dc\\u0007Z\\u0002\\u0002\\u0590\\u05dc\",\n    \"\\u0007[\\u0002\\u0002\\u0591\\u05dc\\u0007]\\u0002\\u0002\\u0592\\u05dc\\u0007\",\n    \"^\\u0002\\u0002\\u0593\\u05dc\\u0007_\\u0002\\u0002\\u0594\\u05dc\\u0007`\\u0002\",\n    \"\\u0002\\u0595\\u05dc\\u0007\\u0094\\u0002\\u0002\\u0596\\u05dc\\u0007\\u0093\\u0002\",\n    \"\\u0002\\u0597\\u05dc\\u00074\\u0002\\u0002\\u0598\\u05dc\\u00075\\u0002\\u0002\",\n    \"\\u0599\\u05dc\\u00076\\u0002\\u0002\\u059a\\u05dc\\u00077\\u0002\\u0002\\u059b\",\n    \"\\u05dc\\u00078\\u0002\\u0002\\u059c\\u05dc\\u00079\\u0002\\u0002\\u059d\\u05dc\",\n    \"\\u0007:\\u0002\\u0002\\u059e\\u05dc\\u0007A\\u0002\\u0002\\u059f\\u05dc\\u0007\",\n    \";\\u0002\\u0002\\u05a0\\u05dc\\u0007<\\u0002\\u0002\\u05a1\\u05dc\\u0007=\\u0002\",\n    \"\\u0002\\u05a2\\u05dc\\u0007>\\u0002\\u0002\\u05a3\\u05dc\\u0007?\\u0002\\u0002\",\n    \"\\u05a4\\u05dc\\u0007@\\u0002\\u0002\\u05a5\\u05dc\\u0007s\\u0002\\u0002\\u05a6\",\n    \"\\u05dc\\u0007t\\u0002\\u0002\\u05a7\\u05dc\\u0007u\\u0002\\u0002\\u05a8\\u05dc\",\n    \"\\u0007v\\u0002\\u0002\\u05a9\\u05dc\\u0007w\\u0002\\u0002\\u05aa\\u05dc\\u0007\",\n    \"x\\u0002\\u0002\\u05ab\\u05dc\\u0007y\\u0002\\u0002\\u05ac\\u05dc\\u0007z\\u0002\",\n    \"\\u0002\\u05ad\\u05dc\\u0007\\u008e\\u0002\\u0002\\u05ae\\u05dc\\u0007\\u008b\\u0002\",\n    \"\\u0002\\u05af\\u05dc\\u0007\\u008c\\u0002\\u0002\\u05b0\\u05dc\\u0007\\u008d\\u0002\",\n    \"\\u0002\\u05b1\\u05dc\\u0007\\u0083\\u0002\\u0002\\u05b2\\u05dc\\u0007\\u008a\\u0002\",\n    \"\\u0002\\u05b3\\u05dc\\u0007\\u0095\\u0002\\u0002\\u05b4\\u05dc\\u0007\\u0096\\u0002\",\n    \"\\u0002\\u05b5\\u05dc\\u0007g\\u0002\\u0002\\u05b6\\u05dc\\u0007h\\u0002\\u0002\",\n    \"\\u05b7\\u05dc\\u0007\\u00b7\\u0002\\u0002\\u05b8\\u05dc\\u0007\\u00b8\\u0002\\u0002\",\n    \"\\u05b9\\u05dc\\u0007\\u00b9\\u0002\\u0002\\u05ba\\u05dc\\u0005|?\\u0002\\u05bb\",\n    \"\\u05dc\\u00072\\u0002\\u0002\\u05bc\\u05dc\\u0007#\\u0002\\u0002\\u05bd\\u05dc\",\n    \"\\u0007\\u0098\\u0002\\u0002\\u05be\\u05dc\\u0007\\u0099\\u0002\\u0002\\u05bf\\u05dc\",\n    \"\\u0007\\u009a\\u0002\\u0002\\u05c0\\u05dc\\u0007\\u009b\\u0002\\u0002\\u05c1\\u05dc\",\n    \"\\u0007\\u009c\\u0002\\u0002\\u05c2\\u05dc\\u0007\\u009d\\u0002\\u0002\\u05c3\\u05dc\",\n    \"\\u0007\\u009e\\u0002\\u0002\\u05c4\\u05dc\\u0007\\u009f\\u0002\\u0002\\u05c5\\u05dc\",\n    \"\\u0007\\u00a0\\u0002\\u0002\\u05c6\\u05dc\\u0007\\u00a1\\u0002\\u0002\\u05c7\\u05dc\",\n    \"\\u0007\\u00a2\\u0002\\u0002\\u05c8\\u05dc\\u0007\\u00a3\\u0002\\u0002\\u05c9\\u05dc\",\n    \"\\u0007\\u00a4\\u0002\\u0002\\u05ca\\u05dc\\u0007\\u00a5\\u0002\\u0002\\u05cb\\u05dc\",\n    \"\\u0007\\u00a6\\u0002\\u0002\\u05cc\\u05dc\\u0007\\u00a7\\u0002\\u0002\\u05cd\\u05dc\",\n    \"\\u0007n\\u0002\\u0002\\u05ce\\u05dc\\u0007o\\u0002\\u0002\\u05cf\\u05dc\\u0007\",\n    \"p\\u0002\\u0002\\u05d0\\u05dc\\u0007q\\u0002\\u0002\\u05d1\\u05dc\\u0007r\\u0002\",\n    \"\\u0002\\u05d2\\u05dc\\u00071\\u0002\\u0002\\u05d3\\u05dc\\u0007e\\u0002\\u0002\",\n    \"\\u05d4\\u05dc\\u0007\\u00ad\\u0002\\u0002\\u05d5\\u05dc\\u0007\\u00ae\\u0002\\u0002\",\n    \"\\u05d6\\u05dc\\u0007\\u00ab\\u0002\\u0002\\u05d7\\u05dc\\u0007\\u00ac\\u0002\\u0002\",\n    \"\\u05d8\\u05dc\\u0007\\u00af\\u0002\\u0002\\u05d9\\u05dc\\u0007\\u00b0\\u0002\\u0002\",\n    \"\\u05da\\u05dc\\u0007\\u00b1\\u0002\\u0002\\u05db\\u0582\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0583\\u0003\\u0002\\u0002\\u0002\\u05db\\u0584\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0585\\u0003\\u0002\\u0002\\u0002\\u05db\\u0586\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0587\\u0003\\u0002\\u0002\\u0002\\u05db\\u0588\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0589\\u0003\\u0002\\u0002\\u0002\\u05db\\u058a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u058b\\u0003\\u0002\\u0002\\u0002\\u05db\\u058c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u058d\\u0003\\u0002\\u0002\\u0002\\u05db\\u058e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u058f\\u0003\\u0002\\u0002\\u0002\\u05db\\u0590\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0591\\u0003\\u0002\\u0002\\u0002\\u05db\\u0592\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0593\\u0003\\u0002\\u0002\\u0002\\u05db\\u0594\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0595\\u0003\\u0002\\u0002\\u0002\\u05db\\u0596\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0597\\u0003\\u0002\\u0002\\u0002\\u05db\\u0598\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u0599\\u0003\\u0002\\u0002\\u0002\\u05db\\u059a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u059b\\u0003\\u0002\\u0002\\u0002\\u05db\\u059c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u059d\\u0003\\u0002\\u0002\\u0002\\u05db\\u059e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u059f\\u0003\\u0002\\u0002\\u0002\\u05db\\u05a0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05a1\\u0003\\u0002\\u0002\\u0002\\u05db\\u05a2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05a3\\u0003\\u0002\\u0002\\u0002\\u05db\\u05a4\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05a5\\u0003\\u0002\\u0002\\u0002\\u05db\\u05a6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05a7\\u0003\\u0002\\u0002\\u0002\\u05db\\u05a8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05a9\\u0003\\u0002\\u0002\\u0002\\u05db\\u05aa\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05ab\\u0003\\u0002\\u0002\\u0002\\u05db\\u05ac\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05ad\\u0003\\u0002\\u0002\\u0002\\u05db\\u05ae\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05af\\u0003\\u0002\\u0002\\u0002\\u05db\\u05b0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05b1\\u0003\\u0002\\u0002\\u0002\\u05db\\u05b2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05b3\\u0003\\u0002\\u0002\\u0002\\u05db\\u05b4\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05b5\\u0003\\u0002\\u0002\\u0002\\u05db\\u05b6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05b7\\u0003\\u0002\\u0002\\u0002\\u05db\\u05b8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05b9\\u0003\\u0002\\u0002\\u0002\\u05db\\u05ba\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05bb\\u0003\\u0002\\u0002\\u0002\\u05db\\u05bc\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05bd\\u0003\\u0002\\u0002\\u0002\\u05db\\u05be\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05bf\\u0003\\u0002\\u0002\\u0002\\u05db\\u05c0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05c1\\u0003\\u0002\\u0002\\u0002\\u05db\\u05c2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05c3\\u0003\\u0002\\u0002\\u0002\\u05db\\u05c4\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05c5\\u0003\\u0002\\u0002\\u0002\\u05db\\u05c6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05c7\\u0003\\u0002\\u0002\\u0002\\u05db\\u05c8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05c9\\u0003\\u0002\\u0002\\u0002\\u05db\\u05ca\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05cb\\u0003\\u0002\\u0002\\u0002\\u05db\\u05cc\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05cd\\u0003\\u0002\\u0002\\u0002\\u05db\\u05ce\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05cf\\u0003\\u0002\\u0002\\u0002\\u05db\\u05d0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05d1\\u0003\\u0002\\u0002\\u0002\\u05db\\u05d2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05d3\\u0003\\u0002\\u0002\\u0002\\u05db\\u05d4\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05d5\\u0003\\u0002\\u0002\\u0002\\u05db\\u05d6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05d7\\u0003\\u0002\\u0002\\u0002\\u05db\\u05d8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05db\\u05d9\\u0003\\u0002\\u0002\\u0002\\u05db\\u05da\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u05dc{\\u0003\\u0002\\u0002\\u0002\\u05dd\\u05de\\t\\u0015\\u0002\\u0002\\u05de\",\n    \"}\\u0003\\u0002\\u0002\\u0002\\u00af\\u0083\\u0087\\u009e\\u00a3\\u00a9\\u00ad\",\n    \"\\u00bb\\u00c0\\u00c6\\u00c9\\u00d0\\u00d9\\u00df\\u00e5\\u00ec\\u00f5\\u0111\\u011c\",\n    \"\\u0127\\u012a\\u0134\\u0139\\u013d\\u0145\\u014b\\u0152\\u0157\\u015b\\u0163\\u016b\",\n    \"\\u0170\\u017f\\u0183\\u0189\\u018d\\u0193\\u01b1\\u01b4\\u01b8\\u01bc\\u01c4\\u01cd\",\n    \"\\u01d0\\u01d4\\u01e6\\u01e9\\u01f1\\u01f4\\u01fa\\u0201\\u0206\\u020f\\u0217\\u0228\",\n    \"\\u022b\\u022f\\u0237\\u023d\\u0240\\u0242\\u024e\\u0255\\u0259\\u025d\\u0261\\u0268\",\n    \"\\u0271\\u0274\\u0278\\u027d\\u0281\\u0284\\u028b\\u0296\\u0299\\u02a3\\u02a6\\u02b1\",\n    \"\\u02b6\\u02be\\u02c1\\u02c5\\u02cd\\u02d0\\u02d4\\u02d8\\u02e3\\u02e6\\u02ed\\u0300\",\n    \"\\u0304\\u0308\\u030c\\u0310\\u0314\\u0316\\u0321\\u0326\\u032f\\u0335\\u0339\\u033b\",\n    \"\\u0343\\u0354\\u035a\\u0360\\u0368\\u0370\\u0372\\u0377\\u0383\\u038b\\u0394\\u039a\",\n    \"\\u03a2\\u03a8\\u03ac\\u03b1\\u03b6\\u03bc\\u03ca\\u03cc\\u03e9\\u03f5\\u03ff\\u0402\",\n    \"\\u0407\\u040e\\u0411\\u0415\\u0418\\u0424\\u0439\\u043d\\u0445\\u0449\\u0462\\u0465\",\n    \"\\u046e\\u0474\\u047a\\u0480\\u0489\\u0492\\u049d\\u04a7\\u04a9\\u04b2\\u04bc\\u04c2\",\n    \"\\u04dd\\u04e9\\u04ee\\u04f0\\u04f6\\u04fb\\u0501\\u0517\\u051a\\u0523\\u0526\\u0529\",\n    \"\\u053d\\u0548\\u054e\\u0555\\u055e\\u0565\\u056b\\u0572\\u057a\\u0580\\u05db\"].join(\"\");\n\n\nvar atn = new _atn.ATNDeserializer().deserialize(serializedATN);\n\nvar decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new dfa.DFA(ds, index); });\n\nvar sharedContextCache = new PredictionContextCache();\n\nvar literalNames = [ null, \"'.'\", \"'('\", \"','\", \"')'\", \"'?'\", \"'->'\", \"'['\", \n                     \"']'\", \"'=>'\", null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, null, \n                     null, null, null, null, null, null, \"'='\", null, \"'<'\", \n                     \"'<='\", \"'>'\", \"'>='\", \"'+'\", \"'-'\", \"'*'\", \"'/'\", \n                     \"'%'\", \"'||'\", null, null, null, null, null, null, \n                     null, null, null, null, null, null, null, null, \"';'\" ];\n\nvar symbolicNames = [ null, null, null, null, null, null, null, null, null, \n                      null, \"SELECT\", \"FROM\", \"ADD\", \"AS\", \"ALL\", \"SOME\", \n                      \"ANY\", \"DISTINCT\", \"WHERE\", \"GROUP\", \"BY\", \"GROUPING\", \n                      \"SETS\", \"CUBE\", \"ROLLUP\", \"ORDER\", \"HAVING\", \"LIMIT\", \n                      \"AT\", \"OR\", \"AND\", \"IN\", \"NOT\", \"NO\", \"EXISTS\", \"BETWEEN\", \n                      \"LIKE\", \"IS\", \"NULL\", \"TRUE\", \"FALSE\", \"NULLS\", \"FIRST\", \n                      \"LAST\", \"ESCAPE\", \"ASC\", \"DESC\", \"SUBSTRING\", \"POSITION\", \n                      \"FOR\", \"TINYINT\", \"SMALLINT\", \"INTEGER\", \"DATE\", \"TIME\", \n                      \"TIMESTAMP\", \"INTERVAL\", \"YEAR\", \"MONTH\", \"DAY\", \"HOUR\", \n                      \"MINUTE\", \"SECOND\", \"ZONE\", \"CURRENT_DATE\", \"CURRENT_TIME\", \n                      \"CURRENT_TIMESTAMP\", \"LOCALTIME\", \"LOCALTIMESTAMP\", \n                      \"EXTRACT\", \"CASE\", \"WHEN\", \"THEN\", \"ELSE\", \"END\", \n                      \"JOIN\", \"CROSS\", \"OUTER\", \"INNER\", \"LEFT\", \"RIGHT\", \n                      \"FULL\", \"NATURAL\", \"USING\", \"ON\", \"FILTER\", \"OVER\", \n                      \"PARTITION\", \"RANGE\", \"ROWS\", \"UNBOUNDED\", \"PRECEDING\", \n                      \"FOLLOWING\", \"CURRENT\", \"ROW\", \"WITH\", \"RECURSIVE\", \n                      \"VALUES\", \"CREATE\", \"SCHEMA\", \"TABLE\", \"VIEW\", \"REPLACE\", \n                      \"INSERT\", \"DELETE\", \"INTO\", \"CONSTRAINT\", \"DESCRIBE\", \n                      \"GRANT\", \"REVOKE\", \"PRIVILEGES\", \"PUBLIC\", \"OPTION\", \n                      \"EXPLAIN\", \"ANALYZE\", \"FORMAT\", \"TYPE\", \"TEXT\", \"GRAPHVIZ\", \n                      \"LOGICAL\", \"DISTRIBUTED\", \"CAST\", \"TRY_CAST\", \"SHOW\", \n                      \"TABLES\", \"SCHEMAS\", \"CATALOGS\", \"COLUMNS\", \"COLUMN\", \n                      \"USE\", \"PARTITIONS\", \"FUNCTIONS\", \"DROP\", \"UNION\", \n                      \"EXCEPT\", \"INTERSECT\", \"TO\", \"SYSTEM\", \"BERNOULLI\", \n                      \"POISSONIZED\", \"TABLESAMPLE\", \"ALTER\", \"RENAME\", \"UNNEST\", \n                      \"ORDINALITY\", \"ARRAY\", \"MAP\", \"SET\", \"RESET\", \"SESSION\", \n                      \"DATA\", \"START\", \"TRANSACTION\", \"COMMIT\", \"ROLLBACK\", \n                      \"WORK\", \"ISOLATION\", \"LEVEL\", \"SERIALIZABLE\", \"REPEATABLE\", \n                      \"COMMITTED\", \"UNCOMMITTED\", \"READ\", \"WRITE\", \"ONLY\", \n                      \"CALL\", \"PREPARE\", \"DEALLOCATE\", \"EXECUTE\", \"INPUT\", \n                      \"OUTPUT\", \"CASCADE\", \"RESTRICT\", \"INCLUDING\", \"EXCLUDING\", \n                      \"PROPERTIES\", \"NORMALIZE\", \"NFD\", \"NFC\", \"NFKD\", \"NFKC\", \n                      \"IF\", \"NULLIF\", \"COALESCE\", \"EQ\", \"NEQ\", \"LT\", \"LTE\", \n                      \"GT\", \"GTE\", \"PLUS\", \"MINUS\", \"ASTERISK\", \"SLASH\", \n                      \"PERCENT\", \"CONCAT\", \"STRING\", \"BINARY_LITERAL\", \"INTEGER_VALUE\", \n                      \"DECIMAL_VALUE\", \"IDENTIFIER\", \"DIGIT_IDENTIFIER\", \n                      \"QUOTED_IDENTIFIER\", \"BACKQUOTED_IDENTIFIER\", \"TIME_WITH_TIME_ZONE\", \n                      \"TIMESTAMP_WITH_TIME_ZONE\", \"DOUBLE_PRECISION\", \"SIMPLE_COMMENT\", \n                      \"BRACKETED_COMMENT\", \"WS\", \"SEMICOLON\", \"UNRECOGNIZED\", \n                      \"DELIMITER\" ];\n\nvar ruleNames =  [ \"multiStatement\", \"singleStatement\", \"singleExpression\", \n                   \"statement\", \"query\", \"presto_with\", \"tableElement\", \n                   \"columnDefinition\", \"likeClause\", \"tableProperties\", \n                   \"tableProperty\", \"queryNoWith\", \"queryTerm\", \"queryPrimary\", \n                   \"sortItem\", \"querySpecification\", \"groupBy\", \"groupingElement\", \n                   \"groupingExpressions\", \"groupingSet\", \"namedQuery\", \"setQuantifier\", \n                   \"selectItem\", \"relation\", \"joinType\", \"joinCriteria\", \n                   \"sampledRelation\", \"sampleType\", \"aliasedRelation\", \"columnAliases\", \n                   \"relationPrimary\", \"expression\", \"booleanExpression\", \n                   \"predicated\", \"predicate\", \"valueExpression\", \"primaryExpression\", \n                   \"timeZoneSpecifier\", \"comparisonOperator\", \"comparisonQuantifier\", \n                   \"booleanValue\", \"interval\", \"intervalField\", \"type\", \n                   \"typeParameter\", \"baseType\", \"whenClause\", \"filter\", \n                   \"over\", \"windowFrame\", \"frameBound\", \"explainOption\", \n                   \"transactionMode\", \"levelOfIsolation\", \"callArgument\", \n                   \"privilege\", \"qualifiedName\", \"identifier\", \"quotedIdentifier\", \n                   \"number\", \"nonReserved\", \"normalForm\" ];\n\nexport const SqlBaseParser = function(input){\n\tParser.call(this, input);\n    this._interp = new _atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache);\n    this.ruleNames = ruleNames;\n    this.literalNames = literalNames;\n    this.symbolicNames = symbolicNames;\n    // return this;\n} as any;\n\nSqlBaseParser.prototype = Object.create(Parser.prototype);\nSqlBaseParser.prototype.constructor = SqlBaseParser;\n\nObject.defineProperty(SqlBaseParser.prototype, \"atn\", {\n\tget : function() {\n\t\treturn atn;\n\t}\n});\n\nSqlBaseParser.EOF = Token.EOF;\nSqlBaseParser.T__0 = 1;\nSqlBaseParser.T__1 = 2;\nSqlBaseParser.T__2 = 3;\nSqlBaseParser.T__3 = 4;\nSqlBaseParser.T__4 = 5;\nSqlBaseParser.T__5 = 6;\nSqlBaseParser.T__6 = 7;\nSqlBaseParser.T__7 = 8;\nSqlBaseParser.T__8 = 9;\nSqlBaseParser.SELECT = 10;\nSqlBaseParser.FROM = 11;\nSqlBaseParser.ADD = 12;\nSqlBaseParser.AS = 13;\nSqlBaseParser.ALL = 14;\nSqlBaseParser.SOME = 15;\nSqlBaseParser.ANY = 16;\nSqlBaseParser.DISTINCT = 17;\nSqlBaseParser.WHERE = 18;\nSqlBaseParser.GROUP = 19;\nSqlBaseParser.BY = 20;\nSqlBaseParser.GROUPING = 21;\nSqlBaseParser.SETS = 22;\nSqlBaseParser.CUBE = 23;\nSqlBaseParser.ROLLUP = 24;\nSqlBaseParser.ORDER = 25;\nSqlBaseParser.HAVING = 26;\nSqlBaseParser.LIMIT = 27;\nSqlBaseParser.AT = 28;\nSqlBaseParser.OR = 29;\nSqlBaseParser.AND = 30;\nSqlBaseParser.IN = 31;\nSqlBaseParser.NOT = 32;\nSqlBaseParser.NO = 33;\nSqlBaseParser.EXISTS = 34;\nSqlBaseParser.BETWEEN = 35;\nSqlBaseParser.LIKE = 36;\nSqlBaseParser.IS = 37;\nSqlBaseParser.NULL = 38;\nSqlBaseParser.TRUE = 39;\nSqlBaseParser.FALSE = 40;\nSqlBaseParser.NULLS = 41;\nSqlBaseParser.FIRST = 42;\nSqlBaseParser.LAST = 43;\nSqlBaseParser.ESCAPE = 44;\nSqlBaseParser.ASC = 45;\nSqlBaseParser.DESC = 46;\nSqlBaseParser.SUBSTRING = 47;\nSqlBaseParser.POSITION = 48;\nSqlBaseParser.FOR = 49;\nSqlBaseParser.TINYINT = 50;\nSqlBaseParser.SMALLINT = 51;\nSqlBaseParser.INTEGER = 52;\nSqlBaseParser.DATE = 53;\nSqlBaseParser.TIME = 54;\nSqlBaseParser.TIMESTAMP = 55;\nSqlBaseParser.INTERVAL = 56;\nSqlBaseParser.YEAR = 57;\nSqlBaseParser.MONTH = 58;\nSqlBaseParser.DAY = 59;\nSqlBaseParser.HOUR = 60;\nSqlBaseParser.MINUTE = 61;\nSqlBaseParser.SECOND = 62;\nSqlBaseParser.ZONE = 63;\nSqlBaseParser.CURRENT_DATE = 64;\nSqlBaseParser.CURRENT_TIME = 65;\nSqlBaseParser.CURRENT_TIMESTAMP = 66;\nSqlBaseParser.LOCALTIME = 67;\nSqlBaseParser.LOCALTIMESTAMP = 68;\nSqlBaseParser.EXTRACT = 69;\nSqlBaseParser.CASE = 70;\nSqlBaseParser.WHEN = 71;\nSqlBaseParser.THEN = 72;\nSqlBaseParser.ELSE = 73;\nSqlBaseParser.END = 74;\nSqlBaseParser.JOIN = 75;\nSqlBaseParser.CROSS = 76;\nSqlBaseParser.OUTER = 77;\nSqlBaseParser.INNER = 78;\nSqlBaseParser.LEFT = 79;\nSqlBaseParser.RIGHT = 80;\nSqlBaseParser.FULL = 81;\nSqlBaseParser.NATURAL = 82;\nSqlBaseParser.USING = 83;\nSqlBaseParser.ON = 84;\nSqlBaseParser.FILTER = 85;\nSqlBaseParser.OVER = 86;\nSqlBaseParser.PARTITION = 87;\nSqlBaseParser.RANGE = 88;\nSqlBaseParser.ROWS = 89;\nSqlBaseParser.UNBOUNDED = 90;\nSqlBaseParser.PRECEDING = 91;\nSqlBaseParser.FOLLOWING = 92;\nSqlBaseParser.CURRENT = 93;\nSqlBaseParser.ROW = 94;\nSqlBaseParser.WITH = 95;\nSqlBaseParser.RECURSIVE = 96;\nSqlBaseParser.VALUES = 97;\nSqlBaseParser.CREATE = 98;\nSqlBaseParser.SCHEMA = 99;\nSqlBaseParser.TABLE = 100;\nSqlBaseParser.VIEW = 101;\nSqlBaseParser.REPLACE = 102;\nSqlBaseParser.INSERT = 103;\nSqlBaseParser.DELETE = 104;\nSqlBaseParser.INTO = 105;\nSqlBaseParser.CONSTRAINT = 106;\nSqlBaseParser.DESCRIBE = 107;\nSqlBaseParser.GRANT = 108;\nSqlBaseParser.REVOKE = 109;\nSqlBaseParser.PRIVILEGES = 110;\nSqlBaseParser.PUBLIC = 111;\nSqlBaseParser.OPTION = 112;\nSqlBaseParser.EXPLAIN = 113;\nSqlBaseParser.ANALYZE = 114;\nSqlBaseParser.FORMAT = 115;\nSqlBaseParser.TYPE = 116;\nSqlBaseParser.TEXT = 117;\nSqlBaseParser.GRAPHVIZ = 118;\nSqlBaseParser.LOGICAL = 119;\nSqlBaseParser.DISTRIBUTED = 120;\nSqlBaseParser.CAST = 121;\nSqlBaseParser.TRY_CAST = 122;\nSqlBaseParser.SHOW = 123;\nSqlBaseParser.TABLES = 124;\nSqlBaseParser.SCHEMAS = 125;\nSqlBaseParser.CATALOGS = 126;\nSqlBaseParser.COLUMNS = 127;\nSqlBaseParser.COLUMN = 128;\nSqlBaseParser.USE = 129;\nSqlBaseParser.PARTITIONS = 130;\nSqlBaseParser.FUNCTIONS = 131;\nSqlBaseParser.DROP = 132;\nSqlBaseParser.UNION = 133;\nSqlBaseParser.EXCEPT = 134;\nSqlBaseParser.INTERSECT = 135;\nSqlBaseParser.TO = 136;\nSqlBaseParser.SYSTEM = 137;\nSqlBaseParser.BERNOULLI = 138;\nSqlBaseParser.POISSONIZED = 139;\nSqlBaseParser.TABLESAMPLE = 140;\nSqlBaseParser.ALTER = 141;\nSqlBaseParser.RENAME = 142;\nSqlBaseParser.UNNEST = 143;\nSqlBaseParser.ORDINALITY = 144;\nSqlBaseParser.ARRAY = 145;\nSqlBaseParser.MAP = 146;\nSqlBaseParser.SET = 147;\nSqlBaseParser.RESET = 148;\nSqlBaseParser.SESSION = 149;\nSqlBaseParser.DATA = 150;\nSqlBaseParser.START = 151;\nSqlBaseParser.TRANSACTION = 152;\nSqlBaseParser.COMMIT = 153;\nSqlBaseParser.ROLLBACK = 154;\nSqlBaseParser.WORK = 155;\nSqlBaseParser.ISOLATION = 156;\nSqlBaseParser.LEVEL = 157;\nSqlBaseParser.SERIALIZABLE = 158;\nSqlBaseParser.REPEATABLE = 159;\nSqlBaseParser.COMMITTED = 160;\nSqlBaseParser.UNCOMMITTED = 161;\nSqlBaseParser.READ = 162;\nSqlBaseParser.WRITE = 163;\nSqlBaseParser.ONLY = 164;\nSqlBaseParser.CALL = 165;\nSqlBaseParser.PREPARE = 166;\nSqlBaseParser.DEALLOCATE = 167;\nSqlBaseParser.EXECUTE = 168;\nSqlBaseParser.INPUT = 169;\nSqlBaseParser.OUTPUT = 170;\nSqlBaseParser.CASCADE = 171;\nSqlBaseParser.RESTRICT = 172;\nSqlBaseParser.INCLUDING = 173;\nSqlBaseParser.EXCLUDING = 174;\nSqlBaseParser.PROPERTIES = 175;\nSqlBaseParser.NORMALIZE = 176;\nSqlBaseParser.NFD = 177;\nSqlBaseParser.NFC = 178;\nSqlBaseParser.NFKD = 179;\nSqlBaseParser.NFKC = 180;\nSqlBaseParser.IF = 181;\nSqlBaseParser.NULLIF = 182;\nSqlBaseParser.COALESCE = 183;\nSqlBaseParser.EQ = 184;\nSqlBaseParser.NEQ = 185;\nSqlBaseParser.LT = 186;\nSqlBaseParser.LTE = 187;\nSqlBaseParser.GT = 188;\nSqlBaseParser.GTE = 189;\nSqlBaseParser.PLUS = 190;\nSqlBaseParser.MINUS = 191;\nSqlBaseParser.ASTERISK = 192;\nSqlBaseParser.SLASH = 193;\nSqlBaseParser.PERCENT = 194;\nSqlBaseParser.CONCAT = 195;\nSqlBaseParser.STRING = 196;\nSqlBaseParser.BINARY_LITERAL = 197;\nSqlBaseParser.INTEGER_VALUE = 198;\nSqlBaseParser.DECIMAL_VALUE = 199;\nSqlBaseParser.IDENTIFIER = 200;\nSqlBaseParser.DIGIT_IDENTIFIER = 201;\nSqlBaseParser.QUOTED_IDENTIFIER = 202;\nSqlBaseParser.BACKQUOTED_IDENTIFIER = 203;\nSqlBaseParser.TIME_WITH_TIME_ZONE = 204;\nSqlBaseParser.TIMESTAMP_WITH_TIME_ZONE = 205;\nSqlBaseParser.DOUBLE_PRECISION = 206;\nSqlBaseParser.SIMPLE_COMMENT = 207;\nSqlBaseParser.BRACKETED_COMMENT = 208;\nSqlBaseParser.WS = 209;\nSqlBaseParser.SEMICOLON = 210;\nSqlBaseParser.UNRECOGNIZED = 211;\nSqlBaseParser.DELIMITER = 212;\n\nSqlBaseParser.RULE_multiStatement = 0;\nSqlBaseParser.RULE_singleStatement = 1;\nSqlBaseParser.RULE_singleExpression = 2;\nSqlBaseParser.RULE_statement = 3;\nSqlBaseParser.RULE_query = 4;\nSqlBaseParser.RULE_presto_with = 5;\nSqlBaseParser.RULE_tableElement = 6;\nSqlBaseParser.RULE_columnDefinition = 7;\nSqlBaseParser.RULE_likeClause = 8;\nSqlBaseParser.RULE_tableProperties = 9;\nSqlBaseParser.RULE_tableProperty = 10;\nSqlBaseParser.RULE_queryNoWith = 11;\nSqlBaseParser.RULE_queryTerm = 12;\nSqlBaseParser.RULE_queryPrimary = 13;\nSqlBaseParser.RULE_sortItem = 14;\nSqlBaseParser.RULE_querySpecification = 15;\nSqlBaseParser.RULE_groupBy = 16;\nSqlBaseParser.RULE_groupingElement = 17;\nSqlBaseParser.RULE_groupingExpressions = 18;\nSqlBaseParser.RULE_groupingSet = 19;\nSqlBaseParser.RULE_namedQuery = 20;\nSqlBaseParser.RULE_setQuantifier = 21;\nSqlBaseParser.RULE_selectItem = 22;\nSqlBaseParser.RULE_relation = 23;\nSqlBaseParser.RULE_joinType = 24;\nSqlBaseParser.RULE_joinCriteria = 25;\nSqlBaseParser.RULE_sampledRelation = 26;\nSqlBaseParser.RULE_sampleType = 27;\nSqlBaseParser.RULE_aliasedRelation = 28;\nSqlBaseParser.RULE_columnAliases = 29;\nSqlBaseParser.RULE_relationPrimary = 30;\nSqlBaseParser.RULE_expression = 31;\nSqlBaseParser.RULE_booleanExpression = 32;\nSqlBaseParser.RULE_predicated = 33;\nSqlBaseParser.RULE_predicate = 34;\nSqlBaseParser.RULE_valueExpression = 35;\nSqlBaseParser.RULE_primaryExpression = 36;\nSqlBaseParser.RULE_timeZoneSpecifier = 37;\nSqlBaseParser.RULE_comparisonOperator = 38;\nSqlBaseParser.RULE_comparisonQuantifier = 39;\nSqlBaseParser.RULE_booleanValue = 40;\nSqlBaseParser.RULE_interval = 41;\nSqlBaseParser.RULE_intervalField = 42;\nSqlBaseParser.RULE_type = 43;\nSqlBaseParser.RULE_typeParameter = 44;\nSqlBaseParser.RULE_baseType = 45;\nSqlBaseParser.RULE_whenClause = 46;\nSqlBaseParser.RULE_filter = 47;\nSqlBaseParser.RULE_over = 48;\nSqlBaseParser.RULE_windowFrame = 49;\nSqlBaseParser.RULE_frameBound = 50;\nSqlBaseParser.RULE_explainOption = 51;\nSqlBaseParser.RULE_transactionMode = 52;\nSqlBaseParser.RULE_levelOfIsolation = 53;\nSqlBaseParser.RULE_callArgument = 54;\nSqlBaseParser.RULE_privilege = 55;\nSqlBaseParser.RULE_qualifiedName = 56;\nSqlBaseParser.RULE_identifier = 57;\nSqlBaseParser.RULE_quotedIdentifier = 58;\nSqlBaseParser.RULE_number = 59;\nSqlBaseParser.RULE_nonReserved = 60;\nSqlBaseParser.RULE_normalForm = 61;\n\nfunction MultiStatementContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_multiStatement;\n    // return this;\n}\n\nMultiStatementContext.prototype = Object.create(ParserRuleContext.prototype);\nMultiStatementContext.prototype.constructor = MultiStatementContext;\n\nMultiStatementContext.prototype.statement = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(StatementContext);\n    } else {\n        return this.getTypedRuleContext(StatementContext,i);\n    }\n};\n\nMultiStatementContext.prototype.EOF = function() {\n    return this.getToken(SqlBaseParser.EOF, 0);\n};\n\nMultiStatementContext.prototype.SEMICOLON = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(SqlBaseParser.SEMICOLON);\n    } else {\n        return this.getToken(SqlBaseParser.SEMICOLON, i);\n    }\n};\n\n\nMultiStatementContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterMultiStatement(this);\n\t}\n};\n\nMultiStatementContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitMultiStatement(this);\n\t}\n};\n\nMultiStatementContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitMultiStatement(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.MultiStatementContext = MultiStatementContext;\n\nSqlBaseParser.prototype.multiStatement = function() {\n\n    var localctx = new MultiStatementContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 0, SqlBaseParser.RULE_multiStatement);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 124;\n        this.statement();\n        this.state = 129;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,0,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 125;\n                this.match(SqlBaseParser.SEMICOLON);\n                this.state = 126;\n                this.statement(); \n            }\n            this.state = 131;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,0,this._ctx);\n        }\n\n        this.state = 133;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.SEMICOLON) {\n            this.state = 132;\n            this.match(SqlBaseParser.SEMICOLON);\n        }\n\n        this.state = 135;\n        this.match(SqlBaseParser.EOF);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SingleStatementContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_singleStatement;\n    // return this;\n}\n\nSingleStatementContext.prototype = Object.create(ParserRuleContext.prototype);\nSingleStatementContext.prototype.constructor = SingleStatementContext;\n\nSingleStatementContext.prototype.statement = function() {\n    return this.getTypedRuleContext(StatementContext,0);\n};\n\nSingleStatementContext.prototype.EOF = function() {\n    return this.getToken(SqlBaseParser.EOF, 0);\n};\n\nSingleStatementContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSingleStatement(this);\n\t}\n};\n\nSingleStatementContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSingleStatement(this);\n\t}\n};\n\nSingleStatementContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSingleStatement(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.SingleStatementContext = SingleStatementContext;\n\nSqlBaseParser.prototype.singleStatement = function() {\n\n    var localctx = new SingleStatementContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 2, SqlBaseParser.RULE_singleStatement);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 137;\n        this.statement();\n        this.state = 138;\n        this.match(SqlBaseParser.EOF);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SingleExpressionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_singleExpression;\n    // return this;\n}\n\nSingleExpressionContext.prototype = Object.create(ParserRuleContext.prototype);\nSingleExpressionContext.prototype.constructor = SingleExpressionContext;\n\nSingleExpressionContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nSingleExpressionContext.prototype.EOF = function() {\n    return this.getToken(SqlBaseParser.EOF, 0);\n};\n\nSingleExpressionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSingleExpression(this);\n\t}\n};\n\nSingleExpressionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSingleExpression(this);\n\t}\n};\n\nSingleExpressionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSingleExpression(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.SingleExpressionContext = SingleExpressionContext;\n\nSqlBaseParser.prototype.singleExpression = function() {\n\n    var localctx = new (SingleExpressionContext as any)(this, this._ctx, this.state);\n    this.enterRule(localctx, 4, SqlBaseParser.RULE_singleExpression);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 140;\n        this.expression();\n        this.state = 141;\n        this.match(SqlBaseParser.EOF);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction StatementContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_statement;\n    // return this;\n}\n\nStatementContext.prototype = Object.create(ParserRuleContext.prototype);\nStatementContext.prototype.constructor = StatementContext;\n\n\n \nStatementContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction ExplainContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nExplainContext.prototype = Object.create(StatementContext.prototype);\nExplainContext.prototype.constructor = ExplainContext;\n\nSqlBaseParser.ExplainContext = ExplainContext;\n\nExplainContext.prototype.EXPLAIN = function() {\n    return this.getToken(SqlBaseParser.EXPLAIN, 0);\n};\n\nExplainContext.prototype.statement = function() {\n    return this.getTypedRuleContext(StatementContext,0);\n};\n\nExplainContext.prototype.ANALYZE = function() {\n    return this.getToken(SqlBaseParser.ANALYZE, 0);\n};\n\nExplainContext.prototype.explainOption = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExplainOptionContext);\n    } else {\n        return this.getTypedRuleContext(ExplainOptionContext,i);\n    }\n};\nExplainContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExplain(this);\n\t}\n};\n\nExplainContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExplain(this);\n\t}\n};\n\nExplainContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExplain(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction PrepareContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nPrepareContext.prototype = Object.create(StatementContext.prototype);\nPrepareContext.prototype.constructor = PrepareContext;\n\nSqlBaseParser.PrepareContext = PrepareContext;\n\nPrepareContext.prototype.PREPARE = function() {\n    return this.getToken(SqlBaseParser.PREPARE, 0);\n};\n\nPrepareContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nPrepareContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nPrepareContext.prototype.statement = function() {\n    return this.getTypedRuleContext(StatementContext,0);\n};\nPrepareContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterPrepare(this);\n\t}\n};\n\nPrepareContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitPrepare(this);\n\t}\n};\n\nPrepareContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitPrepare(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CreateTableContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCreateTableContext.prototype = Object.create(StatementContext.prototype);\nCreateTableContext.prototype.constructor = CreateTableContext;\n\nSqlBaseParser.CreateTableContext = CreateTableContext;\n\nCreateTableContext.prototype.CREATE = function() {\n    return this.getToken(SqlBaseParser.CREATE, 0);\n};\n\nCreateTableContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nCreateTableContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nCreateTableContext.prototype.tableElement = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TableElementContext);\n    } else {\n        return this.getTypedRuleContext(TableElementContext,i);\n    }\n};\n\nCreateTableContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nCreateTableContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\n\nCreateTableContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\n\nCreateTableContext.prototype.WITH = function() {\n    return this.getToken(SqlBaseParser.WITH, 0);\n};\n\nCreateTableContext.prototype.tableProperties = function() {\n    return this.getTypedRuleContext(TablePropertiesContext,0);\n};\nCreateTableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCreateTable(this);\n\t}\n};\n\nCreateTableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCreateTable(this);\n\t}\n};\n\nCreateTableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCreateTable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction StartTransactionContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nStartTransactionContext.prototype = Object.create(StatementContext.prototype);\nStartTransactionContext.prototype.constructor = StartTransactionContext;\n\nSqlBaseParser.StartTransactionContext = StartTransactionContext;\n\nStartTransactionContext.prototype.START = function() {\n    return this.getToken(SqlBaseParser.START, 0);\n};\n\nStartTransactionContext.prototype.TRANSACTION = function() {\n    return this.getToken(SqlBaseParser.TRANSACTION, 0);\n};\n\nStartTransactionContext.prototype.transactionMode = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TransactionModeContext);\n    } else {\n        return this.getTypedRuleContext(TransactionModeContext,i);\n    }\n};\nStartTransactionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterStartTransaction(this);\n\t}\n};\n\nStartTransactionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitStartTransaction(this);\n\t}\n};\n\nStartTransactionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitStartTransaction(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CreateTableAsSelectContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCreateTableAsSelectContext.prototype = Object.create(StatementContext.prototype);\nCreateTableAsSelectContext.prototype.constructor = CreateTableAsSelectContext;\n\nSqlBaseParser.CreateTableAsSelectContext = CreateTableAsSelectContext;\n\nCreateTableAsSelectContext.prototype.CREATE = function() {\n    return this.getToken(SqlBaseParser.CREATE, 0);\n};\n\nCreateTableAsSelectContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nCreateTableAsSelectContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nCreateTableAsSelectContext.prototype.AS = function() {\n    return this.getToken(SqlBaseParser.AS, 0);\n};\n\nCreateTableAsSelectContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\n\nCreateTableAsSelectContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nCreateTableAsSelectContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\n\nCreateTableAsSelectContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\n\nCreateTableAsSelectContext.prototype.WITH = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(SqlBaseParser.WITH);\n    } else {\n        return this.getToken(SqlBaseParser.WITH, i);\n    }\n};\n\n\nCreateTableAsSelectContext.prototype.tableProperties = function() {\n    return this.getTypedRuleContext(TablePropertiesContext,0);\n};\n\nCreateTableAsSelectContext.prototype.DATA = function() {\n    return this.getToken(SqlBaseParser.DATA, 0);\n};\n\nCreateTableAsSelectContext.prototype.NO = function() {\n    return this.getToken(SqlBaseParser.NO, 0);\n};\nCreateTableAsSelectContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCreateTableAsSelect(this);\n\t}\n};\n\nCreateTableAsSelectContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCreateTableAsSelect(this);\n\t}\n};\n\nCreateTableAsSelectContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCreateTableAsSelect(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction UseContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.schema = null; // IdentifierContext;\n    this.catalog = null; // IdentifierContext;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nUseContext.prototype = Object.create(StatementContext.prototype);\nUseContext.prototype.constructor = UseContext;\n\nSqlBaseParser.UseContext = UseContext;\n\nUseContext.prototype.USE = function() {\n    return this.getToken(SqlBaseParser.USE, 0);\n};\n\nUseContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\nUseContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterUse(this);\n\t}\n};\n\nUseContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitUse(this);\n\t}\n};\n\nUseContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitUse(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DeallocateContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDeallocateContext.prototype = Object.create(StatementContext.prototype);\nDeallocateContext.prototype.constructor = DeallocateContext;\n\nSqlBaseParser.DeallocateContext = DeallocateContext;\n\nDeallocateContext.prototype.DEALLOCATE = function() {\n    return this.getToken(SqlBaseParser.DEALLOCATE, 0);\n};\n\nDeallocateContext.prototype.PREPARE = function() {\n    return this.getToken(SqlBaseParser.PREPARE, 0);\n};\n\nDeallocateContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\nDeallocateContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDeallocate(this);\n\t}\n};\n\nDeallocateContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDeallocate(this);\n\t}\n};\n\nDeallocateContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDeallocate(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RenameTableContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.from = null; // QualifiedNameContext;\n    this.to = null; // QualifiedNameContext;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRenameTableContext.prototype = Object.create(StatementContext.prototype);\nRenameTableContext.prototype.constructor = RenameTableContext;\n\nSqlBaseParser.RenameTableContext = RenameTableContext;\n\nRenameTableContext.prototype.ALTER = function() {\n    return this.getToken(SqlBaseParser.ALTER, 0);\n};\n\nRenameTableContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nRenameTableContext.prototype.RENAME = function() {\n    return this.getToken(SqlBaseParser.RENAME, 0);\n};\n\nRenameTableContext.prototype.TO = function() {\n    return this.getToken(SqlBaseParser.TO, 0);\n};\n\nRenameTableContext.prototype.qualifiedName = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(QualifiedNameContext);\n    } else {\n        return this.getTypedRuleContext(QualifiedNameContext,i);\n    }\n};\nRenameTableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRenameTable(this);\n\t}\n};\n\nRenameTableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRenameTable(this);\n\t}\n};\n\nRenameTableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRenameTable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CommitContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCommitContext.prototype = Object.create(StatementContext.prototype);\nCommitContext.prototype.constructor = CommitContext;\n\nSqlBaseParser.CommitContext = CommitContext;\n\nCommitContext.prototype.COMMIT = function() {\n    return this.getToken(SqlBaseParser.COMMIT, 0);\n};\n\nCommitContext.prototype.WORK = function() {\n    return this.getToken(SqlBaseParser.WORK, 0);\n};\nCommitContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCommit(this);\n\t}\n};\n\nCommitContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCommit(this);\n\t}\n};\n\nCommitContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCommit(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RevokeContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.grantee = null; // IdentifierContext;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRevokeContext.prototype = Object.create(StatementContext.prototype);\nRevokeContext.prototype.constructor = RevokeContext;\n\nSqlBaseParser.RevokeContext = RevokeContext;\n\nRevokeContext.prototype.REVOKE = function() {\n    return this.getToken(SqlBaseParser.REVOKE, 0);\n};\n\nRevokeContext.prototype.ON = function() {\n    return this.getToken(SqlBaseParser.ON, 0);\n};\n\nRevokeContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nRevokeContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nRevokeContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nRevokeContext.prototype.privilege = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(PrivilegeContext);\n    } else {\n        return this.getTypedRuleContext(PrivilegeContext,i);\n    }\n};\n\nRevokeContext.prototype.ALL = function() {\n    return this.getToken(SqlBaseParser.ALL, 0);\n};\n\nRevokeContext.prototype.PRIVILEGES = function() {\n    return this.getToken(SqlBaseParser.PRIVILEGES, 0);\n};\n\nRevokeContext.prototype.GRANT = function() {\n    return this.getToken(SqlBaseParser.GRANT, 0);\n};\n\nRevokeContext.prototype.OPTION = function() {\n    return this.getToken(SqlBaseParser.OPTION, 0);\n};\n\nRevokeContext.prototype.FOR = function() {\n    return this.getToken(SqlBaseParser.FOR, 0);\n};\n\nRevokeContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\nRevokeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRevoke(this);\n\t}\n};\n\nRevokeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRevoke(this);\n\t}\n};\n\nRevokeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRevoke(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowPartitionsContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.limit = null; // Token;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowPartitionsContext.prototype = Object.create(StatementContext.prototype);\nShowPartitionsContext.prototype.constructor = ShowPartitionsContext;\n\nSqlBaseParser.ShowPartitionsContext = ShowPartitionsContext;\n\nShowPartitionsContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowPartitionsContext.prototype.PARTITIONS = function() {\n    return this.getToken(SqlBaseParser.PARTITIONS, 0);\n};\n\nShowPartitionsContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nShowPartitionsContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nShowPartitionsContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\n\nShowPartitionsContext.prototype.WHERE = function() {\n    return this.getToken(SqlBaseParser.WHERE, 0);\n};\n\nShowPartitionsContext.prototype.booleanExpression = function() {\n    return this.getTypedRuleContext(BooleanExpressionContext,0);\n};\n\nShowPartitionsContext.prototype.ORDER = function() {\n    return this.getToken(SqlBaseParser.ORDER, 0);\n};\n\nShowPartitionsContext.prototype.BY = function() {\n    return this.getToken(SqlBaseParser.BY, 0);\n};\n\nShowPartitionsContext.prototype.sortItem = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SortItemContext);\n    } else {\n        return this.getTypedRuleContext(SortItemContext,i);\n    }\n};\n\nShowPartitionsContext.prototype.LIMIT = function() {\n    return this.getToken(SqlBaseParser.LIMIT, 0);\n};\n\nShowPartitionsContext.prototype.INTEGER_VALUE = function() {\n    return this.getToken(SqlBaseParser.INTEGER_VALUE, 0);\n};\n\nShowPartitionsContext.prototype.ALL = function() {\n    return this.getToken(SqlBaseParser.ALL, 0);\n};\nShowPartitionsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowPartitions(this);\n\t}\n};\n\nShowPartitionsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowPartitions(this);\n\t}\n};\n\nShowPartitionsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowPartitions(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DropViewContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDropViewContext.prototype = Object.create(StatementContext.prototype);\nDropViewContext.prototype.constructor = DropViewContext;\n\nSqlBaseParser.DropViewContext = DropViewContext;\n\nDropViewContext.prototype.DROP = function() {\n    return this.getToken(SqlBaseParser.DROP, 0);\n};\n\nDropViewContext.prototype.VIEW = function() {\n    return this.getToken(SqlBaseParser.VIEW, 0);\n};\n\nDropViewContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nDropViewContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nDropViewContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\nDropViewContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDropView(this);\n\t}\n};\n\nDropViewContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDropView(this);\n\t}\n};\n\nDropViewContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDropView(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DeleteContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDeleteContext.prototype = Object.create(StatementContext.prototype);\nDeleteContext.prototype.constructor = DeleteContext;\n\nSqlBaseParser.DeleteContext = DeleteContext;\n\nDeleteContext.prototype.DELETE = function() {\n    return this.getToken(SqlBaseParser.DELETE, 0);\n};\n\nDeleteContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nDeleteContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nDeleteContext.prototype.WHERE = function() {\n    return this.getToken(SqlBaseParser.WHERE, 0);\n};\n\nDeleteContext.prototype.booleanExpression = function() {\n    return this.getTypedRuleContext(BooleanExpressionContext,0);\n};\nDeleteContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDelete(this);\n\t}\n};\n\nDeleteContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDelete(this);\n\t}\n};\n\nDeleteContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDelete(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowTablesContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.pattern = null; // Token;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowTablesContext.prototype = Object.create(StatementContext.prototype);\nShowTablesContext.prototype.constructor = ShowTablesContext;\n\nSqlBaseParser.ShowTablesContext = ShowTablesContext;\n\nShowTablesContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowTablesContext.prototype.TABLES = function() {\n    return this.getToken(SqlBaseParser.TABLES, 0);\n};\n\nShowTablesContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nShowTablesContext.prototype.LIKE = function() {\n    return this.getToken(SqlBaseParser.LIKE, 0);\n};\n\nShowTablesContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nShowTablesContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\n\nShowTablesContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\nShowTablesContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowTables(this);\n\t}\n};\n\nShowTablesContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowTables(this);\n\t}\n};\n\nShowTablesContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowTables(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DescribeInputContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDescribeInputContext.prototype = Object.create(StatementContext.prototype);\nDescribeInputContext.prototype.constructor = DescribeInputContext;\n\nSqlBaseParser.DescribeInputContext = DescribeInputContext;\n\nDescribeInputContext.prototype.DESCRIBE = function() {\n    return this.getToken(SqlBaseParser.DESCRIBE, 0);\n};\n\nDescribeInputContext.prototype.INPUT = function() {\n    return this.getToken(SqlBaseParser.INPUT, 0);\n};\n\nDescribeInputContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\nDescribeInputContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDescribeInput(this);\n\t}\n};\n\nDescribeInputContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDescribeInput(this);\n\t}\n};\n\nDescribeInputContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDescribeInput(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowCatalogsContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.pattern = null; // Token;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowCatalogsContext.prototype = Object.create(StatementContext.prototype);\nShowCatalogsContext.prototype.constructor = ShowCatalogsContext;\n\nSqlBaseParser.ShowCatalogsContext = ShowCatalogsContext;\n\nShowCatalogsContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowCatalogsContext.prototype.CATALOGS = function() {\n    return this.getToken(SqlBaseParser.CATALOGS, 0);\n};\n\nShowCatalogsContext.prototype.LIKE = function() {\n    return this.getToken(SqlBaseParser.LIKE, 0);\n};\n\nShowCatalogsContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\nShowCatalogsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowCatalogs(this);\n\t}\n};\n\nShowCatalogsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowCatalogs(this);\n\t}\n};\n\nShowCatalogsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowCatalogs(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction StatementDefaultContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nStatementDefaultContext.prototype = Object.create(StatementContext.prototype);\nStatementDefaultContext.prototype.constructor = StatementDefaultContext;\n\nSqlBaseParser.StatementDefaultContext = StatementDefaultContext;\n\nStatementDefaultContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\nStatementDefaultContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterStatementDefault(this);\n\t}\n};\n\nStatementDefaultContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitStatementDefault(this);\n\t}\n};\n\nStatementDefaultContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitStatementDefault(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RenameColumnContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.tableName = null; // QualifiedNameContext;\n    this.from = null; // IdentifierContext;\n    this.to = null; // IdentifierContext;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRenameColumnContext.prototype = Object.create(StatementContext.prototype);\nRenameColumnContext.prototype.constructor = RenameColumnContext;\n\nSqlBaseParser.RenameColumnContext = RenameColumnContext;\n\nRenameColumnContext.prototype.ALTER = function() {\n    return this.getToken(SqlBaseParser.ALTER, 0);\n};\n\nRenameColumnContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nRenameColumnContext.prototype.RENAME = function() {\n    return this.getToken(SqlBaseParser.RENAME, 0);\n};\n\nRenameColumnContext.prototype.COLUMN = function() {\n    return this.getToken(SqlBaseParser.COLUMN, 0);\n};\n\nRenameColumnContext.prototype.TO = function() {\n    return this.getToken(SqlBaseParser.TO, 0);\n};\n\nRenameColumnContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nRenameColumnContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\nRenameColumnContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRenameColumn(this);\n\t}\n};\n\nRenameColumnContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRenameColumn(this);\n\t}\n};\n\nRenameColumnContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRenameColumn(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SetSessionContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSetSessionContext.prototype = Object.create(StatementContext.prototype);\nSetSessionContext.prototype.constructor = SetSessionContext;\n\nSqlBaseParser.SetSessionContext = SetSessionContext;\n\nSetSessionContext.prototype.SET = function() {\n    return this.getToken(SqlBaseParser.SET, 0);\n};\n\nSetSessionContext.prototype.SESSION = function() {\n    return this.getToken(SqlBaseParser.SESSION, 0);\n};\n\nSetSessionContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nSetSessionContext.prototype.EQ = function() {\n    return this.getToken(SqlBaseParser.EQ, 0);\n};\n\nSetSessionContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\nSetSessionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSetSession(this);\n\t}\n};\n\nSetSessionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSetSession(this);\n\t}\n};\n\nSetSessionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSetSession(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CreateViewContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCreateViewContext.prototype = Object.create(StatementContext.prototype);\nCreateViewContext.prototype.constructor = CreateViewContext;\n\nSqlBaseParser.CreateViewContext = CreateViewContext;\n\nCreateViewContext.prototype.CREATE = function() {\n    return this.getToken(SqlBaseParser.CREATE, 0);\n};\n\nCreateViewContext.prototype.VIEW = function() {\n    return this.getToken(SqlBaseParser.VIEW, 0);\n};\n\nCreateViewContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nCreateViewContext.prototype.AS = function() {\n    return this.getToken(SqlBaseParser.AS, 0);\n};\n\nCreateViewContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\n\nCreateViewContext.prototype.OR = function() {\n    return this.getToken(SqlBaseParser.OR, 0);\n};\n\nCreateViewContext.prototype.REPLACE = function() {\n    return this.getToken(SqlBaseParser.REPLACE, 0);\n};\nCreateViewContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCreateView(this);\n\t}\n};\n\nCreateViewContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCreateView(this);\n\t}\n};\n\nCreateViewContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCreateView(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowCreateTableContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowCreateTableContext.prototype = Object.create(StatementContext.prototype);\nShowCreateTableContext.prototype.constructor = ShowCreateTableContext;\n\nSqlBaseParser.ShowCreateTableContext = ShowCreateTableContext;\n\nShowCreateTableContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowCreateTableContext.prototype.CREATE = function() {\n    return this.getToken(SqlBaseParser.CREATE, 0);\n};\n\nShowCreateTableContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nShowCreateTableContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\nShowCreateTableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowCreateTable(this);\n\t}\n};\n\nShowCreateTableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowCreateTable(this);\n\t}\n};\n\nShowCreateTableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowCreateTable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowSchemasContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.pattern = null; // Token;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowSchemasContext.prototype = Object.create(StatementContext.prototype);\nShowSchemasContext.prototype.constructor = ShowSchemasContext;\n\nSqlBaseParser.ShowSchemasContext = ShowSchemasContext;\n\nShowSchemasContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowSchemasContext.prototype.SCHEMAS = function() {\n    return this.getToken(SqlBaseParser.SCHEMAS, 0);\n};\n\nShowSchemasContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nShowSchemasContext.prototype.LIKE = function() {\n    return this.getToken(SqlBaseParser.LIKE, 0);\n};\n\nShowSchemasContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nShowSchemasContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\n\nShowSchemasContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\nShowSchemasContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowSchemas(this);\n\t}\n};\n\nShowSchemasContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowSchemas(this);\n\t}\n};\n\nShowSchemasContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowSchemas(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DropTableContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDropTableContext.prototype = Object.create(StatementContext.prototype);\nDropTableContext.prototype.constructor = DropTableContext;\n\nSqlBaseParser.DropTableContext = DropTableContext;\n\nDropTableContext.prototype.DROP = function() {\n    return this.getToken(SqlBaseParser.DROP, 0);\n};\n\nDropTableContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nDropTableContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nDropTableContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nDropTableContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\nDropTableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDropTable(this);\n\t}\n};\n\nDropTableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDropTable(this);\n\t}\n};\n\nDropTableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDropTable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowColumnsContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowColumnsContext.prototype = Object.create(StatementContext.prototype);\nShowColumnsContext.prototype.constructor = ShowColumnsContext;\n\nSqlBaseParser.ShowColumnsContext = ShowColumnsContext;\n\nShowColumnsContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowColumnsContext.prototype.COLUMNS = function() {\n    return this.getToken(SqlBaseParser.COLUMNS, 0);\n};\n\nShowColumnsContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nShowColumnsContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nShowColumnsContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\n\nShowColumnsContext.prototype.DESCRIBE = function() {\n    return this.getToken(SqlBaseParser.DESCRIBE, 0);\n};\n\nShowColumnsContext.prototype.DESC = function() {\n    return this.getToken(SqlBaseParser.DESC, 0);\n};\nShowColumnsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowColumns(this);\n\t}\n};\n\nShowColumnsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowColumns(this);\n\t}\n};\n\nShowColumnsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowColumns(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RollbackContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRollbackContext.prototype = Object.create(StatementContext.prototype);\nRollbackContext.prototype.constructor = RollbackContext;\n\nSqlBaseParser.RollbackContext = RollbackContext;\n\nRollbackContext.prototype.ROLLBACK = function() {\n    return this.getToken(SqlBaseParser.ROLLBACK, 0);\n};\n\nRollbackContext.prototype.WORK = function() {\n    return this.getToken(SqlBaseParser.WORK, 0);\n};\nRollbackContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRollback(this);\n\t}\n};\n\nRollbackContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRollback(this);\n\t}\n};\n\nRollbackContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRollback(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction AddColumnContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.tableName = null; // QualifiedNameContext;\n    this.column = null; // ColumnDefinitionContext;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nAddColumnContext.prototype = Object.create(StatementContext.prototype);\nAddColumnContext.prototype.constructor = AddColumnContext;\n\nSqlBaseParser.AddColumnContext = AddColumnContext;\n\nAddColumnContext.prototype.ALTER = function() {\n    return this.getToken(SqlBaseParser.ALTER, 0);\n};\n\nAddColumnContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nAddColumnContext.prototype.ADD = function() {\n    return this.getToken(SqlBaseParser.ADD, 0);\n};\n\nAddColumnContext.prototype.COLUMN = function() {\n    return this.getToken(SqlBaseParser.COLUMN, 0);\n};\n\nAddColumnContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nAddColumnContext.prototype.columnDefinition = function() {\n    return this.getTypedRuleContext(ColumnDefinitionContext,0);\n};\nAddColumnContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterAddColumn(this);\n\t}\n};\n\nAddColumnContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitAddColumn(this);\n\t}\n};\n\nAddColumnContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitAddColumn(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ResetSessionContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nResetSessionContext.prototype = Object.create(StatementContext.prototype);\nResetSessionContext.prototype.constructor = ResetSessionContext;\n\nSqlBaseParser.ResetSessionContext = ResetSessionContext;\n\nResetSessionContext.prototype.RESET = function() {\n    return this.getToken(SqlBaseParser.RESET, 0);\n};\n\nResetSessionContext.prototype.SESSION = function() {\n    return this.getToken(SqlBaseParser.SESSION, 0);\n};\n\nResetSessionContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\nResetSessionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterResetSession(this);\n\t}\n};\n\nResetSessionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitResetSession(this);\n\t}\n};\n\nResetSessionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitResetSession(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction InsertIntoContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nInsertIntoContext.prototype = Object.create(StatementContext.prototype);\nInsertIntoContext.prototype.constructor = InsertIntoContext;\n\nSqlBaseParser.InsertIntoContext = InsertIntoContext;\n\nInsertIntoContext.prototype.INSERT = function() {\n    return this.getToken(SqlBaseParser.INSERT, 0);\n};\n\nInsertIntoContext.prototype.INTO = function() {\n    return this.getToken(SqlBaseParser.INTO, 0);\n};\n\nInsertIntoContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nInsertIntoContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\n\nInsertIntoContext.prototype.columnAliases = function() {\n    return this.getTypedRuleContext(ColumnAliasesContext,0);\n};\nInsertIntoContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterInsertInto(this);\n\t}\n};\n\nInsertIntoContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitInsertInto(this);\n\t}\n};\n\nInsertIntoContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitInsertInto(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowSessionContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowSessionContext.prototype = Object.create(StatementContext.prototype);\nShowSessionContext.prototype.constructor = ShowSessionContext;\n\nSqlBaseParser.ShowSessionContext = ShowSessionContext;\n\nShowSessionContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowSessionContext.prototype.SESSION = function() {\n    return this.getToken(SqlBaseParser.SESSION, 0);\n};\nShowSessionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowSession(this);\n\t}\n};\n\nShowSessionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowSession(this);\n\t}\n};\n\nShowSessionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowSession(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CreateSchemaContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCreateSchemaContext.prototype = Object.create(StatementContext.prototype);\nCreateSchemaContext.prototype.constructor = CreateSchemaContext;\n\nSqlBaseParser.CreateSchemaContext = CreateSchemaContext;\n\nCreateSchemaContext.prototype.CREATE = function() {\n    return this.getToken(SqlBaseParser.CREATE, 0);\n};\n\nCreateSchemaContext.prototype.SCHEMA = function() {\n    return this.getToken(SqlBaseParser.SCHEMA, 0);\n};\n\nCreateSchemaContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nCreateSchemaContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nCreateSchemaContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\n\nCreateSchemaContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\n\nCreateSchemaContext.prototype.WITH = function() {\n    return this.getToken(SqlBaseParser.WITH, 0);\n};\n\nCreateSchemaContext.prototype.tableProperties = function() {\n    return this.getTypedRuleContext(TablePropertiesContext,0);\n};\nCreateSchemaContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCreateSchema(this);\n\t}\n};\n\nCreateSchemaContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCreateSchema(this);\n\t}\n};\n\nCreateSchemaContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCreateSchema(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ExecuteContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nExecuteContext.prototype = Object.create(StatementContext.prototype);\nExecuteContext.prototype.constructor = ExecuteContext;\n\nSqlBaseParser.ExecuteContext = ExecuteContext;\n\nExecuteContext.prototype.EXECUTE = function() {\n    return this.getToken(SqlBaseParser.EXECUTE, 0);\n};\n\nExecuteContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nExecuteContext.prototype.USING = function() {\n    return this.getToken(SqlBaseParser.USING, 0);\n};\n\nExecuteContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\nExecuteContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExecute(this);\n\t}\n};\n\nExecuteContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExecute(this);\n\t}\n};\n\nExecuteContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExecute(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CallContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCallContext.prototype = Object.create(StatementContext.prototype);\nCallContext.prototype.constructor = CallContext;\n\nSqlBaseParser.CallContext = CallContext;\n\nCallContext.prototype.CALL = function() {\n    return this.getToken(SqlBaseParser.CALL, 0);\n};\n\nCallContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nCallContext.prototype.callArgument = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(CallArgumentContext);\n    } else {\n        return this.getTypedRuleContext(CallArgumentContext,i);\n    }\n};\nCallContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCall(this);\n\t}\n};\n\nCallContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCall(this);\n\t}\n};\n\nCallContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCall(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RenameSchemaContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRenameSchemaContext.prototype = Object.create(StatementContext.prototype);\nRenameSchemaContext.prototype.constructor = RenameSchemaContext;\n\nSqlBaseParser.RenameSchemaContext = RenameSchemaContext;\n\nRenameSchemaContext.prototype.ALTER = function() {\n    return this.getToken(SqlBaseParser.ALTER, 0);\n};\n\nRenameSchemaContext.prototype.SCHEMA = function() {\n    return this.getToken(SqlBaseParser.SCHEMA, 0);\n};\n\nRenameSchemaContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nRenameSchemaContext.prototype.RENAME = function() {\n    return this.getToken(SqlBaseParser.RENAME, 0);\n};\n\nRenameSchemaContext.prototype.TO = function() {\n    return this.getToken(SqlBaseParser.TO, 0);\n};\n\nRenameSchemaContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\nRenameSchemaContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRenameSchema(this);\n\t}\n};\n\nRenameSchemaContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRenameSchema(this);\n\t}\n};\n\nRenameSchemaContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRenameSchema(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowFunctionsContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowFunctionsContext.prototype = Object.create(StatementContext.prototype);\nShowFunctionsContext.prototype.constructor = ShowFunctionsContext;\n\nSqlBaseParser.ShowFunctionsContext = ShowFunctionsContext;\n\nShowFunctionsContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowFunctionsContext.prototype.FUNCTIONS = function() {\n    return this.getToken(SqlBaseParser.FUNCTIONS, 0);\n};\nShowFunctionsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowFunctions(this);\n\t}\n};\n\nShowFunctionsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowFunctions(this);\n\t}\n};\n\nShowFunctionsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowFunctions(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DescribeOutputContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDescribeOutputContext.prototype = Object.create(StatementContext.prototype);\nDescribeOutputContext.prototype.constructor = DescribeOutputContext;\n\nSqlBaseParser.DescribeOutputContext = DescribeOutputContext;\n\nDescribeOutputContext.prototype.DESCRIBE = function() {\n    return this.getToken(SqlBaseParser.DESCRIBE, 0);\n};\n\nDescribeOutputContext.prototype.OUTPUT = function() {\n    return this.getToken(SqlBaseParser.OUTPUT, 0);\n};\n\nDescribeOutputContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\nDescribeOutputContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDescribeOutput(this);\n\t}\n};\n\nDescribeOutputContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDescribeOutput(this);\n\t}\n};\n\nDescribeOutputContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDescribeOutput(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DropSchemaContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDropSchemaContext.prototype = Object.create(StatementContext.prototype);\nDropSchemaContext.prototype.constructor = DropSchemaContext;\n\nSqlBaseParser.DropSchemaContext = DropSchemaContext;\n\nDropSchemaContext.prototype.DROP = function() {\n    return this.getToken(SqlBaseParser.DROP, 0);\n};\n\nDropSchemaContext.prototype.SCHEMA = function() {\n    return this.getToken(SqlBaseParser.SCHEMA, 0);\n};\n\nDropSchemaContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nDropSchemaContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nDropSchemaContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\n\nDropSchemaContext.prototype.CASCADE = function() {\n    return this.getToken(SqlBaseParser.CASCADE, 0);\n};\n\nDropSchemaContext.prototype.RESTRICT = function() {\n    return this.getToken(SqlBaseParser.RESTRICT, 0);\n};\nDropSchemaContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDropSchema(this);\n\t}\n};\n\nDropSchemaContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDropSchema(this);\n\t}\n};\n\nDropSchemaContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDropSchema(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction GrantContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    this.grantee = null; // IdentifierContext;\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nGrantContext.prototype = Object.create(StatementContext.prototype);\nGrantContext.prototype.constructor = GrantContext;\n\nSqlBaseParser.GrantContext = GrantContext;\n\nGrantContext.prototype.GRANT = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(SqlBaseParser.GRANT);\n    } else {\n        return this.getToken(SqlBaseParser.GRANT, i);\n    }\n};\n\n\nGrantContext.prototype.ON = function() {\n    return this.getToken(SqlBaseParser.ON, 0);\n};\n\nGrantContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nGrantContext.prototype.TO = function() {\n    return this.getToken(SqlBaseParser.TO, 0);\n};\n\nGrantContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nGrantContext.prototype.privilege = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(PrivilegeContext);\n    } else {\n        return this.getTypedRuleContext(PrivilegeContext,i);\n    }\n};\n\nGrantContext.prototype.ALL = function() {\n    return this.getToken(SqlBaseParser.ALL, 0);\n};\n\nGrantContext.prototype.PRIVILEGES = function() {\n    return this.getToken(SqlBaseParser.PRIVILEGES, 0);\n};\n\nGrantContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nGrantContext.prototype.WITH = function() {\n    return this.getToken(SqlBaseParser.WITH, 0);\n};\n\nGrantContext.prototype.OPTION = function() {\n    return this.getToken(SqlBaseParser.OPTION, 0);\n};\nGrantContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterGrant(this);\n\t}\n};\n\nGrantContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitGrant(this);\n\t}\n};\n\nGrantContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitGrant(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ShowCreateViewContext(parser, ctx) {\n\tStatementContext.call(this, parser);\n    StatementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nShowCreateViewContext.prototype = Object.create(StatementContext.prototype);\nShowCreateViewContext.prototype.constructor = ShowCreateViewContext;\n\nSqlBaseParser.ShowCreateViewContext = ShowCreateViewContext;\n\nShowCreateViewContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nShowCreateViewContext.prototype.CREATE = function() {\n    return this.getToken(SqlBaseParser.CREATE, 0);\n};\n\nShowCreateViewContext.prototype.VIEW = function() {\n    return this.getToken(SqlBaseParser.VIEW, 0);\n};\n\nShowCreateViewContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\nShowCreateViewContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterShowCreateView(this);\n\t}\n};\n\nShowCreateViewContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitShowCreateView(this);\n\t}\n};\n\nShowCreateViewContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitShowCreateView(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.StatementContext = StatementContext;\n\nSqlBaseParser.prototype.statement = function() {\n\n    var localctx = new StatementContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 6, SqlBaseParser.RULE_statement);\n    var _la = 0; // Token type\n    try {\n        this.state = 495;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,46,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new StatementDefaultContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 143;\n            this.query();\n            break;\n\n        case 2:\n            localctx = new UseContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 144;\n            this.match(SqlBaseParser.USE);\n            this.state = 145;\n            localctx.schema = this.identifier();\n            break;\n\n        case 3:\n            localctx = new UseContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 146;\n            this.match(SqlBaseParser.USE);\n            this.state = 147;\n            localctx.catalog = this.identifier();\n            this.state = 148;\n            this.match(SqlBaseParser.T__0);\n            this.state = 149;\n            localctx.schema = this.identifier();\n            break;\n\n        case 4:\n            localctx = new CreateSchemaContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 151;\n            this.match(SqlBaseParser.CREATE);\n            this.state = 152;\n            this.match(SqlBaseParser.SCHEMA);\n            this.state = 156;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,2,this._ctx);\n            if(la_===1) {\n                this.state = 153;\n                this.match(SqlBaseParser.IF);\n                this.state = 154;\n                this.match(SqlBaseParser.NOT);\n                this.state = 155;\n                this.match(SqlBaseParser.EXISTS);\n\n            }\n            this.state = 158;\n            this.qualifiedName();\n            this.state = 161;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WITH) {\n                this.state = 159;\n                this.match(SqlBaseParser.WITH);\n                this.state = 160;\n                this.tableProperties();\n            }\n\n            break;\n\n        case 5:\n            localctx = new DropSchemaContext(this, localctx);\n            this.enterOuterAlt(localctx, 5);\n            this.state = 163;\n            this.match(SqlBaseParser.DROP);\n            this.state = 164;\n            this.match(SqlBaseParser.SCHEMA);\n            this.state = 167;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,4,this._ctx);\n            if(la_===1) {\n                this.state = 165;\n                this.match(SqlBaseParser.IF);\n                this.state = 166;\n                this.match(SqlBaseParser.EXISTS);\n\n            }\n            this.state = 169;\n            this.qualifiedName();\n            this.state = 171;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.CASCADE || _la===SqlBaseParser.RESTRICT) {\n                this.state = 170;\n                _la = this._input.LA(1);\n                if(!(_la===SqlBaseParser.CASCADE || _la===SqlBaseParser.RESTRICT)) {\n                this._errHandler.recoverInline(this);\n                }\n                else {\n                \tthis._errHandler.reportMatch(this);\n                    this.consume();\n                }\n            }\n\n            break;\n\n        case 6:\n            localctx = new RenameSchemaContext(this, localctx);\n            this.enterOuterAlt(localctx, 6);\n            this.state = 173;\n            this.match(SqlBaseParser.ALTER);\n            this.state = 174;\n            this.match(SqlBaseParser.SCHEMA);\n            this.state = 175;\n            this.qualifiedName();\n            this.state = 176;\n            this.match(SqlBaseParser.RENAME);\n            this.state = 177;\n            this.match(SqlBaseParser.TO);\n            this.state = 178;\n            this.identifier();\n            break;\n\n        case 7:\n            localctx = new CreateTableAsSelectContext(this, localctx);\n            this.enterOuterAlt(localctx, 7);\n            this.state = 180;\n            this.match(SqlBaseParser.CREATE);\n            this.state = 181;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 185;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,6,this._ctx);\n            if(la_===1) {\n                this.state = 182;\n                this.match(SqlBaseParser.IF);\n                this.state = 183;\n                this.match(SqlBaseParser.NOT);\n                this.state = 184;\n                this.match(SqlBaseParser.EXISTS);\n\n            }\n            this.state = 187;\n            this.qualifiedName();\n            this.state = 190;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WITH) {\n                this.state = 188;\n                this.match(SqlBaseParser.WITH);\n                this.state = 189;\n                this.tableProperties();\n            }\n\n            this.state = 192;\n            this.match(SqlBaseParser.AS);\n            this.state = 193;\n            this.query();\n            this.state = 199;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WITH) {\n                this.state = 194;\n                this.match(SqlBaseParser.WITH);\n                this.state = 196;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                if(_la===SqlBaseParser.NO) {\n                    this.state = 195;\n                    this.match(SqlBaseParser.NO);\n                }\n\n                this.state = 198;\n                this.match(SqlBaseParser.DATA);\n            }\n\n            break;\n\n        case 8:\n            localctx = new CreateTableContext(this, localctx);\n            this.enterOuterAlt(localctx, 8);\n            this.state = 201;\n            this.match(SqlBaseParser.CREATE);\n            this.state = 202;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 206;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,10,this._ctx);\n            if(la_===1) {\n                this.state = 203;\n                this.match(SqlBaseParser.IF);\n                this.state = 204;\n                this.match(SqlBaseParser.NOT);\n                this.state = 205;\n                this.match(SqlBaseParser.EXISTS);\n\n            }\n            this.state = 208;\n            this.qualifiedName();\n            this.state = 209;\n            this.match(SqlBaseParser.T__1);\n            this.state = 210;\n            this.tableElement();\n            this.state = 215;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 211;\n                this.match(SqlBaseParser.T__2);\n                this.state = 212;\n                this.tableElement();\n                this.state = 217;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 218;\n            this.match(SqlBaseParser.T__3);\n            this.state = 221;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WITH) {\n                this.state = 219;\n                this.match(SqlBaseParser.WITH);\n                this.state = 220;\n                this.tableProperties();\n            }\n\n            break;\n\n        case 9:\n            localctx = new DropTableContext(this, localctx);\n            this.enterOuterAlt(localctx, 9);\n            this.state = 223;\n            this.match(SqlBaseParser.DROP);\n            this.state = 224;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 227;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,13,this._ctx);\n            if(la_===1) {\n                this.state = 225;\n                this.match(SqlBaseParser.IF);\n                this.state = 226;\n                this.match(SqlBaseParser.EXISTS);\n\n            }\n            this.state = 229;\n            this.qualifiedName();\n            break;\n\n        case 10:\n            localctx = new InsertIntoContext(this, localctx);\n            this.enterOuterAlt(localctx, 10);\n            this.state = 230;\n            this.match(SqlBaseParser.INSERT);\n            this.state = 231;\n            this.match(SqlBaseParser.INTO);\n            this.state = 232;\n            this.qualifiedName();\n            this.state = 234;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,14,this._ctx);\n            if(la_===1) {\n                this.state = 233;\n                this.columnAliases();\n\n            }\n            this.state = 236;\n            this.query();\n            break;\n\n        case 11:\n            localctx = new DeleteContext(this, localctx);\n            this.enterOuterAlt(localctx, 11);\n            this.state = 238;\n            this.match(SqlBaseParser.DELETE);\n            this.state = 239;\n            this.match(SqlBaseParser.FROM);\n            this.state = 240;\n            this.qualifiedName();\n            this.state = 243;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WHERE) {\n                this.state = 241;\n                this.match(SqlBaseParser.WHERE);\n                this.state = 242;\n                this.booleanExpression(0);\n            }\n\n            break;\n\n        case 12:\n            localctx = new RenameTableContext(this, localctx);\n            this.enterOuterAlt(localctx, 12);\n            this.state = 245;\n            this.match(SqlBaseParser.ALTER);\n            this.state = 246;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 247;\n            localctx.from = this.qualifiedName();\n            this.state = 248;\n            this.match(SqlBaseParser.RENAME);\n            this.state = 249;\n            this.match(SqlBaseParser.TO);\n            this.state = 250;\n            localctx.to = this.qualifiedName();\n            break;\n\n        case 13:\n            localctx = new RenameColumnContext(this, localctx);\n            this.enterOuterAlt(localctx, 13);\n            this.state = 252;\n            this.match(SqlBaseParser.ALTER);\n            this.state = 253;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 254;\n            localctx.tableName = this.qualifiedName();\n            this.state = 255;\n            this.match(SqlBaseParser.RENAME);\n            this.state = 256;\n            this.match(SqlBaseParser.COLUMN);\n            this.state = 257;\n            localctx.from = this.identifier();\n            this.state = 258;\n            this.match(SqlBaseParser.TO);\n            this.state = 259;\n            localctx.to = this.identifier();\n            break;\n\n        case 14:\n            localctx = new AddColumnContext(this, localctx);\n            this.enterOuterAlt(localctx, 14);\n            this.state = 261;\n            this.match(SqlBaseParser.ALTER);\n            this.state = 262;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 263;\n            localctx.tableName = this.qualifiedName();\n            this.state = 264;\n            this.match(SqlBaseParser.ADD);\n            this.state = 265;\n            this.match(SqlBaseParser.COLUMN);\n            this.state = 266;\n            localctx.column = this.columnDefinition();\n            break;\n\n        case 15:\n            localctx = new CreateViewContext(this, localctx);\n            this.enterOuterAlt(localctx, 15);\n            this.state = 268;\n            this.match(SqlBaseParser.CREATE);\n            this.state = 271;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.OR) {\n                this.state = 269;\n                this.match(SqlBaseParser.OR);\n                this.state = 270;\n                this.match(SqlBaseParser.REPLACE);\n            }\n\n            this.state = 273;\n            this.match(SqlBaseParser.VIEW);\n            this.state = 274;\n            this.qualifiedName();\n            this.state = 275;\n            this.match(SqlBaseParser.AS);\n            this.state = 276;\n            this.query();\n            break;\n\n        case 16:\n            localctx = new DropViewContext(this, localctx);\n            this.enterOuterAlt(localctx, 16);\n            this.state = 278;\n            this.match(SqlBaseParser.DROP);\n            this.state = 279;\n            this.match(SqlBaseParser.VIEW);\n            this.state = 282;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,17,this._ctx);\n            if(la_===1) {\n                this.state = 280;\n                this.match(SqlBaseParser.IF);\n                this.state = 281;\n                this.match(SqlBaseParser.EXISTS);\n\n            }\n            this.state = 284;\n            this.qualifiedName();\n            break;\n\n        case 17:\n            localctx = new CallContext(this, localctx);\n            this.enterOuterAlt(localctx, 17);\n            this.state = 285;\n            this.match(SqlBaseParser.CALL);\n            this.state = 286;\n            this.qualifiedName();\n            this.state = 287;\n            this.match(SqlBaseParser.T__1);\n            this.state = 296;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 288;\n                this.callArgument();\n                this.state = 293;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 289;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 290;\n                    this.callArgument();\n                    this.state = 295;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 298;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 18:\n            localctx = new GrantContext(this, localctx);\n            this.enterOuterAlt(localctx, 18);\n            this.state = 300;\n            this.match(SqlBaseParser.GRANT);\n            this.state = 311;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case SqlBaseParser.SELECT:\n            case SqlBaseParser.ADD:\n            case SqlBaseParser.NO:\n            case SqlBaseParser.SUBSTRING:\n            case SqlBaseParser.POSITION:\n            case SqlBaseParser.TINYINT:\n            case SqlBaseParser.SMALLINT:\n            case SqlBaseParser.INTEGER:\n            case SqlBaseParser.DATE:\n            case SqlBaseParser.TIME:\n            case SqlBaseParser.TIMESTAMP:\n            case SqlBaseParser.INTERVAL:\n            case SqlBaseParser.YEAR:\n            case SqlBaseParser.MONTH:\n            case SqlBaseParser.DAY:\n            case SqlBaseParser.HOUR:\n            case SqlBaseParser.MINUTE:\n            case SqlBaseParser.SECOND:\n            case SqlBaseParser.ZONE:\n            case SqlBaseParser.FILTER:\n            case SqlBaseParser.OVER:\n            case SqlBaseParser.PARTITION:\n            case SqlBaseParser.RANGE:\n            case SqlBaseParser.ROWS:\n            case SqlBaseParser.PRECEDING:\n            case SqlBaseParser.FOLLOWING:\n            case SqlBaseParser.CURRENT:\n            case SqlBaseParser.ROW:\n            case SqlBaseParser.SCHEMA:\n            case SqlBaseParser.VIEW:\n            case SqlBaseParser.REPLACE:\n            case SqlBaseParser.INSERT:\n            case SqlBaseParser.DELETE:\n            case SqlBaseParser.GRANT:\n            case SqlBaseParser.REVOKE:\n            case SqlBaseParser.PRIVILEGES:\n            case SqlBaseParser.PUBLIC:\n            case SqlBaseParser.OPTION:\n            case SqlBaseParser.EXPLAIN:\n            case SqlBaseParser.ANALYZE:\n            case SqlBaseParser.FORMAT:\n            case SqlBaseParser.TYPE:\n            case SqlBaseParser.TEXT:\n            case SqlBaseParser.GRAPHVIZ:\n            case SqlBaseParser.LOGICAL:\n            case SqlBaseParser.DISTRIBUTED:\n            case SqlBaseParser.SHOW:\n            case SqlBaseParser.TABLES:\n            case SqlBaseParser.SCHEMAS:\n            case SqlBaseParser.CATALOGS:\n            case SqlBaseParser.COLUMNS:\n            case SqlBaseParser.COLUMN:\n            case SqlBaseParser.USE:\n            case SqlBaseParser.PARTITIONS:\n            case SqlBaseParser.FUNCTIONS:\n            case SqlBaseParser.TO:\n            case SqlBaseParser.SYSTEM:\n            case SqlBaseParser.BERNOULLI:\n            case SqlBaseParser.POISSONIZED:\n            case SqlBaseParser.TABLESAMPLE:\n            case SqlBaseParser.ARRAY:\n            case SqlBaseParser.MAP:\n            case SqlBaseParser.SET:\n            case SqlBaseParser.RESET:\n            case SqlBaseParser.SESSION:\n            case SqlBaseParser.DATA:\n            case SqlBaseParser.START:\n            case SqlBaseParser.TRANSACTION:\n            case SqlBaseParser.COMMIT:\n            case SqlBaseParser.ROLLBACK:\n            case SqlBaseParser.WORK:\n            case SqlBaseParser.ISOLATION:\n            case SqlBaseParser.LEVEL:\n            case SqlBaseParser.SERIALIZABLE:\n            case SqlBaseParser.REPEATABLE:\n            case SqlBaseParser.COMMITTED:\n            case SqlBaseParser.UNCOMMITTED:\n            case SqlBaseParser.READ:\n            case SqlBaseParser.WRITE:\n            case SqlBaseParser.ONLY:\n            case SqlBaseParser.CALL:\n            case SqlBaseParser.INPUT:\n            case SqlBaseParser.OUTPUT:\n            case SqlBaseParser.CASCADE:\n            case SqlBaseParser.RESTRICT:\n            case SqlBaseParser.INCLUDING:\n            case SqlBaseParser.EXCLUDING:\n            case SqlBaseParser.PROPERTIES:\n            case SqlBaseParser.NFD:\n            case SqlBaseParser.NFC:\n            case SqlBaseParser.NFKD:\n            case SqlBaseParser.NFKC:\n            case SqlBaseParser.IF:\n            case SqlBaseParser.NULLIF:\n            case SqlBaseParser.COALESCE:\n            case SqlBaseParser.IDENTIFIER:\n            case SqlBaseParser.DIGIT_IDENTIFIER:\n            case SqlBaseParser.QUOTED_IDENTIFIER:\n            case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n                this.state = 301;\n                this.privilege();\n                this.state = 306;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 302;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 303;\n                    this.privilege();\n                    this.state = 308;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n                break;\n            case SqlBaseParser.ALL:\n                this.state = 309;\n                this.match(SqlBaseParser.ALL);\n                this.state = 310;\n                this.match(SqlBaseParser.PRIVILEGES);\n                break;\n            default:\n                throw new _error.NoViableAltException(this);\n            }\n            this.state = 313;\n            this.match(SqlBaseParser.ON);\n            this.state = 315;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.TABLE) {\n                this.state = 314;\n                this.match(SqlBaseParser.TABLE);\n            }\n\n            this.state = 317;\n            this.qualifiedName();\n            this.state = 318;\n            this.match(SqlBaseParser.TO);\n            this.state = 319;\n            localctx.grantee = this.identifier();\n            this.state = 323;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WITH) {\n                this.state = 320;\n                this.match(SqlBaseParser.WITH);\n                this.state = 321;\n                this.match(SqlBaseParser.GRANT);\n                this.state = 322;\n                this.match(SqlBaseParser.OPTION);\n            }\n\n            break;\n\n        case 19:\n            localctx = new RevokeContext(this, localctx);\n            this.enterOuterAlt(localctx, 19);\n            this.state = 325;\n            this.match(SqlBaseParser.REVOKE);\n            this.state = 329;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,24,this._ctx);\n            if(la_===1) {\n                this.state = 326;\n                this.match(SqlBaseParser.GRANT);\n                this.state = 327;\n                this.match(SqlBaseParser.OPTION);\n                this.state = 328;\n                this.match(SqlBaseParser.FOR);\n\n            }\n            this.state = 341;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case SqlBaseParser.SELECT:\n            case SqlBaseParser.ADD:\n            case SqlBaseParser.NO:\n            case SqlBaseParser.SUBSTRING:\n            case SqlBaseParser.POSITION:\n            case SqlBaseParser.TINYINT:\n            case SqlBaseParser.SMALLINT:\n            case SqlBaseParser.INTEGER:\n            case SqlBaseParser.DATE:\n            case SqlBaseParser.TIME:\n            case SqlBaseParser.TIMESTAMP:\n            case SqlBaseParser.INTERVAL:\n            case SqlBaseParser.YEAR:\n            case SqlBaseParser.MONTH:\n            case SqlBaseParser.DAY:\n            case SqlBaseParser.HOUR:\n            case SqlBaseParser.MINUTE:\n            case SqlBaseParser.SECOND:\n            case SqlBaseParser.ZONE:\n            case SqlBaseParser.FILTER:\n            case SqlBaseParser.OVER:\n            case SqlBaseParser.PARTITION:\n            case SqlBaseParser.RANGE:\n            case SqlBaseParser.ROWS:\n            case SqlBaseParser.PRECEDING:\n            case SqlBaseParser.FOLLOWING:\n            case SqlBaseParser.CURRENT:\n            case SqlBaseParser.ROW:\n            case SqlBaseParser.SCHEMA:\n            case SqlBaseParser.VIEW:\n            case SqlBaseParser.REPLACE:\n            case SqlBaseParser.INSERT:\n            case SqlBaseParser.DELETE:\n            case SqlBaseParser.GRANT:\n            case SqlBaseParser.REVOKE:\n            case SqlBaseParser.PRIVILEGES:\n            case SqlBaseParser.PUBLIC:\n            case SqlBaseParser.OPTION:\n            case SqlBaseParser.EXPLAIN:\n            case SqlBaseParser.ANALYZE:\n            case SqlBaseParser.FORMAT:\n            case SqlBaseParser.TYPE:\n            case SqlBaseParser.TEXT:\n            case SqlBaseParser.GRAPHVIZ:\n            case SqlBaseParser.LOGICAL:\n            case SqlBaseParser.DISTRIBUTED:\n            case SqlBaseParser.SHOW:\n            case SqlBaseParser.TABLES:\n            case SqlBaseParser.SCHEMAS:\n            case SqlBaseParser.CATALOGS:\n            case SqlBaseParser.COLUMNS:\n            case SqlBaseParser.COLUMN:\n            case SqlBaseParser.USE:\n            case SqlBaseParser.PARTITIONS:\n            case SqlBaseParser.FUNCTIONS:\n            case SqlBaseParser.TO:\n            case SqlBaseParser.SYSTEM:\n            case SqlBaseParser.BERNOULLI:\n            case SqlBaseParser.POISSONIZED:\n            case SqlBaseParser.TABLESAMPLE:\n            case SqlBaseParser.ARRAY:\n            case SqlBaseParser.MAP:\n            case SqlBaseParser.SET:\n            case SqlBaseParser.RESET:\n            case SqlBaseParser.SESSION:\n            case SqlBaseParser.DATA:\n            case SqlBaseParser.START:\n            case SqlBaseParser.TRANSACTION:\n            case SqlBaseParser.COMMIT:\n            case SqlBaseParser.ROLLBACK:\n            case SqlBaseParser.WORK:\n            case SqlBaseParser.ISOLATION:\n            case SqlBaseParser.LEVEL:\n            case SqlBaseParser.SERIALIZABLE:\n            case SqlBaseParser.REPEATABLE:\n            case SqlBaseParser.COMMITTED:\n            case SqlBaseParser.UNCOMMITTED:\n            case SqlBaseParser.READ:\n            case SqlBaseParser.WRITE:\n            case SqlBaseParser.ONLY:\n            case SqlBaseParser.CALL:\n            case SqlBaseParser.INPUT:\n            case SqlBaseParser.OUTPUT:\n            case SqlBaseParser.CASCADE:\n            case SqlBaseParser.RESTRICT:\n            case SqlBaseParser.INCLUDING:\n            case SqlBaseParser.EXCLUDING:\n            case SqlBaseParser.PROPERTIES:\n            case SqlBaseParser.NFD:\n            case SqlBaseParser.NFC:\n            case SqlBaseParser.NFKD:\n            case SqlBaseParser.NFKC:\n            case SqlBaseParser.IF:\n            case SqlBaseParser.NULLIF:\n            case SqlBaseParser.COALESCE:\n            case SqlBaseParser.IDENTIFIER:\n            case SqlBaseParser.DIGIT_IDENTIFIER:\n            case SqlBaseParser.QUOTED_IDENTIFIER:\n            case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n                this.state = 331;\n                this.privilege();\n                this.state = 336;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 332;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 333;\n                    this.privilege();\n                    this.state = 338;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n                break;\n            case SqlBaseParser.ALL:\n                this.state = 339;\n                this.match(SqlBaseParser.ALL);\n                this.state = 340;\n                this.match(SqlBaseParser.PRIVILEGES);\n                break;\n            default:\n                throw new _error.NoViableAltException(this);\n            }\n            this.state = 343;\n            this.match(SqlBaseParser.ON);\n            this.state = 345;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.TABLE) {\n                this.state = 344;\n                this.match(SqlBaseParser.TABLE);\n            }\n\n            this.state = 347;\n            this.qualifiedName();\n            this.state = 348;\n            this.match(SqlBaseParser.FROM);\n            this.state = 349;\n            localctx.grantee = this.identifier();\n            break;\n\n        case 20:\n            localctx = new ExplainContext(this, localctx);\n            this.enterOuterAlt(localctx, 20);\n            this.state = 351;\n            this.match(SqlBaseParser.EXPLAIN);\n            this.state = 353;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.ANALYZE) {\n                this.state = 352;\n                this.match(SqlBaseParser.ANALYZE);\n            }\n\n            this.state = 366;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,30,this._ctx);\n            if(la_===1) {\n                this.state = 355;\n                this.match(SqlBaseParser.T__1);\n                this.state = 356;\n                this.explainOption();\n                this.state = 361;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 357;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 358;\n                    this.explainOption();\n                    this.state = 363;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n                this.state = 364;\n                this.match(SqlBaseParser.T__3);\n\n            }\n            this.state = 368;\n            this.statement();\n            break;\n\n        case 21:\n            localctx = new ShowCreateTableContext(this, localctx);\n            this.enterOuterAlt(localctx, 21);\n            this.state = 369;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 370;\n            this.match(SqlBaseParser.CREATE);\n            this.state = 371;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 372;\n            this.qualifiedName();\n            break;\n\n        case 22:\n            localctx = new ShowCreateViewContext(this, localctx);\n            this.enterOuterAlt(localctx, 22);\n            this.state = 373;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 374;\n            this.match(SqlBaseParser.CREATE);\n            this.state = 375;\n            this.match(SqlBaseParser.VIEW);\n            this.state = 376;\n            this.qualifiedName();\n            break;\n\n        case 23:\n            localctx = new ShowTablesContext(this, localctx);\n            this.enterOuterAlt(localctx, 23);\n            this.state = 377;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 378;\n            this.match(SqlBaseParser.TABLES);\n            this.state = 381;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN) {\n                this.state = 379;\n                _la = this._input.LA(1);\n                if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) {\n                this._errHandler.recoverInline(this);\n                }\n                else {\n                \tthis._errHandler.reportMatch(this);\n                    this.consume();\n                }\n                this.state = 380;\n                this.qualifiedName();\n            }\n\n            this.state = 385;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.LIKE) {\n                this.state = 383;\n                this.match(SqlBaseParser.LIKE);\n                this.state = 384;\n                localctx.pattern = this.match(SqlBaseParser.STRING);\n            }\n\n            break;\n\n        case 24:\n            localctx = new ShowSchemasContext(this, localctx);\n            this.enterOuterAlt(localctx, 24);\n            this.state = 387;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 388;\n            this.match(SqlBaseParser.SCHEMAS);\n            this.state = 391;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN) {\n                this.state = 389;\n                _la = this._input.LA(1);\n                if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) {\n                this._errHandler.recoverInline(this);\n                }\n                else {\n                \tthis._errHandler.reportMatch(this);\n                    this.consume();\n                }\n                this.state = 390;\n                this.identifier();\n            }\n\n            this.state = 395;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.LIKE) {\n                this.state = 393;\n                this.match(SqlBaseParser.LIKE);\n                this.state = 394;\n                localctx.pattern = this.match(SqlBaseParser.STRING);\n            }\n\n            break;\n\n        case 25:\n            localctx = new ShowCatalogsContext(this, localctx);\n            this.enterOuterAlt(localctx, 25);\n            this.state = 397;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 398;\n            this.match(SqlBaseParser.CATALOGS);\n            this.state = 401;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.LIKE) {\n                this.state = 399;\n                this.match(SqlBaseParser.LIKE);\n                this.state = 400;\n                localctx.pattern = this.match(SqlBaseParser.STRING);\n            }\n\n            break;\n\n        case 26:\n            localctx = new ShowColumnsContext(this, localctx);\n            this.enterOuterAlt(localctx, 26);\n            this.state = 403;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 404;\n            this.match(SqlBaseParser.COLUMNS);\n            this.state = 405;\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) {\n            this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            this.state = 406;\n            this.qualifiedName();\n            break;\n\n        case 27:\n            localctx = new ShowColumnsContext(this, localctx);\n            this.enterOuterAlt(localctx, 27);\n            this.state = 407;\n            this.match(SqlBaseParser.DESCRIBE);\n            this.state = 408;\n            this.qualifiedName();\n            break;\n\n        case 28:\n            localctx = new ShowColumnsContext(this, localctx);\n            this.enterOuterAlt(localctx, 28);\n            this.state = 409;\n            this.match(SqlBaseParser.DESC);\n            this.state = 410;\n            this.qualifiedName();\n            break;\n\n        case 29:\n            localctx = new ShowFunctionsContext(this, localctx);\n            this.enterOuterAlt(localctx, 29);\n            this.state = 411;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 412;\n            this.match(SqlBaseParser.FUNCTIONS);\n            break;\n\n        case 30:\n            localctx = new ShowSessionContext(this, localctx);\n            this.enterOuterAlt(localctx, 30);\n            this.state = 413;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 414;\n            this.match(SqlBaseParser.SESSION);\n            break;\n\n        case 31:\n            localctx = new SetSessionContext(this, localctx);\n            this.enterOuterAlt(localctx, 31);\n            this.state = 415;\n            this.match(SqlBaseParser.SET);\n            this.state = 416;\n            this.match(SqlBaseParser.SESSION);\n            this.state = 417;\n            this.qualifiedName();\n            this.state = 418;\n            this.match(SqlBaseParser.EQ);\n            this.state = 419;\n            this.expression();\n            break;\n\n        case 32:\n            localctx = new ResetSessionContext(this, localctx);\n            this.enterOuterAlt(localctx, 32);\n            this.state = 421;\n            this.match(SqlBaseParser.RESET);\n            this.state = 422;\n            this.match(SqlBaseParser.SESSION);\n            this.state = 423;\n            this.qualifiedName();\n            break;\n\n        case 33:\n            localctx = new StartTransactionContext(this, localctx);\n            this.enterOuterAlt(localctx, 33);\n            this.state = 424;\n            this.match(SqlBaseParser.START);\n            this.state = 425;\n            this.match(SqlBaseParser.TRANSACTION);\n            this.state = 434;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.ISOLATION || _la===SqlBaseParser.READ) {\n                this.state = 426;\n                this.transactionMode();\n                this.state = 431;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 427;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 428;\n                    this.transactionMode();\n                    this.state = 433;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            break;\n\n        case 34:\n            localctx = new CommitContext(this, localctx);\n            this.enterOuterAlt(localctx, 34);\n            this.state = 436;\n            this.match(SqlBaseParser.COMMIT);\n            this.state = 438;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WORK) {\n                this.state = 437;\n                this.match(SqlBaseParser.WORK);\n            }\n\n            break;\n\n        case 35:\n            localctx = new RollbackContext(this, localctx);\n            this.enterOuterAlt(localctx, 35);\n            this.state = 440;\n            this.match(SqlBaseParser.ROLLBACK);\n            this.state = 442;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WORK) {\n                this.state = 441;\n                this.match(SqlBaseParser.WORK);\n            }\n\n            break;\n\n        case 36:\n            localctx = new ShowPartitionsContext(this, localctx);\n            this.enterOuterAlt(localctx, 36);\n            this.state = 444;\n            this.match(SqlBaseParser.SHOW);\n            this.state = 445;\n            this.match(SqlBaseParser.PARTITIONS);\n            this.state = 446;\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.FROM || _la===SqlBaseParser.IN)) {\n            this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            this.state = 447;\n            this.qualifiedName();\n            this.state = 450;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.WHERE) {\n                this.state = 448;\n                this.match(SqlBaseParser.WHERE);\n                this.state = 449;\n                this.booleanExpression(0);\n            }\n\n            this.state = 462;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.ORDER) {\n                this.state = 452;\n                this.match(SqlBaseParser.ORDER);\n                this.state = 453;\n                this.match(SqlBaseParser.BY);\n                this.state = 454;\n                this.sortItem();\n                this.state = 459;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 455;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 456;\n                    this.sortItem();\n                    this.state = 461;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 466;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.LIMIT) {\n                this.state = 464;\n                this.match(SqlBaseParser.LIMIT);\n                this.state = 465;\n                localctx.limit = this._input.LT(1);\n                _la = this._input.LA(1);\n                if(!(_la===SqlBaseParser.ALL || _la===SqlBaseParser.INTEGER_VALUE)) {\n                    localctx.limit = this._errHandler.recoverInline(this);\n                }\n                else {\n                \tthis._errHandler.reportMatch(this);\n                    this.consume();\n                }\n            }\n\n            break;\n\n        case 37:\n            localctx = new PrepareContext(this, localctx);\n            this.enterOuterAlt(localctx, 37);\n            this.state = 468;\n            this.match(SqlBaseParser.PREPARE);\n            this.state = 469;\n            this.identifier();\n            this.state = 470;\n            this.match(SqlBaseParser.FROM);\n            this.state = 471;\n            this.statement();\n            break;\n\n        case 38:\n            localctx = new DeallocateContext(this, localctx);\n            this.enterOuterAlt(localctx, 38);\n            this.state = 473;\n            this.match(SqlBaseParser.DEALLOCATE);\n            this.state = 474;\n            this.match(SqlBaseParser.PREPARE);\n            this.state = 475;\n            this.identifier();\n            break;\n\n        case 39:\n            localctx = new ExecuteContext(this, localctx);\n            this.enterOuterAlt(localctx, 39);\n            this.state = 476;\n            this.match(SqlBaseParser.EXECUTE);\n            this.state = 477;\n            this.identifier();\n            this.state = 487;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.USING) {\n                this.state = 478;\n                this.match(SqlBaseParser.USING);\n                this.state = 479;\n                this.expression();\n                this.state = 484;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 480;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 481;\n                    this.expression();\n                    this.state = 486;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            break;\n\n        case 40:\n            localctx = new DescribeInputContext(this, localctx);\n            this.enterOuterAlt(localctx, 40);\n            this.state = 489;\n            this.match(SqlBaseParser.DESCRIBE);\n            this.state = 490;\n            this.match(SqlBaseParser.INPUT);\n            this.state = 491;\n            this.identifier();\n            break;\n\n        case 41:\n            localctx = new DescribeOutputContext(this, localctx);\n            this.enterOuterAlt(localctx, 41);\n            this.state = 492;\n            this.match(SqlBaseParser.DESCRIBE);\n            this.state = 493;\n            this.match(SqlBaseParser.OUTPUT);\n            this.state = 494;\n            this.identifier();\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction QueryContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_query;\n    // return this;\n}\n\nQueryContext.prototype = Object.create(ParserRuleContext.prototype);\nQueryContext.prototype.constructor = QueryContext;\n\nQueryContext.prototype.queryNoWith = function() {\n    return this.getTypedRuleContext(QueryNoWithContext,0);\n};\n\nQueryContext.prototype.presto_with = function() {\n    return this.getTypedRuleContext(Presto_withContext,0);\n};\n\nQueryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQuery(this);\n\t}\n};\n\nQueryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQuery(this);\n\t}\n};\n\nQueryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQuery(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.QueryContext = QueryContext;\n\nSqlBaseParser.prototype.query = function() {\n\n    var localctx = new QueryContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 8, SqlBaseParser.RULE_query);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 498;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.WITH) {\n            this.state = 497;\n            this.presto_with();\n        }\n\n        this.state = 500;\n        this.queryNoWith();\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Presto_withContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_presto_with;\n    // return this;\n}\n\nPresto_withContext.prototype = Object.create(ParserRuleContext.prototype);\nPresto_withContext.prototype.constructor = Presto_withContext;\n\nPresto_withContext.prototype.WITH = function() {\n    return this.getToken(SqlBaseParser.WITH, 0);\n};\n\nPresto_withContext.prototype.namedQuery = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(NamedQueryContext);\n    } else {\n        return this.getTypedRuleContext(NamedQueryContext,i);\n    }\n};\n\nPresto_withContext.prototype.RECURSIVE = function() {\n    return this.getToken(SqlBaseParser.RECURSIVE, 0);\n};\n\nPresto_withContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterPresto_with(this);\n\t}\n};\n\nPresto_withContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitPresto_with(this);\n\t}\n};\n\nPresto_withContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitPresto_with(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.Presto_withContext = Presto_withContext;\n\nSqlBaseParser.prototype.presto_with = function() {\n\n    var localctx = new Presto_withContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 10, SqlBaseParser.RULE_presto_with);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 502;\n        this.match(SqlBaseParser.WITH);\n        this.state = 504;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.RECURSIVE) {\n            this.state = 503;\n            this.match(SqlBaseParser.RECURSIVE);\n        }\n\n        this.state = 506;\n        this.namedQuery();\n        this.state = 511;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===SqlBaseParser.T__2) {\n            this.state = 507;\n            this.match(SqlBaseParser.T__2);\n            this.state = 508;\n            this.namedQuery();\n            this.state = 513;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TableElementContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_tableElement;\n    // return this;\n}\n\nTableElementContext.prototype = Object.create(ParserRuleContext.prototype);\nTableElementContext.prototype.constructor = TableElementContext;\n\nTableElementContext.prototype.columnDefinition = function() {\n    return this.getTypedRuleContext(ColumnDefinitionContext,0);\n};\n\nTableElementContext.prototype.likeClause = function() {\n    return this.getTypedRuleContext(LikeClauseContext,0);\n};\n\nTableElementContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTableElement(this);\n\t}\n};\n\nTableElementContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTableElement(this);\n\t}\n};\n\nTableElementContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTableElement(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.TableElementContext = TableElementContext;\n\nSqlBaseParser.prototype.tableElement = function() {\n\n    var localctx = new TableElementContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 12, SqlBaseParser.RULE_tableElement);\n    try {\n        this.state = 516;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 514;\n            this.columnDefinition();\n            break;\n        case SqlBaseParser.LIKE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 515;\n            this.likeClause();\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ColumnDefinitionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_columnDefinition;\n    // return this;\n}\n\nColumnDefinitionContext.prototype = Object.create(ParserRuleContext.prototype);\nColumnDefinitionContext.prototype.constructor = ColumnDefinitionContext;\n\nColumnDefinitionContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nColumnDefinitionContext.prototype.type = function() {\n    return this.getTypedRuleContext(TypeContext,0);\n};\n\nColumnDefinitionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterColumnDefinition(this);\n\t}\n};\n\nColumnDefinitionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitColumnDefinition(this);\n\t}\n};\n\nColumnDefinitionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitColumnDefinition(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.ColumnDefinitionContext = ColumnDefinitionContext;\n\nSqlBaseParser.prototype.columnDefinition = function() {\n\n    var localctx = new ColumnDefinitionContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 14, SqlBaseParser.RULE_columnDefinition);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 518;\n        this.identifier();\n        this.state = 519;\n        this.type(0);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction LikeClauseContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_likeClause;\n    this.optionType = null; // Token\n    // return this;\n}\n\nLikeClauseContext.prototype = Object.create(ParserRuleContext.prototype);\nLikeClauseContext.prototype.constructor = LikeClauseContext;\n\nLikeClauseContext.prototype.LIKE = function() {\n    return this.getToken(SqlBaseParser.LIKE, 0);\n};\n\nLikeClauseContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nLikeClauseContext.prototype.PROPERTIES = function() {\n    return this.getToken(SqlBaseParser.PROPERTIES, 0);\n};\n\nLikeClauseContext.prototype.INCLUDING = function() {\n    return this.getToken(SqlBaseParser.INCLUDING, 0);\n};\n\nLikeClauseContext.prototype.EXCLUDING = function() {\n    return this.getToken(SqlBaseParser.EXCLUDING, 0);\n};\n\nLikeClauseContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterLikeClause(this);\n\t}\n};\n\nLikeClauseContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitLikeClause(this);\n\t}\n};\n\nLikeClauseContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitLikeClause(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.LikeClauseContext = LikeClauseContext;\n\nSqlBaseParser.prototype.likeClause = function() {\n\n    var localctx = new LikeClauseContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 16, SqlBaseParser.RULE_likeClause);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 521;\n        this.match(SqlBaseParser.LIKE);\n        this.state = 522;\n        this.qualifiedName();\n        this.state = 525;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.INCLUDING || _la===SqlBaseParser.EXCLUDING) {\n            this.state = 523;\n            localctx.optionType = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.INCLUDING || _la===SqlBaseParser.EXCLUDING)) {\n                localctx.optionType = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            this.state = 524;\n            this.match(SqlBaseParser.PROPERTIES);\n        }\n\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TablePropertiesContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_tableProperties;\n    // return this;\n}\n\nTablePropertiesContext.prototype = Object.create(ParserRuleContext.prototype);\nTablePropertiesContext.prototype.constructor = TablePropertiesContext;\n\nTablePropertiesContext.prototype.tableProperty = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TablePropertyContext);\n    } else {\n        return this.getTypedRuleContext(TablePropertyContext,i);\n    }\n};\n\nTablePropertiesContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTableProperties(this);\n\t}\n};\n\nTablePropertiesContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTableProperties(this);\n\t}\n};\n\nTablePropertiesContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTableProperties(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.TablePropertiesContext = TablePropertiesContext;\n\nSqlBaseParser.prototype.tableProperties = function() {\n\n    var localctx = new TablePropertiesContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 18, SqlBaseParser.RULE_tableProperties);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 527;\n        this.match(SqlBaseParser.T__1);\n        this.state = 528;\n        this.tableProperty();\n        this.state = 533;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===SqlBaseParser.T__2) {\n            this.state = 529;\n            this.match(SqlBaseParser.T__2);\n            this.state = 530;\n            this.tableProperty();\n            this.state = 535;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 536;\n        this.match(SqlBaseParser.T__3);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TablePropertyContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_tableProperty;\n    // return this;\n}\n\nTablePropertyContext.prototype = Object.create(ParserRuleContext.prototype);\nTablePropertyContext.prototype.constructor = TablePropertyContext;\n\nTablePropertyContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nTablePropertyContext.prototype.EQ = function() {\n    return this.getToken(SqlBaseParser.EQ, 0);\n};\n\nTablePropertyContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nTablePropertyContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTableProperty(this);\n\t}\n};\n\nTablePropertyContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTableProperty(this);\n\t}\n};\n\nTablePropertyContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTableProperty(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.TablePropertyContext = TablePropertyContext;\n\nSqlBaseParser.prototype.tableProperty = function() {\n\n    var localctx = new TablePropertyContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 20, SqlBaseParser.RULE_tableProperty);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 538;\n        this.identifier();\n        this.state = 539;\n        this.match(SqlBaseParser.EQ);\n        this.state = 540;\n        this.expression();\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction QueryNoWithContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_queryNoWith;\n    this.limit = null; // Token\n    // return this;\n}\n\nQueryNoWithContext.prototype = Object.create(ParserRuleContext.prototype);\nQueryNoWithContext.prototype.constructor = QueryNoWithContext;\n\nQueryNoWithContext.prototype.queryTerm = function() {\n    return this.getTypedRuleContext(QueryTermContext,0);\n};\n\nQueryNoWithContext.prototype.ORDER = function() {\n    return this.getToken(SqlBaseParser.ORDER, 0);\n};\n\nQueryNoWithContext.prototype.BY = function() {\n    return this.getToken(SqlBaseParser.BY, 0);\n};\n\nQueryNoWithContext.prototype.sortItem = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SortItemContext);\n    } else {\n        return this.getTypedRuleContext(SortItemContext,i);\n    }\n};\n\nQueryNoWithContext.prototype.LIMIT = function() {\n    return this.getToken(SqlBaseParser.LIMIT, 0);\n};\n\nQueryNoWithContext.prototype.INTEGER_VALUE = function() {\n    return this.getToken(SqlBaseParser.INTEGER_VALUE, 0);\n};\n\nQueryNoWithContext.prototype.ALL = function() {\n    return this.getToken(SqlBaseParser.ALL, 0);\n};\n\nQueryNoWithContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQueryNoWith(this);\n\t}\n};\n\nQueryNoWithContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQueryNoWith(this);\n\t}\n};\n\nQueryNoWithContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQueryNoWith(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.QueryNoWithContext = QueryNoWithContext;\n\nSqlBaseParser.prototype.queryNoWith = function() {\n\n    var localctx = new QueryNoWithContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 22, SqlBaseParser.RULE_queryNoWith);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 542;\n        this.queryTerm(0);\n        this.state = 553;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.ORDER) {\n            this.state = 543;\n            this.match(SqlBaseParser.ORDER);\n            this.state = 544;\n            this.match(SqlBaseParser.BY);\n            this.state = 545;\n            this.sortItem();\n            this.state = 550;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 546;\n                this.match(SqlBaseParser.T__2);\n                this.state = 547;\n                this.sortItem();\n                this.state = 552;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n        }\n\n        this.state = 557;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.LIMIT) {\n            this.state = 555;\n            this.match(SqlBaseParser.LIMIT);\n            this.state = 556;\n            localctx.limit = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.ALL || _la===SqlBaseParser.INTEGER_VALUE)) {\n                localctx.limit = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n        }\n\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction QueryTermContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_queryTerm;\n    //return this;\n}\n\nQueryTermContext.prototype = Object.create(ParserRuleContext.prototype);\nQueryTermContext.prototype.constructor = QueryTermContext;\n\n\n \nQueryTermContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\nfunction QueryTermDefaultContext(parser, ctx) {\n\tQueryTermContext.call(this, parser);\n    QueryTermContext.prototype.copyFrom.call(this, ctx);\n    //return this;\n}\n\nQueryTermDefaultContext.prototype = Object.create(QueryTermContext.prototype);\nQueryTermDefaultContext.prototype.constructor = QueryTermDefaultContext;\n\nSqlBaseParser.QueryTermDefaultContext = QueryTermDefaultContext;\n\nQueryTermDefaultContext.prototype.queryPrimary = function() {\n    return this.getTypedRuleContext(QueryPrimaryContext,0);\n};\nQueryTermDefaultContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQueryTermDefault(this);\n\t}\n};\n\nQueryTermDefaultContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQueryTermDefault(this);\n\t}\n};\n\nQueryTermDefaultContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQueryTermDefault(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SetOperationContext(parser, ctx) {\n\tQueryTermContext.call(this, parser);\n    this.left = null; // QueryTermContext;\n    this.operator = null; // Token;\n    this.right = null; // QueryTermContext;\n    QueryTermContext.prototype.copyFrom.call(this, ctx);\n    //return this;\n}\n\nSetOperationContext.prototype = Object.create(QueryTermContext.prototype);\nSetOperationContext.prototype.constructor = SetOperationContext;\n\nSqlBaseParser.SetOperationContext = SetOperationContext;\n\nSetOperationContext.prototype.queryTerm = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(QueryTermContext);\n    } else {\n        return this.getTypedRuleContext(QueryTermContext,i);\n    }\n};\n\nSetOperationContext.prototype.INTERSECT = function() {\n    return this.getToken(SqlBaseParser.INTERSECT, 0);\n};\n\nSetOperationContext.prototype.setQuantifier = function() {\n    return this.getTypedRuleContext(SetQuantifierContext,0);\n};\n\nSetOperationContext.prototype.UNION = function() {\n    return this.getToken(SqlBaseParser.UNION, 0);\n};\n\nSetOperationContext.prototype.EXCEPT = function() {\n    return this.getToken(SqlBaseParser.EXCEPT, 0);\n};\nSetOperationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSetOperation(this);\n\t}\n};\n\nSetOperationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSetOperation(this);\n\t}\n};\n\nSetOperationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSetOperation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.prototype.queryTerm = function(_p) {\n\tif(_p===undefined) {\n\t    _p = 0;\n\t}\n    var _parentctx = this._ctx;\n    var _parentState = this.state;\n    var localctx = new QueryTermContext(this, this._ctx, _parentState);\n    var _prevctx = localctx;\n    var _startState = 24;\n    this.enterRecursionRule(localctx, 24, SqlBaseParser.RULE_queryTerm, _p);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        localctx = new QueryTermDefaultContext(this, localctx);\n        this._ctx = localctx;\n        _prevctx = localctx;\n\n        this.state = 560;\n        this.queryPrimary();\n        this._ctx.stop = this._input.LT(-1);\n        this.state = 576;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,59,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                if(this._parseListeners!==null) {\n                    this.triggerExitRuleEvent();\n                }\n                _prevctx = localctx;\n                this.state = 574;\n                this._errHandler.sync(this);\n                var la_ = this._interp.adaptivePredict(this._input,58,this._ctx);\n                switch(la_) {\n                case 1:\n                    localctx = new SetOperationContext(this, new QueryTermContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_queryTerm);\n                    this.state = 562;\n                    if (!( this.precpred(this._ctx, 2))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 2)\");\n                    }\n                    this.state = 563;\n                    localctx.operator = this.match(SqlBaseParser.INTERSECT);\n                    this.state = 565;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                    if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) {\n                        this.state = 564;\n                        this.setQuantifier();\n                    }\n\n                    this.state = 567;\n                    localctx.right = this.queryTerm(3);\n                    break;\n\n                case 2:\n                    localctx = new SetOperationContext(this, new QueryTermContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_queryTerm);\n                    this.state = 568;\n                    if (!( this.precpred(this._ctx, 1))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 1)\");\n                    }\n                    this.state = 569;\n                    localctx.operator = this._input.LT(1);\n                    _la = this._input.LA(1);\n                    if(!(_la===SqlBaseParser.UNION || _la===SqlBaseParser.EXCEPT)) {\n                        localctx.operator = this._errHandler.recoverInline(this);\n                    }\n                    else {\n                    \tthis._errHandler.reportMatch(this);\n                        this.consume();\n                    }\n                    this.state = 571;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                    if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) {\n                        this.state = 570;\n                        this.setQuantifier();\n                    }\n\n                    this.state = 573;\n                    localctx.right = this.queryTerm(2);\n                    break;\n\n                } \n            }\n            this.state = 578;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,59,this._ctx);\n        }\n\n    } catch( error) {\n        if(error instanceof _error.RecognitionException) {\n\t        localctx.exception = error;\n\t        this._errHandler.reportError(this, error);\n\t        this._errHandler.recover(this, error);\n\t    } else {\n\t    \tthrow error;\n\t    }\n    } finally {\n        this.unrollRecursionContexts(_parentctx)\n    }\n    return localctx;\n};\n\nfunction QueryPrimaryContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_queryPrimary;\n    // return this;\n}\n\nQueryPrimaryContext.prototype = Object.create(ParserRuleContext.prototype);\nQueryPrimaryContext.prototype.constructor = QueryPrimaryContext;\n\n\n \nQueryPrimaryContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction SubqueryContext(parser, ctx) {\n\tQueryPrimaryContext.call(this, parser);\n    QueryPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSubqueryContext.prototype = Object.create(QueryPrimaryContext.prototype);\nSubqueryContext.prototype.constructor = SubqueryContext;\n\nSqlBaseParser.SubqueryContext = SubqueryContext;\n\nSubqueryContext.prototype.queryNoWith = function() {\n    return this.getTypedRuleContext(QueryNoWithContext,0);\n};\nSubqueryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSubquery(this);\n\t}\n};\n\nSubqueryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSubquery(this);\n\t}\n};\n\nSubqueryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSubquery(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction QueryPrimaryDefaultContext(parser, ctx) {\n\tQueryPrimaryContext.call(this, parser);\n    QueryPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nQueryPrimaryDefaultContext.prototype = Object.create(QueryPrimaryContext.prototype);\nQueryPrimaryDefaultContext.prototype.constructor = QueryPrimaryDefaultContext;\n\nSqlBaseParser.QueryPrimaryDefaultContext = QueryPrimaryDefaultContext;\n\nQueryPrimaryDefaultContext.prototype.querySpecification = function() {\n    return this.getTypedRuleContext(QuerySpecificationContext,0);\n};\nQueryPrimaryDefaultContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQueryPrimaryDefault(this);\n\t}\n};\n\nQueryPrimaryDefaultContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQueryPrimaryDefault(this);\n\t}\n};\n\nQueryPrimaryDefaultContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQueryPrimaryDefault(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction TableContext(parser, ctx) {\n\tQueryPrimaryContext.call(this, parser);\n    QueryPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nTableContext.prototype = Object.create(QueryPrimaryContext.prototype);\nTableContext.prototype.constructor = TableContext;\n\nSqlBaseParser.TableContext = TableContext;\n\nTableContext.prototype.TABLE = function() {\n    return this.getToken(SqlBaseParser.TABLE, 0);\n};\n\nTableContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\nTableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTable(this);\n\t}\n};\n\nTableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTable(this);\n\t}\n};\n\nTableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction InlineTableContext(parser, ctx) {\n\tQueryPrimaryContext.call(this, parser);\n    QueryPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nInlineTableContext.prototype = Object.create(QueryPrimaryContext.prototype);\nInlineTableContext.prototype.constructor = InlineTableContext;\n\nSqlBaseParser.InlineTableContext = InlineTableContext;\n\nInlineTableContext.prototype.VALUES = function() {\n    return this.getToken(SqlBaseParser.VALUES, 0);\n};\n\nInlineTableContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\nInlineTableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterInlineTable(this);\n\t}\n};\n\nInlineTableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitInlineTable(this);\n\t}\n};\n\nInlineTableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitInlineTable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.QueryPrimaryContext = QueryPrimaryContext;\n\nSqlBaseParser.prototype.queryPrimary = function() {\n\n    var localctx = new QueryPrimaryContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 26, SqlBaseParser.RULE_queryPrimary);\n    try {\n        this.state = 595;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.SELECT:\n            localctx = new QueryPrimaryDefaultContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 579;\n            this.querySpecification();\n            break;\n        case SqlBaseParser.TABLE:\n            localctx = new TableContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 580;\n            this.match(SqlBaseParser.TABLE);\n            this.state = 581;\n            this.qualifiedName();\n            break;\n        case SqlBaseParser.VALUES:\n            localctx = new InlineTableContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 582;\n            this.match(SqlBaseParser.VALUES);\n            this.state = 583;\n            this.expression();\n            this.state = 588;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,60,this._ctx)\n            while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 584;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 585;\n                    this.expression(); \n                }\n                this.state = 590;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,60,this._ctx);\n            }\n\n            break;\n        case SqlBaseParser.T__1:\n            localctx = new SubqueryContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 591;\n            this.match(SqlBaseParser.T__1);\n            this.state = 592;\n            this.queryNoWith();\n            this.state = 593;\n            this.match(SqlBaseParser.T__3);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SortItemContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_sortItem;\n    this.ordering = null; // Token\n    this.nullOrdering = null; // Token\n    // return this;\n}\n\nSortItemContext.prototype = Object.create(ParserRuleContext.prototype);\nSortItemContext.prototype.constructor = SortItemContext;\n\nSortItemContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nSortItemContext.prototype.NULLS = function() {\n    return this.getToken(SqlBaseParser.NULLS, 0);\n};\n\nSortItemContext.prototype.ASC = function() {\n    return this.getToken(SqlBaseParser.ASC, 0);\n};\n\nSortItemContext.prototype.DESC = function() {\n    return this.getToken(SqlBaseParser.DESC, 0);\n};\n\nSortItemContext.prototype.FIRST = function() {\n    return this.getToken(SqlBaseParser.FIRST, 0);\n};\n\nSortItemContext.prototype.LAST = function() {\n    return this.getToken(SqlBaseParser.LAST, 0);\n};\n\nSortItemContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSortItem(this);\n\t}\n};\n\nSortItemContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSortItem(this);\n\t}\n};\n\nSortItemContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSortItem(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.SortItemContext = SortItemContext;\n\nSqlBaseParser.prototype.sortItem = function() {\n\n    var localctx = new SortItemContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 28, SqlBaseParser.RULE_sortItem);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 597;\n        this.expression();\n        this.state = 599;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.ASC || _la===SqlBaseParser.DESC) {\n            this.state = 598;\n            localctx.ordering = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.ASC || _la===SqlBaseParser.DESC)) {\n                localctx.ordering = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n        }\n\n        this.state = 603;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.NULLS) {\n            this.state = 601;\n            this.match(SqlBaseParser.NULLS);\n            this.state = 602;\n            localctx.nullOrdering = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.FIRST || _la===SqlBaseParser.LAST)) {\n                localctx.nullOrdering = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n        }\n\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction QuerySpecificationContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_querySpecification;\n    this.where = null; // BooleanExpressionContext\n    this.having = null; // BooleanExpressionContext\n    // return this;\n}\n\nQuerySpecificationContext.prototype = Object.create(ParserRuleContext.prototype);\nQuerySpecificationContext.prototype.constructor = QuerySpecificationContext;\n\nQuerySpecificationContext.prototype.SELECT = function() {\n    return this.getToken(SqlBaseParser.SELECT, 0);\n};\n\nQuerySpecificationContext.prototype.selectItem = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SelectItemContext);\n    } else {\n        return this.getTypedRuleContext(SelectItemContext,i);\n    }\n};\n\nQuerySpecificationContext.prototype.setQuantifier = function() {\n    return this.getTypedRuleContext(SetQuantifierContext,0);\n};\n\nQuerySpecificationContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nQuerySpecificationContext.prototype.relation = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(RelationContext);\n    } else {\n        return this.getTypedRuleContext(RelationContext,i);\n    }\n};\n\nQuerySpecificationContext.prototype.WHERE = function() {\n    return this.getToken(SqlBaseParser.WHERE, 0);\n};\n\nQuerySpecificationContext.prototype.GROUP = function() {\n    return this.getToken(SqlBaseParser.GROUP, 0);\n};\n\nQuerySpecificationContext.prototype.BY = function() {\n    return this.getToken(SqlBaseParser.BY, 0);\n};\n\nQuerySpecificationContext.prototype.groupBy = function() {\n    return this.getTypedRuleContext(GroupByContext,0);\n};\n\nQuerySpecificationContext.prototype.HAVING = function() {\n    return this.getToken(SqlBaseParser.HAVING, 0);\n};\n\nQuerySpecificationContext.prototype.booleanExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(BooleanExpressionContext);\n    } else {\n        return this.getTypedRuleContext(BooleanExpressionContext,i);\n    }\n};\n\nQuerySpecificationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQuerySpecification(this);\n\t}\n};\n\nQuerySpecificationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQuerySpecification(this);\n\t}\n};\n\nQuerySpecificationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQuerySpecification(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.QuerySpecificationContext = QuerySpecificationContext;\n\nSqlBaseParser.prototype.querySpecification = function() {\n\n    var localctx = new QuerySpecificationContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 30, SqlBaseParser.RULE_querySpecification);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 605;\n        this.match(SqlBaseParser.SELECT);\n        this.state = 607;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) {\n            this.state = 606;\n            this.setQuantifier();\n        }\n\n        this.state = 609;\n        this.selectItem();\n        this.state = 614;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,65,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 610;\n                this.match(SqlBaseParser.T__2);\n                this.state = 611;\n                this.selectItem(); \n            }\n            this.state = 616;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,65,this._ctx);\n        }\n\n        this.state = 626;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,67,this._ctx);\n        if(la_===1) {\n            this.state = 617;\n            this.match(SqlBaseParser.FROM);\n            this.state = 618;\n            this.relation(0);\n            this.state = 623;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,66,this._ctx)\n            while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 619;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 620;\n                    this.relation(0); \n                }\n                this.state = 625;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,66,this._ctx);\n            }\n\n\n        }\n        this.state = 630;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,68,this._ctx);\n        if(la_===1) {\n            this.state = 628;\n            this.match(SqlBaseParser.WHERE);\n            this.state = 629;\n            localctx.where = this.booleanExpression(0);\n\n        }\n        this.state = 635;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,69,this._ctx);\n        if(la_===1) {\n            this.state = 632;\n            this.match(SqlBaseParser.GROUP);\n            this.state = 633;\n            this.match(SqlBaseParser.BY);\n            this.state = 634;\n            this.groupBy();\n\n        }\n        this.state = 639;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,70,this._ctx);\n        if(la_===1) {\n            this.state = 637;\n            this.match(SqlBaseParser.HAVING);\n            this.state = 638;\n            localctx.having = this.booleanExpression(0);\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction GroupByContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_groupBy;\n    // return this;\n}\n\nGroupByContext.prototype = Object.create(ParserRuleContext.prototype);\nGroupByContext.prototype.constructor = GroupByContext;\n\nGroupByContext.prototype.groupingElement = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(GroupingElementContext);\n    } else {\n        return this.getTypedRuleContext(GroupingElementContext,i);\n    }\n};\n\nGroupByContext.prototype.setQuantifier = function() {\n    return this.getTypedRuleContext(SetQuantifierContext,0);\n};\n\nGroupByContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterGroupBy(this);\n\t}\n};\n\nGroupByContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitGroupBy(this);\n\t}\n};\n\nGroupByContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitGroupBy(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.GroupByContext = GroupByContext;\n\nSqlBaseParser.prototype.groupBy = function() {\n\n    var localctx = new GroupByContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 32, SqlBaseParser.RULE_groupBy);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 642;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) {\n            this.state = 641;\n            this.setQuantifier();\n        }\n\n        this.state = 644;\n        this.groupingElement();\n        this.state = 649;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,72,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 645;\n                this.match(SqlBaseParser.T__2);\n                this.state = 646;\n                this.groupingElement(); \n            }\n            this.state = 651;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,72,this._ctx);\n        }\n\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction GroupingElementContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_groupingElement;\n    // return this;\n}\n\nGroupingElementContext.prototype = Object.create(ParserRuleContext.prototype);\nGroupingElementContext.prototype.constructor = GroupingElementContext;\n\n\n \nGroupingElementContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction MultipleGroupingSetsContext(parser, ctx) {\n\tGroupingElementContext.call(this, parser);\n    GroupingElementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nMultipleGroupingSetsContext.prototype = Object.create(GroupingElementContext.prototype);\nMultipleGroupingSetsContext.prototype.constructor = MultipleGroupingSetsContext;\n\nSqlBaseParser.MultipleGroupingSetsContext = MultipleGroupingSetsContext;\n\nMultipleGroupingSetsContext.prototype.GROUPING = function() {\n    return this.getToken(SqlBaseParser.GROUPING, 0);\n};\n\nMultipleGroupingSetsContext.prototype.SETS = function() {\n    return this.getToken(SqlBaseParser.SETS, 0);\n};\n\nMultipleGroupingSetsContext.prototype.groupingSet = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(GroupingSetContext);\n    } else {\n        return this.getTypedRuleContext(GroupingSetContext,i);\n    }\n};\nMultipleGroupingSetsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterMultipleGroupingSets(this);\n\t}\n};\n\nMultipleGroupingSetsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitMultipleGroupingSets(this);\n\t}\n};\n\nMultipleGroupingSetsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitMultipleGroupingSets(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SingleGroupingSetContext(parser, ctx) {\n\tGroupingElementContext.call(this, parser);\n    GroupingElementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSingleGroupingSetContext.prototype = Object.create(GroupingElementContext.prototype);\nSingleGroupingSetContext.prototype.constructor = SingleGroupingSetContext;\n\nSqlBaseParser.SingleGroupingSetContext = SingleGroupingSetContext;\n\nSingleGroupingSetContext.prototype.groupingExpressions = function() {\n    return this.getTypedRuleContext(GroupingExpressionsContext,0);\n};\nSingleGroupingSetContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSingleGroupingSet(this);\n\t}\n};\n\nSingleGroupingSetContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSingleGroupingSet(this);\n\t}\n};\n\nSingleGroupingSetContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSingleGroupingSet(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CubeContext(parser, ctx) {\n\tGroupingElementContext.call(this, parser);\n    GroupingElementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCubeContext.prototype = Object.create(GroupingElementContext.prototype);\nCubeContext.prototype.constructor = CubeContext;\n\nSqlBaseParser.CubeContext = CubeContext;\n\nCubeContext.prototype.CUBE = function() {\n    return this.getToken(SqlBaseParser.CUBE, 0);\n};\n\nCubeContext.prototype.qualifiedName = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(QualifiedNameContext);\n    } else {\n        return this.getTypedRuleContext(QualifiedNameContext,i);\n    }\n};\nCubeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCube(this);\n\t}\n};\n\nCubeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCube(this);\n\t}\n};\n\nCubeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCube(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RollupContext(parser, ctx) {\n\tGroupingElementContext.call(this, parser);\n    GroupingElementContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRollupContext.prototype = Object.create(GroupingElementContext.prototype);\nRollupContext.prototype.constructor = RollupContext;\n\nSqlBaseParser.RollupContext = RollupContext;\n\nRollupContext.prototype.ROLLUP = function() {\n    return this.getToken(SqlBaseParser.ROLLUP, 0);\n};\n\nRollupContext.prototype.qualifiedName = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(QualifiedNameContext);\n    } else {\n        return this.getTypedRuleContext(QualifiedNameContext,i);\n    }\n};\nRollupContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRollup(this);\n\t}\n};\n\nRollupContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRollup(this);\n\t}\n};\n\nRollupContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRollup(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.GroupingElementContext = GroupingElementContext;\n\nSqlBaseParser.prototype.groupingElement = function() {\n\n    var localctx = new GroupingElementContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 34, SqlBaseParser.RULE_groupingElement);\n    var _la = 0; // Token type\n    try {\n        this.state = 692;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.T__1:\n        case SqlBaseParser.T__4:\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NOT:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.EXISTS:\n        case SqlBaseParser.NULL:\n        case SqlBaseParser.TRUE:\n        case SqlBaseParser.FALSE:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.CURRENT_DATE:\n        case SqlBaseParser.CURRENT_TIME:\n        case SqlBaseParser.CURRENT_TIMESTAMP:\n        case SqlBaseParser.LOCALTIME:\n        case SqlBaseParser.LOCALTIMESTAMP:\n        case SqlBaseParser.EXTRACT:\n        case SqlBaseParser.CASE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.CAST:\n        case SqlBaseParser.TRY_CAST:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NORMALIZE:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.PLUS:\n        case SqlBaseParser.MINUS:\n        case SqlBaseParser.STRING:\n        case SqlBaseParser.BINARY_LITERAL:\n        case SqlBaseParser.INTEGER_VALUE:\n        case SqlBaseParser.DECIMAL_VALUE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n        case SqlBaseParser.DOUBLE_PRECISION:\n            localctx = new SingleGroupingSetContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 652;\n            this.groupingExpressions();\n            break;\n        case SqlBaseParser.ROLLUP:\n            localctx = new RollupContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 653;\n            this.match(SqlBaseParser.ROLLUP);\n            this.state = 654;\n            this.match(SqlBaseParser.T__1);\n            this.state = 663;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 655;\n                this.qualifiedName();\n                this.state = 660;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 656;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 657;\n                    this.qualifiedName();\n                    this.state = 662;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 665;\n            this.match(SqlBaseParser.T__3);\n            break;\n        case SqlBaseParser.CUBE:\n            localctx = new CubeContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 666;\n            this.match(SqlBaseParser.CUBE);\n            this.state = 667;\n            this.match(SqlBaseParser.T__1);\n            this.state = 676;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 668;\n                this.qualifiedName();\n                this.state = 673;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 669;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 670;\n                    this.qualifiedName();\n                    this.state = 675;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 678;\n            this.match(SqlBaseParser.T__3);\n            break;\n        case SqlBaseParser.GROUPING:\n            localctx = new MultipleGroupingSetsContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 679;\n            this.match(SqlBaseParser.GROUPING);\n            this.state = 680;\n            this.match(SqlBaseParser.SETS);\n            this.state = 681;\n            this.match(SqlBaseParser.T__1);\n            this.state = 682;\n            this.groupingSet();\n            this.state = 687;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 683;\n                this.match(SqlBaseParser.T__2);\n                this.state = 684;\n                this.groupingSet();\n                this.state = 689;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 690;\n            this.match(SqlBaseParser.T__3);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction GroupingExpressionsContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_groupingExpressions;\n    // return this;\n}\n\nGroupingExpressionsContext.prototype = Object.create(ParserRuleContext.prototype);\nGroupingExpressionsContext.prototype.constructor = GroupingExpressionsContext;\n\nGroupingExpressionsContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\n\nGroupingExpressionsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterGroupingExpressions(this);\n\t}\n};\n\nGroupingExpressionsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitGroupingExpressions(this);\n\t}\n};\n\nGroupingExpressionsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitGroupingExpressions(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.GroupingExpressionsContext = GroupingExpressionsContext;\n\nSqlBaseParser.prototype.groupingExpressions = function() {\n\n    var localctx = new GroupingExpressionsContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 36, SqlBaseParser.RULE_groupingExpressions);\n    var _la = 0; // Token type\n    try {\n        this.state = 707;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,81,this._ctx);\n        switch(la_) {\n        case 1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 694;\n            this.match(SqlBaseParser.T__1);\n            this.state = 703;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 695;\n                this.expression();\n                this.state = 700;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 696;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 697;\n                    this.expression();\n                    this.state = 702;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 705;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 2:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 706;\n            this.expression();\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction GroupingSetContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_groupingSet;\n    // return this;\n}\n\nGroupingSetContext.prototype = Object.create(ParserRuleContext.prototype);\nGroupingSetContext.prototype.constructor = GroupingSetContext;\n\nGroupingSetContext.prototype.qualifiedName = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(QualifiedNameContext);\n    } else {\n        return this.getTypedRuleContext(QualifiedNameContext,i);\n    }\n};\n\nGroupingSetContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterGroupingSet(this);\n\t}\n};\n\nGroupingSetContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitGroupingSet(this);\n\t}\n};\n\nGroupingSetContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitGroupingSet(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.GroupingSetContext = GroupingSetContext;\n\nSqlBaseParser.prototype.groupingSet = function() {\n\n    var localctx = new GroupingSetContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 38, SqlBaseParser.RULE_groupingSet);\n    var _la = 0; // Token type\n    try {\n        this.state = 722;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.T__1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 709;\n            this.match(SqlBaseParser.T__1);\n            this.state = 718;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 710;\n                this.qualifiedName();\n                this.state = 715;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 711;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 712;\n                    this.qualifiedName();\n                    this.state = 717;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 720;\n            this.match(SqlBaseParser.T__3);\n            break;\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 721;\n            this.qualifiedName();\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction NamedQueryContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_namedQuery;\n    this.name = null; // IdentifierContext\n    // return this;\n}\n\nNamedQueryContext.prototype = Object.create(ParserRuleContext.prototype);\nNamedQueryContext.prototype.constructor = NamedQueryContext;\n\nNamedQueryContext.prototype.AS = function() {\n    return this.getToken(SqlBaseParser.AS, 0);\n};\n\nNamedQueryContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\n\nNamedQueryContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nNamedQueryContext.prototype.columnAliases = function() {\n    return this.getTypedRuleContext(ColumnAliasesContext,0);\n};\n\nNamedQueryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNamedQuery(this);\n\t}\n};\n\nNamedQueryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNamedQuery(this);\n\t}\n};\n\nNamedQueryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNamedQuery(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.NamedQueryContext = NamedQueryContext;\n\nSqlBaseParser.prototype.namedQuery = function() {\n\n    var localctx = new NamedQueryContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 40, SqlBaseParser.RULE_namedQuery);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 724;\n        localctx.name = this.identifier();\n        this.state = 726;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.T__1) {\n            this.state = 725;\n            this.columnAliases();\n        }\n\n        this.state = 728;\n        this.match(SqlBaseParser.AS);\n        this.state = 729;\n        this.match(SqlBaseParser.T__1);\n        this.state = 730;\n        this.query();\n        this.state = 731;\n        this.match(SqlBaseParser.T__3);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SetQuantifierContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_setQuantifier;\n    // return this;\n}\n\nSetQuantifierContext.prototype = Object.create(ParserRuleContext.prototype);\nSetQuantifierContext.prototype.constructor = SetQuantifierContext;\n\nSetQuantifierContext.prototype.DISTINCT = function() {\n    return this.getToken(SqlBaseParser.DISTINCT, 0);\n};\n\nSetQuantifierContext.prototype.ALL = function() {\n    return this.getToken(SqlBaseParser.ALL, 0);\n};\n\nSetQuantifierContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSetQuantifier(this);\n\t}\n};\n\nSetQuantifierContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSetQuantifier(this);\n\t}\n};\n\nSetQuantifierContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSetQuantifier(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.SetQuantifierContext = SetQuantifierContext;\n\nSqlBaseParser.prototype.setQuantifier = function() {\n\n    var localctx = new SetQuantifierContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 42, SqlBaseParser.RULE_setQuantifier);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 733;\n        _la = this._input.LA(1);\n        if(!(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT)) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SelectItemContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_selectItem;\n    // return this;\n}\n\nSelectItemContext.prototype = Object.create(ParserRuleContext.prototype);\nSelectItemContext.prototype.constructor = SelectItemContext;\n\n\n \nSelectItemContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction SelectAllContext(parser, ctx) {\n\tSelectItemContext.call(this, parser);\n    SelectItemContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSelectAllContext.prototype = Object.create(SelectItemContext.prototype);\nSelectAllContext.prototype.constructor = SelectAllContext;\n\nSqlBaseParser.SelectAllContext = SelectAllContext;\n\nSelectAllContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nSelectAllContext.prototype.ASTERISK = function() {\n    return this.getToken(SqlBaseParser.ASTERISK, 0);\n};\nSelectAllContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSelectAll(this);\n\t}\n};\n\nSelectAllContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSelectAll(this);\n\t}\n};\n\nSelectAllContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSelectAll(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SelectSingleContext(parser, ctx) {\n\tSelectItemContext.call(this, parser);\n    SelectItemContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSelectSingleContext.prototype = Object.create(SelectItemContext.prototype);\nSelectSingleContext.prototype.constructor = SelectSingleContext;\n\nSqlBaseParser.SelectSingleContext = SelectSingleContext;\n\nSelectSingleContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nSelectSingleContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nSelectSingleContext.prototype.AS = function() {\n    return this.getToken(SqlBaseParser.AS, 0);\n};\nSelectSingleContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSelectSingle(this);\n\t}\n};\n\nSelectSingleContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSelectSingle(this);\n\t}\n};\n\nSelectSingleContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSelectSingle(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.SelectItemContext = SelectItemContext;\n\nSqlBaseParser.prototype.selectItem = function() {\n\n    var localctx = new SelectItemContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 44, SqlBaseParser.RULE_selectItem);\n    var _la = 0; // Token type\n    try {\n        this.state = 747;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,88,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new SelectSingleContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 735;\n            this.expression();\n            this.state = 740;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,87,this._ctx);\n            if(la_===1) {\n                this.state = 737;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                if(_la===SqlBaseParser.AS) {\n                    this.state = 736;\n                    this.match(SqlBaseParser.AS);\n                }\n\n                this.state = 739;\n                this.identifier();\n\n            }\n            break;\n\n        case 2:\n            localctx = new SelectAllContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 742;\n            this.qualifiedName();\n            this.state = 743;\n            this.match(SqlBaseParser.T__0);\n            this.state = 744;\n            this.match(SqlBaseParser.ASTERISK);\n            break;\n\n        case 3:\n            localctx = new SelectAllContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 746;\n            this.match(SqlBaseParser.ASTERISK);\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction RelationContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_relation;\n    // return this;\n}\n\nRelationContext.prototype = Object.create(ParserRuleContext.prototype);\nRelationContext.prototype.constructor = RelationContext;\n\n\n \nRelationContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\nfunction RelationDefaultContext(parser, ctx) {\n\tRelationContext.call(this, parser);\n    RelationContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRelationDefaultContext.prototype = Object.create(RelationContext.prototype);\nRelationDefaultContext.prototype.constructor = RelationDefaultContext;\n\nSqlBaseParser.RelationDefaultContext = RelationDefaultContext;\n\nRelationDefaultContext.prototype.sampledRelation = function() {\n    return this.getTypedRuleContext(SampledRelationContext,0);\n};\nRelationDefaultContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRelationDefault(this);\n\t}\n};\n\nRelationDefaultContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRelationDefault(this);\n\t}\n};\n\nRelationDefaultContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRelationDefault(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction JoinRelationContext(parser, ctx) {\n\tRelationContext.call(this, parser);\n    this.left = null; // RelationContext;\n    this.right = null; // SampledRelationContext;\n    this.rightRelation = null; // RelationContext;\n    RelationContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nJoinRelationContext.prototype = Object.create(RelationContext.prototype);\nJoinRelationContext.prototype.constructor = JoinRelationContext;\n\nSqlBaseParser.JoinRelationContext = JoinRelationContext;\n\nJoinRelationContext.prototype.relation = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(RelationContext);\n    } else {\n        return this.getTypedRuleContext(RelationContext,i);\n    }\n};\n\nJoinRelationContext.prototype.CROSS = function() {\n    return this.getToken(SqlBaseParser.CROSS, 0);\n};\n\nJoinRelationContext.prototype.JOIN = function() {\n    return this.getToken(SqlBaseParser.JOIN, 0);\n};\n\nJoinRelationContext.prototype.joinType = function() {\n    return this.getTypedRuleContext(JoinTypeContext,0);\n};\n\nJoinRelationContext.prototype.joinCriteria = function() {\n    return this.getTypedRuleContext(JoinCriteriaContext,0);\n};\n\nJoinRelationContext.prototype.NATURAL = function() {\n    return this.getToken(SqlBaseParser.NATURAL, 0);\n};\n\nJoinRelationContext.prototype.sampledRelation = function() {\n    return this.getTypedRuleContext(SampledRelationContext,0);\n};\nJoinRelationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterJoinRelation(this);\n\t}\n};\n\nJoinRelationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitJoinRelation(this);\n\t}\n};\n\nJoinRelationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitJoinRelation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.prototype.relation = function(_p) {\n\tif(_p===undefined) {\n\t    _p = 0;\n\t}\n    var _parentctx = this._ctx;\n    var _parentState = this.state;\n    var localctx = new RelationContext(this, this._ctx, _parentState);\n    var _prevctx = localctx;\n    var _startState = 46;\n    this.enterRecursionRule(localctx, 46, SqlBaseParser.RULE_relation, _p);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        localctx = new RelationDefaultContext(this, localctx);\n        this._ctx = localctx;\n        _prevctx = localctx;\n\n        this.state = 750;\n        this.sampledRelation();\n        this._ctx.stop = this._input.LT(-1);\n        this.state = 770;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,90,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                if(this._parseListeners!==null) {\n                    this.triggerExitRuleEvent();\n                }\n                _prevctx = localctx;\n                localctx = new JoinRelationContext(this, new RelationContext(this, _parentctx, _parentState));\n                localctx.left = _prevctx;\n                this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_relation);\n                this.state = 752;\n                if (!( this.precpred(this._ctx, 2))) {\n                    throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 2)\");\n                }\n                this.state = 766;\n                this._errHandler.sync(this);\n                switch(this._input.LA(1)) {\n                case SqlBaseParser.CROSS:\n                    this.state = 753;\n                    this.match(SqlBaseParser.CROSS);\n                    this.state = 754;\n                    this.match(SqlBaseParser.JOIN);\n                    this.state = 755;\n                    localctx.right = this.sampledRelation();\n                    break;\n                case SqlBaseParser.JOIN:\n                case SqlBaseParser.INNER:\n                case SqlBaseParser.LEFT:\n                case SqlBaseParser.RIGHT:\n                case SqlBaseParser.FULL:\n                    this.state = 756;\n                    this.joinType();\n                    this.state = 757;\n                    this.match(SqlBaseParser.JOIN);\n                    this.state = 758;\n                    localctx.rightRelation = this.relation(0);\n                    this.state = 759;\n                    this.joinCriteria();\n                    break;\n                case SqlBaseParser.NATURAL:\n                    this.state = 761;\n                    this.match(SqlBaseParser.NATURAL);\n                    this.state = 762;\n                    this.joinType();\n                    this.state = 763;\n                    this.match(SqlBaseParser.JOIN);\n                    this.state = 764;\n                    localctx.right = this.sampledRelation();\n                    break;\n                default:\n                    throw new _error.NoViableAltException(this);\n                } \n            }\n            this.state = 772;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,90,this._ctx);\n        }\n\n    } catch( error) {\n        if(error instanceof _error.RecognitionException) {\n\t        localctx.exception = error;\n\t        this._errHandler.reportError(this, error);\n\t        this._errHandler.recover(this, error);\n\t    } else {\n\t    \tthrow error;\n\t    }\n    } finally {\n        this.unrollRecursionContexts(_parentctx)\n    }\n    return localctx;\n};\n\nfunction JoinTypeContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_joinType;\n    // return this;\n}\n\nJoinTypeContext.prototype = Object.create(ParserRuleContext.prototype);\nJoinTypeContext.prototype.constructor = JoinTypeContext;\n\nJoinTypeContext.prototype.INNER = function() {\n    return this.getToken(SqlBaseParser.INNER, 0);\n};\n\nJoinTypeContext.prototype.LEFT = function() {\n    return this.getToken(SqlBaseParser.LEFT, 0);\n};\n\nJoinTypeContext.prototype.OUTER = function() {\n    return this.getToken(SqlBaseParser.OUTER, 0);\n};\n\nJoinTypeContext.prototype.RIGHT = function() {\n    return this.getToken(SqlBaseParser.RIGHT, 0);\n};\n\nJoinTypeContext.prototype.FULL = function() {\n    return this.getToken(SqlBaseParser.FULL, 0);\n};\n\nJoinTypeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterJoinType(this);\n\t}\n};\n\nJoinTypeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitJoinType(this);\n\t}\n};\n\nJoinTypeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitJoinType(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.JoinTypeContext = JoinTypeContext;\n\nSqlBaseParser.prototype.joinType = function() {\n\n    var localctx = new JoinTypeContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 48, SqlBaseParser.RULE_joinType);\n    var _la = 0; // Token type\n    try {\n        this.state = 788;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.JOIN:\n        case SqlBaseParser.INNER:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 774;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.INNER) {\n                this.state = 773;\n                this.match(SqlBaseParser.INNER);\n            }\n\n            break;\n        case SqlBaseParser.LEFT:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 776;\n            this.match(SqlBaseParser.LEFT);\n            this.state = 778;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.OUTER) {\n                this.state = 777;\n                this.match(SqlBaseParser.OUTER);\n            }\n\n            break;\n        case SqlBaseParser.RIGHT:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 780;\n            this.match(SqlBaseParser.RIGHT);\n            this.state = 782;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.OUTER) {\n                this.state = 781;\n                this.match(SqlBaseParser.OUTER);\n            }\n\n            break;\n        case SqlBaseParser.FULL:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 784;\n            this.match(SqlBaseParser.FULL);\n            this.state = 786;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.OUTER) {\n                this.state = 785;\n                this.match(SqlBaseParser.OUTER);\n            }\n\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction JoinCriteriaContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_joinCriteria;\n    // return this;\n}\n\nJoinCriteriaContext.prototype = Object.create(ParserRuleContext.prototype);\nJoinCriteriaContext.prototype.constructor = JoinCriteriaContext;\n\nJoinCriteriaContext.prototype.ON = function() {\n    return this.getToken(SqlBaseParser.ON, 0);\n};\n\nJoinCriteriaContext.prototype.booleanExpression = function() {\n    return this.getTypedRuleContext(BooleanExpressionContext,0);\n};\n\nJoinCriteriaContext.prototype.USING = function() {\n    return this.getToken(SqlBaseParser.USING, 0);\n};\n\nJoinCriteriaContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\n\nJoinCriteriaContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterJoinCriteria(this);\n\t}\n};\n\nJoinCriteriaContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitJoinCriteria(this);\n\t}\n};\n\nJoinCriteriaContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitJoinCriteria(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.JoinCriteriaContext = JoinCriteriaContext;\n\nSqlBaseParser.prototype.joinCriteria = function() {\n\n    var localctx = new JoinCriteriaContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 50, SqlBaseParser.RULE_joinCriteria);\n    var _la = 0; // Token type\n    try {\n        this.state = 804;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.ON:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 790;\n            this.match(SqlBaseParser.ON);\n            this.state = 791;\n            this.booleanExpression(0);\n            break;\n        case SqlBaseParser.USING:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 792;\n            this.match(SqlBaseParser.USING);\n            this.state = 793;\n            this.match(SqlBaseParser.T__1);\n            this.state = 794;\n            this.identifier();\n            this.state = 799;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 795;\n                this.match(SqlBaseParser.T__2);\n                this.state = 796;\n                this.identifier();\n                this.state = 801;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 802;\n            this.match(SqlBaseParser.T__3);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SampledRelationContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_sampledRelation;\n    this.percentage = null; // ExpressionContext\n    // return this;\n}\n\nSampledRelationContext.prototype = Object.create(ParserRuleContext.prototype);\nSampledRelationContext.prototype.constructor = SampledRelationContext;\n\nSampledRelationContext.prototype.aliasedRelation = function() {\n    return this.getTypedRuleContext(AliasedRelationContext,0);\n};\n\nSampledRelationContext.prototype.TABLESAMPLE = function() {\n    return this.getToken(SqlBaseParser.TABLESAMPLE, 0);\n};\n\nSampledRelationContext.prototype.sampleType = function() {\n    return this.getTypedRuleContext(SampleTypeContext,0);\n};\n\nSampledRelationContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nSampledRelationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSampledRelation(this);\n\t}\n};\n\nSampledRelationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSampledRelation(this);\n\t}\n};\n\nSampledRelationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSampledRelation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.SampledRelationContext = SampledRelationContext;\n\nSqlBaseParser.prototype.sampledRelation = function() {\n\n    var localctx = new SampledRelationContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 52, SqlBaseParser.RULE_sampledRelation);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 806;\n        this.aliasedRelation();\n        this.state = 813;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,98,this._ctx);\n        if(la_===1) {\n            this.state = 807;\n            this.match(SqlBaseParser.TABLESAMPLE);\n            this.state = 808;\n            this.sampleType();\n            this.state = 809;\n            this.match(SqlBaseParser.T__1);\n            this.state = 810;\n            localctx.percentage = this.expression();\n            this.state = 811;\n            this.match(SqlBaseParser.T__3);\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SampleTypeContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_sampleType;\n    // return this;\n}\n\nSampleTypeContext.prototype = Object.create(ParserRuleContext.prototype);\nSampleTypeContext.prototype.constructor = SampleTypeContext;\n\nSampleTypeContext.prototype.BERNOULLI = function() {\n    return this.getToken(SqlBaseParser.BERNOULLI, 0);\n};\n\nSampleTypeContext.prototype.SYSTEM = function() {\n    return this.getToken(SqlBaseParser.SYSTEM, 0);\n};\n\nSampleTypeContext.prototype.POISSONIZED = function() {\n    return this.getToken(SqlBaseParser.POISSONIZED, 0);\n};\n\nSampleTypeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSampleType(this);\n\t}\n};\n\nSampleTypeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSampleType(this);\n\t}\n};\n\nSampleTypeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSampleType(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.SampleTypeContext = SampleTypeContext;\n\nSqlBaseParser.prototype.sampleType = function() {\n\n    var localctx = new SampleTypeContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 54, SqlBaseParser.RULE_sampleType);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 815;\n        _la = this._input.LA(1);\n        if(!(((((_la - 137)) & ~0x1f) == 0 && ((1 << (_la - 137)) & ((1 << (SqlBaseParser.SYSTEM - 137)) | (1 << (SqlBaseParser.BERNOULLI - 137)) | (1 << (SqlBaseParser.POISSONIZED - 137)))) !== 0))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction AliasedRelationContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_aliasedRelation;\n    this.relationP = null; // RelationPrimaryContext\n    this.as = null; // Token\n    this.alias = null; // IdentifierContext\n    // return this;\n}\n\nAliasedRelationContext.prototype = Object.create(ParserRuleContext.prototype);\nAliasedRelationContext.prototype.constructor = AliasedRelationContext;\n\nAliasedRelationContext.prototype.relationPrimary = function() {\n    return this.getTypedRuleContext(RelationPrimaryContext,0);\n};\n\nAliasedRelationContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nAliasedRelationContext.prototype.columnAliases = function() {\n    return this.getTypedRuleContext(ColumnAliasesContext,0);\n};\n\nAliasedRelationContext.prototype.AS = function() {\n    return this.getToken(SqlBaseParser.AS, 0);\n};\n\nAliasedRelationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterAliasedRelation(this);\n\t}\n};\n\nAliasedRelationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitAliasedRelation(this);\n\t}\n};\n\nAliasedRelationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitAliasedRelation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.AliasedRelationContext = AliasedRelationContext;\n\nSqlBaseParser.prototype.aliasedRelation = function() {\n\n    var localctx = new AliasedRelationContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 56, SqlBaseParser.RULE_aliasedRelation);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 817;\n        localctx.relationP = this.relationPrimary();\n        this.state = 825;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,101,this._ctx);\n        if(la_===1) {\n            this.state = 819;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.AS) {\n                this.state = 818;\n                localctx.as = this.match(SqlBaseParser.AS);\n            }\n\n            this.state = 821;\n            localctx.alias = this.identifier();\n            this.state = 823;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,100,this._ctx);\n            if(la_===1) {\n                this.state = 822;\n                this.columnAliases();\n\n            }\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ColumnAliasesContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_columnAliases;\n    // return this;\n}\n\nColumnAliasesContext.prototype = Object.create(ParserRuleContext.prototype);\nColumnAliasesContext.prototype.constructor = ColumnAliasesContext;\n\nColumnAliasesContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\n\nColumnAliasesContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterColumnAliases(this);\n\t}\n};\n\nColumnAliasesContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitColumnAliases(this);\n\t}\n};\n\nColumnAliasesContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitColumnAliases(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.ColumnAliasesContext = ColumnAliasesContext;\n\nSqlBaseParser.prototype.columnAliases = function() {\n\n    var localctx = new ColumnAliasesContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 58, SqlBaseParser.RULE_columnAliases);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 827;\n        this.match(SqlBaseParser.T__1);\n        this.state = 828;\n        this.identifier();\n        this.state = 833;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===SqlBaseParser.T__2) {\n            this.state = 829;\n            this.match(SqlBaseParser.T__2);\n            this.state = 830;\n            this.identifier();\n            this.state = 835;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 836;\n        this.match(SqlBaseParser.T__3);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction RelationPrimaryContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_relationPrimary;\n    // return this;\n}\n\nRelationPrimaryContext.prototype = Object.create(ParserRuleContext.prototype);\nRelationPrimaryContext.prototype.constructor = RelationPrimaryContext;\n\n\n \nRelationPrimaryContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction SubqueryRelationContext(parser, ctx) {\n\tRelationPrimaryContext.call(this, parser);\n    RelationPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSubqueryRelationContext.prototype = Object.create(RelationPrimaryContext.prototype);\nSubqueryRelationContext.prototype.constructor = SubqueryRelationContext;\n\nSqlBaseParser.SubqueryRelationContext = SubqueryRelationContext;\n\nSubqueryRelationContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\nSubqueryRelationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSubqueryRelation(this);\n\t}\n};\n\nSubqueryRelationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSubqueryRelation(this);\n\t}\n};\n\nSubqueryRelationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSubqueryRelation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ParenthesizedRelationContext(parser, ctx) {\n\tRelationPrimaryContext.call(this, parser);\n    RelationPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nParenthesizedRelationContext.prototype = Object.create(RelationPrimaryContext.prototype);\nParenthesizedRelationContext.prototype.constructor = ParenthesizedRelationContext;\n\nSqlBaseParser.ParenthesizedRelationContext = ParenthesizedRelationContext;\n\nParenthesizedRelationContext.prototype.relation = function() {\n    return this.getTypedRuleContext(RelationContext,0);\n};\nParenthesizedRelationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterParenthesizedRelation(this);\n\t}\n};\n\nParenthesizedRelationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitParenthesizedRelation(this);\n\t}\n};\n\nParenthesizedRelationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitParenthesizedRelation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction UnnestContext(parser, ctx) {\n\tRelationPrimaryContext.call(this, parser);\n    RelationPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nUnnestContext.prototype = Object.create(RelationPrimaryContext.prototype);\nUnnestContext.prototype.constructor = UnnestContext;\n\nSqlBaseParser.UnnestContext = UnnestContext;\n\nUnnestContext.prototype.UNNEST = function() {\n    return this.getToken(SqlBaseParser.UNNEST, 0);\n};\n\nUnnestContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\n\nUnnestContext.prototype.WITH = function() {\n    return this.getToken(SqlBaseParser.WITH, 0);\n};\n\nUnnestContext.prototype.ORDINALITY = function() {\n    return this.getToken(SqlBaseParser.ORDINALITY, 0);\n};\nUnnestContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterUnnest(this);\n\t}\n};\n\nUnnestContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitUnnest(this);\n\t}\n};\n\nUnnestContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitUnnest(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction TableNameContext(parser, ctx) {\n\tRelationPrimaryContext.call(this, parser);\n    RelationPrimaryContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nTableNameContext.prototype = Object.create(RelationPrimaryContext.prototype);\nTableNameContext.prototype.constructor = TableNameContext;\n\nSqlBaseParser.TableNameContext = TableNameContext;\n\nTableNameContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\nTableNameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTableName(this);\n\t}\n};\n\nTableNameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTableName(this);\n\t}\n};\n\nTableNameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTableName(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.RelationPrimaryContext = RelationPrimaryContext;\n\nSqlBaseParser.prototype.relationPrimary = function() {\n\n    var localctx = new RelationPrimaryContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 60, SqlBaseParser.RULE_relationPrimary);\n    var _la = 0; // Token type\n    try {\n        this.state = 862;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,105,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new TableNameContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 838;\n            this.qualifiedName();\n            break;\n\n        case 2:\n            localctx = new SubqueryRelationContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 839;\n            this.match(SqlBaseParser.T__1);\n            this.state = 840;\n            this.query();\n            this.state = 841;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 3:\n            localctx = new UnnestContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 843;\n            this.match(SqlBaseParser.UNNEST);\n            this.state = 844;\n            this.match(SqlBaseParser.T__1);\n            this.state = 845;\n            this.expression();\n            this.state = 850;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 846;\n                this.match(SqlBaseParser.T__2);\n                this.state = 847;\n                this.expression();\n                this.state = 852;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 853;\n            this.match(SqlBaseParser.T__3);\n            this.state = 856;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,104,this._ctx);\n            if(la_===1) {\n                this.state = 854;\n                this.match(SqlBaseParser.WITH);\n                this.state = 855;\n                this.match(SqlBaseParser.ORDINALITY);\n\n            }\n            break;\n\n        case 4:\n            localctx = new ParenthesizedRelationContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 858;\n            this.match(SqlBaseParser.T__1);\n            this.state = 859;\n            this.relation(0);\n            this.state = 860;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ExpressionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_expression;\n    // return this;\n}\n\nExpressionContext.prototype = Object.create(ParserRuleContext.prototype);\nExpressionContext.prototype.constructor = ExpressionContext;\n\nExpressionContext.prototype.booleanExpression = function() {\n    return this.getTypedRuleContext(BooleanExpressionContext,0);\n};\n\nExpressionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExpression(this);\n\t}\n};\n\nExpressionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExpression(this);\n\t}\n};\n\nExpressionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExpression(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.ExpressionContext = ExpressionContext;\n\nSqlBaseParser.prototype.expression = function() {\n\n    var localctx = new ExpressionContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 62, SqlBaseParser.RULE_expression);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 864;\n        this.booleanExpression(0);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction BooleanExpressionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_booleanExpression;\n    // return this;\n}\n\nBooleanExpressionContext.prototype = Object.create(ParserRuleContext.prototype);\nBooleanExpressionContext.prototype.constructor = BooleanExpressionContext;\n\n\n \nBooleanExpressionContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\nfunction LogicalNotContext(parser, ctx) {\n\tBooleanExpressionContext.call(this, parser);\n    BooleanExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nLogicalNotContext.prototype = Object.create(BooleanExpressionContext.prototype);\nLogicalNotContext.prototype.constructor = LogicalNotContext;\n\nSqlBaseParser.LogicalNotContext = LogicalNotContext;\n\nLogicalNotContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\n\nLogicalNotContext.prototype.booleanExpression = function() {\n    return this.getTypedRuleContext(BooleanExpressionContext,0);\n};\nLogicalNotContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterLogicalNot(this);\n\t}\n};\n\nLogicalNotContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitLogicalNot(this);\n\t}\n};\n\nLogicalNotContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitLogicalNot(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction BooleanDefaultContext(parser, ctx) {\n\tBooleanExpressionContext.call(this, parser);\n    BooleanExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nBooleanDefaultContext.prototype = Object.create(BooleanExpressionContext.prototype);\nBooleanDefaultContext.prototype.constructor = BooleanDefaultContext;\n\nSqlBaseParser.BooleanDefaultContext = BooleanDefaultContext;\n\nBooleanDefaultContext.prototype.predicated = function() {\n    return this.getTypedRuleContext(PredicatedContext,0);\n};\nBooleanDefaultContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBooleanDefault(this);\n\t}\n};\n\nBooleanDefaultContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBooleanDefault(this);\n\t}\n};\n\nBooleanDefaultContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBooleanDefault(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction LogicalBinaryContext(parser, ctx) {\n\tBooleanExpressionContext.call(this, parser);\n    this.left = null; // BooleanExpressionContext;\n    this.operator = null; // Token;\n    this.right = null; // BooleanExpressionContext;\n    BooleanExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nLogicalBinaryContext.prototype = Object.create(BooleanExpressionContext.prototype);\nLogicalBinaryContext.prototype.constructor = LogicalBinaryContext;\n\nSqlBaseParser.LogicalBinaryContext = LogicalBinaryContext;\n\nLogicalBinaryContext.prototype.booleanExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(BooleanExpressionContext);\n    } else {\n        return this.getTypedRuleContext(BooleanExpressionContext,i);\n    }\n};\n\nLogicalBinaryContext.prototype.AND = function() {\n    return this.getToken(SqlBaseParser.AND, 0);\n};\n\nLogicalBinaryContext.prototype.OR = function() {\n    return this.getToken(SqlBaseParser.OR, 0);\n};\nLogicalBinaryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterLogicalBinary(this);\n\t}\n};\n\nLogicalBinaryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitLogicalBinary(this);\n\t}\n};\n\nLogicalBinaryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitLogicalBinary(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.prototype.booleanExpression = function(_p) {\n\tif(_p===undefined) {\n\t    _p = 0;\n\t}\n    var _parentctx = this._ctx;\n    var _parentState = this.state;\n    var localctx = new BooleanExpressionContext(this, this._ctx, _parentState);\n    var _prevctx = localctx;\n    var _startState = 64;\n    this.enterRecursionRule(localctx, 64, SqlBaseParser.RULE_booleanExpression, _p);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 870;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.T__1:\n        case SqlBaseParser.T__4:\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.EXISTS:\n        case SqlBaseParser.NULL:\n        case SqlBaseParser.TRUE:\n        case SqlBaseParser.FALSE:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.CURRENT_DATE:\n        case SqlBaseParser.CURRENT_TIME:\n        case SqlBaseParser.CURRENT_TIMESTAMP:\n        case SqlBaseParser.LOCALTIME:\n        case SqlBaseParser.LOCALTIMESTAMP:\n        case SqlBaseParser.EXTRACT:\n        case SqlBaseParser.CASE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.CAST:\n        case SqlBaseParser.TRY_CAST:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NORMALIZE:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.PLUS:\n        case SqlBaseParser.MINUS:\n        case SqlBaseParser.STRING:\n        case SqlBaseParser.BINARY_LITERAL:\n        case SqlBaseParser.INTEGER_VALUE:\n        case SqlBaseParser.DECIMAL_VALUE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n        case SqlBaseParser.DOUBLE_PRECISION:\n            localctx = new BooleanDefaultContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n\n            this.state = 867;\n            this.predicated();\n            break;\n        case SqlBaseParser.NOT:\n            localctx = new LogicalNotContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 868;\n            this.match(SqlBaseParser.NOT);\n            this.state = 869;\n            this.booleanExpression(3);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n        this._ctx.stop = this._input.LT(-1);\n        this.state = 880;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,108,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                if(this._parseListeners!==null) {\n                    this.triggerExitRuleEvent();\n                }\n                _prevctx = localctx;\n                this.state = 878;\n                this._errHandler.sync(this);\n                var la_ = this._interp.adaptivePredict(this._input,107,this._ctx);\n                switch(la_) {\n                case 1:\n                    localctx = new LogicalBinaryContext(this, new BooleanExpressionContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_booleanExpression);\n                    this.state = 872;\n                    if (!( this.precpred(this._ctx, 2))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 2)\");\n                    }\n                    this.state = 873;\n                    localctx.operator = this.match(SqlBaseParser.AND);\n                    this.state = 874;\n                    localctx.right = this.booleanExpression(3);\n                    break;\n\n                case 2:\n                    localctx = new LogicalBinaryContext(this, new BooleanExpressionContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_booleanExpression);\n                    this.state = 875;\n                    if (!( this.precpred(this._ctx, 1))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 1)\");\n                    }\n                    this.state = 876;\n                    localctx.operator = this.match(SqlBaseParser.OR);\n                    this.state = 877;\n                    localctx.right = this.booleanExpression(2);\n                    break;\n\n                } \n            }\n            this.state = 882;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,108,this._ctx);\n        }\n\n    } catch( error) {\n        if(error instanceof _error.RecognitionException) {\n\t        localctx.exception = error;\n\t        this._errHandler.reportError(this, error);\n\t        this._errHandler.recover(this, error);\n\t    } else {\n\t    \tthrow error;\n\t    }\n    } finally {\n        this.unrollRecursionContexts(_parentctx)\n    }\n    return localctx;\n};\n\nfunction PredicatedContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_predicated;\n    this._valueExpression = null; // ValueExpressionContext\n    // return this;\n}\n\nPredicatedContext.prototype = Object.create(ParserRuleContext.prototype);\nPredicatedContext.prototype.constructor = PredicatedContext;\n\nPredicatedContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\n\nPredicatedContext.prototype.predicate = function() {\n    return this.getTypedRuleContext(PredicateContext,0);\n};\n\nPredicatedContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterPredicated(this);\n\t}\n};\n\nPredicatedContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitPredicated(this);\n\t}\n};\n\nPredicatedContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitPredicated(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.PredicatedContext = PredicatedContext;\n\nSqlBaseParser.prototype.predicated = function() {\n\n    var localctx = new PredicatedContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 66, SqlBaseParser.RULE_predicated);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 883;\n        localctx._valueExpression = this.valueExpression(0);\n        this.state = 885;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,109,this._ctx);\n        if(la_===1) {\n            this.state = 884;\n            this.predicate(localctx._valueExpression);\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction PredicateContext(parser, parent, invokingState, value) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_predicate;\n    this.value = null\n    this.value = value || null;\n    // return this;\n}\n\nPredicateContext.prototype = Object.create(ParserRuleContext.prototype);\nPredicateContext.prototype.constructor = PredicateContext;\n\n\n \nPredicateContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n    this.value = ctx.value;\n};\n\n\nfunction ComparisonContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    this.right = null; // ValueExpressionContext;\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nComparisonContext.prototype = Object.create(PredicateContext.prototype);\nComparisonContext.prototype.constructor = ComparisonContext;\n\nSqlBaseParser.ComparisonContext = ComparisonContext;\n\nComparisonContext.prototype.comparisonOperator = function() {\n    return this.getTypedRuleContext(ComparisonOperatorContext,0);\n};\n\nComparisonContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\nComparisonContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterComparison(this);\n\t}\n};\n\nComparisonContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitComparison(this);\n\t}\n};\n\nComparisonContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitComparison(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction LikeContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    this.pattern = null; // ValueExpressionContext;\n    this.escape = null; // ValueExpressionContext;\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nLikeContext.prototype = Object.create(PredicateContext.prototype);\nLikeContext.prototype.constructor = LikeContext;\n\nSqlBaseParser.LikeContext = LikeContext;\n\nLikeContext.prototype.LIKE = function() {\n    return this.getToken(SqlBaseParser.LIKE, 0);\n};\n\nLikeContext.prototype.valueExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ValueExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ValueExpressionContext,i);\n    }\n};\n\nLikeContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\n\nLikeContext.prototype.ESCAPE = function() {\n    return this.getToken(SqlBaseParser.ESCAPE, 0);\n};\nLikeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterLike(this);\n\t}\n};\n\nLikeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitLike(this);\n\t}\n};\n\nLikeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitLike(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction InSubqueryContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nInSubqueryContext.prototype = Object.create(PredicateContext.prototype);\nInSubqueryContext.prototype.constructor = InSubqueryContext;\n\nSqlBaseParser.InSubqueryContext = InSubqueryContext;\n\nInSubqueryContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\n\nInSubqueryContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\n\nInSubqueryContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\nInSubqueryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterInSubquery(this);\n\t}\n};\n\nInSubqueryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitInSubquery(this);\n\t}\n};\n\nInSubqueryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitInSubquery(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DistinctFromContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    this.right = null; // ValueExpressionContext;\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDistinctFromContext.prototype = Object.create(PredicateContext.prototype);\nDistinctFromContext.prototype.constructor = DistinctFromContext;\n\nSqlBaseParser.DistinctFromContext = DistinctFromContext;\n\nDistinctFromContext.prototype.IS = function() {\n    return this.getToken(SqlBaseParser.IS, 0);\n};\n\nDistinctFromContext.prototype.DISTINCT = function() {\n    return this.getToken(SqlBaseParser.DISTINCT, 0);\n};\n\nDistinctFromContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nDistinctFromContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\n\nDistinctFromContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\nDistinctFromContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDistinctFrom(this);\n\t}\n};\n\nDistinctFromContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDistinctFrom(this);\n\t}\n};\n\nDistinctFromContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDistinctFrom(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction InListContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nInListContext.prototype = Object.create(PredicateContext.prototype);\nInListContext.prototype.constructor = InListContext;\n\nSqlBaseParser.InListContext = InListContext;\n\nInListContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\n\nInListContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\n\nInListContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\nInListContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterInList(this);\n\t}\n};\n\nInListContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitInList(this);\n\t}\n};\n\nInListContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitInList(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction NullPredicateContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nNullPredicateContext.prototype = Object.create(PredicateContext.prototype);\nNullPredicateContext.prototype.constructor = NullPredicateContext;\n\nSqlBaseParser.NullPredicateContext = NullPredicateContext;\n\nNullPredicateContext.prototype.IS = function() {\n    return this.getToken(SqlBaseParser.IS, 0);\n};\n\nNullPredicateContext.prototype.NULL = function() {\n    return this.getToken(SqlBaseParser.NULL, 0);\n};\n\nNullPredicateContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\nNullPredicateContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNullPredicate(this);\n\t}\n};\n\nNullPredicateContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNullPredicate(this);\n\t}\n};\n\nNullPredicateContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNullPredicate(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction BetweenContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    this.lower = null; // ValueExpressionContext;\n    this.upper = null; // ValueExpressionContext;\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nBetweenContext.prototype = Object.create(PredicateContext.prototype);\nBetweenContext.prototype.constructor = BetweenContext;\n\nSqlBaseParser.BetweenContext = BetweenContext;\n\nBetweenContext.prototype.BETWEEN = function() {\n    return this.getToken(SqlBaseParser.BETWEEN, 0);\n};\n\nBetweenContext.prototype.AND = function() {\n    return this.getToken(SqlBaseParser.AND, 0);\n};\n\nBetweenContext.prototype.valueExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ValueExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ValueExpressionContext,i);\n    }\n};\n\nBetweenContext.prototype.NOT = function() {\n    return this.getToken(SqlBaseParser.NOT, 0);\n};\nBetweenContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBetween(this);\n\t}\n};\n\nBetweenContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBetween(this);\n\t}\n};\n\nBetweenContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBetween(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction QuantifiedComparisonContext(parser, ctx) {\n\tPredicateContext.call(this, parser);\n    PredicateContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nQuantifiedComparisonContext.prototype = Object.create(PredicateContext.prototype);\nQuantifiedComparisonContext.prototype.constructor = QuantifiedComparisonContext;\n\nSqlBaseParser.QuantifiedComparisonContext = QuantifiedComparisonContext;\n\nQuantifiedComparisonContext.prototype.comparisonOperator = function() {\n    return this.getTypedRuleContext(ComparisonOperatorContext,0);\n};\n\nQuantifiedComparisonContext.prototype.comparisonQuantifier = function() {\n    return this.getTypedRuleContext(ComparisonQuantifierContext,0);\n};\n\nQuantifiedComparisonContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\nQuantifiedComparisonContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQuantifiedComparison(this);\n\t}\n};\n\nQuantifiedComparisonContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQuantifiedComparison(this);\n\t}\n};\n\nQuantifiedComparisonContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQuantifiedComparison(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.PredicateContext = PredicateContext;\n\nSqlBaseParser.prototype.predicate = function(value) {\n\n    var localctx = new PredicateContext(this, this._ctx, this.state, value);\n    this.enterRule(localctx, 68, SqlBaseParser.RULE_predicate);\n    var _la = 0; // Token type\n    try {\n        this.state = 948;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,118,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new ComparisonContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 887;\n            this.comparisonOperator();\n            this.state = 888;\n            localctx.right = this.valueExpression(0);\n            break;\n\n        case 2:\n            localctx = new QuantifiedComparisonContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 890;\n            this.comparisonOperator();\n            this.state = 891;\n            this.comparisonQuantifier();\n            this.state = 892;\n            this.match(SqlBaseParser.T__1);\n            this.state = 893;\n            this.query();\n            this.state = 894;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 3:\n            localctx = new BetweenContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 897;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.NOT) {\n                this.state = 896;\n                this.match(SqlBaseParser.NOT);\n            }\n\n            this.state = 899;\n            this.match(SqlBaseParser.BETWEEN);\n            this.state = 900;\n            localctx.lower = this.valueExpression(0);\n            this.state = 901;\n            this.match(SqlBaseParser.AND);\n            this.state = 902;\n            localctx.upper = this.valueExpression(0);\n            break;\n\n        case 4:\n            localctx = new InListContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 905;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.NOT) {\n                this.state = 904;\n                this.match(SqlBaseParser.NOT);\n            }\n\n            this.state = 907;\n            this.match(SqlBaseParser.IN);\n            this.state = 908;\n            this.match(SqlBaseParser.T__1);\n            this.state = 909;\n            this.expression();\n            this.state = 914;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 910;\n                this.match(SqlBaseParser.T__2);\n                this.state = 911;\n                this.expression();\n                this.state = 916;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 917;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 5:\n            localctx = new InSubqueryContext(this, localctx);\n            this.enterOuterAlt(localctx, 5);\n            this.state = 920;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.NOT) {\n                this.state = 919;\n                this.match(SqlBaseParser.NOT);\n            }\n\n            this.state = 922;\n            this.match(SqlBaseParser.IN);\n            this.state = 923;\n            this.match(SqlBaseParser.T__1);\n            this.state = 924;\n            this.query();\n            this.state = 925;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 6:\n            localctx = new LikeContext(this, localctx);\n            this.enterOuterAlt(localctx, 6);\n            this.state = 928;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.NOT) {\n                this.state = 927;\n                this.match(SqlBaseParser.NOT);\n            }\n\n            this.state = 930;\n            this.match(SqlBaseParser.LIKE);\n            this.state = 931;\n            localctx.pattern = this.valueExpression(0);\n            this.state = 934;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,115,this._ctx);\n            if(la_===1) {\n                this.state = 932;\n                this.match(SqlBaseParser.ESCAPE);\n                this.state = 933;\n                localctx.escape = this.valueExpression(0);\n\n            }\n            break;\n\n        case 7:\n            localctx = new NullPredicateContext(this, localctx);\n            this.enterOuterAlt(localctx, 7);\n            this.state = 936;\n            this.match(SqlBaseParser.IS);\n            this.state = 938;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.NOT) {\n                this.state = 937;\n                this.match(SqlBaseParser.NOT);\n            }\n\n            this.state = 940;\n            this.match(SqlBaseParser.NULL);\n            break;\n\n        case 8:\n            localctx = new DistinctFromContext(this, localctx);\n            this.enterOuterAlt(localctx, 8);\n            this.state = 941;\n            this.match(SqlBaseParser.IS);\n            this.state = 943;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.NOT) {\n                this.state = 942;\n                this.match(SqlBaseParser.NOT);\n            }\n\n            this.state = 945;\n            this.match(SqlBaseParser.DISTINCT);\n            this.state = 946;\n            this.match(SqlBaseParser.FROM);\n            this.state = 947;\n            localctx.right = this.valueExpression(0);\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ValueExpressionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_valueExpression;\n    // return this;\n}\n\nValueExpressionContext.prototype = Object.create(ParserRuleContext.prototype);\nValueExpressionContext.prototype.constructor = ValueExpressionContext;\n\n\n \nValueExpressionContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\nfunction ValueExpressionDefaultContext(parser, ctx) {\n\tValueExpressionContext.call(this, parser);\n    ValueExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nValueExpressionDefaultContext.prototype = Object.create(ValueExpressionContext.prototype);\nValueExpressionDefaultContext.prototype.constructor = ValueExpressionDefaultContext;\n\nSqlBaseParser.ValueExpressionDefaultContext = ValueExpressionDefaultContext;\n\nValueExpressionDefaultContext.prototype.primaryExpression = function() {\n    return this.getTypedRuleContext(PrimaryExpressionContext,0);\n};\nValueExpressionDefaultContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterValueExpressionDefault(this);\n\t}\n};\n\nValueExpressionDefaultContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitValueExpressionDefault(this);\n\t}\n};\n\nValueExpressionDefaultContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitValueExpressionDefault(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ConcatenationContext(parser, ctx) {\n\tValueExpressionContext.call(this, parser);\n    this.left = null; // ValueExpressionContext;\n    this.right = null; // ValueExpressionContext;\n    ValueExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nConcatenationContext.prototype = Object.create(ValueExpressionContext.prototype);\nConcatenationContext.prototype.constructor = ConcatenationContext;\n\nSqlBaseParser.ConcatenationContext = ConcatenationContext;\n\nConcatenationContext.prototype.CONCAT = function() {\n    return this.getToken(SqlBaseParser.CONCAT, 0);\n};\n\nConcatenationContext.prototype.valueExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ValueExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ValueExpressionContext,i);\n    }\n};\nConcatenationContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterConcatenation(this);\n\t}\n};\n\nConcatenationContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitConcatenation(this);\n\t}\n};\n\nConcatenationContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitConcatenation(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ArithmeticBinaryContext(parser, ctx) {\n\tValueExpressionContext.call(this, parser);\n    this.left = null; // ValueExpressionContext;\n    this.operator = null; // Token;\n    this.right = null; // ValueExpressionContext;\n    ValueExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nArithmeticBinaryContext.prototype = Object.create(ValueExpressionContext.prototype);\nArithmeticBinaryContext.prototype.constructor = ArithmeticBinaryContext;\n\nSqlBaseParser.ArithmeticBinaryContext = ArithmeticBinaryContext;\n\nArithmeticBinaryContext.prototype.valueExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ValueExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ValueExpressionContext,i);\n    }\n};\n\nArithmeticBinaryContext.prototype.ASTERISK = function() {\n    return this.getToken(SqlBaseParser.ASTERISK, 0);\n};\n\nArithmeticBinaryContext.prototype.SLASH = function() {\n    return this.getToken(SqlBaseParser.SLASH, 0);\n};\n\nArithmeticBinaryContext.prototype.PERCENT = function() {\n    return this.getToken(SqlBaseParser.PERCENT, 0);\n};\n\nArithmeticBinaryContext.prototype.PLUS = function() {\n    return this.getToken(SqlBaseParser.PLUS, 0);\n};\n\nArithmeticBinaryContext.prototype.MINUS = function() {\n    return this.getToken(SqlBaseParser.MINUS, 0);\n};\nArithmeticBinaryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterArithmeticBinary(this);\n\t}\n};\n\nArithmeticBinaryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitArithmeticBinary(this);\n\t}\n};\n\nArithmeticBinaryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitArithmeticBinary(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ArithmeticUnaryContext(parser, ctx) {\n\tValueExpressionContext.call(this, parser);\n    this.operator = null; // Token;\n    ValueExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nArithmeticUnaryContext.prototype = Object.create(ValueExpressionContext.prototype);\nArithmeticUnaryContext.prototype.constructor = ArithmeticUnaryContext;\n\nSqlBaseParser.ArithmeticUnaryContext = ArithmeticUnaryContext;\n\nArithmeticUnaryContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\n\nArithmeticUnaryContext.prototype.MINUS = function() {\n    return this.getToken(SqlBaseParser.MINUS, 0);\n};\n\nArithmeticUnaryContext.prototype.PLUS = function() {\n    return this.getToken(SqlBaseParser.PLUS, 0);\n};\nArithmeticUnaryContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterArithmeticUnary(this);\n\t}\n};\n\nArithmeticUnaryContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitArithmeticUnary(this);\n\t}\n};\n\nArithmeticUnaryContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitArithmeticUnary(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction AtTimeZoneContext(parser, ctx) {\n\tValueExpressionContext.call(this, parser);\n    ValueExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nAtTimeZoneContext.prototype = Object.create(ValueExpressionContext.prototype);\nAtTimeZoneContext.prototype.constructor = AtTimeZoneContext;\n\nSqlBaseParser.AtTimeZoneContext = AtTimeZoneContext;\n\nAtTimeZoneContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\n\nAtTimeZoneContext.prototype.AT = function() {\n    return this.getToken(SqlBaseParser.AT, 0);\n};\n\nAtTimeZoneContext.prototype.timeZoneSpecifier = function() {\n    return this.getTypedRuleContext(TimeZoneSpecifierContext,0);\n};\nAtTimeZoneContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterAtTimeZone(this);\n\t}\n};\n\nAtTimeZoneContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitAtTimeZone(this);\n\t}\n};\n\nAtTimeZoneContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitAtTimeZone(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.prototype.valueExpression = function(_p) {\n\tif(_p===undefined) {\n\t    _p = 0;\n\t}\n    var _parentctx = this._ctx;\n    var _parentState = this.state;\n    var localctx = new ValueExpressionContext(this, this._ctx, _parentState);\n    var _prevctx = localctx;\n    var _startState = 70;\n    this.enterRecursionRule(localctx, 70, SqlBaseParser.RULE_valueExpression, _p);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 954;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.T__1:\n        case SqlBaseParser.T__4:\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.EXISTS:\n        case SqlBaseParser.NULL:\n        case SqlBaseParser.TRUE:\n        case SqlBaseParser.FALSE:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.CURRENT_DATE:\n        case SqlBaseParser.CURRENT_TIME:\n        case SqlBaseParser.CURRENT_TIMESTAMP:\n        case SqlBaseParser.LOCALTIME:\n        case SqlBaseParser.LOCALTIMESTAMP:\n        case SqlBaseParser.EXTRACT:\n        case SqlBaseParser.CASE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.CAST:\n        case SqlBaseParser.TRY_CAST:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NORMALIZE:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.STRING:\n        case SqlBaseParser.BINARY_LITERAL:\n        case SqlBaseParser.INTEGER_VALUE:\n        case SqlBaseParser.DECIMAL_VALUE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n        case SqlBaseParser.DOUBLE_PRECISION:\n            localctx = new ValueExpressionDefaultContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n\n            this.state = 951;\n            this.primaryExpression(0);\n            break;\n        case SqlBaseParser.PLUS:\n        case SqlBaseParser.MINUS:\n            localctx = new ArithmeticUnaryContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 952;\n            localctx.operator = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS)) {\n                localctx.operator = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            this.state = 953;\n            this.valueExpression(4);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n        this._ctx.stop = this._input.LT(-1);\n        this.state = 970;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,121,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                if(this._parseListeners!==null) {\n                    this.triggerExitRuleEvent();\n                }\n                _prevctx = localctx;\n                this.state = 968;\n                this._errHandler.sync(this);\n                var la_ = this._interp.adaptivePredict(this._input,120,this._ctx);\n                switch(la_) {\n                case 1:\n                    localctx = new ArithmeticBinaryContext(this, new ValueExpressionContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression);\n                    this.state = 956;\n                    if (!( this.precpred(this._ctx, 3))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 3)\");\n                    }\n                    this.state = 957;\n                    localctx.operator = this._input.LT(1);\n                    _la = this._input.LA(1);\n                    if(!(((((_la - 192)) & ~0x1f) == 0 && ((1 << (_la - 192)) & ((1 << (SqlBaseParser.ASTERISK - 192)) | (1 << (SqlBaseParser.SLASH - 192)) | (1 << (SqlBaseParser.PERCENT - 192)))) !== 0))) {\n                        localctx.operator = this._errHandler.recoverInline(this);\n                    }\n                    else {\n                    \tthis._errHandler.reportMatch(this);\n                        this.consume();\n                    }\n                    this.state = 958;\n                    localctx.right = this.valueExpression(4);\n                    break;\n\n                case 2:\n                    localctx = new ArithmeticBinaryContext(this, new ValueExpressionContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression);\n                    this.state = 959;\n                    if (!( this.precpred(this._ctx, 2))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 2)\");\n                    }\n                    this.state = 960;\n                    localctx.operator = this._input.LT(1);\n                    _la = this._input.LA(1);\n                    if(!(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS)) {\n                        localctx.operator = this._errHandler.recoverInline(this);\n                    }\n                    else {\n                    \tthis._errHandler.reportMatch(this);\n                        this.consume();\n                    }\n                    this.state = 961;\n                    localctx.right = this.valueExpression(3);\n                    break;\n\n                case 3:\n                    localctx = new ConcatenationContext(this, new ValueExpressionContext(this, _parentctx, _parentState));\n                    localctx.left = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression);\n                    this.state = 962;\n                    if (!( this.precpred(this._ctx, 1))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 1)\");\n                    }\n                    this.state = 963;\n                    this.match(SqlBaseParser.CONCAT);\n                    this.state = 964;\n                    localctx.right = this.valueExpression(2);\n                    break;\n\n                case 4:\n                    localctx = new AtTimeZoneContext(this, new ValueExpressionContext(this, _parentctx, _parentState));\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_valueExpression);\n                    this.state = 965;\n                    if (!( this.precpred(this._ctx, 5))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 5)\");\n                    }\n                    this.state = 966;\n                    this.match(SqlBaseParser.AT);\n                    this.state = 967;\n                    this.timeZoneSpecifier();\n                    break;\n\n                } \n            }\n            this.state = 972;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,121,this._ctx);\n        }\n\n    } catch( error) {\n        if(error instanceof _error.RecognitionException) {\n\t        localctx.exception = error;\n\t        this._errHandler.reportError(this, error);\n\t        this._errHandler.recover(this, error);\n\t    } else {\n\t    \tthrow error;\n\t    }\n    } finally {\n        this.unrollRecursionContexts(_parentctx)\n    }\n    return localctx;\n};\n\nfunction PrimaryExpressionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_primaryExpression;\n    // return this;\n}\n\nPrimaryExpressionContext.prototype = Object.create(ParserRuleContext.prototype);\nPrimaryExpressionContext.prototype.constructor = PrimaryExpressionContext;\n\n\n \nPrimaryExpressionContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\nfunction DereferenceContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    this.base = null; // PrimaryExpressionContext;\n    this.fieldName = null; // IdentifierContext;\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDereferenceContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nDereferenceContext.prototype.constructor = DereferenceContext;\n\nSqlBaseParser.DereferenceContext = DereferenceContext;\n\nDereferenceContext.prototype.primaryExpression = function() {\n    return this.getTypedRuleContext(PrimaryExpressionContext,0);\n};\n\nDereferenceContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\nDereferenceContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDereference(this);\n\t}\n};\n\nDereferenceContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDereference(this);\n\t}\n};\n\nDereferenceContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDereference(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction TypeConstructorContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nTypeConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nTypeConstructorContext.prototype.constructor = TypeConstructorContext;\n\nSqlBaseParser.TypeConstructorContext = TypeConstructorContext;\n\nTypeConstructorContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nTypeConstructorContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\n\nTypeConstructorContext.prototype.DOUBLE_PRECISION = function() {\n    return this.getToken(SqlBaseParser.DOUBLE_PRECISION, 0);\n};\nTypeConstructorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTypeConstructor(this);\n\t}\n};\n\nTypeConstructorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTypeConstructor(this);\n\t}\n};\n\nTypeConstructorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTypeConstructor(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SpecialDateTimeFunctionContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    this.name = null; // Token;\n    this.precision = null; // Token;\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSpecialDateTimeFunctionContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nSpecialDateTimeFunctionContext.prototype.constructor = SpecialDateTimeFunctionContext;\n\nSqlBaseParser.SpecialDateTimeFunctionContext = SpecialDateTimeFunctionContext;\n\nSpecialDateTimeFunctionContext.prototype.CURRENT_DATE = function() {\n    return this.getToken(SqlBaseParser.CURRENT_DATE, 0);\n};\n\nSpecialDateTimeFunctionContext.prototype.CURRENT_TIME = function() {\n    return this.getToken(SqlBaseParser.CURRENT_TIME, 0);\n};\n\nSpecialDateTimeFunctionContext.prototype.INTEGER_VALUE = function() {\n    return this.getToken(SqlBaseParser.INTEGER_VALUE, 0);\n};\n\nSpecialDateTimeFunctionContext.prototype.CURRENT_TIMESTAMP = function() {\n    return this.getToken(SqlBaseParser.CURRENT_TIMESTAMP, 0);\n};\n\nSpecialDateTimeFunctionContext.prototype.LOCALTIME = function() {\n    return this.getToken(SqlBaseParser.LOCALTIME, 0);\n};\n\nSpecialDateTimeFunctionContext.prototype.LOCALTIMESTAMP = function() {\n    return this.getToken(SqlBaseParser.LOCALTIMESTAMP, 0);\n};\nSpecialDateTimeFunctionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSpecialDateTimeFunction(this);\n\t}\n};\n\nSpecialDateTimeFunctionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSpecialDateTimeFunction(this);\n\t}\n};\n\nSpecialDateTimeFunctionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSpecialDateTimeFunction(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SubstringContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSubstringContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nSubstringContext.prototype.constructor = SubstringContext;\n\nSqlBaseParser.SubstringContext = SubstringContext;\n\nSubstringContext.prototype.SUBSTRING = function() {\n    return this.getToken(SqlBaseParser.SUBSTRING, 0);\n};\n\nSubstringContext.prototype.valueExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ValueExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ValueExpressionContext,i);\n    }\n};\n\nSubstringContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nSubstringContext.prototype.FOR = function() {\n    return this.getToken(SqlBaseParser.FOR, 0);\n};\nSubstringContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSubstring(this);\n\t}\n};\n\nSubstringContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSubstring(this);\n\t}\n};\n\nSubstringContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSubstring(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CastContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCastContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nCastContext.prototype.constructor = CastContext;\n\nSqlBaseParser.CastContext = CastContext;\n\nCastContext.prototype.CAST = function() {\n    return this.getToken(SqlBaseParser.CAST, 0);\n};\n\nCastContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nCastContext.prototype.AS = function() {\n    return this.getToken(SqlBaseParser.AS, 0);\n};\n\nCastContext.prototype.type = function() {\n    return this.getTypedRuleContext(TypeContext,0);\n};\n\nCastContext.prototype.TRY_CAST = function() {\n    return this.getToken(SqlBaseParser.TRY_CAST, 0);\n};\nCastContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCast(this);\n\t}\n};\n\nCastContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCast(this);\n\t}\n};\n\nCastContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCast(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction LambdaContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nLambdaContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nLambdaContext.prototype.constructor = LambdaContext;\n\nSqlBaseParser.LambdaContext = LambdaContext;\n\nLambdaContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\n\nLambdaContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\nLambdaContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterLambda(this);\n\t}\n};\n\nLambdaContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitLambda(this);\n\t}\n};\n\nLambdaContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitLambda(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ParameterContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nParameterContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nParameterContext.prototype.constructor = ParameterContext;\n\nSqlBaseParser.ParameterContext = ParameterContext;\n\nParameterContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterParameter(this);\n\t}\n};\n\nParameterContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitParameter(this);\n\t}\n};\n\nParameterContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitParameter(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction NormalizeContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nNormalizeContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nNormalizeContext.prototype.constructor = NormalizeContext;\n\nSqlBaseParser.NormalizeContext = NormalizeContext;\n\nNormalizeContext.prototype.NORMALIZE = function() {\n    return this.getToken(SqlBaseParser.NORMALIZE, 0);\n};\n\nNormalizeContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\n\nNormalizeContext.prototype.normalForm = function() {\n    return this.getTypedRuleContext(NormalFormContext,0);\n};\nNormalizeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNormalize(this);\n\t}\n};\n\nNormalizeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNormalize(this);\n\t}\n};\n\nNormalizeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNormalize(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction IntervalLiteralContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nIntervalLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nIntervalLiteralContext.prototype.constructor = IntervalLiteralContext;\n\nSqlBaseParser.IntervalLiteralContext = IntervalLiteralContext;\n\nIntervalLiteralContext.prototype.interval = function() {\n    return this.getTypedRuleContext(IntervalContext,0);\n};\nIntervalLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterIntervalLiteral(this);\n\t}\n};\n\nIntervalLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitIntervalLiteral(this);\n\t}\n};\n\nIntervalLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitIntervalLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction NumericLiteralContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nNumericLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nNumericLiteralContext.prototype.constructor = NumericLiteralContext;\n\nSqlBaseParser.NumericLiteralContext = NumericLiteralContext;\n\nNumericLiteralContext.prototype.number = function() {\n    return this.getTypedRuleContext(NumberContext,0);\n};\nNumericLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNumericLiteral(this);\n\t}\n};\n\nNumericLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNumericLiteral(this);\n\t}\n};\n\nNumericLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNumericLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction BooleanLiteralContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nBooleanLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nBooleanLiteralContext.prototype.constructor = BooleanLiteralContext;\n\nSqlBaseParser.BooleanLiteralContext = BooleanLiteralContext;\n\nBooleanLiteralContext.prototype.booleanValue = function() {\n    return this.getTypedRuleContext(BooleanValueContext,0);\n};\nBooleanLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBooleanLiteral(this);\n\t}\n};\n\nBooleanLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBooleanLiteral(this);\n\t}\n};\n\nBooleanLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBooleanLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ImplicitRowConstructorContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nImplicitRowConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nImplicitRowConstructorContext.prototype.constructor = ImplicitRowConstructorContext;\n\nSqlBaseParser.ImplicitRowConstructorContext = ImplicitRowConstructorContext;\n\nImplicitRowConstructorContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\nImplicitRowConstructorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterImplicitRowConstructor(this);\n\t}\n};\n\nImplicitRowConstructorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitImplicitRowConstructor(this);\n\t}\n};\n\nImplicitRowConstructorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitImplicitRowConstructor(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SimpleCaseContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    this.elseExpression = null; // ExpressionContext;\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSimpleCaseContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nSimpleCaseContext.prototype.constructor = SimpleCaseContext;\n\nSqlBaseParser.SimpleCaseContext = SimpleCaseContext;\n\nSimpleCaseContext.prototype.CASE = function() {\n    return this.getToken(SqlBaseParser.CASE, 0);\n};\n\nSimpleCaseContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\n\nSimpleCaseContext.prototype.END = function() {\n    return this.getToken(SqlBaseParser.END, 0);\n};\n\nSimpleCaseContext.prototype.whenClause = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(WhenClauseContext);\n    } else {\n        return this.getTypedRuleContext(WhenClauseContext,i);\n    }\n};\n\nSimpleCaseContext.prototype.ELSE = function() {\n    return this.getToken(SqlBaseParser.ELSE, 0);\n};\n\nSimpleCaseContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\nSimpleCaseContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSimpleCase(this);\n\t}\n};\n\nSimpleCaseContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSimpleCase(this);\n\t}\n};\n\nSimpleCaseContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSimpleCase(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ColumnReferenceContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nColumnReferenceContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nColumnReferenceContext.prototype.constructor = ColumnReferenceContext;\n\nSqlBaseParser.ColumnReferenceContext = ColumnReferenceContext;\n\nColumnReferenceContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\nColumnReferenceContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterColumnReference(this);\n\t}\n};\n\nColumnReferenceContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitColumnReference(this);\n\t}\n};\n\nColumnReferenceContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitColumnReference(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction NullLiteralContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nNullLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nNullLiteralContext.prototype.constructor = NullLiteralContext;\n\nSqlBaseParser.NullLiteralContext = NullLiteralContext;\n\nNullLiteralContext.prototype.NULL = function() {\n    return this.getToken(SqlBaseParser.NULL, 0);\n};\nNullLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNullLiteral(this);\n\t}\n};\n\nNullLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNullLiteral(this);\n\t}\n};\n\nNullLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNullLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RowConstructorContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRowConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nRowConstructorContext.prototype.constructor = RowConstructorContext;\n\nSqlBaseParser.RowConstructorContext = RowConstructorContext;\n\nRowConstructorContext.prototype.ROW = function() {\n    return this.getToken(SqlBaseParser.ROW, 0);\n};\n\nRowConstructorContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\nRowConstructorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRowConstructor(this);\n\t}\n};\n\nRowConstructorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRowConstructor(this);\n\t}\n};\n\nRowConstructorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRowConstructor(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SubscriptContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    this.value = null; // PrimaryExpressionContext;\n    this.index = null; // ValueExpressionContext;\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSubscriptContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nSubscriptContext.prototype.constructor = SubscriptContext;\n\nSqlBaseParser.SubscriptContext = SubscriptContext;\n\nSubscriptContext.prototype.primaryExpression = function() {\n    return this.getTypedRuleContext(PrimaryExpressionContext,0);\n};\n\nSubscriptContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\nSubscriptContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSubscript(this);\n\t}\n};\n\nSubscriptContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSubscript(this);\n\t}\n};\n\nSubscriptContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSubscript(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SubqueryExpressionContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSubqueryExpressionContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nSubqueryExpressionContext.prototype.constructor = SubqueryExpressionContext;\n\nSqlBaseParser.SubqueryExpressionContext = SubqueryExpressionContext;\n\nSubqueryExpressionContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\nSubqueryExpressionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSubqueryExpression(this);\n\t}\n};\n\nSubqueryExpressionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSubqueryExpression(this);\n\t}\n};\n\nSubqueryExpressionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSubqueryExpression(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction BinaryLiteralContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nBinaryLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nBinaryLiteralContext.prototype.constructor = BinaryLiteralContext;\n\nSqlBaseParser.BinaryLiteralContext = BinaryLiteralContext;\n\nBinaryLiteralContext.prototype.BINARY_LITERAL = function() {\n    return this.getToken(SqlBaseParser.BINARY_LITERAL, 0);\n};\nBinaryLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBinaryLiteral(this);\n\t}\n};\n\nBinaryLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBinaryLiteral(this);\n\t}\n};\n\nBinaryLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBinaryLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ExtractContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nExtractContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nExtractContext.prototype.constructor = ExtractContext;\n\nSqlBaseParser.ExtractContext = ExtractContext;\n\nExtractContext.prototype.EXTRACT = function() {\n    return this.getToken(SqlBaseParser.EXTRACT, 0);\n};\n\nExtractContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nExtractContext.prototype.FROM = function() {\n    return this.getToken(SqlBaseParser.FROM, 0);\n};\n\nExtractContext.prototype.valueExpression = function() {\n    return this.getTypedRuleContext(ValueExpressionContext,0);\n};\nExtractContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExtract(this);\n\t}\n};\n\nExtractContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExtract(this);\n\t}\n};\n\nExtractContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExtract(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction StringLiteralContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nStringLiteralContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nStringLiteralContext.prototype.constructor = StringLiteralContext;\n\nSqlBaseParser.StringLiteralContext = StringLiteralContext;\n\nStringLiteralContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\nStringLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterStringLiteral(this);\n\t}\n};\n\nStringLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitStringLiteral(this);\n\t}\n};\n\nStringLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitStringLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ArrayConstructorContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nArrayConstructorContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nArrayConstructorContext.prototype.constructor = ArrayConstructorContext;\n\nSqlBaseParser.ArrayConstructorContext = ArrayConstructorContext;\n\nArrayConstructorContext.prototype.ARRAY = function() {\n    return this.getToken(SqlBaseParser.ARRAY, 0);\n};\n\nArrayConstructorContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\nArrayConstructorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterArrayConstructor(this);\n\t}\n};\n\nArrayConstructorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitArrayConstructor(this);\n\t}\n};\n\nArrayConstructorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitArrayConstructor(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction FunctionCallContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nFunctionCallContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nFunctionCallContext.prototype.constructor = FunctionCallContext;\n\nSqlBaseParser.FunctionCallContext = FunctionCallContext;\n\nFunctionCallContext.prototype.qualifiedName = function() {\n    return this.getTypedRuleContext(QualifiedNameContext,0);\n};\n\nFunctionCallContext.prototype.ASTERISK = function() {\n    return this.getToken(SqlBaseParser.ASTERISK, 0);\n};\n\nFunctionCallContext.prototype.filter = function() {\n    return this.getTypedRuleContext(FilterContext,0);\n};\n\nFunctionCallContext.prototype.over = function() {\n    return this.getTypedRuleContext(OverContext,0);\n};\n\nFunctionCallContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\n\nFunctionCallContext.prototype.setQuantifier = function() {\n    return this.getTypedRuleContext(SetQuantifierContext,0);\n};\nFunctionCallContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterFunctionCall(this);\n\t}\n};\n\nFunctionCallContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitFunctionCall(this);\n\t}\n};\n\nFunctionCallContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitFunctionCall(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ExistsContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nExistsContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nExistsContext.prototype.constructor = ExistsContext;\n\nSqlBaseParser.ExistsContext = ExistsContext;\n\nExistsContext.prototype.EXISTS = function() {\n    return this.getToken(SqlBaseParser.EXISTS, 0);\n};\n\nExistsContext.prototype.query = function() {\n    return this.getTypedRuleContext(QueryContext,0);\n};\nExistsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExists(this);\n\t}\n};\n\nExistsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExists(this);\n\t}\n};\n\nExistsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExists(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction PositionContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nPositionContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nPositionContext.prototype.constructor = PositionContext;\n\nSqlBaseParser.PositionContext = PositionContext;\n\nPositionContext.prototype.POSITION = function() {\n    return this.getToken(SqlBaseParser.POSITION, 0);\n};\n\nPositionContext.prototype.valueExpression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ValueExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ValueExpressionContext,i);\n    }\n};\n\nPositionContext.prototype.IN = function() {\n    return this.getToken(SqlBaseParser.IN, 0);\n};\nPositionContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterPosition(this);\n\t}\n};\n\nPositionContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitPosition(this);\n\t}\n};\n\nPositionContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitPosition(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SearchedCaseContext(parser, ctx) {\n\tPrimaryExpressionContext.call(this, parser);\n    this.elseExpression = null; // ExpressionContext;\n    PrimaryExpressionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSearchedCaseContext.prototype = Object.create(PrimaryExpressionContext.prototype);\nSearchedCaseContext.prototype.constructor = SearchedCaseContext;\n\nSqlBaseParser.SearchedCaseContext = SearchedCaseContext;\n\nSearchedCaseContext.prototype.CASE = function() {\n    return this.getToken(SqlBaseParser.CASE, 0);\n};\n\nSearchedCaseContext.prototype.END = function() {\n    return this.getToken(SqlBaseParser.END, 0);\n};\n\nSearchedCaseContext.prototype.whenClause = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(WhenClauseContext);\n    } else {\n        return this.getTypedRuleContext(WhenClauseContext,i);\n    }\n};\n\nSearchedCaseContext.prototype.ELSE = function() {\n    return this.getToken(SqlBaseParser.ELSE, 0);\n};\n\nSearchedCaseContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\nSearchedCaseContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSearchedCase(this);\n\t}\n};\n\nSearchedCaseContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSearchedCase(this);\n\t}\n};\n\nSearchedCaseContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSearchedCase(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.prototype.primaryExpression = function(_p) {\n\tif(_p===undefined) {\n\t    _p = 0;\n\t}\n    var _parentctx = this._ctx;\n    var _parentState = this.state;\n    var localctx = new PrimaryExpressionContext(this, this._ctx, _parentState);\n    var _prevctx = localctx;\n    var _startState = 72;\n    this.enterRecursionRule(localctx, 72, SqlBaseParser.RULE_primaryExpression, _p);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1179;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,144,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new NullLiteralContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n\n            this.state = 974;\n            this.match(SqlBaseParser.NULL);\n            break;\n\n        case 2:\n            localctx = new IntervalLiteralContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 975;\n            this.interval();\n            break;\n\n        case 3:\n            localctx = new TypeConstructorContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 976;\n            this.identifier();\n            this.state = 977;\n            this.match(SqlBaseParser.STRING);\n            break;\n\n        case 4:\n            localctx = new TypeConstructorContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 979;\n            this.match(SqlBaseParser.DOUBLE_PRECISION);\n            this.state = 980;\n            this.match(SqlBaseParser.STRING);\n            break;\n\n        case 5:\n            localctx = new NumericLiteralContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 981;\n            this.number();\n            break;\n\n        case 6:\n            localctx = new BooleanLiteralContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 982;\n            this.booleanValue();\n            break;\n\n        case 7:\n            localctx = new StringLiteralContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 983;\n            this.match(SqlBaseParser.STRING);\n            break;\n\n        case 8:\n            localctx = new BinaryLiteralContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 984;\n            this.match(SqlBaseParser.BINARY_LITERAL);\n            break;\n\n        case 9:\n            localctx = new ParameterContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 985;\n            this.match(SqlBaseParser.T__4);\n            break;\n\n        case 10:\n            localctx = new PositionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 986;\n            this.match(SqlBaseParser.POSITION);\n            this.state = 987;\n            this.match(SqlBaseParser.T__1);\n            this.state = 988;\n            this.valueExpression(0);\n            this.state = 989;\n            this.match(SqlBaseParser.IN);\n            this.state = 990;\n            this.valueExpression(0);\n            this.state = 991;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 11:\n            localctx = new ImplicitRowConstructorContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 993;\n            this.match(SqlBaseParser.T__1);\n            this.state = 994;\n            this.expression();\n            this.state = 999;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 995;\n                this.match(SqlBaseParser.T__2);\n                this.state = 996;\n                this.expression();\n                this.state = 1001;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 1002;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 12:\n            localctx = new RowConstructorContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1004;\n            this.match(SqlBaseParser.ROW);\n            this.state = 1005;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1006;\n            this.expression();\n            this.state = 1011;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 1007;\n                this.match(SqlBaseParser.T__2);\n                this.state = 1008;\n                this.expression();\n                this.state = 1013;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 1014;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 13:\n            localctx = new FunctionCallContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1016;\n            this.qualifiedName();\n            this.state = 1017;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1018;\n            this.match(SqlBaseParser.ASTERISK);\n            this.state = 1019;\n            this.match(SqlBaseParser.T__3);\n            this.state = 1021;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,124,this._ctx);\n            if(la_===1) {\n                this.state = 1020;\n                this.filter();\n\n            }\n            this.state = 1024;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,125,this._ctx);\n            if(la_===1) {\n                this.state = 1023;\n                this.over();\n\n            }\n            break;\n\n        case 14:\n            localctx = new FunctionCallContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1026;\n            this.qualifiedName();\n            this.state = 1027;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1039;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 1029;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                if(_la===SqlBaseParser.ALL || _la===SqlBaseParser.DISTINCT) {\n                    this.state = 1028;\n                    this.setQuantifier();\n                }\n\n                this.state = 1031;\n                this.expression();\n                this.state = 1036;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 1032;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 1033;\n                    this.expression();\n                    this.state = 1038;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 1041;\n            this.match(SqlBaseParser.T__3);\n            this.state = 1043;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,129,this._ctx);\n            if(la_===1) {\n                this.state = 1042;\n                this.filter();\n\n            }\n            this.state = 1046;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,130,this._ctx);\n            if(la_===1) {\n                this.state = 1045;\n                this.over();\n\n            }\n            break;\n\n        case 15:\n            localctx = new LambdaContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1048;\n            this.identifier();\n            this.state = 1049;\n            this.match(SqlBaseParser.T__5);\n            this.state = 1050;\n            this.expression();\n            break;\n\n        case 16:\n            localctx = new LambdaContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1052;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1053;\n            this.identifier();\n            this.state = 1058;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 1054;\n                this.match(SqlBaseParser.T__2);\n                this.state = 1055;\n                this.identifier();\n                this.state = 1060;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 1061;\n            this.match(SqlBaseParser.T__3);\n            this.state = 1062;\n            this.match(SqlBaseParser.T__5);\n            this.state = 1063;\n            this.expression();\n            break;\n\n        case 17:\n            localctx = new SubqueryExpressionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1065;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1066;\n            this.query();\n            this.state = 1067;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 18:\n            localctx = new ExistsContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1069;\n            this.match(SqlBaseParser.EXISTS);\n            this.state = 1070;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1071;\n            this.query();\n            this.state = 1072;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 19:\n            localctx = new SimpleCaseContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1074;\n            this.match(SqlBaseParser.CASE);\n            this.state = 1075;\n            this.valueExpression(0);\n            this.state = 1077; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            do {\n                this.state = 1076;\n                this.whenClause();\n                this.state = 1079; \n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            } while(_la===SqlBaseParser.WHEN);\n            this.state = 1083;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.ELSE) {\n                this.state = 1081;\n                this.match(SqlBaseParser.ELSE);\n                this.state = 1082;\n                localctx.elseExpression = this.expression();\n            }\n\n            this.state = 1085;\n            this.match(SqlBaseParser.END);\n            break;\n\n        case 20:\n            localctx = new SearchedCaseContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1087;\n            this.match(SqlBaseParser.CASE);\n            this.state = 1089; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            do {\n                this.state = 1088;\n                this.whenClause();\n                this.state = 1091; \n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            } while(_la===SqlBaseParser.WHEN);\n            this.state = 1095;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.ELSE) {\n                this.state = 1093;\n                this.match(SqlBaseParser.ELSE);\n                this.state = 1094;\n                localctx.elseExpression = this.expression();\n            }\n\n            this.state = 1097;\n            this.match(SqlBaseParser.END);\n            break;\n\n        case 21:\n            localctx = new CastContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1099;\n            this.match(SqlBaseParser.CAST);\n            this.state = 1100;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1101;\n            this.expression();\n            this.state = 1102;\n            this.match(SqlBaseParser.AS);\n            this.state = 1103;\n            this.type(0);\n            this.state = 1104;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 22:\n            localctx = new CastContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1106;\n            this.match(SqlBaseParser.TRY_CAST);\n            this.state = 1107;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1108;\n            this.expression();\n            this.state = 1109;\n            this.match(SqlBaseParser.AS);\n            this.state = 1110;\n            this.type(0);\n            this.state = 1111;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 23:\n            localctx = new ArrayConstructorContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1113;\n            this.match(SqlBaseParser.ARRAY);\n            this.state = 1114;\n            this.match(SqlBaseParser.T__6);\n            this.state = 1123;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 1115;\n                this.expression();\n                this.state = 1120;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 1116;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 1117;\n                    this.expression();\n                    this.state = 1122;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n            }\n\n            this.state = 1125;\n            this.match(SqlBaseParser.T__7);\n            break;\n\n        case 24:\n            localctx = new ColumnReferenceContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1126;\n            this.identifier();\n            break;\n\n        case 25:\n            localctx = new SpecialDateTimeFunctionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1127;\n            localctx.name = this.match(SqlBaseParser.CURRENT_DATE);\n            break;\n\n        case 26:\n            localctx = new SpecialDateTimeFunctionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1128;\n            localctx.name = this.match(SqlBaseParser.CURRENT_TIME);\n            this.state = 1132;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,138,this._ctx);\n            if(la_===1) {\n                this.state = 1129;\n                this.match(SqlBaseParser.T__1);\n                this.state = 1130;\n                localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE);\n                this.state = 1131;\n                this.match(SqlBaseParser.T__3);\n\n            }\n            break;\n\n        case 27:\n            localctx = new SpecialDateTimeFunctionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1134;\n            localctx.name = this.match(SqlBaseParser.CURRENT_TIMESTAMP);\n            this.state = 1138;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,139,this._ctx);\n            if(la_===1) {\n                this.state = 1135;\n                this.match(SqlBaseParser.T__1);\n                this.state = 1136;\n                localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE);\n                this.state = 1137;\n                this.match(SqlBaseParser.T__3);\n\n            }\n            break;\n\n        case 28:\n            localctx = new SpecialDateTimeFunctionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1140;\n            localctx.name = this.match(SqlBaseParser.LOCALTIME);\n            this.state = 1144;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,140,this._ctx);\n            if(la_===1) {\n                this.state = 1141;\n                this.match(SqlBaseParser.T__1);\n                this.state = 1142;\n                localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE);\n                this.state = 1143;\n                this.match(SqlBaseParser.T__3);\n\n            }\n            break;\n\n        case 29:\n            localctx = new SpecialDateTimeFunctionContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1146;\n            localctx.name = this.match(SqlBaseParser.LOCALTIMESTAMP);\n            this.state = 1150;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,141,this._ctx);\n            if(la_===1) {\n                this.state = 1147;\n                this.match(SqlBaseParser.T__1);\n                this.state = 1148;\n                localctx.precision = this.match(SqlBaseParser.INTEGER_VALUE);\n                this.state = 1149;\n                this.match(SqlBaseParser.T__3);\n\n            }\n            break;\n\n        case 30:\n            localctx = new SubstringContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1152;\n            this.match(SqlBaseParser.SUBSTRING);\n            this.state = 1153;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1154;\n            this.valueExpression(0);\n            this.state = 1155;\n            this.match(SqlBaseParser.FROM);\n            this.state = 1156;\n            this.valueExpression(0);\n            this.state = 1159;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.FOR) {\n                this.state = 1157;\n                this.match(SqlBaseParser.FOR);\n                this.state = 1158;\n                this.valueExpression(0);\n            }\n\n            this.state = 1161;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 31:\n            localctx = new NormalizeContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1163;\n            this.match(SqlBaseParser.NORMALIZE);\n            this.state = 1164;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1165;\n            this.valueExpression(0);\n            this.state = 1168;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===SqlBaseParser.T__2) {\n                this.state = 1166;\n                this.match(SqlBaseParser.T__2);\n                this.state = 1167;\n                this.normalForm();\n            }\n\n            this.state = 1170;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 32:\n            localctx = new ExtractContext(this, localctx);\n            this._ctx = localctx;\n            _prevctx = localctx;\n            this.state = 1172;\n            this.match(SqlBaseParser.EXTRACT);\n            this.state = 1173;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1174;\n            this.identifier();\n            this.state = 1175;\n            this.match(SqlBaseParser.FROM);\n            this.state = 1176;\n            this.valueExpression(0);\n            this.state = 1177;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        }\n        this._ctx.stop = this._input.LT(-1);\n        this.state = 1191;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,146,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                if(this._parseListeners!==null) {\n                    this.triggerExitRuleEvent();\n                }\n                _prevctx = localctx;\n                this.state = 1189;\n                this._errHandler.sync(this);\n                var la_ = this._interp.adaptivePredict(this._input,145,this._ctx);\n                switch(la_) {\n                case 1:\n                    localctx = new SubscriptContext(this, new PrimaryExpressionContext(this, _parentctx, _parentState));\n                    localctx.value = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_primaryExpression);\n                    this.state = 1181;\n                    if (!( this.precpred(this._ctx, 11))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 11)\");\n                    }\n                    this.state = 1182;\n                    this.match(SqlBaseParser.T__6);\n                    this.state = 1183;\n                    localctx.index = this.valueExpression(0);\n                    this.state = 1184;\n                    this.match(SqlBaseParser.T__7);\n                    break;\n\n                case 2:\n                    localctx = new DereferenceContext(this, new PrimaryExpressionContext(this, _parentctx, _parentState));\n                    localctx.base = _prevctx;\n                    this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_primaryExpression);\n                    this.state = 1186;\n                    if (!( this.precpred(this._ctx, 9))) {\n                        throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 9)\");\n                    }\n                    this.state = 1187;\n                    this.match(SqlBaseParser.T__0);\n                    this.state = 1188;\n                    localctx.fieldName = this.identifier();\n                    break;\n\n                } \n            }\n            this.state = 1193;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,146,this._ctx);\n        }\n\n    } catch( error) {\n        if(error instanceof _error.RecognitionException) {\n\t        localctx.exception = error;\n\t        this._errHandler.reportError(this, error);\n\t        this._errHandler.recover(this, error);\n\t    } else {\n\t    \tthrow error;\n\t    }\n    } finally {\n        this.unrollRecursionContexts(_parentctx)\n    }\n    return localctx;\n};\n\nfunction TimeZoneSpecifierContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_timeZoneSpecifier;\n    // return this;\n}\n\nTimeZoneSpecifierContext.prototype = Object.create(ParserRuleContext.prototype);\nTimeZoneSpecifierContext.prototype.constructor = TimeZoneSpecifierContext;\n\n\n \nTimeZoneSpecifierContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction TimeZoneIntervalContext(parser, ctx) {\n\tTimeZoneSpecifierContext.call(this, parser);\n    TimeZoneSpecifierContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nTimeZoneIntervalContext.prototype = Object.create(TimeZoneSpecifierContext.prototype);\nTimeZoneIntervalContext.prototype.constructor = TimeZoneIntervalContext;\n\nSqlBaseParser.TimeZoneIntervalContext = TimeZoneIntervalContext;\n\nTimeZoneIntervalContext.prototype.TIME = function() {\n    return this.getToken(SqlBaseParser.TIME, 0);\n};\n\nTimeZoneIntervalContext.prototype.ZONE = function() {\n    return this.getToken(SqlBaseParser.ZONE, 0);\n};\n\nTimeZoneIntervalContext.prototype.interval = function() {\n    return this.getTypedRuleContext(IntervalContext,0);\n};\nTimeZoneIntervalContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTimeZoneInterval(this);\n\t}\n};\n\nTimeZoneIntervalContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTimeZoneInterval(this);\n\t}\n};\n\nTimeZoneIntervalContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTimeZoneInterval(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction TimeZoneStringContext(parser, ctx) {\n\tTimeZoneSpecifierContext.call(this, parser);\n    TimeZoneSpecifierContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nTimeZoneStringContext.prototype = Object.create(TimeZoneSpecifierContext.prototype);\nTimeZoneStringContext.prototype.constructor = TimeZoneStringContext;\n\nSqlBaseParser.TimeZoneStringContext = TimeZoneStringContext;\n\nTimeZoneStringContext.prototype.TIME = function() {\n    return this.getToken(SqlBaseParser.TIME, 0);\n};\n\nTimeZoneStringContext.prototype.ZONE = function() {\n    return this.getToken(SqlBaseParser.ZONE, 0);\n};\n\nTimeZoneStringContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\nTimeZoneStringContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTimeZoneString(this);\n\t}\n};\n\nTimeZoneStringContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTimeZoneString(this);\n\t}\n};\n\nTimeZoneStringContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTimeZoneString(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.TimeZoneSpecifierContext = TimeZoneSpecifierContext;\n\nSqlBaseParser.prototype.timeZoneSpecifier = function() {\n\n    var localctx = new TimeZoneSpecifierContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 74, SqlBaseParser.RULE_timeZoneSpecifier);\n    try {\n        this.state = 1200;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,147,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new TimeZoneIntervalContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1194;\n            this.match(SqlBaseParser.TIME);\n            this.state = 1195;\n            this.match(SqlBaseParser.ZONE);\n            this.state = 1196;\n            this.interval();\n            break;\n\n        case 2:\n            localctx = new TimeZoneStringContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1197;\n            this.match(SqlBaseParser.TIME);\n            this.state = 1198;\n            this.match(SqlBaseParser.ZONE);\n            this.state = 1199;\n            this.match(SqlBaseParser.STRING);\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ComparisonOperatorContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_comparisonOperator;\n    // return this;\n}\n\nComparisonOperatorContext.prototype = Object.create(ParserRuleContext.prototype);\nComparisonOperatorContext.prototype.constructor = ComparisonOperatorContext;\n\nComparisonOperatorContext.prototype.EQ = function() {\n    return this.getToken(SqlBaseParser.EQ, 0);\n};\n\nComparisonOperatorContext.prototype.NEQ = function() {\n    return this.getToken(SqlBaseParser.NEQ, 0);\n};\n\nComparisonOperatorContext.prototype.LT = function() {\n    return this.getToken(SqlBaseParser.LT, 0);\n};\n\nComparisonOperatorContext.prototype.LTE = function() {\n    return this.getToken(SqlBaseParser.LTE, 0);\n};\n\nComparisonOperatorContext.prototype.GT = function() {\n    return this.getToken(SqlBaseParser.GT, 0);\n};\n\nComparisonOperatorContext.prototype.GTE = function() {\n    return this.getToken(SqlBaseParser.GTE, 0);\n};\n\nComparisonOperatorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterComparisonOperator(this);\n\t}\n};\n\nComparisonOperatorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitComparisonOperator(this);\n\t}\n};\n\nComparisonOperatorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitComparisonOperator(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.ComparisonOperatorContext = ComparisonOperatorContext;\n\nSqlBaseParser.prototype.comparisonOperator = function() {\n\n    var localctx = new ComparisonOperatorContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 76, SqlBaseParser.RULE_comparisonOperator);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1202;\n        _la = this._input.LA(1);\n        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))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ComparisonQuantifierContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_comparisonQuantifier;\n    // return this;\n}\n\nComparisonQuantifierContext.prototype = Object.create(ParserRuleContext.prototype);\nComparisonQuantifierContext.prototype.constructor = ComparisonQuantifierContext;\n\nComparisonQuantifierContext.prototype.ALL = function() {\n    return this.getToken(SqlBaseParser.ALL, 0);\n};\n\nComparisonQuantifierContext.prototype.SOME = function() {\n    return this.getToken(SqlBaseParser.SOME, 0);\n};\n\nComparisonQuantifierContext.prototype.ANY = function() {\n    return this.getToken(SqlBaseParser.ANY, 0);\n};\n\nComparisonQuantifierContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterComparisonQuantifier(this);\n\t}\n};\n\nComparisonQuantifierContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitComparisonQuantifier(this);\n\t}\n};\n\nComparisonQuantifierContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitComparisonQuantifier(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.ComparisonQuantifierContext = ComparisonQuantifierContext;\n\nSqlBaseParser.prototype.comparisonQuantifier = function() {\n\n    var localctx = new ComparisonQuantifierContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 78, SqlBaseParser.RULE_comparisonQuantifier);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1204;\n        _la = this._input.LA(1);\n        if(!((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << SqlBaseParser.ALL) | (1 << SqlBaseParser.SOME) | (1 << SqlBaseParser.ANY))) !== 0))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction BooleanValueContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_booleanValue;\n    // return this;\n}\n\nBooleanValueContext.prototype = Object.create(ParserRuleContext.prototype);\nBooleanValueContext.prototype.constructor = BooleanValueContext;\n\nBooleanValueContext.prototype.TRUE = function() {\n    return this.getToken(SqlBaseParser.TRUE, 0);\n};\n\nBooleanValueContext.prototype.FALSE = function() {\n    return this.getToken(SqlBaseParser.FALSE, 0);\n};\n\nBooleanValueContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBooleanValue(this);\n\t}\n};\n\nBooleanValueContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBooleanValue(this);\n\t}\n};\n\nBooleanValueContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBooleanValue(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.BooleanValueContext = BooleanValueContext;\n\nSqlBaseParser.prototype.booleanValue = function() {\n\n    var localctx = new BooleanValueContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 80, SqlBaseParser.RULE_booleanValue);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1206;\n        _la = this._input.LA(1);\n        if(!(_la===SqlBaseParser.TRUE || _la===SqlBaseParser.FALSE)) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction IntervalContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_interval;\n    this.sign = null; // Token\n    this.from = null; // IntervalFieldContext\n    this.to = null; // IntervalFieldContext\n    // return this;\n}\n\nIntervalContext.prototype = Object.create(ParserRuleContext.prototype);\nIntervalContext.prototype.constructor = IntervalContext;\n\nIntervalContext.prototype.INTERVAL = function() {\n    return this.getToken(SqlBaseParser.INTERVAL, 0);\n};\n\nIntervalContext.prototype.STRING = function() {\n    return this.getToken(SqlBaseParser.STRING, 0);\n};\n\nIntervalContext.prototype.intervalField = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IntervalFieldContext);\n    } else {\n        return this.getTypedRuleContext(IntervalFieldContext,i);\n    }\n};\n\nIntervalContext.prototype.TO = function() {\n    return this.getToken(SqlBaseParser.TO, 0);\n};\n\nIntervalContext.prototype.PLUS = function() {\n    return this.getToken(SqlBaseParser.PLUS, 0);\n};\n\nIntervalContext.prototype.MINUS = function() {\n    return this.getToken(SqlBaseParser.MINUS, 0);\n};\n\nIntervalContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterInterval(this);\n\t}\n};\n\nIntervalContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitInterval(this);\n\t}\n};\n\nIntervalContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitInterval(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.IntervalContext = IntervalContext;\n\nSqlBaseParser.prototype.interval = function() {\n\n    var localctx = new IntervalContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 82, SqlBaseParser.RULE_interval);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1208;\n        this.match(SqlBaseParser.INTERVAL);\n        this.state = 1210;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS) {\n            this.state = 1209;\n            localctx.sign = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.PLUS || _la===SqlBaseParser.MINUS)) {\n                localctx.sign = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n        }\n\n        this.state = 1212;\n        this.match(SqlBaseParser.STRING);\n        this.state = 1213;\n        localctx.from = this.intervalField();\n        this.state = 1216;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,149,this._ctx);\n        if(la_===1) {\n            this.state = 1214;\n            this.match(SqlBaseParser.TO);\n            this.state = 1215;\n            localctx.to = this.intervalField();\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction IntervalFieldContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_intervalField;\n    // return this;\n}\n\nIntervalFieldContext.prototype = Object.create(ParserRuleContext.prototype);\nIntervalFieldContext.prototype.constructor = IntervalFieldContext;\n\nIntervalFieldContext.prototype.YEAR = function() {\n    return this.getToken(SqlBaseParser.YEAR, 0);\n};\n\nIntervalFieldContext.prototype.MONTH = function() {\n    return this.getToken(SqlBaseParser.MONTH, 0);\n};\n\nIntervalFieldContext.prototype.DAY = function() {\n    return this.getToken(SqlBaseParser.DAY, 0);\n};\n\nIntervalFieldContext.prototype.HOUR = function() {\n    return this.getToken(SqlBaseParser.HOUR, 0);\n};\n\nIntervalFieldContext.prototype.MINUTE = function() {\n    return this.getToken(SqlBaseParser.MINUTE, 0);\n};\n\nIntervalFieldContext.prototype.SECOND = function() {\n    return this.getToken(SqlBaseParser.SECOND, 0);\n};\n\nIntervalFieldContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterIntervalField(this);\n\t}\n};\n\nIntervalFieldContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitIntervalField(this);\n\t}\n};\n\nIntervalFieldContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitIntervalField(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.IntervalFieldContext = IntervalFieldContext;\n\nSqlBaseParser.prototype.intervalField = function() {\n\n    var localctx = new IntervalFieldContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 84, SqlBaseParser.RULE_intervalField);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1218;\n        _la = this._input.LA(1);\n        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))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TypeContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_type;\n    // return this;\n}\n\nTypeContext.prototype = Object.create(ParserRuleContext.prototype);\nTypeContext.prototype.constructor = TypeContext;\n\nTypeContext.prototype.ARRAY = function() {\n    return this.getToken(SqlBaseParser.ARRAY, 0);\n};\n\nTypeContext.prototype.type = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TypeContext);\n    } else {\n        return this.getTypedRuleContext(TypeContext,i);\n    }\n};\n\nTypeContext.prototype.MAP = function() {\n    return this.getToken(SqlBaseParser.MAP, 0);\n};\n\nTypeContext.prototype.ROW = function() {\n    return this.getToken(SqlBaseParser.ROW, 0);\n};\n\nTypeContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\n\nTypeContext.prototype.baseType = function() {\n    return this.getTypedRuleContext(BaseTypeContext,0);\n};\n\nTypeContext.prototype.typeParameter = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TypeParameterContext);\n    } else {\n        return this.getTypedRuleContext(TypeParameterContext,i);\n    }\n};\n\nTypeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterType(this);\n\t}\n};\n\nTypeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitType(this);\n\t}\n};\n\nTypeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitType(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.prototype.type = function(_p) {\n\tif(_p===undefined) {\n\t    _p = 0;\n\t}\n    var _parentctx = this._ctx;\n    var _parentState = this.state;\n    var localctx = new TypeContext(this, this._ctx, _parentState);\n    var _prevctx = localctx;\n    var _startState = 86;\n    this.enterRecursionRule(localctx, 86, SqlBaseParser.RULE_type, _p);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1262;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,153,this._ctx);\n        switch(la_) {\n        case 1:\n            this.state = 1221;\n            this.match(SqlBaseParser.ARRAY);\n            this.state = 1222;\n            this.match(SqlBaseParser.LT);\n            this.state = 1223;\n            this.type(0);\n            this.state = 1224;\n            this.match(SqlBaseParser.GT);\n            break;\n\n        case 2:\n            this.state = 1226;\n            this.match(SqlBaseParser.MAP);\n            this.state = 1227;\n            this.match(SqlBaseParser.LT);\n            this.state = 1228;\n            this.type(0);\n            this.state = 1229;\n            this.match(SqlBaseParser.T__2);\n            this.state = 1230;\n            this.type(0);\n            this.state = 1231;\n            this.match(SqlBaseParser.GT);\n            break;\n\n        case 3:\n            this.state = 1233;\n            this.match(SqlBaseParser.ROW);\n            this.state = 1234;\n            this.match(SqlBaseParser.T__1);\n            this.state = 1235;\n            this.identifier();\n            this.state = 1236;\n            this.type(0);\n            this.state = 1243;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 1237;\n                this.match(SqlBaseParser.T__2);\n                this.state = 1238;\n                this.identifier();\n                this.state = 1239;\n                this.type(0);\n                this.state = 1245;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 1246;\n            this.match(SqlBaseParser.T__3);\n            break;\n\n        case 4:\n            this.state = 1248;\n            this.baseType();\n            this.state = 1260;\n            this._errHandler.sync(this);\n            var la_ = this._interp.adaptivePredict(this._input,152,this._ctx);\n            if(la_===1) {\n                this.state = 1249;\n                this.match(SqlBaseParser.T__1);\n                this.state = 1250;\n                this.typeParameter();\n                this.state = 1255;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                while(_la===SqlBaseParser.T__2) {\n                    this.state = 1251;\n                    this.match(SqlBaseParser.T__2);\n                    this.state = 1252;\n                    this.typeParameter();\n                    this.state = 1257;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                }\n                this.state = 1258;\n                this.match(SqlBaseParser.T__3);\n\n            }\n            break;\n\n        }\n        this._ctx.stop = this._input.LT(-1);\n        this.state = 1268;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,154,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                if(this._parseListeners!==null) {\n                    this.triggerExitRuleEvent();\n                }\n                _prevctx = localctx;\n                localctx = new TypeContext(this, _parentctx, _parentState);\n                this.pushNewRecursionContext(localctx, _startState, SqlBaseParser.RULE_type);\n                this.state = 1264;\n                if (!( this.precpred(this._ctx, 5))) {\n                    throw new _error.FailedPredicateException(this, \"this.precpred(this._ctx, 5)\");\n                }\n                this.state = 1265;\n                this.match(SqlBaseParser.ARRAY); \n            }\n            this.state = 1270;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,154,this._ctx);\n        }\n\n    } catch( error) {\n        if(error instanceof _error.RecognitionException) {\n\t        localctx.exception = error;\n\t        this._errHandler.reportError(this, error);\n\t        this._errHandler.recover(this, error);\n\t    } else {\n\t    \tthrow error;\n\t    }\n    } finally {\n        this.unrollRecursionContexts(_parentctx)\n    }\n    return localctx;\n};\n\nfunction TypeParameterContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_typeParameter;\n    // return this;\n}\n\nTypeParameterContext.prototype = Object.create(ParserRuleContext.prototype);\nTypeParameterContext.prototype.constructor = TypeParameterContext;\n\nTypeParameterContext.prototype.INTEGER_VALUE = function() {\n    return this.getToken(SqlBaseParser.INTEGER_VALUE, 0);\n};\n\nTypeParameterContext.prototype.type = function() {\n    return this.getTypedRuleContext(TypeContext,0);\n};\n\nTypeParameterContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTypeParameter(this);\n\t}\n};\n\nTypeParameterContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTypeParameter(this);\n\t}\n};\n\nTypeParameterContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTypeParameter(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.TypeParameterContext = TypeParameterContext;\n\nSqlBaseParser.prototype.typeParameter = function() {\n\n    var localctx = new TypeParameterContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 88, SqlBaseParser.RULE_typeParameter);\n    try {\n        this.state = 1273;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.INTEGER_VALUE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1271;\n            this.match(SqlBaseParser.INTEGER_VALUE);\n            break;\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n        case SqlBaseParser.TIME_WITH_TIME_ZONE:\n        case SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE:\n        case SqlBaseParser.DOUBLE_PRECISION:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1272;\n            this.type(0);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction BaseTypeContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_baseType;\n    // return this;\n}\n\nBaseTypeContext.prototype = Object.create(ParserRuleContext.prototype);\nBaseTypeContext.prototype.constructor = BaseTypeContext;\n\nBaseTypeContext.prototype.TIME_WITH_TIME_ZONE = function() {\n    return this.getToken(SqlBaseParser.TIME_WITH_TIME_ZONE, 0);\n};\n\nBaseTypeContext.prototype.TIMESTAMP_WITH_TIME_ZONE = function() {\n    return this.getToken(SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE, 0);\n};\n\nBaseTypeContext.prototype.DOUBLE_PRECISION = function() {\n    return this.getToken(SqlBaseParser.DOUBLE_PRECISION, 0);\n};\n\nBaseTypeContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nBaseTypeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBaseType(this);\n\t}\n};\n\nBaseTypeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBaseType(this);\n\t}\n};\n\nBaseTypeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBaseType(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.BaseTypeContext = BaseTypeContext;\n\nSqlBaseParser.prototype.baseType = function() {\n\n    var localctx = new BaseTypeContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 90, SqlBaseParser.RULE_baseType);\n    try {\n        this.state = 1279;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.TIME_WITH_TIME_ZONE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1275;\n            this.match(SqlBaseParser.TIME_WITH_TIME_ZONE);\n            break;\n        case SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1276;\n            this.match(SqlBaseParser.TIMESTAMP_WITH_TIME_ZONE);\n            break;\n        case SqlBaseParser.DOUBLE_PRECISION:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1277;\n            this.match(SqlBaseParser.DOUBLE_PRECISION);\n            break;\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1278;\n            this.identifier();\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction WhenClauseContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_whenClause;\n    this.condition = null; // ExpressionContext\n    this.result = null; // ExpressionContext\n    // return this;\n}\n\nWhenClauseContext.prototype = Object.create(ParserRuleContext.prototype);\nWhenClauseContext.prototype.constructor = WhenClauseContext;\n\nWhenClauseContext.prototype.WHEN = function() {\n    return this.getToken(SqlBaseParser.WHEN, 0);\n};\n\nWhenClauseContext.prototype.THEN = function() {\n    return this.getToken(SqlBaseParser.THEN, 0);\n};\n\nWhenClauseContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\n\nWhenClauseContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterWhenClause(this);\n\t}\n};\n\nWhenClauseContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitWhenClause(this);\n\t}\n};\n\nWhenClauseContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitWhenClause(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.WhenClauseContext = WhenClauseContext;\n\nSqlBaseParser.prototype.whenClause = function() {\n\n    var localctx = new WhenClauseContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 92, SqlBaseParser.RULE_whenClause);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1281;\n        this.match(SqlBaseParser.WHEN);\n        this.state = 1282;\n        localctx.condition = this.expression();\n        this.state = 1283;\n        this.match(SqlBaseParser.THEN);\n        this.state = 1284;\n        localctx.result = this.expression();\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction FilterContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_filter;\n    // return this;\n}\n\nFilterContext.prototype = Object.create(ParserRuleContext.prototype);\nFilterContext.prototype.constructor = FilterContext;\n\nFilterContext.prototype.FILTER = function() {\n    return this.getToken(SqlBaseParser.FILTER, 0);\n};\n\nFilterContext.prototype.WHERE = function() {\n    return this.getToken(SqlBaseParser.WHERE, 0);\n};\n\nFilterContext.prototype.booleanExpression = function() {\n    return this.getTypedRuleContext(BooleanExpressionContext,0);\n};\n\nFilterContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterFilter(this);\n\t}\n};\n\nFilterContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitFilter(this);\n\t}\n};\n\nFilterContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitFilter(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.FilterContext = FilterContext;\n\nSqlBaseParser.prototype.filter = function() {\n\n    var localctx = new FilterContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 94, SqlBaseParser.RULE_filter);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1286;\n        this.match(SqlBaseParser.FILTER);\n        this.state = 1287;\n        this.match(SqlBaseParser.T__1);\n        this.state = 1288;\n        this.match(SqlBaseParser.WHERE);\n        this.state = 1289;\n        this.booleanExpression(0);\n        this.state = 1290;\n        this.match(SqlBaseParser.T__3);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction OverContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_over;\n    this._expression = null; // ExpressionContext\n    this.partition = []; // of ExpressionContexts\n    // return this;\n}\n\nOverContext.prototype = Object.create(ParserRuleContext.prototype);\nOverContext.prototype.constructor = OverContext;\n\nOverContext.prototype.OVER = function() {\n    return this.getToken(SqlBaseParser.OVER, 0);\n};\n\nOverContext.prototype.PARTITION = function() {\n    return this.getToken(SqlBaseParser.PARTITION, 0);\n};\n\nOverContext.prototype.BY = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(SqlBaseParser.BY);\n    } else {\n        return this.getToken(SqlBaseParser.BY, i);\n    }\n};\n\n\nOverContext.prototype.ORDER = function() {\n    return this.getToken(SqlBaseParser.ORDER, 0);\n};\n\nOverContext.prototype.sortItem = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SortItemContext);\n    } else {\n        return this.getTypedRuleContext(SortItemContext,i);\n    }\n};\n\nOverContext.prototype.windowFrame = function() {\n    return this.getTypedRuleContext(WindowFrameContext,0);\n};\n\nOverContext.prototype.expression = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ExpressionContext);\n    } else {\n        return this.getTypedRuleContext(ExpressionContext,i);\n    }\n};\n\nOverContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterOver(this);\n\t}\n};\n\nOverContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitOver(this);\n\t}\n};\n\nOverContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitOver(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.OverContext = OverContext;\n\nSqlBaseParser.prototype.over = function() {\n\n    var localctx = new OverContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 96, SqlBaseParser.RULE_over);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1292;\n        this.match(SqlBaseParser.OVER);\n        this.state = 1293;\n        this.match(SqlBaseParser.T__1);\n        this.state = 1304;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.PARTITION) {\n            this.state = 1294;\n            this.match(SqlBaseParser.PARTITION);\n            this.state = 1295;\n            this.match(SqlBaseParser.BY);\n            this.state = 1296;\n            localctx._expression = this.expression();\n            localctx.partition.push(localctx._expression);\n            this.state = 1301;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 1297;\n                this.match(SqlBaseParser.T__2);\n                this.state = 1298;\n                localctx._expression = this.expression();\n                localctx.partition.push(localctx._expression);\n                this.state = 1303;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n        }\n\n        this.state = 1316;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.ORDER) {\n            this.state = 1306;\n            this.match(SqlBaseParser.ORDER);\n            this.state = 1307;\n            this.match(SqlBaseParser.BY);\n            this.state = 1308;\n            this.sortItem();\n            this.state = 1313;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===SqlBaseParser.T__2) {\n                this.state = 1309;\n                this.match(SqlBaseParser.T__2);\n                this.state = 1310;\n                this.sortItem();\n                this.state = 1315;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n        }\n\n        this.state = 1319;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===SqlBaseParser.RANGE || _la===SqlBaseParser.ROWS) {\n            this.state = 1318;\n            this.windowFrame();\n        }\n\n        this.state = 1321;\n        this.match(SqlBaseParser.T__3);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction WindowFrameContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_windowFrame;\n    this.frameType = null; // Token\n    this.start = null; // FrameBoundContext\n    this.end = null; // FrameBoundContext\n    // return this;\n}\n\nWindowFrameContext.prototype = Object.create(ParserRuleContext.prototype);\nWindowFrameContext.prototype.constructor = WindowFrameContext;\n\nWindowFrameContext.prototype.RANGE = function() {\n    return this.getToken(SqlBaseParser.RANGE, 0);\n};\n\nWindowFrameContext.prototype.frameBound = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(FrameBoundContext);\n    } else {\n        return this.getTypedRuleContext(FrameBoundContext,i);\n    }\n};\n\nWindowFrameContext.prototype.ROWS = function() {\n    return this.getToken(SqlBaseParser.ROWS, 0);\n};\n\nWindowFrameContext.prototype.BETWEEN = function() {\n    return this.getToken(SqlBaseParser.BETWEEN, 0);\n};\n\nWindowFrameContext.prototype.AND = function() {\n    return this.getToken(SqlBaseParser.AND, 0);\n};\n\nWindowFrameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterWindowFrame(this);\n\t}\n};\n\nWindowFrameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitWindowFrame(this);\n\t}\n};\n\nWindowFrameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitWindowFrame(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.WindowFrameContext = WindowFrameContext;\n\nSqlBaseParser.prototype.windowFrame = function() {\n\n    var localctx = new WindowFrameContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 98, SqlBaseParser.RULE_windowFrame);\n    try {\n        this.state = 1339;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,162,this._ctx);\n        switch(la_) {\n        case 1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1323;\n            localctx.frameType = this.match(SqlBaseParser.RANGE);\n            this.state = 1324;\n            localctx.start = this.frameBound();\n            break;\n\n        case 2:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1325;\n            localctx.frameType = this.match(SqlBaseParser.ROWS);\n            this.state = 1326;\n            localctx.start = this.frameBound();\n            break;\n\n        case 3:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1327;\n            localctx.frameType = this.match(SqlBaseParser.RANGE);\n            this.state = 1328;\n            this.match(SqlBaseParser.BETWEEN);\n            this.state = 1329;\n            localctx.start = this.frameBound();\n            this.state = 1330;\n            this.match(SqlBaseParser.AND);\n            this.state = 1331;\n            localctx.end = this.frameBound();\n            break;\n\n        case 4:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1333;\n            localctx.frameType = this.match(SqlBaseParser.ROWS);\n            this.state = 1334;\n            this.match(SqlBaseParser.BETWEEN);\n            this.state = 1335;\n            localctx.start = this.frameBound();\n            this.state = 1336;\n            this.match(SqlBaseParser.AND);\n            this.state = 1337;\n            localctx.end = this.frameBound();\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction FrameBoundContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_frameBound;\n    // return this;\n}\n\nFrameBoundContext.prototype = Object.create(ParserRuleContext.prototype);\nFrameBoundContext.prototype.constructor = FrameBoundContext;\n\n\n \nFrameBoundContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction BoundedFrameContext(parser, ctx) {\n\tFrameBoundContext.call(this, parser);\n    this.boundType = null; // Token;\n    FrameBoundContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nBoundedFrameContext.prototype = Object.create(FrameBoundContext.prototype);\nBoundedFrameContext.prototype.constructor = BoundedFrameContext;\n\nSqlBaseParser.BoundedFrameContext = BoundedFrameContext;\n\nBoundedFrameContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\n\nBoundedFrameContext.prototype.PRECEDING = function() {\n    return this.getToken(SqlBaseParser.PRECEDING, 0);\n};\n\nBoundedFrameContext.prototype.FOLLOWING = function() {\n    return this.getToken(SqlBaseParser.FOLLOWING, 0);\n};\nBoundedFrameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBoundedFrame(this);\n\t}\n};\n\nBoundedFrameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBoundedFrame(this);\n\t}\n};\n\nBoundedFrameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBoundedFrame(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction UnboundedFrameContext(parser, ctx) {\n\tFrameBoundContext.call(this, parser);\n    this.boundType = null; // Token;\n    FrameBoundContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nUnboundedFrameContext.prototype = Object.create(FrameBoundContext.prototype);\nUnboundedFrameContext.prototype.constructor = UnboundedFrameContext;\n\nSqlBaseParser.UnboundedFrameContext = UnboundedFrameContext;\n\nUnboundedFrameContext.prototype.UNBOUNDED = function() {\n    return this.getToken(SqlBaseParser.UNBOUNDED, 0);\n};\n\nUnboundedFrameContext.prototype.PRECEDING = function() {\n    return this.getToken(SqlBaseParser.PRECEDING, 0);\n};\n\nUnboundedFrameContext.prototype.FOLLOWING = function() {\n    return this.getToken(SqlBaseParser.FOLLOWING, 0);\n};\nUnboundedFrameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterUnboundedFrame(this);\n\t}\n};\n\nUnboundedFrameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitUnboundedFrame(this);\n\t}\n};\n\nUnboundedFrameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitUnboundedFrame(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction CurrentRowBoundContext(parser, ctx) {\n\tFrameBoundContext.call(this, parser);\n    FrameBoundContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nCurrentRowBoundContext.prototype = Object.create(FrameBoundContext.prototype);\nCurrentRowBoundContext.prototype.constructor = CurrentRowBoundContext;\n\nSqlBaseParser.CurrentRowBoundContext = CurrentRowBoundContext;\n\nCurrentRowBoundContext.prototype.CURRENT = function() {\n    return this.getToken(SqlBaseParser.CURRENT, 0);\n};\n\nCurrentRowBoundContext.prototype.ROW = function() {\n    return this.getToken(SqlBaseParser.ROW, 0);\n};\nCurrentRowBoundContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterCurrentRowBound(this);\n\t}\n};\n\nCurrentRowBoundContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitCurrentRowBound(this);\n\t}\n};\n\nCurrentRowBoundContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitCurrentRowBound(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.FrameBoundContext = FrameBoundContext;\n\nSqlBaseParser.prototype.frameBound = function() {\n\n    var localctx = new FrameBoundContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 100, SqlBaseParser.RULE_frameBound);\n    var _la = 0; // Token type\n    try {\n        this.state = 1350;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,163,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new UnboundedFrameContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1341;\n            this.match(SqlBaseParser.UNBOUNDED);\n            this.state = 1342;\n            localctx.boundType = this.match(SqlBaseParser.PRECEDING);\n            break;\n\n        case 2:\n            localctx = new UnboundedFrameContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1343;\n            this.match(SqlBaseParser.UNBOUNDED);\n            this.state = 1344;\n            localctx.boundType = this.match(SqlBaseParser.FOLLOWING);\n            break;\n\n        case 3:\n            localctx = new CurrentRowBoundContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1345;\n            this.match(SqlBaseParser.CURRENT);\n            this.state = 1346;\n            this.match(SqlBaseParser.ROW);\n            break;\n\n        case 4:\n            localctx = new BoundedFrameContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1347;\n            this.expression();\n            this.state = 1348;\n            localctx.boundType = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.PRECEDING || _la===SqlBaseParser.FOLLOWING)) {\n                localctx.boundType = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ExplainOptionContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_explainOption;\n    // return this;\n}\n\nExplainOptionContext.prototype = Object.create(ParserRuleContext.prototype);\nExplainOptionContext.prototype.constructor = ExplainOptionContext;\n\n\n \nExplainOptionContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction ExplainFormatContext(parser, ctx) {\n\tExplainOptionContext.call(this, parser);\n    this.value = null; // Token;\n    ExplainOptionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nExplainFormatContext.prototype = Object.create(ExplainOptionContext.prototype);\nExplainFormatContext.prototype.constructor = ExplainFormatContext;\n\nSqlBaseParser.ExplainFormatContext = ExplainFormatContext;\n\nExplainFormatContext.prototype.FORMAT = function() {\n    return this.getToken(SqlBaseParser.FORMAT, 0);\n};\n\nExplainFormatContext.prototype.TEXT = function() {\n    return this.getToken(SqlBaseParser.TEXT, 0);\n};\n\nExplainFormatContext.prototype.GRAPHVIZ = function() {\n    return this.getToken(SqlBaseParser.GRAPHVIZ, 0);\n};\nExplainFormatContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExplainFormat(this);\n\t}\n};\n\nExplainFormatContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExplainFormat(this);\n\t}\n};\n\nExplainFormatContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExplainFormat(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ExplainTypeContext(parser, ctx) {\n\tExplainOptionContext.call(this, parser);\n    this.value = null; // Token;\n    ExplainOptionContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nExplainTypeContext.prototype = Object.create(ExplainOptionContext.prototype);\nExplainTypeContext.prototype.constructor = ExplainTypeContext;\n\nSqlBaseParser.ExplainTypeContext = ExplainTypeContext;\n\nExplainTypeContext.prototype.TYPE = function() {\n    return this.getToken(SqlBaseParser.TYPE, 0);\n};\n\nExplainTypeContext.prototype.LOGICAL = function() {\n    return this.getToken(SqlBaseParser.LOGICAL, 0);\n};\n\nExplainTypeContext.prototype.DISTRIBUTED = function() {\n    return this.getToken(SqlBaseParser.DISTRIBUTED, 0);\n};\nExplainTypeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterExplainType(this);\n\t}\n};\n\nExplainTypeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitExplainType(this);\n\t}\n};\n\nExplainTypeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitExplainType(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.ExplainOptionContext = ExplainOptionContext;\n\nSqlBaseParser.prototype.explainOption = function() {\n\n    var localctx = new ExplainOptionContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 102, SqlBaseParser.RULE_explainOption);\n    var _la = 0; // Token type\n    try {\n        this.state = 1356;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.FORMAT:\n            localctx = new ExplainFormatContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1352;\n            this.match(SqlBaseParser.FORMAT);\n            this.state = 1353;\n            localctx.value = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.TEXT || _la===SqlBaseParser.GRAPHVIZ)) {\n                localctx.value = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            break;\n        case SqlBaseParser.TYPE:\n            localctx = new ExplainTypeContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1354;\n            this.match(SqlBaseParser.TYPE);\n            this.state = 1355;\n            localctx.value = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.LOGICAL || _la===SqlBaseParser.DISTRIBUTED)) {\n                localctx.value = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TransactionModeContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_transactionMode;\n    // return this;\n}\n\nTransactionModeContext.prototype = Object.create(ParserRuleContext.prototype);\nTransactionModeContext.prototype.constructor = TransactionModeContext;\n\n\n \nTransactionModeContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction TransactionAccessModeContext(parser, ctx) {\n\tTransactionModeContext.call(this, parser);\n    this.accessMode = null; // Token;\n    TransactionModeContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nTransactionAccessModeContext.prototype = Object.create(TransactionModeContext.prototype);\nTransactionAccessModeContext.prototype.constructor = TransactionAccessModeContext;\n\nSqlBaseParser.TransactionAccessModeContext = TransactionAccessModeContext;\n\nTransactionAccessModeContext.prototype.READ = function() {\n    return this.getToken(SqlBaseParser.READ, 0);\n};\n\nTransactionAccessModeContext.prototype.ONLY = function() {\n    return this.getToken(SqlBaseParser.ONLY, 0);\n};\n\nTransactionAccessModeContext.prototype.WRITE = function() {\n    return this.getToken(SqlBaseParser.WRITE, 0);\n};\nTransactionAccessModeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterTransactionAccessMode(this);\n\t}\n};\n\nTransactionAccessModeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitTransactionAccessMode(this);\n\t}\n};\n\nTransactionAccessModeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitTransactionAccessMode(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction IsolationLevelContext(parser, ctx) {\n\tTransactionModeContext.call(this, parser);\n    TransactionModeContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nIsolationLevelContext.prototype = Object.create(TransactionModeContext.prototype);\nIsolationLevelContext.prototype.constructor = IsolationLevelContext;\n\nSqlBaseParser.IsolationLevelContext = IsolationLevelContext;\n\nIsolationLevelContext.prototype.ISOLATION = function() {\n    return this.getToken(SqlBaseParser.ISOLATION, 0);\n};\n\nIsolationLevelContext.prototype.LEVEL = function() {\n    return this.getToken(SqlBaseParser.LEVEL, 0);\n};\n\nIsolationLevelContext.prototype.levelOfIsolation = function() {\n    return this.getTypedRuleContext(LevelOfIsolationContext,0);\n};\nIsolationLevelContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterIsolationLevel(this);\n\t}\n};\n\nIsolationLevelContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitIsolationLevel(this);\n\t}\n};\n\nIsolationLevelContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitIsolationLevel(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.TransactionModeContext = TransactionModeContext;\n\nSqlBaseParser.prototype.transactionMode = function() {\n\n    var localctx = new TransactionModeContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 104, SqlBaseParser.RULE_transactionMode);\n    var _la = 0; // Token type\n    try {\n        this.state = 1363;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.ISOLATION:\n            localctx = new IsolationLevelContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1358;\n            this.match(SqlBaseParser.ISOLATION);\n            this.state = 1359;\n            this.match(SqlBaseParser.LEVEL);\n            this.state = 1360;\n            this.levelOfIsolation();\n            break;\n        case SqlBaseParser.READ:\n            localctx = new TransactionAccessModeContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1361;\n            this.match(SqlBaseParser.READ);\n            this.state = 1362;\n            localctx.accessMode = this._input.LT(1);\n            _la = this._input.LA(1);\n            if(!(_la===SqlBaseParser.WRITE || _la===SqlBaseParser.ONLY)) {\n                localctx.accessMode = this._errHandler.recoverInline(this);\n            }\n            else {\n            \tthis._errHandler.reportMatch(this);\n                this.consume();\n            }\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction LevelOfIsolationContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_levelOfIsolation;\n    // return this;\n}\n\nLevelOfIsolationContext.prototype = Object.create(ParserRuleContext.prototype);\nLevelOfIsolationContext.prototype.constructor = LevelOfIsolationContext;\n\n\n \nLevelOfIsolationContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction ReadUncommittedContext(parser, ctx) {\n\tLevelOfIsolationContext.call(this, parser);\n    LevelOfIsolationContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nReadUncommittedContext.prototype = Object.create(LevelOfIsolationContext.prototype);\nReadUncommittedContext.prototype.constructor = ReadUncommittedContext;\n\nSqlBaseParser.ReadUncommittedContext = ReadUncommittedContext;\n\nReadUncommittedContext.prototype.READ = function() {\n    return this.getToken(SqlBaseParser.READ, 0);\n};\n\nReadUncommittedContext.prototype.UNCOMMITTED = function() {\n    return this.getToken(SqlBaseParser.UNCOMMITTED, 0);\n};\nReadUncommittedContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterReadUncommitted(this);\n\t}\n};\n\nReadUncommittedContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitReadUncommitted(this);\n\t}\n};\n\nReadUncommittedContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitReadUncommitted(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction SerializableContext(parser, ctx) {\n\tLevelOfIsolationContext.call(this, parser);\n    LevelOfIsolationContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nSerializableContext.prototype = Object.create(LevelOfIsolationContext.prototype);\nSerializableContext.prototype.constructor = SerializableContext;\n\nSqlBaseParser.SerializableContext = SerializableContext;\n\nSerializableContext.prototype.SERIALIZABLE = function() {\n    return this.getToken(SqlBaseParser.SERIALIZABLE, 0);\n};\nSerializableContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterSerializable(this);\n\t}\n};\n\nSerializableContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitSerializable(this);\n\t}\n};\n\nSerializableContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitSerializable(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction ReadCommittedContext(parser, ctx) {\n\tLevelOfIsolationContext.call(this, parser);\n    LevelOfIsolationContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nReadCommittedContext.prototype = Object.create(LevelOfIsolationContext.prototype);\nReadCommittedContext.prototype.constructor = ReadCommittedContext;\n\nSqlBaseParser.ReadCommittedContext = ReadCommittedContext;\n\nReadCommittedContext.prototype.READ = function() {\n    return this.getToken(SqlBaseParser.READ, 0);\n};\n\nReadCommittedContext.prototype.COMMITTED = function() {\n    return this.getToken(SqlBaseParser.COMMITTED, 0);\n};\nReadCommittedContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterReadCommitted(this);\n\t}\n};\n\nReadCommittedContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitReadCommitted(this);\n\t}\n};\n\nReadCommittedContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitReadCommitted(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction RepeatableReadContext(parser, ctx) {\n\tLevelOfIsolationContext.call(this, parser);\n    LevelOfIsolationContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nRepeatableReadContext.prototype = Object.create(LevelOfIsolationContext.prototype);\nRepeatableReadContext.prototype.constructor = RepeatableReadContext;\n\nSqlBaseParser.RepeatableReadContext = RepeatableReadContext;\n\nRepeatableReadContext.prototype.REPEATABLE = function() {\n    return this.getToken(SqlBaseParser.REPEATABLE, 0);\n};\n\nRepeatableReadContext.prototype.READ = function() {\n    return this.getToken(SqlBaseParser.READ, 0);\n};\nRepeatableReadContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterRepeatableRead(this);\n\t}\n};\n\nRepeatableReadContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitRepeatableRead(this);\n\t}\n};\n\nRepeatableReadContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitRepeatableRead(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.LevelOfIsolationContext = LevelOfIsolationContext;\n\nSqlBaseParser.prototype.levelOfIsolation = function() {\n\n    var localctx = new LevelOfIsolationContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 106, SqlBaseParser.RULE_levelOfIsolation);\n    try {\n        this.state = 1372;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,166,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new ReadUncommittedContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1365;\n            this.match(SqlBaseParser.READ);\n            this.state = 1366;\n            this.match(SqlBaseParser.UNCOMMITTED);\n            break;\n\n        case 2:\n            localctx = new ReadCommittedContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1367;\n            this.match(SqlBaseParser.READ);\n            this.state = 1368;\n            this.match(SqlBaseParser.COMMITTED);\n            break;\n\n        case 3:\n            localctx = new RepeatableReadContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1369;\n            this.match(SqlBaseParser.REPEATABLE);\n            this.state = 1370;\n            this.match(SqlBaseParser.READ);\n            break;\n\n        case 4:\n            localctx = new SerializableContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1371;\n            this.match(SqlBaseParser.SERIALIZABLE);\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction CallArgumentContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_callArgument;\n    // return this;\n}\n\nCallArgumentContext.prototype = Object.create(ParserRuleContext.prototype);\nCallArgumentContext.prototype.constructor = CallArgumentContext;\n\n\n \nCallArgumentContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction PositionalArgumentContext(parser, ctx) {\n\tCallArgumentContext.call(this, parser);\n    CallArgumentContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nPositionalArgumentContext.prototype = Object.create(CallArgumentContext.prototype);\nPositionalArgumentContext.prototype.constructor = PositionalArgumentContext;\n\nSqlBaseParser.PositionalArgumentContext = PositionalArgumentContext;\n\nPositionalArgumentContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\nPositionalArgumentContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterPositionalArgument(this);\n\t}\n};\n\nPositionalArgumentContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitPositionalArgument(this);\n\t}\n};\n\nPositionalArgumentContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitPositionalArgument(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction NamedArgumentContext(parser, ctx) {\n\tCallArgumentContext.call(this, parser);\n    CallArgumentContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nNamedArgumentContext.prototype = Object.create(CallArgumentContext.prototype);\nNamedArgumentContext.prototype.constructor = NamedArgumentContext;\n\nSqlBaseParser.NamedArgumentContext = NamedArgumentContext;\n\nNamedArgumentContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nNamedArgumentContext.prototype.expression = function() {\n    return this.getTypedRuleContext(ExpressionContext,0);\n};\nNamedArgumentContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNamedArgument(this);\n\t}\n};\n\nNamedArgumentContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNamedArgument(this);\n\t}\n};\n\nNamedArgumentContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNamedArgument(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.CallArgumentContext = CallArgumentContext;\n\nSqlBaseParser.prototype.callArgument = function() {\n\n    var localctx = new CallArgumentContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 108, SqlBaseParser.RULE_callArgument);\n    try {\n        this.state = 1379;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,167,this._ctx);\n        switch(la_) {\n        case 1:\n            localctx = new PositionalArgumentContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1374;\n            this.expression();\n            break;\n\n        case 2:\n            localctx = new NamedArgumentContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1375;\n            this.identifier();\n            this.state = 1376;\n            this.match(SqlBaseParser.T__8);\n            this.state = 1377;\n            this.expression();\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction PrivilegeContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_privilege;\n    // return this;\n}\n\nPrivilegeContext.prototype = Object.create(ParserRuleContext.prototype);\nPrivilegeContext.prototype.constructor = PrivilegeContext;\n\nPrivilegeContext.prototype.SELECT = function() {\n    return this.getToken(SqlBaseParser.SELECT, 0);\n};\n\nPrivilegeContext.prototype.DELETE = function() {\n    return this.getToken(SqlBaseParser.DELETE, 0);\n};\n\nPrivilegeContext.prototype.INSERT = function() {\n    return this.getToken(SqlBaseParser.INSERT, 0);\n};\n\nPrivilegeContext.prototype.identifier = function() {\n    return this.getTypedRuleContext(IdentifierContext,0);\n};\n\nPrivilegeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterPrivilege(this);\n\t}\n};\n\nPrivilegeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitPrivilege(this);\n\t}\n};\n\nPrivilegeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitPrivilege(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.PrivilegeContext = PrivilegeContext;\n\nSqlBaseParser.prototype.privilege = function() {\n\n    var localctx = new PrivilegeContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 110, SqlBaseParser.RULE_privilege);\n    try {\n        this.state = 1385;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.SELECT:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1381;\n            this.match(SqlBaseParser.SELECT);\n            break;\n        case SqlBaseParser.DELETE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1382;\n            this.match(SqlBaseParser.DELETE);\n            break;\n        case SqlBaseParser.INSERT:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1383;\n            this.match(SqlBaseParser.INSERT);\n            break;\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n        case SqlBaseParser.IDENTIFIER:\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1384;\n            this.identifier();\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction QualifiedNameContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_qualifiedName;\n    // return this;\n}\n\nQualifiedNameContext.prototype = Object.create(ParserRuleContext.prototype);\nQualifiedNameContext.prototype.constructor = QualifiedNameContext;\n\nQualifiedNameContext.prototype.identifier = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(IdentifierContext);\n    } else {\n        return this.getTypedRuleContext(IdentifierContext,i);\n    }\n};\n\nQualifiedNameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQualifiedName(this);\n\t}\n};\n\nQualifiedNameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQualifiedName(this);\n\t}\n};\n\nQualifiedNameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQualifiedName(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.QualifiedNameContext = QualifiedNameContext;\n\nSqlBaseParser.prototype.qualifiedName = function() {\n\n    var localctx = new QualifiedNameContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 112, SqlBaseParser.RULE_qualifiedName);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1387;\n        this.identifier();\n        this.state = 1392;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,169,this._ctx)\n        while(_alt!=2 && _alt!=_atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 1388;\n                this.match(SqlBaseParser.T__0);\n                this.state = 1389;\n                this.identifier(); \n            }\n            this.state = 1394;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,169,this._ctx);\n        }\n\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction IdentifierContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_identifier;\n    // return this;\n}\n\nIdentifierContext.prototype = Object.create(ParserRuleContext.prototype);\nIdentifierContext.prototype.constructor = IdentifierContext;\n\n\n \nIdentifierContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction BackQuotedIdentifierContext(parser, ctx) {\n\tIdentifierContext.call(this, parser);\n    IdentifierContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nBackQuotedIdentifierContext.prototype = Object.create(IdentifierContext.prototype);\nBackQuotedIdentifierContext.prototype.constructor = BackQuotedIdentifierContext;\n\nSqlBaseParser.BackQuotedIdentifierContext = BackQuotedIdentifierContext;\n\nBackQuotedIdentifierContext.prototype.BACKQUOTED_IDENTIFIER = function() {\n    return this.getToken(SqlBaseParser.BACKQUOTED_IDENTIFIER, 0);\n};\nBackQuotedIdentifierContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterBackQuotedIdentifier(this);\n\t}\n};\n\nBackQuotedIdentifierContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitBackQuotedIdentifier(this);\n\t}\n};\n\nBackQuotedIdentifierContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitBackQuotedIdentifier(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction QuotedIdentifierAlternativeContext(parser, ctx) {\n\tIdentifierContext.call(this, parser);\n    IdentifierContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nQuotedIdentifierAlternativeContext.prototype = Object.create(IdentifierContext.prototype);\nQuotedIdentifierAlternativeContext.prototype.constructor = QuotedIdentifierAlternativeContext;\n\nSqlBaseParser.QuotedIdentifierAlternativeContext = QuotedIdentifierAlternativeContext;\n\nQuotedIdentifierAlternativeContext.prototype.quotedIdentifier = function() {\n    return this.getTypedRuleContext(QuotedIdentifierContext,0);\n};\nQuotedIdentifierAlternativeContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQuotedIdentifierAlternative(this);\n\t}\n};\n\nQuotedIdentifierAlternativeContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQuotedIdentifierAlternative(this);\n\t}\n};\n\nQuotedIdentifierAlternativeContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQuotedIdentifierAlternative(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction DigitIdentifierContext(parser, ctx) {\n\tIdentifierContext.call(this, parser);\n    IdentifierContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDigitIdentifierContext.prototype = Object.create(IdentifierContext.prototype);\nDigitIdentifierContext.prototype.constructor = DigitIdentifierContext;\n\nSqlBaseParser.DigitIdentifierContext = DigitIdentifierContext;\n\nDigitIdentifierContext.prototype.DIGIT_IDENTIFIER = function() {\n    return this.getToken(SqlBaseParser.DIGIT_IDENTIFIER, 0);\n};\nDigitIdentifierContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDigitIdentifier(this);\n\t}\n};\n\nDigitIdentifierContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDigitIdentifier(this);\n\t}\n};\n\nDigitIdentifierContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDigitIdentifier(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction UnquotedIdentifierContext(parser, ctx) {\n\tIdentifierContext.call(this, parser);\n    IdentifierContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nUnquotedIdentifierContext.prototype = Object.create(IdentifierContext.prototype);\nUnquotedIdentifierContext.prototype.constructor = UnquotedIdentifierContext;\n\nSqlBaseParser.UnquotedIdentifierContext = UnquotedIdentifierContext;\n\nUnquotedIdentifierContext.prototype.IDENTIFIER = function() {\n    return this.getToken(SqlBaseParser.IDENTIFIER, 0);\n};\n\nUnquotedIdentifierContext.prototype.nonReserved = function() {\n    return this.getTypedRuleContext(NonReservedContext,0);\n};\nUnquotedIdentifierContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterUnquotedIdentifier(this);\n\t}\n};\n\nUnquotedIdentifierContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitUnquotedIdentifier(this);\n\t}\n};\n\nUnquotedIdentifierContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitUnquotedIdentifier(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.IdentifierContext = IdentifierContext;\n\nSqlBaseParser.prototype.identifier = function() {\n\n    var localctx = new IdentifierContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 114, SqlBaseParser.RULE_identifier);\n    try {\n        this.state = 1400;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.IDENTIFIER:\n            localctx = new UnquotedIdentifierContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1395;\n            this.match(SqlBaseParser.IDENTIFIER);\n            break;\n        case SqlBaseParser.QUOTED_IDENTIFIER:\n            localctx = new QuotedIdentifierAlternativeContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1396;\n            this.quotedIdentifier();\n            break;\n        case SqlBaseParser.ADD:\n        case SqlBaseParser.NO:\n        case SqlBaseParser.SUBSTRING:\n        case SqlBaseParser.POSITION:\n        case SqlBaseParser.TINYINT:\n        case SqlBaseParser.SMALLINT:\n        case SqlBaseParser.INTEGER:\n        case SqlBaseParser.DATE:\n        case SqlBaseParser.TIME:\n        case SqlBaseParser.TIMESTAMP:\n        case SqlBaseParser.INTERVAL:\n        case SqlBaseParser.YEAR:\n        case SqlBaseParser.MONTH:\n        case SqlBaseParser.DAY:\n        case SqlBaseParser.HOUR:\n        case SqlBaseParser.MINUTE:\n        case SqlBaseParser.SECOND:\n        case SqlBaseParser.ZONE:\n        case SqlBaseParser.FILTER:\n        case SqlBaseParser.OVER:\n        case SqlBaseParser.PARTITION:\n        case SqlBaseParser.RANGE:\n        case SqlBaseParser.ROWS:\n        case SqlBaseParser.PRECEDING:\n        case SqlBaseParser.FOLLOWING:\n        case SqlBaseParser.CURRENT:\n        case SqlBaseParser.ROW:\n        case SqlBaseParser.SCHEMA:\n        case SqlBaseParser.VIEW:\n        case SqlBaseParser.REPLACE:\n        case SqlBaseParser.GRANT:\n        case SqlBaseParser.REVOKE:\n        case SqlBaseParser.PRIVILEGES:\n        case SqlBaseParser.PUBLIC:\n        case SqlBaseParser.OPTION:\n        case SqlBaseParser.EXPLAIN:\n        case SqlBaseParser.ANALYZE:\n        case SqlBaseParser.FORMAT:\n        case SqlBaseParser.TYPE:\n        case SqlBaseParser.TEXT:\n        case SqlBaseParser.GRAPHVIZ:\n        case SqlBaseParser.LOGICAL:\n        case SqlBaseParser.DISTRIBUTED:\n        case SqlBaseParser.SHOW:\n        case SqlBaseParser.TABLES:\n        case SqlBaseParser.SCHEMAS:\n        case SqlBaseParser.CATALOGS:\n        case SqlBaseParser.COLUMNS:\n        case SqlBaseParser.COLUMN:\n        case SqlBaseParser.USE:\n        case SqlBaseParser.PARTITIONS:\n        case SqlBaseParser.FUNCTIONS:\n        case SqlBaseParser.TO:\n        case SqlBaseParser.SYSTEM:\n        case SqlBaseParser.BERNOULLI:\n        case SqlBaseParser.POISSONIZED:\n        case SqlBaseParser.TABLESAMPLE:\n        case SqlBaseParser.ARRAY:\n        case SqlBaseParser.MAP:\n        case SqlBaseParser.SET:\n        case SqlBaseParser.RESET:\n        case SqlBaseParser.SESSION:\n        case SqlBaseParser.DATA:\n        case SqlBaseParser.START:\n        case SqlBaseParser.TRANSACTION:\n        case SqlBaseParser.COMMIT:\n        case SqlBaseParser.ROLLBACK:\n        case SqlBaseParser.WORK:\n        case SqlBaseParser.ISOLATION:\n        case SqlBaseParser.LEVEL:\n        case SqlBaseParser.SERIALIZABLE:\n        case SqlBaseParser.REPEATABLE:\n        case SqlBaseParser.COMMITTED:\n        case SqlBaseParser.UNCOMMITTED:\n        case SqlBaseParser.READ:\n        case SqlBaseParser.WRITE:\n        case SqlBaseParser.ONLY:\n        case SqlBaseParser.CALL:\n        case SqlBaseParser.INPUT:\n        case SqlBaseParser.OUTPUT:\n        case SqlBaseParser.CASCADE:\n        case SqlBaseParser.RESTRICT:\n        case SqlBaseParser.INCLUDING:\n        case SqlBaseParser.EXCLUDING:\n        case SqlBaseParser.PROPERTIES:\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n        case SqlBaseParser.IF:\n        case SqlBaseParser.NULLIF:\n        case SqlBaseParser.COALESCE:\n            localctx = new UnquotedIdentifierContext(this, localctx);\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1397;\n            this.nonReserved();\n            break;\n        case SqlBaseParser.BACKQUOTED_IDENTIFIER:\n            localctx = new BackQuotedIdentifierContext(this, localctx);\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1398;\n            this.match(SqlBaseParser.BACKQUOTED_IDENTIFIER);\n            break;\n        case SqlBaseParser.DIGIT_IDENTIFIER:\n            localctx = new DigitIdentifierContext(this, localctx);\n            this.enterOuterAlt(localctx, 5);\n            this.state = 1399;\n            this.match(SqlBaseParser.DIGIT_IDENTIFIER);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction QuotedIdentifierContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_quotedIdentifier;\n    // return this;\n}\n\nQuotedIdentifierContext.prototype = Object.create(ParserRuleContext.prototype);\nQuotedIdentifierContext.prototype.constructor = QuotedIdentifierContext;\n\nQuotedIdentifierContext.prototype.QUOTED_IDENTIFIER = function() {\n    return this.getToken(SqlBaseParser.QUOTED_IDENTIFIER, 0);\n};\n\nQuotedIdentifierContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterQuotedIdentifier(this);\n\t}\n};\n\nQuotedIdentifierContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitQuotedIdentifier(this);\n\t}\n};\n\nQuotedIdentifierContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitQuotedIdentifier(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.QuotedIdentifierContext = QuotedIdentifierContext;\n\nSqlBaseParser.prototype.quotedIdentifier = function() {\n\n    var localctx = new QuotedIdentifierContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 116, SqlBaseParser.RULE_quotedIdentifier);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1402;\n        this.match(SqlBaseParser.QUOTED_IDENTIFIER);\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction NumberContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_number;\n    // return this;\n}\n\nNumberContext.prototype = Object.create(ParserRuleContext.prototype);\nNumberContext.prototype.constructor = NumberContext;\n\n\n \nNumberContext.prototype.copyFrom = function(ctx) {\n    ParserRuleContext.prototype.copyFrom.call(this, ctx);\n};\n\n\nfunction DecimalLiteralContext(parser, ctx) {\n\tNumberContext.call(this, parser);\n    NumberContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nDecimalLiteralContext.prototype = Object.create(NumberContext.prototype);\nDecimalLiteralContext.prototype.constructor = DecimalLiteralContext;\n\nSqlBaseParser.DecimalLiteralContext = DecimalLiteralContext;\n\nDecimalLiteralContext.prototype.DECIMAL_VALUE = function() {\n    return this.getToken(SqlBaseParser.DECIMAL_VALUE, 0);\n};\nDecimalLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterDecimalLiteral(this);\n\t}\n};\n\nDecimalLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitDecimalLiteral(this);\n\t}\n};\n\nDecimalLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitDecimalLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\nfunction IntegerLiteralContext(parser, ctx) {\n\tNumberContext.call(this, parser);\n    NumberContext.prototype.copyFrom.call(this, ctx);\n    // return this;\n}\n\nIntegerLiteralContext.prototype = Object.create(NumberContext.prototype);\nIntegerLiteralContext.prototype.constructor = IntegerLiteralContext;\n\nSqlBaseParser.IntegerLiteralContext = IntegerLiteralContext;\n\nIntegerLiteralContext.prototype.INTEGER_VALUE = function() {\n    return this.getToken(SqlBaseParser.INTEGER_VALUE, 0);\n};\nIntegerLiteralContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterIntegerLiteral(this);\n\t}\n};\n\nIntegerLiteralContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitIntegerLiteral(this);\n\t}\n};\n\nIntegerLiteralContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitIntegerLiteral(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\nSqlBaseParser.NumberContext = NumberContext;\n\nSqlBaseParser.prototype.number = function() {\n\n    var localctx = new NumberContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 118, SqlBaseParser.RULE_number);\n    try {\n        this.state = 1406;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.DECIMAL_VALUE:\n            localctx = new DecimalLiteralContext(this, localctx);\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1404;\n            this.match(SqlBaseParser.DECIMAL_VALUE);\n            break;\n        case SqlBaseParser.INTEGER_VALUE:\n            localctx = new IntegerLiteralContext(this, localctx);\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1405;\n            this.match(SqlBaseParser.INTEGER_VALUE);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction NonReservedContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_nonReserved;\n    // return this;\n}\n\nNonReservedContext.prototype = Object.create(ParserRuleContext.prototype);\nNonReservedContext.prototype.constructor = NonReservedContext;\n\nNonReservedContext.prototype.SHOW = function() {\n    return this.getToken(SqlBaseParser.SHOW, 0);\n};\n\nNonReservedContext.prototype.TABLES = function() {\n    return this.getToken(SqlBaseParser.TABLES, 0);\n};\n\nNonReservedContext.prototype.COLUMNS = function() {\n    return this.getToken(SqlBaseParser.COLUMNS, 0);\n};\n\nNonReservedContext.prototype.COLUMN = function() {\n    return this.getToken(SqlBaseParser.COLUMN, 0);\n};\n\nNonReservedContext.prototype.PARTITIONS = function() {\n    return this.getToken(SqlBaseParser.PARTITIONS, 0);\n};\n\nNonReservedContext.prototype.FUNCTIONS = function() {\n    return this.getToken(SqlBaseParser.FUNCTIONS, 0);\n};\n\nNonReservedContext.prototype.SCHEMAS = function() {\n    return this.getToken(SqlBaseParser.SCHEMAS, 0);\n};\n\nNonReservedContext.prototype.CATALOGS = function() {\n    return this.getToken(SqlBaseParser.CATALOGS, 0);\n};\n\nNonReservedContext.prototype.SESSION = function() {\n    return this.getToken(SqlBaseParser.SESSION, 0);\n};\n\nNonReservedContext.prototype.ADD = function() {\n    return this.getToken(SqlBaseParser.ADD, 0);\n};\n\nNonReservedContext.prototype.FILTER = function() {\n    return this.getToken(SqlBaseParser.FILTER, 0);\n};\n\nNonReservedContext.prototype.OVER = function() {\n    return this.getToken(SqlBaseParser.OVER, 0);\n};\n\nNonReservedContext.prototype.PARTITION = function() {\n    return this.getToken(SqlBaseParser.PARTITION, 0);\n};\n\nNonReservedContext.prototype.RANGE = function() {\n    return this.getToken(SqlBaseParser.RANGE, 0);\n};\n\nNonReservedContext.prototype.ROWS = function() {\n    return this.getToken(SqlBaseParser.ROWS, 0);\n};\n\nNonReservedContext.prototype.PRECEDING = function() {\n    return this.getToken(SqlBaseParser.PRECEDING, 0);\n};\n\nNonReservedContext.prototype.FOLLOWING = function() {\n    return this.getToken(SqlBaseParser.FOLLOWING, 0);\n};\n\nNonReservedContext.prototype.CURRENT = function() {\n    return this.getToken(SqlBaseParser.CURRENT, 0);\n};\n\nNonReservedContext.prototype.ROW = function() {\n    return this.getToken(SqlBaseParser.ROW, 0);\n};\n\nNonReservedContext.prototype.MAP = function() {\n    return this.getToken(SqlBaseParser.MAP, 0);\n};\n\nNonReservedContext.prototype.ARRAY = function() {\n    return this.getToken(SqlBaseParser.ARRAY, 0);\n};\n\nNonReservedContext.prototype.TINYINT = function() {\n    return this.getToken(SqlBaseParser.TINYINT, 0);\n};\n\nNonReservedContext.prototype.SMALLINT = function() {\n    return this.getToken(SqlBaseParser.SMALLINT, 0);\n};\n\nNonReservedContext.prototype.INTEGER = function() {\n    return this.getToken(SqlBaseParser.INTEGER, 0);\n};\n\nNonReservedContext.prototype.DATE = function() {\n    return this.getToken(SqlBaseParser.DATE, 0);\n};\n\nNonReservedContext.prototype.TIME = function() {\n    return this.getToken(SqlBaseParser.TIME, 0);\n};\n\nNonReservedContext.prototype.TIMESTAMP = function() {\n    return this.getToken(SqlBaseParser.TIMESTAMP, 0);\n};\n\nNonReservedContext.prototype.INTERVAL = function() {\n    return this.getToken(SqlBaseParser.INTERVAL, 0);\n};\n\nNonReservedContext.prototype.ZONE = function() {\n    return this.getToken(SqlBaseParser.ZONE, 0);\n};\n\nNonReservedContext.prototype.YEAR = function() {\n    return this.getToken(SqlBaseParser.YEAR, 0);\n};\n\nNonReservedContext.prototype.MONTH = function() {\n    return this.getToken(SqlBaseParser.MONTH, 0);\n};\n\nNonReservedContext.prototype.DAY = function() {\n    return this.getToken(SqlBaseParser.DAY, 0);\n};\n\nNonReservedContext.prototype.HOUR = function() {\n    return this.getToken(SqlBaseParser.HOUR, 0);\n};\n\nNonReservedContext.prototype.MINUTE = function() {\n    return this.getToken(SqlBaseParser.MINUTE, 0);\n};\n\nNonReservedContext.prototype.SECOND = function() {\n    return this.getToken(SqlBaseParser.SECOND, 0);\n};\n\nNonReservedContext.prototype.EXPLAIN = function() {\n    return this.getToken(SqlBaseParser.EXPLAIN, 0);\n};\n\nNonReservedContext.prototype.ANALYZE = function() {\n    return this.getToken(SqlBaseParser.ANALYZE, 0);\n};\n\nNonReservedContext.prototype.FORMAT = function() {\n    return this.getToken(SqlBaseParser.FORMAT, 0);\n};\n\nNonReservedContext.prototype.TYPE = function() {\n    return this.getToken(SqlBaseParser.TYPE, 0);\n};\n\nNonReservedContext.prototype.TEXT = function() {\n    return this.getToken(SqlBaseParser.TEXT, 0);\n};\n\nNonReservedContext.prototype.GRAPHVIZ = function() {\n    return this.getToken(SqlBaseParser.GRAPHVIZ, 0);\n};\n\nNonReservedContext.prototype.LOGICAL = function() {\n    return this.getToken(SqlBaseParser.LOGICAL, 0);\n};\n\nNonReservedContext.prototype.DISTRIBUTED = function() {\n    return this.getToken(SqlBaseParser.DISTRIBUTED, 0);\n};\n\nNonReservedContext.prototype.TABLESAMPLE = function() {\n    return this.getToken(SqlBaseParser.TABLESAMPLE, 0);\n};\n\nNonReservedContext.prototype.SYSTEM = function() {\n    return this.getToken(SqlBaseParser.SYSTEM, 0);\n};\n\nNonReservedContext.prototype.BERNOULLI = function() {\n    return this.getToken(SqlBaseParser.BERNOULLI, 0);\n};\n\nNonReservedContext.prototype.POISSONIZED = function() {\n    return this.getToken(SqlBaseParser.POISSONIZED, 0);\n};\n\nNonReservedContext.prototype.USE = function() {\n    return this.getToken(SqlBaseParser.USE, 0);\n};\n\nNonReservedContext.prototype.TO = function() {\n    return this.getToken(SqlBaseParser.TO, 0);\n};\n\nNonReservedContext.prototype.SET = function() {\n    return this.getToken(SqlBaseParser.SET, 0);\n};\n\nNonReservedContext.prototype.RESET = function() {\n    return this.getToken(SqlBaseParser.RESET, 0);\n};\n\nNonReservedContext.prototype.VIEW = function() {\n    return this.getToken(SqlBaseParser.VIEW, 0);\n};\n\nNonReservedContext.prototype.REPLACE = function() {\n    return this.getToken(SqlBaseParser.REPLACE, 0);\n};\n\nNonReservedContext.prototype.IF = function() {\n    return this.getToken(SqlBaseParser.IF, 0);\n};\n\nNonReservedContext.prototype.NULLIF = function() {\n    return this.getToken(SqlBaseParser.NULLIF, 0);\n};\n\nNonReservedContext.prototype.COALESCE = function() {\n    return this.getToken(SqlBaseParser.COALESCE, 0);\n};\n\nNonReservedContext.prototype.normalForm = function() {\n    return this.getTypedRuleContext(NormalFormContext,0);\n};\n\nNonReservedContext.prototype.POSITION = function() {\n    return this.getToken(SqlBaseParser.POSITION, 0);\n};\n\nNonReservedContext.prototype.NO = function() {\n    return this.getToken(SqlBaseParser.NO, 0);\n};\n\nNonReservedContext.prototype.DATA = function() {\n    return this.getToken(SqlBaseParser.DATA, 0);\n};\n\nNonReservedContext.prototype.START = function() {\n    return this.getToken(SqlBaseParser.START, 0);\n};\n\nNonReservedContext.prototype.TRANSACTION = function() {\n    return this.getToken(SqlBaseParser.TRANSACTION, 0);\n};\n\nNonReservedContext.prototype.COMMIT = function() {\n    return this.getToken(SqlBaseParser.COMMIT, 0);\n};\n\nNonReservedContext.prototype.ROLLBACK = function() {\n    return this.getToken(SqlBaseParser.ROLLBACK, 0);\n};\n\nNonReservedContext.prototype.WORK = function() {\n    return this.getToken(SqlBaseParser.WORK, 0);\n};\n\nNonReservedContext.prototype.ISOLATION = function() {\n    return this.getToken(SqlBaseParser.ISOLATION, 0);\n};\n\nNonReservedContext.prototype.LEVEL = function() {\n    return this.getToken(SqlBaseParser.LEVEL, 0);\n};\n\nNonReservedContext.prototype.SERIALIZABLE = function() {\n    return this.getToken(SqlBaseParser.SERIALIZABLE, 0);\n};\n\nNonReservedContext.prototype.REPEATABLE = function() {\n    return this.getToken(SqlBaseParser.REPEATABLE, 0);\n};\n\nNonReservedContext.prototype.COMMITTED = function() {\n    return this.getToken(SqlBaseParser.COMMITTED, 0);\n};\n\nNonReservedContext.prototype.UNCOMMITTED = function() {\n    return this.getToken(SqlBaseParser.UNCOMMITTED, 0);\n};\n\nNonReservedContext.prototype.READ = function() {\n    return this.getToken(SqlBaseParser.READ, 0);\n};\n\nNonReservedContext.prototype.WRITE = function() {\n    return this.getToken(SqlBaseParser.WRITE, 0);\n};\n\nNonReservedContext.prototype.ONLY = function() {\n    return this.getToken(SqlBaseParser.ONLY, 0);\n};\n\nNonReservedContext.prototype.CALL = function() {\n    return this.getToken(SqlBaseParser.CALL, 0);\n};\n\nNonReservedContext.prototype.GRANT = function() {\n    return this.getToken(SqlBaseParser.GRANT, 0);\n};\n\nNonReservedContext.prototype.REVOKE = function() {\n    return this.getToken(SqlBaseParser.REVOKE, 0);\n};\n\nNonReservedContext.prototype.PRIVILEGES = function() {\n    return this.getToken(SqlBaseParser.PRIVILEGES, 0);\n};\n\nNonReservedContext.prototype.PUBLIC = function() {\n    return this.getToken(SqlBaseParser.PUBLIC, 0);\n};\n\nNonReservedContext.prototype.OPTION = function() {\n    return this.getToken(SqlBaseParser.OPTION, 0);\n};\n\nNonReservedContext.prototype.SUBSTRING = function() {\n    return this.getToken(SqlBaseParser.SUBSTRING, 0);\n};\n\nNonReservedContext.prototype.SCHEMA = function() {\n    return this.getToken(SqlBaseParser.SCHEMA, 0);\n};\n\nNonReservedContext.prototype.CASCADE = function() {\n    return this.getToken(SqlBaseParser.CASCADE, 0);\n};\n\nNonReservedContext.prototype.RESTRICT = function() {\n    return this.getToken(SqlBaseParser.RESTRICT, 0);\n};\n\nNonReservedContext.prototype.INPUT = function() {\n    return this.getToken(SqlBaseParser.INPUT, 0);\n};\n\nNonReservedContext.prototype.OUTPUT = function() {\n    return this.getToken(SqlBaseParser.OUTPUT, 0);\n};\n\nNonReservedContext.prototype.INCLUDING = function() {\n    return this.getToken(SqlBaseParser.INCLUDING, 0);\n};\n\nNonReservedContext.prototype.EXCLUDING = function() {\n    return this.getToken(SqlBaseParser.EXCLUDING, 0);\n};\n\nNonReservedContext.prototype.PROPERTIES = function() {\n    return this.getToken(SqlBaseParser.PROPERTIES, 0);\n};\n\nNonReservedContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNonReserved(this);\n\t}\n};\n\nNonReservedContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNonReserved(this);\n\t}\n};\n\nNonReservedContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNonReserved(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.NonReservedContext = NonReservedContext;\n\nSqlBaseParser.prototype.nonReserved = function() {\n\n    var localctx = new NonReservedContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 120, SqlBaseParser.RULE_nonReserved);\n    try {\n        this.state = 1497;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case SqlBaseParser.SHOW:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1408;\n            this.match(SqlBaseParser.SHOW);\n            break;\n        case SqlBaseParser.TABLES:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1409;\n            this.match(SqlBaseParser.TABLES);\n            break;\n        case SqlBaseParser.COLUMNS:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1410;\n            this.match(SqlBaseParser.COLUMNS);\n            break;\n        case SqlBaseParser.COLUMN:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 1411;\n            this.match(SqlBaseParser.COLUMN);\n            break;\n        case SqlBaseParser.PARTITIONS:\n            this.enterOuterAlt(localctx, 5);\n            this.state = 1412;\n            this.match(SqlBaseParser.PARTITIONS);\n            break;\n        case SqlBaseParser.FUNCTIONS:\n            this.enterOuterAlt(localctx, 6);\n            this.state = 1413;\n            this.match(SqlBaseParser.FUNCTIONS);\n            break;\n        case SqlBaseParser.SCHEMAS:\n            this.enterOuterAlt(localctx, 7);\n            this.state = 1414;\n            this.match(SqlBaseParser.SCHEMAS);\n            break;\n        case SqlBaseParser.CATALOGS:\n            this.enterOuterAlt(localctx, 8);\n            this.state = 1415;\n            this.match(SqlBaseParser.CATALOGS);\n            break;\n        case SqlBaseParser.SESSION:\n            this.enterOuterAlt(localctx, 9);\n            this.state = 1416;\n            this.match(SqlBaseParser.SESSION);\n            break;\n        case SqlBaseParser.ADD:\n            this.enterOuterAlt(localctx, 10);\n            this.state = 1417;\n            this.match(SqlBaseParser.ADD);\n            break;\n        case SqlBaseParser.FILTER:\n            this.enterOuterAlt(localctx, 11);\n            this.state = 1418;\n            this.match(SqlBaseParser.FILTER);\n            break;\n        case SqlBaseParser.OVER:\n            this.enterOuterAlt(localctx, 12);\n            this.state = 1419;\n            this.match(SqlBaseParser.OVER);\n            break;\n        case SqlBaseParser.PARTITION:\n            this.enterOuterAlt(localctx, 13);\n            this.state = 1420;\n            this.match(SqlBaseParser.PARTITION);\n            break;\n        case SqlBaseParser.RANGE:\n            this.enterOuterAlt(localctx, 14);\n            this.state = 1421;\n            this.match(SqlBaseParser.RANGE);\n            break;\n        case SqlBaseParser.ROWS:\n            this.enterOuterAlt(localctx, 15);\n            this.state = 1422;\n            this.match(SqlBaseParser.ROWS);\n            break;\n        case SqlBaseParser.PRECEDING:\n            this.enterOuterAlt(localctx, 16);\n            this.state = 1423;\n            this.match(SqlBaseParser.PRECEDING);\n            break;\n        case SqlBaseParser.FOLLOWING:\n            this.enterOuterAlt(localctx, 17);\n            this.state = 1424;\n            this.match(SqlBaseParser.FOLLOWING);\n            break;\n        case SqlBaseParser.CURRENT:\n            this.enterOuterAlt(localctx, 18);\n            this.state = 1425;\n            this.match(SqlBaseParser.CURRENT);\n            break;\n        case SqlBaseParser.ROW:\n            this.enterOuterAlt(localctx, 19);\n            this.state = 1426;\n            this.match(SqlBaseParser.ROW);\n            break;\n        case SqlBaseParser.MAP:\n            this.enterOuterAlt(localctx, 20);\n            this.state = 1427;\n            this.match(SqlBaseParser.MAP);\n            break;\n        case SqlBaseParser.ARRAY:\n            this.enterOuterAlt(localctx, 21);\n            this.state = 1428;\n            this.match(SqlBaseParser.ARRAY);\n            break;\n        case SqlBaseParser.TINYINT:\n            this.enterOuterAlt(localctx, 22);\n            this.state = 1429;\n            this.match(SqlBaseParser.TINYINT);\n            break;\n        case SqlBaseParser.SMALLINT:\n            this.enterOuterAlt(localctx, 23);\n            this.state = 1430;\n            this.match(SqlBaseParser.SMALLINT);\n            break;\n        case SqlBaseParser.INTEGER:\n            this.enterOuterAlt(localctx, 24);\n            this.state = 1431;\n            this.match(SqlBaseParser.INTEGER);\n            break;\n        case SqlBaseParser.DATE:\n            this.enterOuterAlt(localctx, 25);\n            this.state = 1432;\n            this.match(SqlBaseParser.DATE);\n            break;\n        case SqlBaseParser.TIME:\n            this.enterOuterAlt(localctx, 26);\n            this.state = 1433;\n            this.match(SqlBaseParser.TIME);\n            break;\n        case SqlBaseParser.TIMESTAMP:\n            this.enterOuterAlt(localctx, 27);\n            this.state = 1434;\n            this.match(SqlBaseParser.TIMESTAMP);\n            break;\n        case SqlBaseParser.INTERVAL:\n            this.enterOuterAlt(localctx, 28);\n            this.state = 1435;\n            this.match(SqlBaseParser.INTERVAL);\n            break;\n        case SqlBaseParser.ZONE:\n            this.enterOuterAlt(localctx, 29);\n            this.state = 1436;\n            this.match(SqlBaseParser.ZONE);\n            break;\n        case SqlBaseParser.YEAR:\n            this.enterOuterAlt(localctx, 30);\n            this.state = 1437;\n            this.match(SqlBaseParser.YEAR);\n            break;\n        case SqlBaseParser.MONTH:\n            this.enterOuterAlt(localctx, 31);\n            this.state = 1438;\n            this.match(SqlBaseParser.MONTH);\n            break;\n        case SqlBaseParser.DAY:\n            this.enterOuterAlt(localctx, 32);\n            this.state = 1439;\n            this.match(SqlBaseParser.DAY);\n            break;\n        case SqlBaseParser.HOUR:\n            this.enterOuterAlt(localctx, 33);\n            this.state = 1440;\n            this.match(SqlBaseParser.HOUR);\n            break;\n        case SqlBaseParser.MINUTE:\n            this.enterOuterAlt(localctx, 34);\n            this.state = 1441;\n            this.match(SqlBaseParser.MINUTE);\n            break;\n        case SqlBaseParser.SECOND:\n            this.enterOuterAlt(localctx, 35);\n            this.state = 1442;\n            this.match(SqlBaseParser.SECOND);\n            break;\n        case SqlBaseParser.EXPLAIN:\n            this.enterOuterAlt(localctx, 36);\n            this.state = 1443;\n            this.match(SqlBaseParser.EXPLAIN);\n            break;\n        case SqlBaseParser.ANALYZE:\n            this.enterOuterAlt(localctx, 37);\n            this.state = 1444;\n            this.match(SqlBaseParser.ANALYZE);\n            break;\n        case SqlBaseParser.FORMAT:\n            this.enterOuterAlt(localctx, 38);\n            this.state = 1445;\n            this.match(SqlBaseParser.FORMAT);\n            break;\n        case SqlBaseParser.TYPE:\n            this.enterOuterAlt(localctx, 39);\n            this.state = 1446;\n            this.match(SqlBaseParser.TYPE);\n            break;\n        case SqlBaseParser.TEXT:\n            this.enterOuterAlt(localctx, 40);\n            this.state = 1447;\n            this.match(SqlBaseParser.TEXT);\n            break;\n        case SqlBaseParser.GRAPHVIZ:\n            this.enterOuterAlt(localctx, 41);\n            this.state = 1448;\n            this.match(SqlBaseParser.GRAPHVIZ);\n            break;\n        case SqlBaseParser.LOGICAL:\n            this.enterOuterAlt(localctx, 42);\n            this.state = 1449;\n            this.match(SqlBaseParser.LOGICAL);\n            break;\n        case SqlBaseParser.DISTRIBUTED:\n            this.enterOuterAlt(localctx, 43);\n            this.state = 1450;\n            this.match(SqlBaseParser.DISTRIBUTED);\n            break;\n        case SqlBaseParser.TABLESAMPLE:\n            this.enterOuterAlt(localctx, 44);\n            this.state = 1451;\n            this.match(SqlBaseParser.TABLESAMPLE);\n            break;\n        case SqlBaseParser.SYSTEM:\n            this.enterOuterAlt(localctx, 45);\n            this.state = 1452;\n            this.match(SqlBaseParser.SYSTEM);\n            break;\n        case SqlBaseParser.BERNOULLI:\n            this.enterOuterAlt(localctx, 46);\n            this.state = 1453;\n            this.match(SqlBaseParser.BERNOULLI);\n            break;\n        case SqlBaseParser.POISSONIZED:\n            this.enterOuterAlt(localctx, 47);\n            this.state = 1454;\n            this.match(SqlBaseParser.POISSONIZED);\n            break;\n        case SqlBaseParser.USE:\n            this.enterOuterAlt(localctx, 48);\n            this.state = 1455;\n            this.match(SqlBaseParser.USE);\n            break;\n        case SqlBaseParser.TO:\n            this.enterOuterAlt(localctx, 49);\n            this.state = 1456;\n            this.match(SqlBaseParser.TO);\n            break;\n        case SqlBaseParser.SET:\n            this.enterOuterAlt(localctx, 50);\n            this.state = 1457;\n            this.match(SqlBaseParser.SET);\n            break;\n        case SqlBaseParser.RESET:\n            this.enterOuterAlt(localctx, 51);\n            this.state = 1458;\n            this.match(SqlBaseParser.RESET);\n            break;\n        case SqlBaseParser.VIEW:\n            this.enterOuterAlt(localctx, 52);\n            this.state = 1459;\n            this.match(SqlBaseParser.VIEW);\n            break;\n        case SqlBaseParser.REPLACE:\n            this.enterOuterAlt(localctx, 53);\n            this.state = 1460;\n            this.match(SqlBaseParser.REPLACE);\n            break;\n        case SqlBaseParser.IF:\n            this.enterOuterAlt(localctx, 54);\n            this.state = 1461;\n            this.match(SqlBaseParser.IF);\n            break;\n        case SqlBaseParser.NULLIF:\n            this.enterOuterAlt(localctx, 55);\n            this.state = 1462;\n            this.match(SqlBaseParser.NULLIF);\n            break;\n        case SqlBaseParser.COALESCE:\n            this.enterOuterAlt(localctx, 56);\n            this.state = 1463;\n            this.match(SqlBaseParser.COALESCE);\n            break;\n        case SqlBaseParser.NFD:\n        case SqlBaseParser.NFC:\n        case SqlBaseParser.NFKD:\n        case SqlBaseParser.NFKC:\n            this.enterOuterAlt(localctx, 57);\n            this.state = 1464;\n            this.normalForm();\n            break;\n        case SqlBaseParser.POSITION:\n            this.enterOuterAlt(localctx, 58);\n            this.state = 1465;\n            this.match(SqlBaseParser.POSITION);\n            break;\n        case SqlBaseParser.NO:\n            this.enterOuterAlt(localctx, 59);\n            this.state = 1466;\n            this.match(SqlBaseParser.NO);\n            break;\n        case SqlBaseParser.DATA:\n            this.enterOuterAlt(localctx, 60);\n            this.state = 1467;\n            this.match(SqlBaseParser.DATA);\n            break;\n        case SqlBaseParser.START:\n            this.enterOuterAlt(localctx, 61);\n            this.state = 1468;\n            this.match(SqlBaseParser.START);\n            break;\n        case SqlBaseParser.TRANSACTION:\n            this.enterOuterAlt(localctx, 62);\n            this.state = 1469;\n            this.match(SqlBaseParser.TRANSACTION);\n            break;\n        case SqlBaseParser.COMMIT:\n            this.enterOuterAlt(localctx, 63);\n            this.state = 1470;\n            this.match(SqlBaseParser.COMMIT);\n            break;\n        case SqlBaseParser.ROLLBACK:\n            this.enterOuterAlt(localctx, 64);\n            this.state = 1471;\n            this.match(SqlBaseParser.ROLLBACK);\n            break;\n        case SqlBaseParser.WORK:\n            this.enterOuterAlt(localctx, 65);\n            this.state = 1472;\n            this.match(SqlBaseParser.WORK);\n            break;\n        case SqlBaseParser.ISOLATION:\n            this.enterOuterAlt(localctx, 66);\n            this.state = 1473;\n            this.match(SqlBaseParser.ISOLATION);\n            break;\n        case SqlBaseParser.LEVEL:\n            this.enterOuterAlt(localctx, 67);\n            this.state = 1474;\n            this.match(SqlBaseParser.LEVEL);\n            break;\n        case SqlBaseParser.SERIALIZABLE:\n            this.enterOuterAlt(localctx, 68);\n            this.state = 1475;\n            this.match(SqlBaseParser.SERIALIZABLE);\n            break;\n        case SqlBaseParser.REPEATABLE:\n            this.enterOuterAlt(localctx, 69);\n            this.state = 1476;\n            this.match(SqlBaseParser.REPEATABLE);\n            break;\n        case SqlBaseParser.COMMITTED:\n            this.enterOuterAlt(localctx, 70);\n            this.state = 1477;\n            this.match(SqlBaseParser.COMMITTED);\n            break;\n        case SqlBaseParser.UNCOMMITTED:\n            this.enterOuterAlt(localctx, 71);\n            this.state = 1478;\n            this.match(SqlBaseParser.UNCOMMITTED);\n            break;\n        case SqlBaseParser.READ:\n            this.enterOuterAlt(localctx, 72);\n            this.state = 1479;\n            this.match(SqlBaseParser.READ);\n            break;\n        case SqlBaseParser.WRITE:\n            this.enterOuterAlt(localctx, 73);\n            this.state = 1480;\n            this.match(SqlBaseParser.WRITE);\n            break;\n        case SqlBaseParser.ONLY:\n            this.enterOuterAlt(localctx, 74);\n            this.state = 1481;\n            this.match(SqlBaseParser.ONLY);\n            break;\n        case SqlBaseParser.CALL:\n            this.enterOuterAlt(localctx, 75);\n            this.state = 1482;\n            this.match(SqlBaseParser.CALL);\n            break;\n        case SqlBaseParser.GRANT:\n            this.enterOuterAlt(localctx, 76);\n            this.state = 1483;\n            this.match(SqlBaseParser.GRANT);\n            break;\n        case SqlBaseParser.REVOKE:\n            this.enterOuterAlt(localctx, 77);\n            this.state = 1484;\n            this.match(SqlBaseParser.REVOKE);\n            break;\n        case SqlBaseParser.PRIVILEGES:\n            this.enterOuterAlt(localctx, 78);\n            this.state = 1485;\n            this.match(SqlBaseParser.PRIVILEGES);\n            break;\n        case SqlBaseParser.PUBLIC:\n            this.enterOuterAlt(localctx, 79);\n            this.state = 1486;\n            this.match(SqlBaseParser.PUBLIC);\n            break;\n        case SqlBaseParser.OPTION:\n            this.enterOuterAlt(localctx, 80);\n            this.state = 1487;\n            this.match(SqlBaseParser.OPTION);\n            break;\n        case SqlBaseParser.SUBSTRING:\n            this.enterOuterAlt(localctx, 81);\n            this.state = 1488;\n            this.match(SqlBaseParser.SUBSTRING);\n            break;\n        case SqlBaseParser.SCHEMA:\n            this.enterOuterAlt(localctx, 82);\n            this.state = 1489;\n            this.match(SqlBaseParser.SCHEMA);\n            break;\n        case SqlBaseParser.CASCADE:\n            this.enterOuterAlt(localctx, 83);\n            this.state = 1490;\n            this.match(SqlBaseParser.CASCADE);\n            break;\n        case SqlBaseParser.RESTRICT:\n            this.enterOuterAlt(localctx, 84);\n            this.state = 1491;\n            this.match(SqlBaseParser.RESTRICT);\n            break;\n        case SqlBaseParser.INPUT:\n            this.enterOuterAlt(localctx, 85);\n            this.state = 1492;\n            this.match(SqlBaseParser.INPUT);\n            break;\n        case SqlBaseParser.OUTPUT:\n            this.enterOuterAlt(localctx, 86);\n            this.state = 1493;\n            this.match(SqlBaseParser.OUTPUT);\n            break;\n        case SqlBaseParser.INCLUDING:\n            this.enterOuterAlt(localctx, 87);\n            this.state = 1494;\n            this.match(SqlBaseParser.INCLUDING);\n            break;\n        case SqlBaseParser.EXCLUDING:\n            this.enterOuterAlt(localctx, 88);\n            this.state = 1495;\n            this.match(SqlBaseParser.EXCLUDING);\n            break;\n        case SqlBaseParser.PROPERTIES:\n            this.enterOuterAlt(localctx, 89);\n            this.state = 1496;\n            this.match(SqlBaseParser.PROPERTIES);\n            break;\n        default:\n            throw new _error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction NormalFormContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = SqlBaseParser.RULE_normalForm;\n    // return this;\n}\n\nNormalFormContext.prototype = Object.create(ParserRuleContext.prototype);\nNormalFormContext.prototype.constructor = NormalFormContext;\n\nNormalFormContext.prototype.NFD = function() {\n    return this.getToken(SqlBaseParser.NFD, 0);\n};\n\nNormalFormContext.prototype.NFC = function() {\n    return this.getToken(SqlBaseParser.NFC, 0);\n};\n\nNormalFormContext.prototype.NFKD = function() {\n    return this.getToken(SqlBaseParser.NFKD, 0);\n};\n\nNormalFormContext.prototype.NFKC = function() {\n    return this.getToken(SqlBaseParser.NFKC, 0);\n};\n\nNormalFormContext.prototype.enterRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).enterNormalForm(this);\n\t}\n};\n\nNormalFormContext.prototype.exitRule = function(listener) {\n    if(listener instanceof SqlBaseListener ) {\n        (listener as any).exitNormalForm(this);\n\t}\n};\n\nNormalFormContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof SqlBaseVisitor ) {\n        return (visitor as any).visitNormalForm(this);\n    } else {\n        return (visitor as any).visitChildren(this);\n    }\n};\n\n\n\n\nSqlBaseParser.NormalFormContext = NormalFormContext;\n\nSqlBaseParser.prototype.normalForm = function() {\n\n    var localctx = new NormalFormContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 122, SqlBaseParser.RULE_normalForm);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1499;\n        _la = this._input.LA(1);\n        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))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof _error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\n\nSqlBaseParser.prototype.sempred = function(localctx, ruleIndex, predIndex) {\n\tswitch(ruleIndex) {\n\tcase 12:\n\t\t\treturn this.queryTerm_sempred(localctx, predIndex);\n\tcase 23:\n\t\t\treturn this.relation_sempred(localctx, predIndex);\n\tcase 32:\n\t\t\treturn this.booleanExpression_sempred(localctx, predIndex);\n\tcase 35:\n\t\t\treturn this.valueExpression_sempred(localctx, predIndex);\n\tcase 36:\n\t\t\treturn this.primaryExpression_sempred(localctx, predIndex);\n\tcase 43:\n\t\t\treturn this.type_sempred(localctx, predIndex);\n    default:\n        throw \"No predicate with index:\" + ruleIndex;\n   }\n};\n\nSqlBaseParser.prototype.queryTerm_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 0:\n\t\t\treturn this.precpred(this._ctx, 2);\n\t\tcase 1:\n\t\t\treturn this.precpred(this._ctx, 1);\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n\nSqlBaseParser.prototype.relation_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 2:\n\t\t\treturn this.precpred(this._ctx, 2);\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n\nSqlBaseParser.prototype.booleanExpression_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 3:\n\t\t\treturn this.precpred(this._ctx, 2);\n\t\tcase 4:\n\t\t\treturn this.precpred(this._ctx, 1);\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n\nSqlBaseParser.prototype.valueExpression_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 5:\n\t\t\treturn this.precpred(this._ctx, 3);\n\t\tcase 6:\n\t\t\treturn this.precpred(this._ctx, 2);\n\t\tcase 7:\n\t\t\treturn this.precpred(this._ctx, 1);\n\t\tcase 8:\n\t\t\treturn this.precpred(this._ctx, 5);\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n\nSqlBaseParser.prototype.primaryExpression_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 9:\n\t\t\treturn this.precpred(this._ctx, 11);\n\t\tcase 10:\n\t\t\treturn this.precpred(this._ctx, 9);\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n\nSqlBaseParser.prototype.type_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 11:\n\t\t\treturn this.precpred(this._ctx, 5);\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/presto-grammar/lang/presto/SqlBaseVisitor.ts",
    "content": "// Generated from ./lang/presto/SqlBase.g4 by ANTLR 4.7\n// jshint ignore: start\nimport { tree } from 'antlr4';\n\n// This class defines a complete generic visitor for a parse tree produced by SqlBaseParser.\n\nexport const SqlBaseVisitor = function() {\n  tree.ParseTreeVisitor.call(this);\n  return this;\n} as any;\n\nSqlBaseVisitor.prototype = Object.create(tree.ParseTreeVisitor.prototype);\nSqlBaseVisitor.prototype.constructor = SqlBaseVisitor;\n\n// Visit a parse tree produced by SqlBaseParser#multiStatement.\nSqlBaseVisitor.prototype.visitMultiStatement = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#singleStatement.\nSqlBaseVisitor.prototype.visitSingleStatement = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#singleExpression.\nSqlBaseVisitor.prototype.visitSingleExpression = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#statementDefault.\nSqlBaseVisitor.prototype.visitStatementDefault = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#use.\nSqlBaseVisitor.prototype.visitUse = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#createSchema.\nSqlBaseVisitor.prototype.visitCreateSchema = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#dropSchema.\nSqlBaseVisitor.prototype.visitDropSchema = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#renameSchema.\nSqlBaseVisitor.prototype.visitRenameSchema = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#createTableAsSelect.\nSqlBaseVisitor.prototype.visitCreateTableAsSelect = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#createTable.\nSqlBaseVisitor.prototype.visitCreateTable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#dropTable.\nSqlBaseVisitor.prototype.visitDropTable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#insertInto.\nSqlBaseVisitor.prototype.visitInsertInto = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#delete.\nSqlBaseVisitor.prototype.visitDelete = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#renameTable.\nSqlBaseVisitor.prototype.visitRenameTable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#renameColumn.\nSqlBaseVisitor.prototype.visitRenameColumn = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#addColumn.\nSqlBaseVisitor.prototype.visitAddColumn = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#createView.\nSqlBaseVisitor.prototype.visitCreateView = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#dropView.\nSqlBaseVisitor.prototype.visitDropView = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#call.\nSqlBaseVisitor.prototype.visitCall = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#grant.\nSqlBaseVisitor.prototype.visitGrant = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#revoke.\nSqlBaseVisitor.prototype.visitRevoke = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#explain.\nSqlBaseVisitor.prototype.visitExplain = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showCreateTable.\nSqlBaseVisitor.prototype.visitShowCreateTable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showCreateView.\nSqlBaseVisitor.prototype.visitShowCreateView = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showTables.\nSqlBaseVisitor.prototype.visitShowTables = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showSchemas.\nSqlBaseVisitor.prototype.visitShowSchemas = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showCatalogs.\nSqlBaseVisitor.prototype.visitShowCatalogs = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showColumns.\nSqlBaseVisitor.prototype.visitShowColumns = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showFunctions.\nSqlBaseVisitor.prototype.visitShowFunctions = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showSession.\nSqlBaseVisitor.prototype.visitShowSession = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#setSession.\nSqlBaseVisitor.prototype.visitSetSession = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#resetSession.\nSqlBaseVisitor.prototype.visitResetSession = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#startTransaction.\nSqlBaseVisitor.prototype.visitStartTransaction = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#commit.\nSqlBaseVisitor.prototype.visitCommit = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#rollback.\nSqlBaseVisitor.prototype.visitRollback = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#showPartitions.\nSqlBaseVisitor.prototype.visitShowPartitions = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#prepare.\nSqlBaseVisitor.prototype.visitPrepare = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#deallocate.\nSqlBaseVisitor.prototype.visitDeallocate = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#execute.\nSqlBaseVisitor.prototype.visitExecute = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#describeInput.\nSqlBaseVisitor.prototype.visitDescribeInput = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#describeOutput.\nSqlBaseVisitor.prototype.visitDescribeOutput = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#query.\nSqlBaseVisitor.prototype.visitQuery = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#presto_with.\nSqlBaseVisitor.prototype.visitPresto_with = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#tableElement.\nSqlBaseVisitor.prototype.visitTableElement = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#columnDefinition.\nSqlBaseVisitor.prototype.visitColumnDefinition = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#likeClause.\nSqlBaseVisitor.prototype.visitLikeClause = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#tableProperties.\nSqlBaseVisitor.prototype.visitTableProperties = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#tableProperty.\nSqlBaseVisitor.prototype.visitTableProperty = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#queryNoWith.\nSqlBaseVisitor.prototype.visitQueryNoWith = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#queryTermDefault.\nSqlBaseVisitor.prototype.visitQueryTermDefault = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#setOperation.\nSqlBaseVisitor.prototype.visitSetOperation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#queryPrimaryDefault.\nSqlBaseVisitor.prototype.visitQueryPrimaryDefault = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#table.\nSqlBaseVisitor.prototype.visitTable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#inlineTable.\nSqlBaseVisitor.prototype.visitInlineTable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#subquery.\nSqlBaseVisitor.prototype.visitSubquery = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#sortItem.\nSqlBaseVisitor.prototype.visitSortItem = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#querySpecification.\nSqlBaseVisitor.prototype.visitQuerySpecification = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#groupBy.\nSqlBaseVisitor.prototype.visitGroupBy = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#singleGroupingSet.\nSqlBaseVisitor.prototype.visitSingleGroupingSet = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#rollup.\nSqlBaseVisitor.prototype.visitRollup = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#cube.\nSqlBaseVisitor.prototype.visitCube = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#multipleGroupingSets.\nSqlBaseVisitor.prototype.visitMultipleGroupingSets = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#groupingExpressions.\nSqlBaseVisitor.prototype.visitGroupingExpressions = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#groupingSet.\nSqlBaseVisitor.prototype.visitGroupingSet = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#namedQuery.\nSqlBaseVisitor.prototype.visitNamedQuery = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#setQuantifier.\nSqlBaseVisitor.prototype.visitSetQuantifier = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#selectSingle.\nSqlBaseVisitor.prototype.visitSelectSingle = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#selectAll.\nSqlBaseVisitor.prototype.visitSelectAll = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#relationDefault.\nSqlBaseVisitor.prototype.visitRelationDefault = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#joinRelation.\nSqlBaseVisitor.prototype.visitJoinRelation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#joinType.\nSqlBaseVisitor.prototype.visitJoinType = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#joinCriteria.\nSqlBaseVisitor.prototype.visitJoinCriteria = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#sampledRelation.\nSqlBaseVisitor.prototype.visitSampledRelation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#sampleType.\nSqlBaseVisitor.prototype.visitSampleType = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#aliasedRelation.\nSqlBaseVisitor.prototype.visitAliasedRelation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#columnAliases.\nSqlBaseVisitor.prototype.visitColumnAliases = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#tableName.\nSqlBaseVisitor.prototype.visitTableName = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#subqueryRelation.\nSqlBaseVisitor.prototype.visitSubqueryRelation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#unnest.\nSqlBaseVisitor.prototype.visitUnnest = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#parenthesizedRelation.\nSqlBaseVisitor.prototype.visitParenthesizedRelation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#expression.\nSqlBaseVisitor.prototype.visitExpression = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#logicalNot.\nSqlBaseVisitor.prototype.visitLogicalNot = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#booleanDefault.\nSqlBaseVisitor.prototype.visitBooleanDefault = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#logicalBinary.\nSqlBaseVisitor.prototype.visitLogicalBinary = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#predicated.\nSqlBaseVisitor.prototype.visitPredicated = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#comparison.\nSqlBaseVisitor.prototype.visitComparison = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#quantifiedComparison.\nSqlBaseVisitor.prototype.visitQuantifiedComparison = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#between.\nSqlBaseVisitor.prototype.visitBetween = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#inList.\nSqlBaseVisitor.prototype.visitInList = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#inSubquery.\nSqlBaseVisitor.prototype.visitInSubquery = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#like.\nSqlBaseVisitor.prototype.visitLike = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#nullPredicate.\nSqlBaseVisitor.prototype.visitNullPredicate = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#distinctFrom.\nSqlBaseVisitor.prototype.visitDistinctFrom = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#valueExpressionDefault.\nSqlBaseVisitor.prototype.visitValueExpressionDefault = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#concatenation.\nSqlBaseVisitor.prototype.visitConcatenation = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#arithmeticBinary.\nSqlBaseVisitor.prototype.visitArithmeticBinary = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#arithmeticUnary.\nSqlBaseVisitor.prototype.visitArithmeticUnary = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#atTimeZone.\nSqlBaseVisitor.prototype.visitAtTimeZone = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#dereference.\nSqlBaseVisitor.prototype.visitDereference = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#typeConstructor.\nSqlBaseVisitor.prototype.visitTypeConstructor = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#specialDateTimeFunction.\nSqlBaseVisitor.prototype.visitSpecialDateTimeFunction = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#substring.\nSqlBaseVisitor.prototype.visitSubstring = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#cast.\nSqlBaseVisitor.prototype.visitCast = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#lambda.\nSqlBaseVisitor.prototype.visitLambda = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#parameter.\nSqlBaseVisitor.prototype.visitParameter = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#normalize.\nSqlBaseVisitor.prototype.visitNormalize = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#intervalLiteral.\nSqlBaseVisitor.prototype.visitIntervalLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#numericLiteral.\nSqlBaseVisitor.prototype.visitNumericLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#booleanLiteral.\nSqlBaseVisitor.prototype.visitBooleanLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#implicitRowConstructor.\nSqlBaseVisitor.prototype.visitImplicitRowConstructor = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#simpleCase.\nSqlBaseVisitor.prototype.visitSimpleCase = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#columnReference.\nSqlBaseVisitor.prototype.visitColumnReference = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#nullLiteral.\nSqlBaseVisitor.prototype.visitNullLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#rowConstructor.\nSqlBaseVisitor.prototype.visitRowConstructor = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#subscript.\nSqlBaseVisitor.prototype.visitSubscript = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#subqueryExpression.\nSqlBaseVisitor.prototype.visitSubqueryExpression = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#binaryLiteral.\nSqlBaseVisitor.prototype.visitBinaryLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#extract.\nSqlBaseVisitor.prototype.visitExtract = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#stringLiteral.\nSqlBaseVisitor.prototype.visitStringLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#arrayConstructor.\nSqlBaseVisitor.prototype.visitArrayConstructor = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#functionCall.\nSqlBaseVisitor.prototype.visitFunctionCall = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#exists.\nSqlBaseVisitor.prototype.visitExists = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#position.\nSqlBaseVisitor.prototype.visitPosition = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#searchedCase.\nSqlBaseVisitor.prototype.visitSearchedCase = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#timeZoneInterval.\nSqlBaseVisitor.prototype.visitTimeZoneInterval = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#timeZoneString.\nSqlBaseVisitor.prototype.visitTimeZoneString = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#comparisonOperator.\nSqlBaseVisitor.prototype.visitComparisonOperator = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#comparisonQuantifier.\nSqlBaseVisitor.prototype.visitComparisonQuantifier = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#booleanValue.\nSqlBaseVisitor.prototype.visitBooleanValue = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#interval.\nSqlBaseVisitor.prototype.visitInterval = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#intervalField.\nSqlBaseVisitor.prototype.visitIntervalField = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#type.\nSqlBaseVisitor.prototype.visitType = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#typeParameter.\nSqlBaseVisitor.prototype.visitTypeParameter = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#baseType.\nSqlBaseVisitor.prototype.visitBaseType = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#whenClause.\nSqlBaseVisitor.prototype.visitWhenClause = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#filter.\nSqlBaseVisitor.prototype.visitFilter = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#over.\nSqlBaseVisitor.prototype.visitOver = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#windowFrame.\nSqlBaseVisitor.prototype.visitWindowFrame = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#unboundedFrame.\nSqlBaseVisitor.prototype.visitUnboundedFrame = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#currentRowBound.\nSqlBaseVisitor.prototype.visitCurrentRowBound = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#boundedFrame.\nSqlBaseVisitor.prototype.visitBoundedFrame = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#explainFormat.\nSqlBaseVisitor.prototype.visitExplainFormat = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#explainType.\nSqlBaseVisitor.prototype.visitExplainType = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#isolationLevel.\nSqlBaseVisitor.prototype.visitIsolationLevel = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#transactionAccessMode.\nSqlBaseVisitor.prototype.visitTransactionAccessMode = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#readUncommitted.\nSqlBaseVisitor.prototype.visitReadUncommitted = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#readCommitted.\nSqlBaseVisitor.prototype.visitReadCommitted = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#repeatableRead.\nSqlBaseVisitor.prototype.visitRepeatableRead = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#serializable.\nSqlBaseVisitor.prototype.visitSerializable = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#positionalArgument.\nSqlBaseVisitor.prototype.visitPositionalArgument = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#namedArgument.\nSqlBaseVisitor.prototype.visitNamedArgument = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#privilege.\nSqlBaseVisitor.prototype.visitPrivilege = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#qualifiedName.\nSqlBaseVisitor.prototype.visitQualifiedName = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#unquotedIdentifier.\nSqlBaseVisitor.prototype.visitUnquotedIdentifier = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#quotedIdentifierAlternative.\nSqlBaseVisitor.prototype.visitQuotedIdentifierAlternative = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#backQuotedIdentifier.\nSqlBaseVisitor.prototype.visitBackQuotedIdentifier = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#digitIdentifier.\nSqlBaseVisitor.prototype.visitDigitIdentifier = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#quotedIdentifier.\nSqlBaseVisitor.prototype.visitQuotedIdentifier = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#decimalLiteral.\nSqlBaseVisitor.prototype.visitDecimalLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#integerLiteral.\nSqlBaseVisitor.prototype.visitIntegerLiteral = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#nonReserved.\nSqlBaseVisitor.prototype.visitNonReserved = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n// Visit a parse tree produced by SqlBaseParser#normalForm.\nSqlBaseVisitor.prototype.visitNormalForm = function(ctx) {\n  return this.visitChildren(ctx);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Lexer.js",
    "content": "// Generated from ./lang/python/Python3.g4 by ANTLR 4.7\n// jshint ignore: start\nvar antlr4 = require('antlr4/index');\n\n\nvar serializedATN = [\"\\u0003\\u608b\\ua72a\\u8133\\ub9ed\\u417c\\u3be7\\u7786\\u5964\",\n    \"\\u0002^\\u0347\\b\\u0001\\u0004\\u0002\\t\\u0002\\u0004\\u0003\\t\\u0003\\u0004\",\n    \"\\u0004\\t\\u0004\\u0004\\u0005\\t\\u0005\\u0004\\u0006\\t\\u0006\\u0004\\u0007\\t\",\n    \"\\u0007\\u0004\\b\\t\\b\\u0004\\t\\t\\t\\u0004\\n\\t\\n\\u0004\\u000b\\t\\u000b\\u0004\",\n    \"\\f\\t\\f\\u0004\\r\\t\\r\\u0004\\u000e\\t\\u000e\\u0004\\u000f\\t\\u000f\\u0004\\u0010\",\n    \"\\t\\u0010\\u0004\\u0011\\t\\u0011\\u0004\\u0012\\t\\u0012\\u0004\\u0013\\t\\u0013\",\n    \"\\u0004\\u0014\\t\\u0014\\u0004\\u0015\\t\\u0015\\u0004\\u0016\\t\\u0016\\u0004\\u0017\",\n    \"\\t\\u0017\\u0004\\u0018\\t\\u0018\\u0004\\u0019\\t\\u0019\\u0004\\u001a\\t\\u001a\",\n    \"\\u0004\\u001b\\t\\u001b\\u0004\\u001c\\t\\u001c\\u0004\\u001d\\t\\u001d\\u0004\\u001e\",\n    \"\\t\\u001e\\u0004\\u001f\\t\\u001f\\u0004 \\t \\u0004!\\t!\\u0004\\\"\\t\\\"\\u0004#\",\n    \"\\t#\\u0004$\\t$\\u0004%\\t%\\u0004&\\t&\\u0004\\'\\t\\'\\u0004(\\t(\\u0004)\\t)\\u0004\",\n    \"*\\t*\\u0004+\\t+\\u0004,\\t,\\u0004-\\t-\\u0004.\\t.\\u0004/\\t/\\u00040\\t0\\u0004\",\n    \"1\\t1\\u00042\\t2\\u00043\\t3\\u00044\\t4\\u00045\\t5\\u00046\\t6\\u00047\\t7\\u0004\",\n    \"8\\t8\\u00049\\t9\\u0004:\\t:\\u0004;\\t;\\u0004<\\t<\\u0004=\\t=\\u0004>\\t>\\u0004\",\n    \"?\\t?\\u0004@\\t@\\u0004A\\tA\\u0004B\\tB\\u0004C\\tC\\u0004D\\tD\\u0004E\\tE\\u0004\",\n    \"F\\tF\\u0004G\\tG\\u0004H\\tH\\u0004I\\tI\\u0004J\\tJ\\u0004K\\tK\\u0004L\\tL\\u0004\",\n    \"M\\tM\\u0004N\\tN\\u0004O\\tO\\u0004P\\tP\\u0004Q\\tQ\\u0004R\\tR\\u0004S\\tS\\u0004\",\n    \"T\\tT\\u0004U\\tU\\u0004V\\tV\\u0004W\\tW\\u0004X\\tX\\u0004Y\\tY\\u0004Z\\tZ\\u0004\",\n    \"[\\t[\\u0004\\\\\\t\\\\\\u0004]\\t]\\u0004^\\t^\\u0004_\\t_\\u0004`\\t`\\u0004a\\ta\\u0004\",\n    \"b\\tb\\u0004c\\tc\\u0004d\\td\\u0004e\\te\\u0004f\\tf\\u0004g\\tg\\u0004h\\th\\u0004\",\n    \"i\\ti\\u0004j\\tj\\u0004k\\tk\\u0004l\\tl\\u0004m\\tm\\u0004n\\tn\\u0004o\\to\\u0004\",\n    \"p\\tp\\u0004q\\tq\\u0004r\\tr\\u0004s\\ts\\u0004t\\tt\\u0004u\\tu\\u0004v\\tv\\u0004\",\n    \"w\\tw\\u0004x\\tx\\u0003\\u0002\\u0003\\u0002\\u0003\\u0002\\u0003\\u0002\\u0003\",\n    \"\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\",\n    \"\\u0003\\u0003\\u0004\\u0003\\u0004\\u0003\\u0004\\u0003\\u0004\\u0003\\u0004\\u0003\",\n    \"\\u0004\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\",\n    \"\\u0006\\u0003\\u0006\\u0003\\u0006\\u0003\\u0006\\u0003\\u0006\\u0003\\u0006\\u0003\",\n    \"\\u0006\\u0003\\u0007\\u0003\\u0007\\u0003\\u0007\\u0003\\b\\u0003\\b\\u0003\\b\\u0003\",\n    \"\\b\\u0003\\b\\u0003\\b\\u0003\\b\\u0003\\t\\u0003\\t\\u0003\\t\\u0003\\t\\u0003\\t\\u0003\",\n    \"\\t\\u0003\\t\\u0003\\t\\u0003\\t\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\",\n    \"\\n\\u0003\\n\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b\\u0003\\f\\u0003\\f\\u0003\",\n    \"\\f\\u0003\\f\\u0003\\f\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\r\\u0003\\u000e\",\n    \"\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\\u000e\\u0003\\u000f\",\n    \"\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\",\n    \"\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0012\\u0003\\u0012\",\n    \"\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\",\n    \"\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0013\\u0003\\u0014\",\n    \"\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0014\",\n    \"\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\\u0003\\u0015\",\n    \"\\u0003\\u0015\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0017\\u0003\\u0017\",\n    \"\\u0003\\u0017\\u0003\\u0017\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\\u0003\\u0018\",\n    \"\\u0003\\u0019\\u0003\\u0019\\u0003\\u0019\\u0003\\u001a\\u0003\\u001a\\u0003\\u001a\",\n    \"\\u0003\\u001a\\u0003\\u001a\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\\u0003\\u001b\",\n    \"\\u0003\\u001b\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\\u0003\\u001c\",\n    \"\\u0003\\u001c\\u0003\\u001d\\u0003\\u001d\\u0003\\u001d\\u0003\\u001d\\u0003\\u001d\",\n    \"\\u0003\\u001d\\u0003\\u001e\\u0003\\u001e\\u0003\\u001e\\u0003\\u001e\\u0003\\u001e\",\n    \"\\u0003\\u001e\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0003\\u001f\\u0003 \",\n    \"\\u0003 \\u0003 \\u0003 \\u0003 \\u0003!\\u0003!\\u0003!\\u0003!\\u0003!\\u0003\",\n    \"!\\u0003!\\u0003!\\u0003!\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0003\",\n    \"\\\"\\u0003#\\u0003#\\u0003#\\u0005#\\u01a7\\n#\\u0003#\\u0003#\\u0005#\\u01ab\\n\",\n    \"#\\u0003#\\u0005#\\u01ae\\n#\\u0005#\\u01b0\\n#\\u0003#\\u0003#\\u0003$\\u0003\",\n    \"$\\u0007$\\u01b6\\n$\\f$\\u000e$\\u01b9\\u000b$\\u0003%\\u0005%\\u01bc\\n%\\u0003\",\n    \"%\\u0005%\\u01bf\\n%\\u0003%\\u0003%\\u0005%\\u01c3\\n%\\u0003&\\u0003&\\u0005\",\n    \"&\\u01c7\\n&\\u0003&\\u0003&\\u0005&\\u01cb\\n&\\u0003\\'\\u0003\\'\\u0007\\'\\u01cf\",\n    \"\\n\\'\\f\\'\\u000e\\'\\u01d2\\u000b\\'\\u0003\\'\\u0006\\'\\u01d5\\n\\'\\r\\'\\u000e\\'\",\n    \"\\u01d6\\u0005\\'\\u01d9\\n\\'\\u0003(\\u0003(\\u0003(\\u0006(\\u01de\\n(\\r(\\u000e\",\n    \"(\\u01df\\u0003)\\u0003)\\u0003)\\u0006)\\u01e5\\n)\\r)\\u000e)\\u01e6\\u0003*\",\n    \"\\u0003*\\u0003*\\u0006*\\u01ec\\n*\\r*\\u000e*\\u01ed\\u0003+\\u0003+\\u0005+\",\n    \"\\u01f2\\n+\\u0003,\\u0003,\\u0005,\\u01f6\\n,\\u0003,\\u0003,\\u0003-\\u0003-\",\n    \"\\u0003.\\u0003.\\u0003.\\u0003.\\u0003/\\u0003/\\u00030\\u00030\\u00030\\u0003\",\n    \"1\\u00031\\u00031\\u00032\\u00032\\u00033\\u00033\\u00034\\u00034\\u00035\\u0003\",\n    \"5\\u00035\\u00036\\u00036\\u00037\\u00037\\u00037\\u00038\\u00038\\u00038\\u0003\",\n    \"9\\u00039\\u0003:\\u0003:\\u0003;\\u0003;\\u0003<\\u0003<\\u0003<\\u0003=\\u0003\",\n    \"=\\u0003=\\u0003>\\u0003>\\u0003?\\u0003?\\u0003@\\u0003@\\u0003A\\u0003A\\u0003\",\n    \"B\\u0003B\\u0003B\\u0003C\\u0003C\\u0003D\\u0003D\\u0003D\\u0003E\\u0003E\\u0003\",\n    \"E\\u0003F\\u0003F\\u0003G\\u0003G\\u0003H\\u0003H\\u0003H\\u0003I\\u0003I\\u0003\",\n    \"I\\u0003J\\u0003J\\u0003J\\u0003K\\u0003K\\u0003K\\u0003L\\u0003L\\u0003L\\u0003\",\n    \"M\\u0003M\\u0003N\\u0003N\\u0003N\\u0003O\\u0003O\\u0003O\\u0003P\\u0003P\\u0003\",\n    \"P\\u0003Q\\u0003Q\\u0003Q\\u0003R\\u0003R\\u0003R\\u0003S\\u0003S\\u0003S\\u0003\",\n    \"T\\u0003T\\u0003T\\u0003U\\u0003U\\u0003U\\u0003V\\u0003V\\u0003V\\u0003W\\u0003\",\n    \"W\\u0003W\\u0003X\\u0003X\\u0003X\\u0003X\\u0003Y\\u0003Y\\u0003Y\\u0003Y\\u0003\",\n    \"Z\\u0003Z\\u0003Z\\u0003Z\\u0003[\\u0003[\\u0003[\\u0003[\\u0003\\\\\\u0003\\\\\\u0003\",\n    \"\\\\\\u0005\\\\\\u027e\\n\\\\\\u0003\\\\\\u0003\\\\\\u0003]\\u0003]\\u0003^\\u0003^\\u0003\",\n    \"^\\u0007^\\u0287\\n^\\f^\\u000e^\\u028a\\u000b^\\u0003^\\u0003^\\u0003^\\u0003\",\n    \"^\\u0007^\\u0290\\n^\\f^\\u000e^\\u0293\\u000b^\\u0003^\\u0005^\\u0296\\n^\\u0003\",\n    \"_\\u0003_\\u0003_\\u0003_\\u0003_\\u0007_\\u029d\\n_\\f_\\u000e_\\u02a0\\u000b\",\n    \"_\\u0003_\\u0003_\\u0003_\\u0003_\\u0003_\\u0003_\\u0003_\\u0003_\\u0007_\\u02aa\",\n    \"\\n_\\f_\\u000e_\\u02ad\\u000b_\\u0003_\\u0003_\\u0003_\\u0005_\\u02b2\\n_\\u0003\",\n    \"`\\u0003`\\u0005`\\u02b6\\n`\\u0003a\\u0003a\\u0003b\\u0003b\\u0003b\\u0003c\\u0003\",\n    \"c\\u0003d\\u0003d\\u0003e\\u0003e\\u0003f\\u0003f\\u0003g\\u0003g\\u0003h\\u0005\",\n    \"h\\u02c8\\nh\\u0003h\\u0003h\\u0003h\\u0003h\\u0005h\\u02ce\\nh\\u0003i\\u0003\",\n    \"i\\u0005i\\u02d2\\ni\\u0003i\\u0003i\\u0003j\\u0006j\\u02d7\\nj\\rj\\u000ej\\u02d8\",\n    \"\\u0003k\\u0003k\\u0006k\\u02dd\\nk\\rk\\u000ek\\u02de\\u0003l\\u0003l\\u0005l\",\n    \"\\u02e3\\nl\\u0003l\\u0006l\\u02e6\\nl\\rl\\u000el\\u02e7\\u0003m\\u0003m\\u0003\",\n    \"m\\u0007m\\u02ed\\nm\\fm\\u000em\\u02f0\\u000bm\\u0003m\\u0003m\\u0003m\\u0003\",\n    \"m\\u0007m\\u02f6\\nm\\fm\\u000em\\u02f9\\u000bm\\u0003m\\u0005m\\u02fc\\nm\\u0003\",\n    \"n\\u0003n\\u0003n\\u0003n\\u0003n\\u0007n\\u0303\\nn\\fn\\u000en\\u0306\\u000b\",\n    \"n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0003n\\u0007n\\u0310\",\n    \"\\nn\\fn\\u000en\\u0313\\u000bn\\u0003n\\u0003n\\u0003n\\u0005n\\u0318\\nn\\u0003\",\n    \"o\\u0003o\\u0005o\\u031c\\no\\u0003p\\u0005p\\u031f\\np\\u0003q\\u0005q\\u0322\",\n    \"\\nq\\u0003r\\u0005r\\u0325\\nr\\u0003s\\u0003s\\u0003s\\u0003t\\u0006t\\u032b\",\n    \"\\nt\\rt\\u000et\\u032c\\u0003u\\u0003u\\u0007u\\u0331\\nu\\fu\\u000eu\\u0334\\u000b\",\n    \"u\\u0003v\\u0003v\\u0005v\\u0338\\nv\\u0003v\\u0005v\\u033b\\nv\\u0003v\\u0003\",\n    \"v\\u0005v\\u033f\\nv\\u0003w\\u0005w\\u0342\\nw\\u0003x\\u0003x\\u0005x\\u0346\",\n    \"\\nx\\u0006\\u029e\\u02ab\\u0304\\u0311\\u0002y\\u0003\\u0003\\u0005\\u0004\\u0007\",\n    \"\\u0005\\t\\u0006\\u000b\\u0007\\r\\b\\u000f\\t\\u0011\\n\\u0013\\u000b\\u0015\\f\\u0017\",\n    \"\\r\\u0019\\u000e\\u001b\\u000f\\u001d\\u0010\\u001f\\u0011!\\u0012#\\u0013%\\u0014\",\n    \"\\'\\u0015)\\u0016+\\u0017-\\u0018/\\u00191\\u001a3\\u001b5\\u001c7\\u001d9\\u001e\",\n    \";\\u001f= ?!A\\\"C#E$G%I&K\\'M(O)Q*S+U,W-Y.[/]0_1a2c3e4g5i6k7m8o9q:s;u<\",\n    \"w=y>{?}@\\u007fA\\u0081B\\u0083C\\u0085D\\u0087E\\u0089F\\u008bG\\u008dH\\u008f\",\n    \"I\\u0091J\\u0093K\\u0095L\\u0097M\\u0099N\\u009bO\\u009dP\\u009fQ\\u00a1R\\u00a3\",\n    \"S\\u00a5T\\u00a7U\\u00a9V\\u00abW\\u00adX\\u00afY\\u00b1Z\\u00b3[\\u00b5\\\\\\u00b7\",\n    \"]\\u00b9^\\u00bb\\u0002\\u00bd\\u0002\\u00bf\\u0002\\u00c1\\u0002\\u00c3\\u0002\",\n    \"\\u00c5\\u0002\\u00c7\\u0002\\u00c9\\u0002\\u00cb\\u0002\\u00cd\\u0002\\u00cf\\u0002\",\n    \"\\u00d1\\u0002\\u00d3\\u0002\\u00d5\\u0002\\u00d7\\u0002\\u00d9\\u0002\\u00db\\u0002\",\n    \"\\u00dd\\u0002\\u00df\\u0002\\u00e1\\u0002\\u00e3\\u0002\\u00e5\\u0002\\u00e7\\u0002\",\n    \"\\u00e9\\u0002\\u00eb\\u0002\\u00ed\\u0002\\u00ef\\u0002\\u0003\\u0002\\u001a\\u0004\",\n    \"\\u0002WWww\\u0004\\u0002TTtt\\u0004\\u0002DDdd\\u0004\\u0002QQqq\\u0004\\u0002\",\n    \"ZZzz\\u0004\\u0002LLll\\u0006\\u0002\\f\\f\\u000f\\u000f))^^\\u0006\\u0002\\f\\f\",\n    \"\\u000f\\u000f$$^^\\u0003\\u0002^^\\u0003\\u00023;\\u0003\\u00022;\\u0003\\u0002\",\n    \"29\\u0005\\u00022;CHch\\u0003\\u000223\\u0004\\u0002GGgg\\u0004\\u0002--//\\u0007\",\n    \"\\u0002\\u0002\\u000b\\r\\u000e\\u0010(*]_\\u0081\\u0007\\u0002\\u0002\\u000b\\r\",\n    \"\\u000e\\u0010#%]_\\u0081\\u0004\\u0002\\u0002]_\\u0081\\u0003\\u0002\\u0002\\u0081\",\n    \"\\u0004\\u0002\\u000b\\u000b\\\"\\\"\\u0004\\u0002\\f\\f\\u000f\\u000f\\u0129\\u0002\",\n    \"C\\\\aac|\\u00ac\\u00ac\\u00b7\\u00b7\\u00bc\\u00bc\\u00c2\\u00d8\\u00da\\u00f8\",\n    \"\\u00fa\\u0243\\u0252\\u02c3\\u02c8\\u02d3\\u02e2\\u02e6\\u02f0\\u02f0\\u037c\\u037c\",\n    \"\\u0388\\u0388\\u038a\\u038c\\u038e\\u038e\\u0390\\u03a3\\u03a5\\u03d0\\u03d2\\u03f7\",\n    \"\\u03f9\\u0483\\u048c\\u04d0\\u04d2\\u04fb\\u0502\\u0511\\u0533\\u0558\\u055b\\u055b\",\n    \"\\u0563\\u0589\\u05d2\\u05ec\\u05f2\\u05f4\\u0623\\u063c\\u0642\\u064c\\u0670\\u0671\",\n    \"\\u0673\\u06d5\\u06d7\\u06d7\\u06e7\\u06e8\\u06f0\\u06f1\\u06fc\\u06fe\\u0701\\u0701\",\n    \"\\u0712\\u0712\\u0714\\u0731\\u074f\\u076f\\u0782\\u07a7\\u07b3\\u07b3\\u0906\\u093b\",\n    \"\\u093f\\u093f\\u0952\\u0952\\u095a\\u0963\\u097f\\u097f\\u0987\\u098e\\u0991\\u0992\",\n    \"\\u0995\\u09aa\\u09ac\\u09b2\\u09b4\\u09b4\\u09b8\\u09bb\\u09bf\\u09bf\\u09d0\\u09d0\",\n    \"\\u09de\\u09df\\u09e1\\u09e3\\u09f2\\u09f3\\u0a07\\u0a0c\\u0a11\\u0a12\\u0a15\\u0a2a\",\n    \"\\u0a2c\\u0a32\\u0a34\\u0a35\\u0a37\\u0a38\\u0a3a\\u0a3b\\u0a5b\\u0a5e\\u0a60\\u0a60\",\n    \"\\u0a74\\u0a76\\u0a87\\u0a8f\\u0a91\\u0a93\\u0a95\\u0aaa\\u0aac\\u0ab2\\u0ab4\\u0ab5\",\n    \"\\u0ab7\\u0abb\\u0abf\\u0abf\\u0ad2\\u0ad2\\u0ae2\\u0ae3\\u0b07\\u0b0e\\u0b11\\u0b12\",\n    \"\\u0b15\\u0b2a\\u0b2c\\u0b32\\u0b34\\u0b35\\u0b37\\u0b3b\\u0b3f\\u0b3f\\u0b5e\\u0b5f\",\n    \"\\u0b61\\u0b63\\u0b73\\u0b73\\u0b85\\u0b85\\u0b87\\u0b8c\\u0b90\\u0b92\\u0b94\\u0b97\",\n    \"\\u0b9b\\u0b9c\\u0b9e\\u0b9e\\u0ba0\\u0ba1\\u0ba5\\u0ba6\\u0baa\\u0bac\\u0bb0\\u0bbb\",\n    \"\\u0c07\\u0c0e\\u0c10\\u0c12\\u0c14\\u0c2a\\u0c2c\\u0c35\\u0c37\\u0c3b\\u0c62\\u0c63\",\n    \"\\u0c87\\u0c8e\\u0c90\\u0c92\\u0c94\\u0caa\\u0cac\\u0cb5\\u0cb7\\u0cbb\\u0cbf\\u0cbf\",\n    \"\\u0ce0\\u0ce0\\u0ce2\\u0ce3\\u0d07\\u0d0e\\u0d10\\u0d12\\u0d14\\u0d2a\\u0d2c\\u0d3b\",\n    \"\\u0d62\\u0d63\\u0d87\\u0d98\\u0d9c\\u0db3\\u0db5\\u0dbd\\u0dbf\\u0dbf\\u0dc2\\u0dc8\",\n    \"\\u0e03\\u0e32\\u0e34\\u0e35\\u0e42\\u0e48\\u0e83\\u0e84\\u0e86\\u0e86\\u0e89\\u0e8a\",\n    \"\\u0e8c\\u0e8c\\u0e8f\\u0e8f\\u0e96\\u0e99\\u0e9b\\u0ea1\\u0ea3\\u0ea5\\u0ea7\\u0ea7\",\n    \"\\u0ea9\\u0ea9\\u0eac\\u0ead\\u0eaf\\u0eb2\\u0eb4\\u0eb5\\u0ebf\\u0ebf\\u0ec2\\u0ec6\",\n    \"\\u0ec8\\u0ec8\\u0ede\\u0edf\\u0f02\\u0f02\\u0f42\\u0f49\\u0f4b\\u0f6c\\u0f8a\\u0f8d\",\n    \"\\u1002\\u1023\\u1025\\u1029\\u102b\\u102c\\u1052\\u1057\\u10a2\\u10c7\\u10d2\\u10fc\",\n    \"\\u10fe\\u10fe\\u1102\\u115b\\u1161\\u11a4\\u11aa\\u11fb\\u1202\\u124a\\u124c\\u124f\",\n    \"\\u1252\\u1258\\u125a\\u125a\\u125c\\u125f\\u1262\\u128a\\u128c\\u128f\\u1292\\u12b2\",\n    \"\\u12b4\\u12b7\\u12ba\\u12c0\\u12c2\\u12c2\\u12c4\\u12c7\\u12ca\\u12d8\\u12da\\u1312\",\n    \"\\u1314\\u1317\\u131a\\u135c\\u1382\\u1391\\u13a2\\u13f6\\u1403\\u166e\\u1671\\u1678\",\n    \"\\u1683\\u169c\\u16a2\\u16ec\\u16f0\\u16f2\\u1702\\u170e\\u1710\\u1713\\u1722\\u1733\",\n    \"\\u1742\\u1753\\u1762\\u176e\\u1770\\u1772\\u1782\\u17b5\\u17d9\\u17d9\\u17de\\u17de\",\n    \"\\u1822\\u1879\\u1882\\u18aa\\u1902\\u191e\\u1952\\u196f\\u1972\\u1976\\u1982\\u19ab\",\n    \"\\u19c3\\u19c9\\u1a02\\u1a18\\u1d02\\u1dc1\\u1e02\\u1e9d\\u1ea2\\u1efb\\u1f02\\u1f17\",\n    \"\\u1f1a\\u1f1f\\u1f22\\u1f47\\u1f4a\\u1f4f\\u1f52\\u1f59\\u1f5b\\u1f5b\\u1f5d\\u1f5d\",\n    \"\\u1f5f\\u1f5f\\u1f61\\u1f7f\\u1f82\\u1fb6\\u1fb8\\u1fbe\\u1fc0\\u1fc0\\u1fc4\\u1fc6\",\n    \"\\u1fc8\\u1fce\\u1fd2\\u1fd5\\u1fd8\\u1fdd\\u1fe2\\u1fee\\u1ff4\\u1ff6\\u1ff8\\u1ffe\",\n    \"\\u2073\\u2073\\u2081\\u2081\\u2092\\u2096\\u2104\\u2104\\u2109\\u2109\\u210c\\u2115\",\n    \"\\u2117\\u2117\\u211a\\u211f\\u2126\\u2126\\u2128\\u2128\\u212a\\u212a\\u212c\\u2133\",\n    \"\\u2135\\u213b\\u213e\\u2141\\u2147\\u214b\\u2162\\u2185\\u2c02\\u2c30\\u2c32\\u2c60\",\n    \"\\u2c82\\u2ce6\\u2d02\\u2d27\\u2d32\\u2d67\\u2d71\\u2d71\\u2d82\\u2d98\\u2da2\\u2da8\",\n    \"\\u2daa\\u2db0\\u2db2\\u2db8\\u2dba\\u2dc0\\u2dc2\\u2dc8\\u2dca\\u2dd0\\u2dd2\\u2dd8\",\n    \"\\u2dda\\u2de0\\u3007\\u3009\\u3023\\u302b\\u3033\\u3037\\u303a\\u303e\\u3043\\u3098\",\n    \"\\u309d\\u30a1\\u30a3\\u30fc\\u30fe\\u3101\\u3107\\u312e\\u3133\\u3190\\u31a2\\u31b9\",\n    \"\\u31f2\\u3201\\u3402\\u4db7\\u4e02\\u9fbd\\ua002\\ua48e\\ua802\\ua803\\ua805\\ua807\",\n    \"\\ua809\\ua80c\\ua80e\\ua824\\uac02\\ud7a5\\uf902\\ufa2f\\ufa32\\ufa6c\\ufa72\\ufadb\",\n    \"\\ufb02\\ufb08\\ufb15\\ufb19\\ufb1f\\ufb1f\\ufb21\\ufb2a\\ufb2c\\ufb38\\ufb3a\\ufb3e\",\n    \"\\ufb40\\ufb40\\ufb42\\ufb43\\ufb45\\ufb46\\ufb48\\ufbb3\\ufbd5\\ufd3f\\ufd52\\ufd91\",\n    \"\\ufd94\\ufdc9\\ufdf2\\ufdfd\\ufe72\\ufe76\\ufe78\\ufefe\\uff23\\uff3c\\uff43\\uff5c\",\n    \"\\uff68\\uffc0\\uffc4\\uffc9\\uffcc\\uffd1\\uffd4\\uffd9\\uffdc\\uffde\\u0096\\u0002\",\n    \"2;\\u0302\\u0371\\u0485\\u0488\\u0593\\u05bb\\u05bd\\u05bf\\u05c1\\u05c1\\u05c3\",\n    \"\\u05c4\\u05c6\\u05c7\\u05c9\\u05c9\\u0612\\u0617\\u064d\\u0660\\u0662\\u066b\\u0672\",\n    \"\\u0672\\u06d8\\u06de\\u06e1\\u06e6\\u06e9\\u06ea\\u06ec\\u06ef\\u06f2\\u06fb\\u0713\",\n    \"\\u0713\\u0732\\u074c\\u07a8\\u07b2\\u0903\\u0905\\u093e\\u093e\\u0940\\u094f\\u0953\",\n    \"\\u0956\\u0964\\u0965\\u0968\\u0971\\u0983\\u0985\\u09be\\u09be\\u09c0\\u09c6\\u09c9\",\n    \"\\u09ca\\u09cd\\u09cf\\u09d9\\u09d9\\u09e4\\u09e5\\u09e8\\u09f1\\u0a03\\u0a05\\u0a3e\",\n    \"\\u0a3e\\u0a40\\u0a44\\u0a49\\u0a4a\\u0a4d\\u0a4f\\u0a68\\u0a73\\u0a83\\u0a85\\u0abe\",\n    \"\\u0abe\\u0ac0\\u0ac7\\u0ac9\\u0acb\\u0acd\\u0acf\\u0ae4\\u0ae5\\u0ae8\\u0af1\\u0b03\",\n    \"\\u0b05\\u0b3e\\u0b3e\\u0b40\\u0b45\\u0b49\\u0b4a\\u0b4d\\u0b4f\\u0b58\\u0b59\\u0b68\",\n    \"\\u0b71\\u0b84\\u0b84\\u0bc0\\u0bc4\\u0bc8\\u0bca\\u0bcc\\u0bcf\\u0bd9\\u0bd9\\u0be8\",\n    \"\\u0bf1\\u0c03\\u0c05\\u0c40\\u0c46\\u0c48\\u0c4a\\u0c4c\\u0c4f\\u0c57\\u0c58\\u0c68\",\n    \"\\u0c71\\u0c84\\u0c85\\u0cbe\\u0cbe\\u0cc0\\u0cc6\\u0cc8\\u0cca\\u0ccc\\u0ccf\\u0cd7\",\n    \"\\u0cd8\\u0ce8\\u0cf1\\u0d04\\u0d05\\u0d40\\u0d45\\u0d48\\u0d4a\\u0d4c\\u0d4f\\u0d59\",\n    \"\\u0d59\\u0d68\\u0d71\\u0d84\\u0d85\\u0dcc\\u0dcc\\u0dd1\\u0dd6\\u0dd8\\u0dd8\\u0dda\",\n    \"\\u0de1\\u0df4\\u0df5\\u0e33\\u0e33\\u0e36\\u0e3c\\u0e49\\u0e50\\u0e52\\u0e5b\\u0eb3\",\n    \"\\u0eb3\\u0eb6\\u0ebb\\u0ebd\\u0ebe\\u0eca\\u0ecf\\u0ed2\\u0edb\\u0f1a\\u0f1b\\u0f22\",\n    \"\\u0f2b\\u0f37\\u0f37\\u0f39\\u0f39\\u0f3b\\u0f3b\\u0f40\\u0f41\\u0f73\\u0f86\\u0f88\",\n    \"\\u0f89\\u0f92\\u0f99\\u0f9b\\u0fbe\\u0fc8\\u0fc8\\u102e\\u1034\\u1038\\u103b\\u1042\",\n    \"\\u104b\\u1058\\u105b\\u1361\\u1361\\u136b\\u1373\\u1714\\u1716\\u1734\\u1736\\u1754\",\n    \"\\u1755\\u1774\\u1775\\u17b8\\u17d5\\u17df\\u17df\\u17e2\\u17eb\\u180d\\u180f\\u1812\",\n    \"\\u181b\\u18ab\\u18ab\\u1922\\u192d\\u1932\\u193d\\u1948\\u1951\\u19b2\\u19c2\\u19ca\",\n    \"\\u19cb\\u19d2\\u19db\\u1a19\\u1a1d\\u1dc2\\u1dc5\\u2041\\u2042\\u2056\\u2056\\u20d2\",\n    \"\\u20de\\u20e3\\u20e3\\u20e7\\u20ed\\u302c\\u3031\\u309b\\u309c\\ua804\\ua804\\ua808\",\n    \"\\ua808\\ua80d\\ua80d\\ua825\\ua829\\ufb20\\ufb20\\ufe02\\ufe11\\ufe22\\ufe25\\ufe35\",\n    \"\\ufe36\\ufe4f\\ufe51\\uff12\\uff1b\\uff41\\uff41\\u0002\\u035e\\u0002\\u0003\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\u0005\\u0003\\u0002\\u0002\\u0002\\u0002\\u0007\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\t\\u0003\\u0002\\u0002\\u0002\\u0002\\u000b\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\r\\u0003\\u0002\\u0002\\u0002\\u0002\\u000f\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\u0011\\u0003\\u0002\\u0002\\u0002\\u0002\\u0013\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\u0015\\u0003\\u0002\\u0002\\u0002\\u0002\\u0017\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\u0019\\u0003\\u0002\\u0002\\u0002\\u0002\\u001b\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002\\u001d\\u0003\\u0002\\u0002\\u0002\\u0002\\u001f\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002!\\u0003\\u0002\\u0002\\u0002\\u0002#\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002%\\u0003\\u0002\\u0002\\u0002\\u0002\\'\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0002)\\u0003\\u0002\\u0002\\u0002\\u0002+\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0002-\\u0003\\u0002\\u0002\\u0002\\u0002/\\u0003\\u0002\\u0002\\u0002\\u0002\",\n    \"1\\u0003\\u0002\\u0002\\u0002\\u00023\\u0003\\u0002\\u0002\\u0002\\u00025\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00027\\u0003\\u0002\\u0002\\u0002\\u00029\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002;\\u0003\\u0002\\u0002\\u0002\\u0002=\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0002?\\u0003\\u0002\\u0002\\u0002\\u0002A\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0002C\\u0003\\u0002\\u0002\\u0002\\u0002E\\u0003\\u0002\\u0002\\u0002\\u0002\",\n    \"G\\u0003\\u0002\\u0002\\u0002\\u0002I\\u0003\\u0002\\u0002\\u0002\\u0002K\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002M\\u0003\\u0002\\u0002\\u0002\\u0002O\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002Q\\u0003\\u0002\\u0002\\u0002\\u0002S\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0002U\\u0003\\u0002\\u0002\\u0002\\u0002W\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0002Y\\u0003\\u0002\\u0002\\u0002\\u0002[\\u0003\\u0002\\u0002\\u0002\\u0002\",\n    \"]\\u0003\\u0002\\u0002\\u0002\\u0002_\\u0003\\u0002\\u0002\\u0002\\u0002a\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002c\\u0003\\u0002\\u0002\\u0002\\u0002e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002g\\u0003\\u0002\\u0002\\u0002\\u0002i\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0002k\\u0003\\u0002\\u0002\\u0002\\u0002m\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0002o\\u0003\\u0002\\u0002\\u0002\\u0002q\\u0003\\u0002\\u0002\\u0002\\u0002\",\n    \"s\\u0003\\u0002\\u0002\\u0002\\u0002u\\u0003\\u0002\\u0002\\u0002\\u0002w\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0002y\\u0003\\u0002\\u0002\\u0002\\u0002{\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002}\\u0003\\u0002\\u0002\\u0002\\u0002\\u007f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u0081\\u0003\\u0002\\u0002\\u0002\\u0002\\u0083\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u0085\\u0003\\u0002\\u0002\\u0002\\u0002\\u0087\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u0089\\u0003\\u0002\\u0002\\u0002\\u0002\\u008b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u008d\\u0003\\u0002\\u0002\\u0002\\u0002\\u008f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u0091\\u0003\\u0002\\u0002\\u0002\\u0002\\u0093\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u0095\\u0003\\u0002\\u0002\\u0002\\u0002\\u0097\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u0099\\u0003\\u0002\\u0002\\u0002\\u0002\\u009b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u009d\\u0003\\u0002\\u0002\\u0002\\u0002\\u009f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00a1\\u0003\\u0002\\u0002\\u0002\\u0002\\u00a3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00a5\\u0003\\u0002\\u0002\\u0002\\u0002\\u00a7\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00a9\\u0003\\u0002\\u0002\\u0002\\u0002\\u00ab\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00ad\\u0003\\u0002\\u0002\\u0002\\u0002\\u00af\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00b1\\u0003\\u0002\\u0002\\u0002\\u0002\\u00b3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00b5\\u0003\\u0002\\u0002\\u0002\\u0002\\u00b7\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0002\\u00b9\\u0003\\u0002\\u0002\\u0002\\u0003\\u00f1\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0005\\u00f5\\u0003\\u0002\\u0002\\u0002\\u0007\\u00fc\\u0003\\u0002\",\n    \"\\u0002\\u0002\\t\\u0102\\u0003\\u0002\\u0002\\u0002\\u000b\\u0107\\u0003\\u0002\",\n    \"\\u0002\\u0002\\r\\u010e\\u0003\\u0002\\u0002\\u0002\\u000f\\u0111\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0011\\u0118\\u0003\\u0002\\u0002\\u0002\\u0013\\u0121\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0015\\u0128\\u0003\\u0002\\u0002\\u0002\\u0017\\u012b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0019\\u0130\\u0003\\u0002\\u0002\\u0002\\u001b\\u0135\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u001d\\u013b\\u0003\\u0002\\u0002\\u0002\\u001f\\u013f\\u0003\\u0002\",\n    \"\\u0002\\u0002!\\u0142\\u0003\\u0002\\u0002\\u0002#\\u0146\\u0003\\u0002\\u0002\",\n    \"\\u0002%\\u014e\\u0003\\u0002\\u0002\\u0002\\'\\u0153\\u0003\\u0002\\u0002\\u0002\",\n    \")\\u015a\\u0003\\u0002\\u0002\\u0002+\\u0161\\u0003\\u0002\\u0002\\u0002-\\u0164\",\n    \"\\u0003\\u0002\\u0002\\u0002/\\u0168\\u0003\\u0002\\u0002\\u00021\\u016c\\u0003\",\n    \"\\u0002\\u0002\\u00023\\u016f\\u0003\\u0002\\u0002\\u00025\\u0174\\u0003\\u0002\",\n    \"\\u0002\\u00027\\u0179\\u0003\\u0002\\u0002\\u00029\\u017f\\u0003\\u0002\\u0002\",\n    \"\\u0002;\\u0185\\u0003\\u0002\\u0002\\u0002=\\u018b\\u0003\\u0002\\u0002\\u0002\",\n    \"?\\u018f\\u0003\\u0002\\u0002\\u0002A\\u0194\\u0003\\u0002\\u0002\\u0002C\\u019d\",\n    \"\\u0003\\u0002\\u0002\\u0002E\\u01af\\u0003\\u0002\\u0002\\u0002G\\u01b3\\u0003\",\n    \"\\u0002\\u0002\\u0002I\\u01bb\\u0003\\u0002\\u0002\\u0002K\\u01c4\\u0003\\u0002\",\n    \"\\u0002\\u0002M\\u01d8\\u0003\\u0002\\u0002\\u0002O\\u01da\\u0003\\u0002\\u0002\",\n    \"\\u0002Q\\u01e1\\u0003\\u0002\\u0002\\u0002S\\u01e8\\u0003\\u0002\\u0002\\u0002\",\n    \"U\\u01f1\\u0003\\u0002\\u0002\\u0002W\\u01f5\\u0003\\u0002\\u0002\\u0002Y\\u01f9\",\n    \"\\u0003\\u0002\\u0002\\u0002[\\u01fb\\u0003\\u0002\\u0002\\u0002]\\u01ff\\u0003\",\n    \"\\u0002\\u0002\\u0002_\\u0201\\u0003\\u0002\\u0002\\u0002a\\u0204\\u0003\\u0002\",\n    \"\\u0002\\u0002c\\u0207\\u0003\\u0002\\u0002\\u0002e\\u0209\\u0003\\u0002\\u0002\",\n    \"\\u0002g\\u020b\\u0003\\u0002\\u0002\\u0002i\\u020d\\u0003\\u0002\\u0002\\u0002\",\n    \"k\\u0210\\u0003\\u0002\\u0002\\u0002m\\u0212\\u0003\\u0002\\u0002\\u0002o\\u0215\",\n    \"\\u0003\\u0002\\u0002\\u0002q\\u0218\\u0003\\u0002\\u0002\\u0002s\\u021a\\u0003\",\n    \"\\u0002\\u0002\\u0002u\\u021c\\u0003\\u0002\\u0002\\u0002w\\u021e\\u0003\\u0002\",\n    \"\\u0002\\u0002y\\u0221\\u0003\\u0002\\u0002\\u0002{\\u0224\\u0003\\u0002\\u0002\",\n    \"\\u0002}\\u0226\\u0003\\u0002\\u0002\\u0002\\u007f\\u0228\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0081\\u022a\\u0003\\u0002\\u0002\\u0002\\u0083\\u022c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0085\\u022f\\u0003\\u0002\\u0002\\u0002\\u0087\\u0231\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0089\\u0234\\u0003\\u0002\\u0002\\u0002\\u008b\\u0237\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u008d\\u0239\\u0003\\u0002\\u0002\\u0002\\u008f\\u023b\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0091\\u023e\\u0003\\u0002\\u0002\\u0002\\u0093\\u0241\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0095\\u0244\\u0003\\u0002\\u0002\\u0002\\u0097\\u0247\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0099\\u024a\\u0003\\u0002\\u0002\\u0002\\u009b\\u024c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u009d\\u024f\\u0003\\u0002\\u0002\\u0002\\u009f\\u0252\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00a1\\u0255\\u0003\\u0002\\u0002\\u0002\\u00a3\\u0258\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00a5\\u025b\\u0003\\u0002\\u0002\\u0002\\u00a7\\u025e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00a9\\u0261\\u0003\\u0002\\u0002\\u0002\\u00ab\\u0264\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ad\\u0267\\u0003\\u0002\\u0002\\u0002\\u00af\\u026a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00b1\\u026e\\u0003\\u0002\\u0002\\u0002\\u00b3\\u0272\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00b5\\u0276\\u0003\\u0002\\u0002\\u0002\\u00b7\\u027d\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00b9\\u0281\\u0003\\u0002\\u0002\\u0002\\u00bb\\u0295\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00bd\\u02b1\\u0003\\u0002\\u0002\\u0002\\u00bf\\u02b5\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00c1\\u02b7\\u0003\\u0002\\u0002\\u0002\\u00c3\\u02b9\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00c5\\u02bc\\u0003\\u0002\\u0002\\u0002\\u00c7\\u02be\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00c9\\u02c0\\u0003\\u0002\\u0002\\u0002\\u00cb\\u02c2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00cd\\u02c4\\u0003\\u0002\\u0002\\u0002\\u00cf\\u02cd\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00d1\\u02d1\\u0003\\u0002\\u0002\\u0002\\u00d3\\u02d6\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00d5\\u02da\\u0003\\u0002\\u0002\\u0002\\u00d7\\u02e0\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00d9\\u02fb\\u0003\\u0002\\u0002\\u0002\\u00db\\u0317\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00dd\\u031b\\u0003\\u0002\\u0002\\u0002\\u00df\\u031e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00e1\\u0321\\u0003\\u0002\\u0002\\u0002\\u00e3\\u0324\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00e5\\u0326\\u0003\\u0002\\u0002\\u0002\\u00e7\\u032a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00e9\\u032e\\u0003\\u0002\\u0002\\u0002\\u00eb\\u0335\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ed\\u0341\\u0003\\u0002\\u0002\\u0002\\u00ef\\u0345\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00f1\\u00f2\\u0007f\\u0002\\u0002\\u00f2\\u00f3\\u0007g\\u0002\\u0002\",\n    \"\\u00f3\\u00f4\\u0007h\\u0002\\u0002\\u00f4\\u0004\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00f5\\u00f6\\u0007t\\u0002\\u0002\\u00f6\\u00f7\\u0007g\\u0002\\u0002\\u00f7\",\n    \"\\u00f8\\u0007v\\u0002\\u0002\\u00f8\\u00f9\\u0007w\\u0002\\u0002\\u00f9\\u00fa\",\n    \"\\u0007t\\u0002\\u0002\\u00fa\\u00fb\\u0007p\\u0002\\u0002\\u00fb\\u0006\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00fc\\u00fd\\u0007t\\u0002\\u0002\\u00fd\\u00fe\\u0007\",\n    \"c\\u0002\\u0002\\u00fe\\u00ff\\u0007k\\u0002\\u0002\\u00ff\\u0100\\u0007u\\u0002\",\n    \"\\u0002\\u0100\\u0101\\u0007g\\u0002\\u0002\\u0101\\b\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0102\\u0103\\u0007h\\u0002\\u0002\\u0103\\u0104\\u0007t\\u0002\\u0002\\u0104\",\n    \"\\u0105\\u0007q\\u0002\\u0002\\u0105\\u0106\\u0007o\\u0002\\u0002\\u0106\\n\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0107\\u0108\\u0007k\\u0002\\u0002\\u0108\\u0109\\u0007\",\n    \"o\\u0002\\u0002\\u0109\\u010a\\u0007r\\u0002\\u0002\\u010a\\u010b\\u0007q\\u0002\",\n    \"\\u0002\\u010b\\u010c\\u0007t\\u0002\\u0002\\u010c\\u010d\\u0007v\\u0002\\u0002\",\n    \"\\u010d\\f\\u0003\\u0002\\u0002\\u0002\\u010e\\u010f\\u0007c\\u0002\\u0002\\u010f\",\n    \"\\u0110\\u0007u\\u0002\\u0002\\u0110\\u000e\\u0003\\u0002\\u0002\\u0002\\u0111\",\n    \"\\u0112\\u0007i\\u0002\\u0002\\u0112\\u0113\\u0007n\\u0002\\u0002\\u0113\\u0114\",\n    \"\\u0007q\\u0002\\u0002\\u0114\\u0115\\u0007d\\u0002\\u0002\\u0115\\u0116\\u0007\",\n    \"c\\u0002\\u0002\\u0116\\u0117\\u0007n\\u0002\\u0002\\u0117\\u0010\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0118\\u0119\\u0007p\\u0002\\u0002\\u0119\\u011a\\u0007q\\u0002\",\n    \"\\u0002\\u011a\\u011b\\u0007p\\u0002\\u0002\\u011b\\u011c\\u0007n\\u0002\\u0002\",\n    \"\\u011c\\u011d\\u0007q\\u0002\\u0002\\u011d\\u011e\\u0007e\\u0002\\u0002\\u011e\",\n    \"\\u011f\\u0007c\\u0002\\u0002\\u011f\\u0120\\u0007n\\u0002\\u0002\\u0120\\u0012\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0121\\u0122\\u0007c\\u0002\\u0002\\u0122\\u0123\",\n    \"\\u0007u\\u0002\\u0002\\u0123\\u0124\\u0007u\\u0002\\u0002\\u0124\\u0125\\u0007\",\n    \"g\\u0002\\u0002\\u0125\\u0126\\u0007t\\u0002\\u0002\\u0126\\u0127\\u0007v\\u0002\",\n    \"\\u0002\\u0127\\u0014\\u0003\\u0002\\u0002\\u0002\\u0128\\u0129\\u0007k\\u0002\",\n    \"\\u0002\\u0129\\u012a\\u0007h\\u0002\\u0002\\u012a\\u0016\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u012b\\u012c\\u0007g\\u0002\\u0002\\u012c\\u012d\\u0007n\\u0002\\u0002\",\n    \"\\u012d\\u012e\\u0007k\\u0002\\u0002\\u012e\\u012f\\u0007h\\u0002\\u0002\\u012f\",\n    \"\\u0018\\u0003\\u0002\\u0002\\u0002\\u0130\\u0131\\u0007g\\u0002\\u0002\\u0131\",\n    \"\\u0132\\u0007n\\u0002\\u0002\\u0132\\u0133\\u0007u\\u0002\\u0002\\u0133\\u0134\",\n    \"\\u0007g\\u0002\\u0002\\u0134\\u001a\\u0003\\u0002\\u0002\\u0002\\u0135\\u0136\",\n    \"\\u0007y\\u0002\\u0002\\u0136\\u0137\\u0007j\\u0002\\u0002\\u0137\\u0138\\u0007\",\n    \"k\\u0002\\u0002\\u0138\\u0139\\u0007n\\u0002\\u0002\\u0139\\u013a\\u0007g\\u0002\",\n    \"\\u0002\\u013a\\u001c\\u0003\\u0002\\u0002\\u0002\\u013b\\u013c\\u0007h\\u0002\",\n    \"\\u0002\\u013c\\u013d\\u0007q\\u0002\\u0002\\u013d\\u013e\\u0007t\\u0002\\u0002\",\n    \"\\u013e\\u001e\\u0003\\u0002\\u0002\\u0002\\u013f\\u0140\\u0007k\\u0002\\u0002\",\n    \"\\u0140\\u0141\\u0007p\\u0002\\u0002\\u0141 \\u0003\\u0002\\u0002\\u0002\\u0142\",\n    \"\\u0143\\u0007v\\u0002\\u0002\\u0143\\u0144\\u0007t\\u0002\\u0002\\u0144\\u0145\",\n    \"\\u0007{\\u0002\\u0002\\u0145\\\"\\u0003\\u0002\\u0002\\u0002\\u0146\\u0147\\u0007\",\n    \"h\\u0002\\u0002\\u0147\\u0148\\u0007k\\u0002\\u0002\\u0148\\u0149\\u0007p\\u0002\",\n    \"\\u0002\\u0149\\u014a\\u0007c\\u0002\\u0002\\u014a\\u014b\\u0007n\\u0002\\u0002\",\n    \"\\u014b\\u014c\\u0007n\\u0002\\u0002\\u014c\\u014d\\u0007{\\u0002\\u0002\\u014d\",\n    \"$\\u0003\\u0002\\u0002\\u0002\\u014e\\u014f\\u0007y\\u0002\\u0002\\u014f\\u0150\",\n    \"\\u0007k\\u0002\\u0002\\u0150\\u0151\\u0007v\\u0002\\u0002\\u0151\\u0152\\u0007\",\n    \"j\\u0002\\u0002\\u0152&\\u0003\\u0002\\u0002\\u0002\\u0153\\u0154\\u0007g\\u0002\",\n    \"\\u0002\\u0154\\u0155\\u0007z\\u0002\\u0002\\u0155\\u0156\\u0007e\\u0002\\u0002\",\n    \"\\u0156\\u0157\\u0007g\\u0002\\u0002\\u0157\\u0158\\u0007r\\u0002\\u0002\\u0158\",\n    \"\\u0159\\u0007v\\u0002\\u0002\\u0159(\\u0003\\u0002\\u0002\\u0002\\u015a\\u015b\",\n    \"\\u0007n\\u0002\\u0002\\u015b\\u015c\\u0007c\\u0002\\u0002\\u015c\\u015d\\u0007\",\n    \"o\\u0002\\u0002\\u015d\\u015e\\u0007d\\u0002\\u0002\\u015e\\u015f\\u0007f\\u0002\",\n    \"\\u0002\\u015f\\u0160\\u0007c\\u0002\\u0002\\u0160*\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0161\\u0162\\u0007q\\u0002\\u0002\\u0162\\u0163\\u0007t\\u0002\\u0002\\u0163\",\n    \",\\u0003\\u0002\\u0002\\u0002\\u0164\\u0165\\u0007c\\u0002\\u0002\\u0165\\u0166\",\n    \"\\u0007p\\u0002\\u0002\\u0166\\u0167\\u0007f\\u0002\\u0002\\u0167.\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0168\\u0169\\u0007p\\u0002\\u0002\\u0169\\u016a\\u0007q\\u0002\",\n    \"\\u0002\\u016a\\u016b\\u0007v\\u0002\\u0002\\u016b0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u016c\\u016d\\u0007k\\u0002\\u0002\\u016d\\u016e\\u0007u\\u0002\\u0002\\u016e\",\n    \"2\\u0003\\u0002\\u0002\\u0002\\u016f\\u0170\\u0007P\\u0002\\u0002\\u0170\\u0171\",\n    \"\\u0007q\\u0002\\u0002\\u0171\\u0172\\u0007p\\u0002\\u0002\\u0172\\u0173\\u0007\",\n    \"g\\u0002\\u0002\\u01734\\u0003\\u0002\\u0002\\u0002\\u0174\\u0175\\u0007V\\u0002\",\n    \"\\u0002\\u0175\\u0176\\u0007t\\u0002\\u0002\\u0176\\u0177\\u0007w\\u0002\\u0002\",\n    \"\\u0177\\u0178\\u0007g\\u0002\\u0002\\u01786\\u0003\\u0002\\u0002\\u0002\\u0179\",\n    \"\\u017a\\u0007H\\u0002\\u0002\\u017a\\u017b\\u0007c\\u0002\\u0002\\u017b\\u017c\",\n    \"\\u0007n\\u0002\\u0002\\u017c\\u017d\\u0007u\\u0002\\u0002\\u017d\\u017e\\u0007\",\n    \"g\\u0002\\u0002\\u017e8\\u0003\\u0002\\u0002\\u0002\\u017f\\u0180\\u0007e\\u0002\",\n    \"\\u0002\\u0180\\u0181\\u0007n\\u0002\\u0002\\u0181\\u0182\\u0007c\\u0002\\u0002\",\n    \"\\u0182\\u0183\\u0007u\\u0002\\u0002\\u0183\\u0184\\u0007u\\u0002\\u0002\\u0184\",\n    \":\\u0003\\u0002\\u0002\\u0002\\u0185\\u0186\\u0007{\\u0002\\u0002\\u0186\\u0187\",\n    \"\\u0007k\\u0002\\u0002\\u0187\\u0188\\u0007g\\u0002\\u0002\\u0188\\u0189\\u0007\",\n    \"n\\u0002\\u0002\\u0189\\u018a\\u0007f\\u0002\\u0002\\u018a<\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u018b\\u018c\\u0007f\\u0002\\u0002\\u018c\\u018d\\u0007g\\u0002\\u0002\",\n    \"\\u018d\\u018e\\u0007n\\u0002\\u0002\\u018e>\\u0003\\u0002\\u0002\\u0002\\u018f\",\n    \"\\u0190\\u0007r\\u0002\\u0002\\u0190\\u0191\\u0007c\\u0002\\u0002\\u0191\\u0192\",\n    \"\\u0007u\\u0002\\u0002\\u0192\\u0193\\u0007u\\u0002\\u0002\\u0193@\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0194\\u0195\\u0007e\\u0002\\u0002\\u0195\\u0196\\u0007q\\u0002\",\n    \"\\u0002\\u0196\\u0197\\u0007p\\u0002\\u0002\\u0197\\u0198\\u0007v\\u0002\\u0002\",\n    \"\\u0198\\u0199\\u0007k\\u0002\\u0002\\u0199\\u019a\\u0007p\\u0002\\u0002\\u019a\",\n    \"\\u019b\\u0007w\\u0002\\u0002\\u019b\\u019c\\u0007g\\u0002\\u0002\\u019cB\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u019d\\u019e\\u0007d\\u0002\\u0002\\u019e\\u019f\\u0007\",\n    \"t\\u0002\\u0002\\u019f\\u01a0\\u0007g\\u0002\\u0002\\u01a0\\u01a1\\u0007c\\u0002\",\n    \"\\u0002\\u01a1\\u01a2\\u0007m\\u0002\\u0002\\u01a2D\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01a3\\u01a4\\u0006#\\u0002\\u0002\\u01a4\\u01b0\\u0005\\u00e7t\\u0002\\u01a5\",\n    \"\\u01a7\\u0007\\u000f\\u0002\\u0002\\u01a6\\u01a5\\u0003\\u0002\\u0002\\u0002\\u01a6\",\n    \"\\u01a7\\u0003\\u0002\\u0002\\u0002\\u01a7\\u01a8\\u0003\\u0002\\u0002\\u0002\\u01a8\",\n    \"\\u01ab\\u0007\\f\\u0002\\u0002\\u01a9\\u01ab\\u0007\\u000f\\u0002\\u0002\\u01aa\",\n    \"\\u01a6\\u0003\\u0002\\u0002\\u0002\\u01aa\\u01a9\\u0003\\u0002\\u0002\\u0002\\u01ab\",\n    \"\\u01ad\\u0003\\u0002\\u0002\\u0002\\u01ac\\u01ae\\u0005\\u00e7t\\u0002\\u01ad\",\n    \"\\u01ac\\u0003\\u0002\\u0002\\u0002\\u01ad\\u01ae\\u0003\\u0002\\u0002\\u0002\\u01ae\",\n    \"\\u01b0\\u0003\\u0002\\u0002\\u0002\\u01af\\u01a3\\u0003\\u0002\\u0002\\u0002\\u01af\",\n    \"\\u01aa\\u0003\\u0002\\u0002\\u0002\\u01b0\\u01b1\\u0003\\u0002\\u0002\\u0002\\u01b1\",\n    \"\\u01b2\\b#\\u0002\\u0002\\u01b2F\\u0003\\u0002\\u0002\\u0002\\u01b3\\u01b7\\u0005\",\n    \"\\u00edw\\u0002\\u01b4\\u01b6\\u0005\\u00efx\\u0002\\u01b5\\u01b4\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01b6\\u01b9\\u0003\\u0002\\u0002\\u0002\\u01b7\\u01b5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01b7\\u01b8\\u0003\\u0002\\u0002\\u0002\\u01b8H\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01b9\\u01b7\\u0003\\u0002\\u0002\\u0002\\u01ba\\u01bc\\t\\u0002\",\n    \"\\u0002\\u0002\\u01bb\\u01ba\\u0003\\u0002\\u0002\\u0002\\u01bb\\u01bc\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01bc\\u01be\\u0003\\u0002\\u0002\\u0002\\u01bd\\u01bf\\t\\u0003\",\n    \"\\u0002\\u0002\\u01be\\u01bd\\u0003\\u0002\\u0002\\u0002\\u01be\\u01bf\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01bf\\u01c2\\u0003\\u0002\\u0002\\u0002\\u01c0\\u01c3\\u0005\\u00bb\",\n    \"^\\u0002\\u01c1\\u01c3\\u0005\\u00bd_\\u0002\\u01c2\\u01c0\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01c2\\u01c1\\u0003\\u0002\\u0002\\u0002\\u01c3J\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01c4\\u01c6\\t\\u0004\\u0002\\u0002\\u01c5\\u01c7\\t\\u0003\\u0002\\u0002\",\n    \"\\u01c6\\u01c5\\u0003\\u0002\\u0002\\u0002\\u01c6\\u01c7\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01c7\\u01ca\\u0003\\u0002\\u0002\\u0002\\u01c8\\u01cb\\u0005\\u00d9m\\u0002\",\n    \"\\u01c9\\u01cb\\u0005\\u00dbn\\u0002\\u01ca\\u01c8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01ca\\u01c9\\u0003\\u0002\\u0002\\u0002\\u01cbL\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01cc\\u01d0\\u0005\\u00c5c\\u0002\\u01cd\\u01cf\\u0005\\u00c7d\\u0002\\u01ce\",\n    \"\\u01cd\\u0003\\u0002\\u0002\\u0002\\u01cf\\u01d2\\u0003\\u0002\\u0002\\u0002\\u01d0\",\n    \"\\u01ce\\u0003\\u0002\\u0002\\u0002\\u01d0\\u01d1\\u0003\\u0002\\u0002\\u0002\\u01d1\",\n    \"\\u01d9\\u0003\\u0002\\u0002\\u0002\\u01d2\\u01d0\\u0003\\u0002\\u0002\\u0002\\u01d3\",\n    \"\\u01d5\\u00072\\u0002\\u0002\\u01d4\\u01d3\\u0003\\u0002\\u0002\\u0002\\u01d5\",\n    \"\\u01d6\\u0003\\u0002\\u0002\\u0002\\u01d6\\u01d4\\u0003\\u0002\\u0002\\u0002\\u01d6\",\n    \"\\u01d7\\u0003\\u0002\\u0002\\u0002\\u01d7\\u01d9\\u0003\\u0002\\u0002\\u0002\\u01d8\",\n    \"\\u01cc\\u0003\\u0002\\u0002\\u0002\\u01d8\\u01d4\\u0003\\u0002\\u0002\\u0002\\u01d9\",\n    \"N\\u0003\\u0002\\u0002\\u0002\\u01da\\u01db\\u00072\\u0002\\u0002\\u01db\\u01dd\",\n    \"\\t\\u0005\\u0002\\u0002\\u01dc\\u01de\\u0005\\u00c9e\\u0002\\u01dd\\u01dc\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01de\\u01df\\u0003\\u0002\\u0002\\u0002\\u01df\\u01dd\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01df\\u01e0\\u0003\\u0002\\u0002\\u0002\\u01e0P\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01e1\\u01e2\\u00072\\u0002\\u0002\\u01e2\\u01e4\\t\\u0006\",\n    \"\\u0002\\u0002\\u01e3\\u01e5\\u0005\\u00cbf\\u0002\\u01e4\\u01e3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e5\\u01e6\\u0003\\u0002\\u0002\\u0002\\u01e6\\u01e4\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e6\\u01e7\\u0003\\u0002\\u0002\\u0002\\u01e7R\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e8\\u01e9\\u00072\\u0002\\u0002\\u01e9\\u01eb\\t\\u0004\\u0002\",\n    \"\\u0002\\u01ea\\u01ec\\u0005\\u00cdg\\u0002\\u01eb\\u01ea\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01ec\\u01ed\\u0003\\u0002\\u0002\\u0002\\u01ed\\u01eb\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01ed\\u01ee\\u0003\\u0002\\u0002\\u0002\\u01eeT\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01ef\\u01f2\\u0005\\u00cfh\\u0002\\u01f0\\u01f2\\u0005\\u00d1i\\u0002\",\n    \"\\u01f1\\u01ef\\u0003\\u0002\\u0002\\u0002\\u01f1\\u01f0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01f2V\\u0003\\u0002\\u0002\\u0002\\u01f3\\u01f6\\u0005U+\\u0002\\u01f4\\u01f6\",\n    \"\\u0005\\u00d3j\\u0002\\u01f5\\u01f3\\u0003\\u0002\\u0002\\u0002\\u01f5\\u01f4\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01f6\\u01f7\\u0003\\u0002\\u0002\\u0002\\u01f7\\u01f8\",\n    \"\\t\\u0007\\u0002\\u0002\\u01f8X\\u0003\\u0002\\u0002\\u0002\\u01f9\\u01fa\\u0007\",\n    \"0\\u0002\\u0002\\u01faZ\\u0003\\u0002\\u0002\\u0002\\u01fb\\u01fc\\u00070\\u0002\",\n    \"\\u0002\\u01fc\\u01fd\\u00070\\u0002\\u0002\\u01fd\\u01fe\\u00070\\u0002\\u0002\",\n    \"\\u01fe\\\\\\u0003\\u0002\\u0002\\u0002\\u01ff\\u0200\\u0007,\\u0002\\u0002\\u0200\",\n    \"^\\u0003\\u0002\\u0002\\u0002\\u0201\\u0202\\u0007*\\u0002\\u0002\\u0202\\u0203\",\n    \"\\b0\\u0003\\u0002\\u0203`\\u0003\\u0002\\u0002\\u0002\\u0204\\u0205\\u0007+\\u0002\",\n    \"\\u0002\\u0205\\u0206\\b1\\u0004\\u0002\\u0206b\\u0003\\u0002\\u0002\\u0002\\u0207\",\n    \"\\u0208\\u0007.\\u0002\\u0002\\u0208d\\u0003\\u0002\\u0002\\u0002\\u0209\\u020a\",\n    \"\\u0007<\\u0002\\u0002\\u020af\\u0003\\u0002\\u0002\\u0002\\u020b\\u020c\\u0007\",\n    \"=\\u0002\\u0002\\u020ch\\u0003\\u0002\\u0002\\u0002\\u020d\\u020e\\u0007,\\u0002\",\n    \"\\u0002\\u020e\\u020f\\u0007,\\u0002\\u0002\\u020fj\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0210\\u0211\\u0007?\\u0002\\u0002\\u0211l\\u0003\\u0002\\u0002\\u0002\\u0212\",\n    \"\\u0213\\u0007]\\u0002\\u0002\\u0213\\u0214\\b7\\u0005\\u0002\\u0214n\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0215\\u0216\\u0007_\\u0002\\u0002\\u0216\\u0217\\b8\\u0006\\u0002\",\n    \"\\u0217p\\u0003\\u0002\\u0002\\u0002\\u0218\\u0219\\u0007~\\u0002\\u0002\\u0219\",\n    \"r\\u0003\\u0002\\u0002\\u0002\\u021a\\u021b\\u0007`\\u0002\\u0002\\u021bt\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u021c\\u021d\\u0007(\\u0002\\u0002\\u021dv\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u021e\\u021f\\u0007>\\u0002\\u0002\\u021f\\u0220\\u0007>\\u0002\",\n    \"\\u0002\\u0220x\\u0003\\u0002\\u0002\\u0002\\u0221\\u0222\\u0007@\\u0002\\u0002\",\n    \"\\u0222\\u0223\\u0007@\\u0002\\u0002\\u0223z\\u0003\\u0002\\u0002\\u0002\\u0224\",\n    \"\\u0225\\u0007-\\u0002\\u0002\\u0225|\\u0003\\u0002\\u0002\\u0002\\u0226\\u0227\",\n    \"\\u0007/\\u0002\\u0002\\u0227~\\u0003\\u0002\\u0002\\u0002\\u0228\\u0229\\u0007\",\n    \"1\\u0002\\u0002\\u0229\\u0080\\u0003\\u0002\\u0002\\u0002\\u022a\\u022b\\u0007\",\n    \"\\'\\u0002\\u0002\\u022b\\u0082\\u0003\\u0002\\u0002\\u0002\\u022c\\u022d\\u0007\",\n    \"1\\u0002\\u0002\\u022d\\u022e\\u00071\\u0002\\u0002\\u022e\\u0084\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u022f\\u0230\\u0007\\u0080\\u0002\\u0002\\u0230\\u0086\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0231\\u0232\\u0007}\\u0002\\u0002\\u0232\\u0233\\bD\\u0007\\u0002\",\n    \"\\u0233\\u0088\\u0003\\u0002\\u0002\\u0002\\u0234\\u0235\\u0007\\u007f\\u0002\\u0002\",\n    \"\\u0235\\u0236\\bE\\b\\u0002\\u0236\\u008a\\u0003\\u0002\\u0002\\u0002\\u0237\\u0238\",\n    \"\\u0007>\\u0002\\u0002\\u0238\\u008c\\u0003\\u0002\\u0002\\u0002\\u0239\\u023a\",\n    \"\\u0007@\\u0002\\u0002\\u023a\\u008e\\u0003\\u0002\\u0002\\u0002\\u023b\\u023c\",\n    \"\\u0007?\\u0002\\u0002\\u023c\\u023d\\u0007?\\u0002\\u0002\\u023d\\u0090\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u023e\\u023f\\u0007@\\u0002\\u0002\\u023f\\u0240\\u0007\",\n    \"?\\u0002\\u0002\\u0240\\u0092\\u0003\\u0002\\u0002\\u0002\\u0241\\u0242\\u0007\",\n    \">\\u0002\\u0002\\u0242\\u0243\\u0007?\\u0002\\u0002\\u0243\\u0094\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0244\\u0245\\u0007>\\u0002\\u0002\\u0245\\u0246\\u0007@\\u0002\",\n    \"\\u0002\\u0246\\u0096\\u0003\\u0002\\u0002\\u0002\\u0247\\u0248\\u0007#\\u0002\",\n    \"\\u0002\\u0248\\u0249\\u0007?\\u0002\\u0002\\u0249\\u0098\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u024a\\u024b\\u0007B\\u0002\\u0002\\u024b\\u009a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u024c\\u024d\\u0007/\\u0002\\u0002\\u024d\\u024e\\u0007@\\u0002\\u0002\",\n    \"\\u024e\\u009c\\u0003\\u0002\\u0002\\u0002\\u024f\\u0250\\u0007-\\u0002\\u0002\",\n    \"\\u0250\\u0251\\u0007?\\u0002\\u0002\\u0251\\u009e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0252\\u0253\\u0007/\\u0002\\u0002\\u0253\\u0254\\u0007?\\u0002\\u0002\\u0254\",\n    \"\\u00a0\\u0003\\u0002\\u0002\\u0002\\u0255\\u0256\\u0007,\\u0002\\u0002\\u0256\",\n    \"\\u0257\\u0007?\\u0002\\u0002\\u0257\\u00a2\\u0003\\u0002\\u0002\\u0002\\u0258\",\n    \"\\u0259\\u0007B\\u0002\\u0002\\u0259\\u025a\\u0007?\\u0002\\u0002\\u025a\\u00a4\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u025b\\u025c\\u00071\\u0002\\u0002\\u025c\\u025d\",\n    \"\\u0007?\\u0002\\u0002\\u025d\\u00a6\\u0003\\u0002\\u0002\\u0002\\u025e\\u025f\",\n    \"\\u0007\\'\\u0002\\u0002\\u025f\\u0260\\u0007?\\u0002\\u0002\\u0260\\u00a8\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0261\\u0262\\u0007(\\u0002\\u0002\\u0262\\u0263\\u0007\",\n    \"?\\u0002\\u0002\\u0263\\u00aa\\u0003\\u0002\\u0002\\u0002\\u0264\\u0265\\u0007\",\n    \"~\\u0002\\u0002\\u0265\\u0266\\u0007?\\u0002\\u0002\\u0266\\u00ac\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0267\\u0268\\u0007`\\u0002\\u0002\\u0268\\u0269\\u0007?\\u0002\",\n    \"\\u0002\\u0269\\u00ae\\u0003\\u0002\\u0002\\u0002\\u026a\\u026b\\u0007>\\u0002\",\n    \"\\u0002\\u026b\\u026c\\u0007>\\u0002\\u0002\\u026c\\u026d\\u0007?\\u0002\\u0002\",\n    \"\\u026d\\u00b0\\u0003\\u0002\\u0002\\u0002\\u026e\\u026f\\u0007@\\u0002\\u0002\",\n    \"\\u026f\\u0270\\u0007@\\u0002\\u0002\\u0270\\u0271\\u0007?\\u0002\\u0002\\u0271\",\n    \"\\u00b2\\u0003\\u0002\\u0002\\u0002\\u0272\\u0273\\u0007,\\u0002\\u0002\\u0273\",\n    \"\\u0274\\u0007,\\u0002\\u0002\\u0274\\u0275\\u0007?\\u0002\\u0002\\u0275\\u00b4\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0276\\u0277\\u00071\\u0002\\u0002\\u0277\\u0278\",\n    \"\\u00071\\u0002\\u0002\\u0278\\u0279\\u0007?\\u0002\\u0002\\u0279\\u00b6\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u027a\\u027e\\u0005\\u00e7t\\u0002\\u027b\\u027e\\u0005\",\n    \"\\u00e9u\\u0002\\u027c\\u027e\\u0005\\u00ebv\\u0002\\u027d\\u027a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u027d\\u027b\\u0003\\u0002\\u0002\\u0002\\u027d\\u027c\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u027e\\u027f\\u0003\\u0002\\u0002\\u0002\\u027f\\u0280\\b\\\\\\t\\u0002\",\n    \"\\u0280\\u00b8\\u0003\\u0002\\u0002\\u0002\\u0281\\u0282\\u000b\\u0002\\u0002\\u0002\",\n    \"\\u0282\\u00ba\\u0003\\u0002\\u0002\\u0002\\u0283\\u0288\\u0007)\\u0002\\u0002\",\n    \"\\u0284\\u0287\\u0005\\u00c3b\\u0002\\u0285\\u0287\\n\\b\\u0002\\u0002\\u0286\\u0284\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0286\\u0285\\u0003\\u0002\\u0002\\u0002\\u0287\\u028a\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0288\\u0286\\u0003\\u0002\\u0002\\u0002\\u0288\\u0289\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0289\\u028b\\u0003\\u0002\\u0002\\u0002\\u028a\\u0288\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u028b\\u0296\\u0007)\\u0002\\u0002\\u028c\\u0291\",\n    \"\\u0007$\\u0002\\u0002\\u028d\\u0290\\u0005\\u00c3b\\u0002\\u028e\\u0290\\n\\t\\u0002\",\n    \"\\u0002\\u028f\\u028d\\u0003\\u0002\\u0002\\u0002\\u028f\\u028e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0290\\u0293\\u0003\\u0002\\u0002\\u0002\\u0291\\u028f\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0291\\u0292\\u0003\\u0002\\u0002\\u0002\\u0292\\u0294\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0293\\u0291\\u0003\\u0002\\u0002\\u0002\\u0294\\u0296\\u0007$\\u0002\",\n    \"\\u0002\\u0295\\u0283\\u0003\\u0002\\u0002\\u0002\\u0295\\u028c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0296\\u00bc\\u0003\\u0002\\u0002\\u0002\\u0297\\u0298\\u0007)\\u0002\",\n    \"\\u0002\\u0298\\u0299\\u0007)\\u0002\\u0002\\u0299\\u029a\\u0007)\\u0002\\u0002\",\n    \"\\u029a\\u029e\\u0003\\u0002\\u0002\\u0002\\u029b\\u029d\\u0005\\u00bf`\\u0002\",\n    \"\\u029c\\u029b\\u0003\\u0002\\u0002\\u0002\\u029d\\u02a0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u029e\\u029f\\u0003\\u0002\\u0002\\u0002\\u029e\\u029c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u029f\\u02a1\\u0003\\u0002\\u0002\\u0002\\u02a0\\u029e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02a1\\u02a2\\u0007)\\u0002\\u0002\\u02a2\\u02a3\\u0007)\\u0002\\u0002\\u02a3\",\n    \"\\u02b2\\u0007)\\u0002\\u0002\\u02a4\\u02a5\\u0007$\\u0002\\u0002\\u02a5\\u02a6\",\n    \"\\u0007$\\u0002\\u0002\\u02a6\\u02a7\\u0007$\\u0002\\u0002\\u02a7\\u02ab\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02a8\\u02aa\\u0005\\u00bf`\\u0002\\u02a9\\u02a8\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02aa\\u02ad\\u0003\\u0002\\u0002\\u0002\\u02ab\\u02ac\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02ab\\u02a9\\u0003\\u0002\\u0002\\u0002\\u02ac\\u02ae\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02ad\\u02ab\\u0003\\u0002\\u0002\\u0002\\u02ae\\u02af\\u0007\",\n    \"$\\u0002\\u0002\\u02af\\u02b0\\u0007$\\u0002\\u0002\\u02b0\\u02b2\\u0007$\\u0002\",\n    \"\\u0002\\u02b1\\u0297\\u0003\\u0002\\u0002\\u0002\\u02b1\\u02a4\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02b2\\u00be\\u0003\\u0002\\u0002\\u0002\\u02b3\\u02b6\\u0005\\u00c1a\",\n    \"\\u0002\\u02b4\\u02b6\\u0005\\u00c3b\\u0002\\u02b5\\u02b3\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02b5\\u02b4\\u0003\\u0002\\u0002\\u0002\\u02b6\\u00c0\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02b7\\u02b8\\n\\n\\u0002\\u0002\\u02b8\\u00c2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b9\\u02ba\\u0007^\\u0002\\u0002\\u02ba\\u02bb\\u000b\\u0002\\u0002\\u0002\",\n    \"\\u02bb\\u00c4\\u0003\\u0002\\u0002\\u0002\\u02bc\\u02bd\\t\\u000b\\u0002\\u0002\",\n    \"\\u02bd\\u00c6\\u0003\\u0002\\u0002\\u0002\\u02be\\u02bf\\t\\f\\u0002\\u0002\\u02bf\",\n    \"\\u00c8\\u0003\\u0002\\u0002\\u0002\\u02c0\\u02c1\\t\\r\\u0002\\u0002\\u02c1\\u00ca\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c2\\u02c3\\t\\u000e\\u0002\\u0002\\u02c3\\u00cc\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c4\\u02c5\\t\\u000f\\u0002\\u0002\\u02c5\\u00ce\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c6\\u02c8\\u0005\\u00d3j\\u0002\\u02c7\\u02c6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c7\\u02c8\\u0003\\u0002\\u0002\\u0002\\u02c8\\u02c9\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02c9\\u02ce\\u0005\\u00d5k\\u0002\\u02ca\\u02cb\",\n    \"\\u0005\\u00d3j\\u0002\\u02cb\\u02cc\\u00070\\u0002\\u0002\\u02cc\\u02ce\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02cd\\u02c7\\u0003\\u0002\\u0002\\u0002\\u02cd\\u02ca\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02ce\\u00d0\\u0003\\u0002\\u0002\\u0002\\u02cf\\u02d2\\u0005\",\n    \"\\u00d3j\\u0002\\u02d0\\u02d2\\u0005\\u00cfh\\u0002\\u02d1\\u02cf\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02d1\\u02d0\\u0003\\u0002\\u0002\\u0002\\u02d2\\u02d3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02d3\\u02d4\\u0005\\u00d7l\\u0002\\u02d4\\u00d2\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02d5\\u02d7\\u0005\\u00c7d\\u0002\\u02d6\\u02d5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02d7\\u02d8\\u0003\\u0002\\u0002\\u0002\\u02d8\\u02d6\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02d8\\u02d9\\u0003\\u0002\\u0002\\u0002\\u02d9\\u00d4\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02da\\u02dc\\u00070\\u0002\\u0002\\u02db\\u02dd\\u0005\\u00c7\",\n    \"d\\u0002\\u02dc\\u02db\\u0003\\u0002\\u0002\\u0002\\u02dd\\u02de\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02de\\u02dc\\u0003\\u0002\\u0002\\u0002\\u02de\\u02df\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02df\\u00d6\\u0003\\u0002\\u0002\\u0002\\u02e0\\u02e2\\t\\u0010\",\n    \"\\u0002\\u0002\\u02e1\\u02e3\\t\\u0011\\u0002\\u0002\\u02e2\\u02e1\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02e2\\u02e3\\u0003\\u0002\\u0002\\u0002\\u02e3\\u02e5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02e4\\u02e6\\u0005\\u00c7d\\u0002\\u02e5\\u02e4\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02e6\\u02e7\\u0003\\u0002\\u0002\\u0002\\u02e7\\u02e5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02e7\\u02e8\\u0003\\u0002\\u0002\\u0002\\u02e8\\u00d8\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02e9\\u02ee\\u0007)\\u0002\\u0002\\u02ea\\u02ed\\u0005\\u00df\",\n    \"p\\u0002\\u02eb\\u02ed\\u0005\\u00e5s\\u0002\\u02ec\\u02ea\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02ec\\u02eb\\u0003\\u0002\\u0002\\u0002\\u02ed\\u02f0\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02ee\\u02ec\\u0003\\u0002\\u0002\\u0002\\u02ee\\u02ef\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02ef\\u02f1\\u0003\\u0002\\u0002\\u0002\\u02f0\\u02ee\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02f1\\u02fc\\u0007)\\u0002\\u0002\\u02f2\\u02f7\\u0007$\\u0002\\u0002\",\n    \"\\u02f3\\u02f6\\u0005\\u00e1q\\u0002\\u02f4\\u02f6\\u0005\\u00e5s\\u0002\\u02f5\",\n    \"\\u02f3\\u0003\\u0002\\u0002\\u0002\\u02f5\\u02f4\\u0003\\u0002\\u0002\\u0002\\u02f6\",\n    \"\\u02f9\\u0003\\u0002\\u0002\\u0002\\u02f7\\u02f5\\u0003\\u0002\\u0002\\u0002\\u02f7\",\n    \"\\u02f8\\u0003\\u0002\\u0002\\u0002\\u02f8\\u02fa\\u0003\\u0002\\u0002\\u0002\\u02f9\",\n    \"\\u02f7\\u0003\\u0002\\u0002\\u0002\\u02fa\\u02fc\\u0007$\\u0002\\u0002\\u02fb\",\n    \"\\u02e9\\u0003\\u0002\\u0002\\u0002\\u02fb\\u02f2\\u0003\\u0002\\u0002\\u0002\\u02fc\",\n    \"\\u00da\\u0003\\u0002\\u0002\\u0002\\u02fd\\u02fe\\u0007)\\u0002\\u0002\\u02fe\",\n    \"\\u02ff\\u0007)\\u0002\\u0002\\u02ff\\u0300\\u0007)\\u0002\\u0002\\u0300\\u0304\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0301\\u0303\\u0005\\u00ddo\\u0002\\u0302\\u0301\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0303\\u0306\\u0003\\u0002\\u0002\\u0002\\u0304\\u0305\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0304\\u0302\\u0003\\u0002\\u0002\\u0002\\u0305\\u0307\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0306\\u0304\\u0003\\u0002\\u0002\\u0002\\u0307\\u0308\",\n    \"\\u0007)\\u0002\\u0002\\u0308\\u0309\\u0007)\\u0002\\u0002\\u0309\\u0318\\u0007\",\n    \")\\u0002\\u0002\\u030a\\u030b\\u0007$\\u0002\\u0002\\u030b\\u030c\\u0007$\\u0002\",\n    \"\\u0002\\u030c\\u030d\\u0007$\\u0002\\u0002\\u030d\\u0311\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u030e\\u0310\\u0005\\u00ddo\\u0002\\u030f\\u030e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0310\\u0313\\u0003\\u0002\\u0002\\u0002\\u0311\\u0312\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0311\\u030f\\u0003\\u0002\\u0002\\u0002\\u0312\\u0314\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0313\\u0311\\u0003\\u0002\\u0002\\u0002\\u0314\\u0315\\u0007$\\u0002\",\n    \"\\u0002\\u0315\\u0316\\u0007$\\u0002\\u0002\\u0316\\u0318\\u0007$\\u0002\\u0002\",\n    \"\\u0317\\u02fd\\u0003\\u0002\\u0002\\u0002\\u0317\\u030a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0318\\u00dc\\u0003\\u0002\\u0002\\u0002\\u0319\\u031c\\u0005\\u00e3r\\u0002\",\n    \"\\u031a\\u031c\\u0005\\u00e5s\\u0002\\u031b\\u0319\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u031b\\u031a\\u0003\\u0002\\u0002\\u0002\\u031c\\u00de\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u031d\\u031f\\t\\u0012\\u0002\\u0002\\u031e\\u031d\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u031f\\u00e0\\u0003\\u0002\\u0002\\u0002\\u0320\\u0322\\t\\u0013\\u0002\\u0002\",\n    \"\\u0321\\u0320\\u0003\\u0002\\u0002\\u0002\\u0322\\u00e2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0323\\u0325\\t\\u0014\\u0002\\u0002\\u0324\\u0323\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0325\\u00e4\\u0003\\u0002\\u0002\\u0002\\u0326\\u0327\\u0007^\\u0002\\u0002\",\n    \"\\u0327\\u0328\\t\\u0015\\u0002\\u0002\\u0328\\u00e6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0329\\u032b\\t\\u0016\\u0002\\u0002\\u032a\\u0329\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u032b\\u032c\\u0003\\u0002\\u0002\\u0002\\u032c\\u032a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u032c\\u032d\\u0003\\u0002\\u0002\\u0002\\u032d\\u00e8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u032e\\u0332\\u0007%\\u0002\\u0002\\u032f\\u0331\\n\\u0017\\u0002\\u0002\\u0330\",\n    \"\\u032f\\u0003\\u0002\\u0002\\u0002\\u0331\\u0334\\u0003\\u0002\\u0002\\u0002\\u0332\",\n    \"\\u0330\\u0003\\u0002\\u0002\\u0002\\u0332\\u0333\\u0003\\u0002\\u0002\\u0002\\u0333\",\n    \"\\u00ea\\u0003\\u0002\\u0002\\u0002\\u0334\\u0332\\u0003\\u0002\\u0002\\u0002\\u0335\",\n    \"\\u0337\\u0007^\\u0002\\u0002\\u0336\\u0338\\u0005\\u00e7t\\u0002\\u0337\\u0336\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0337\\u0338\\u0003\\u0002\\u0002\\u0002\\u0338\\u033e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0339\\u033b\\u0007\\u000f\\u0002\\u0002\\u033a\\u0339\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033a\\u033b\\u0003\\u0002\\u0002\\u0002\\u033b\\u033c\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033c\\u033f\\u0007\\f\\u0002\\u0002\\u033d\\u033f\",\n    \"\\u0007\\u000f\\u0002\\u0002\\u033e\\u033a\\u0003\\u0002\\u0002\\u0002\\u033e\\u033d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033f\\u00ec\\u0003\\u0002\\u0002\\u0002\\u0340\\u0342\",\n    \"\\t\\u0018\\u0002\\u0002\\u0341\\u0340\\u0003\\u0002\\u0002\\u0002\\u0342\\u00ee\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0343\\u0346\\u0005\\u00edw\\u0002\\u0344\\u0346\",\n    \"\\t\\u0019\\u0002\\u0002\\u0345\\u0343\\u0003\\u0002\\u0002\\u0002\\u0345\\u0344\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0346\\u00f0\\u0003\\u0002\\u0002\\u00029\\u0002\",\n    \"\\u01a6\\u01aa\\u01ad\\u01af\\u01b7\\u01bb\\u01be\\u01c2\\u01c6\\u01ca\\u01d0\\u01d6\",\n    \"\\u01d8\\u01df\\u01e6\\u01ed\\u01f1\\u01f5\\u027d\\u0286\\u0288\\u028f\\u0291\\u0295\",\n    \"\\u029e\\u02ab\\u02b1\\u02b5\\u02c7\\u02cd\\u02d1\\u02d8\\u02de\\u02e2\\u02e7\\u02ec\",\n    \"\\u02ee\\u02f5\\u02f7\\u02fb\\u0304\\u0311\\u0317\\u031b\\u031e\\u0321\\u0324\\u032c\",\n    \"\\u0332\\u0337\\u033a\\u033e\\u0341\\u0345\\n\\u0003#\\u0002\\u00030\\u0003\\u0003\",\n    \"1\\u0004\\u00037\\u0005\\u00038\\u0006\\u0003D\\u0007\\u0003E\\b\\b\\u0002\\u0002\"].join(\"\");\n\n\nvar atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);\n\nvar decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); });\n\nfunction Python3Lexer(input) {\n\tantlr4.Lexer.call(this, input);\n    this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache());\n    return this;\n}\n\nPython3Lexer.prototype = Object.create(antlr4.Lexer.prototype);\nPython3Lexer.prototype.constructor = Python3Lexer;\n\nPython3Lexer.EOF = antlr4.Token.EOF;\nPython3Lexer.DEF = 1;\nPython3Lexer.RETURN = 2;\nPython3Lexer.RAISE = 3;\nPython3Lexer.FROM = 4;\nPython3Lexer.IMPORT = 5;\nPython3Lexer.AS = 6;\nPython3Lexer.GLOBAL = 7;\nPython3Lexer.NONLOCAL = 8;\nPython3Lexer.ASSERT = 9;\nPython3Lexer.IF = 10;\nPython3Lexer.ELIF = 11;\nPython3Lexer.ELSE = 12;\nPython3Lexer.WHILE = 13;\nPython3Lexer.FOR = 14;\nPython3Lexer.IN = 15;\nPython3Lexer.TRY = 16;\nPython3Lexer.FINALLY = 17;\nPython3Lexer.WITH = 18;\nPython3Lexer.EXCEPT = 19;\nPython3Lexer.LAMBDA = 20;\nPython3Lexer.OR = 21;\nPython3Lexer.AND = 22;\nPython3Lexer.NOT = 23;\nPython3Lexer.IS = 24;\nPython3Lexer.NONE = 25;\nPython3Lexer.TRUE = 26;\nPython3Lexer.FALSE = 27;\nPython3Lexer.CLASS = 28;\nPython3Lexer.YIELD = 29;\nPython3Lexer.DEL = 30;\nPython3Lexer.PASS = 31;\nPython3Lexer.CONTINUE = 32;\nPython3Lexer.BREAK = 33;\nPython3Lexer.NEWLINE = 34;\nPython3Lexer.NAME = 35;\nPython3Lexer.STRING_LITERAL = 36;\nPython3Lexer.BYTES_LITERAL = 37;\nPython3Lexer.DECIMAL_INTEGER = 38;\nPython3Lexer.OCT_INTEGER = 39;\nPython3Lexer.HEX_INTEGER = 40;\nPython3Lexer.BIN_INTEGER = 41;\nPython3Lexer.FLOAT_NUMBER = 42;\nPython3Lexer.IMAG_NUMBER = 43;\nPython3Lexer.DOT = 44;\nPython3Lexer.ELLIPSIS = 45;\nPython3Lexer.STAR = 46;\nPython3Lexer.OPEN_PAREN = 47;\nPython3Lexer.CLOSE_PAREN = 48;\nPython3Lexer.COMMA = 49;\nPython3Lexer.COLON = 50;\nPython3Lexer.SEMI_COLON = 51;\nPython3Lexer.POWER = 52;\nPython3Lexer.ASSIGN = 53;\nPython3Lexer.OPEN_BRACK = 54;\nPython3Lexer.CLOSE_BRACK = 55;\nPython3Lexer.OR_OP = 56;\nPython3Lexer.XOR = 57;\nPython3Lexer.AND_OP = 58;\nPython3Lexer.LEFT_SHIFT = 59;\nPython3Lexer.RIGHT_SHIFT = 60;\nPython3Lexer.ADD = 61;\nPython3Lexer.MINUS = 62;\nPython3Lexer.DIV = 63;\nPython3Lexer.MOD = 64;\nPython3Lexer.IDIV = 65;\nPython3Lexer.NOT_OP = 66;\nPython3Lexer.OPEN_BRACE = 67;\nPython3Lexer.CLOSE_BRACE = 68;\nPython3Lexer.LESS_THAN = 69;\nPython3Lexer.GREATER_THAN = 70;\nPython3Lexer.EQUALS = 71;\nPython3Lexer.GT_EQ = 72;\nPython3Lexer.LT_EQ = 73;\nPython3Lexer.NOT_EQ_1 = 74;\nPython3Lexer.NOT_EQ_2 = 75;\nPython3Lexer.AT = 76;\nPython3Lexer.ARROW = 77;\nPython3Lexer.ADD_ASSIGN = 78;\nPython3Lexer.SUB_ASSIGN = 79;\nPython3Lexer.MULT_ASSIGN = 80;\nPython3Lexer.AT_ASSIGN = 81;\nPython3Lexer.DIV_ASSIGN = 82;\nPython3Lexer.MOD_ASSIGN = 83;\nPython3Lexer.AND_ASSIGN = 84;\nPython3Lexer.OR_ASSIGN = 85;\nPython3Lexer.XOR_ASSIGN = 86;\nPython3Lexer.LEFT_SHIFT_ASSIGN = 87;\nPython3Lexer.RIGHT_SHIFT_ASSIGN = 88;\nPython3Lexer.POWER_ASSIGN = 89;\nPython3Lexer.IDIV_ASSIGN = 90;\nPython3Lexer.SKIP_ = 91;\nPython3Lexer.UNKNOWN_CHAR = 92;\n\nPython3Lexer.prototype.channelNames = [ \"DEFAULT_TOKEN_CHANNEL\", \"HIDDEN\" ];\n\nPython3Lexer.prototype.modeNames = [ \"DEFAULT_MODE\" ];\n\nPython3Lexer.prototype.literalNames = [ null, \"'def'\", \"'return'\", \"'raise'\", \n                                        \"'from'\", \"'import'\", \"'as'\", \"'global'\", \n                                        \"'nonlocal'\", \"'assert'\", \"'if'\", \n                                        \"'elif'\", \"'else'\", \"'while'\", \"'for'\", \n                                        \"'in'\", \"'try'\", \"'finally'\", \"'with'\", \n                                        \"'except'\", \"'lambda'\", \"'or'\", \n                                        \"'and'\", \"'not'\", \"'is'\", \"'None'\", \n                                        \"'True'\", \"'False'\", \"'class'\", \n                                        \"'yield'\", \"'del'\", \"'pass'\", \"'continue'\", \n                                        \"'break'\", null, null, null, null, \n                                        null, null, null, null, null, null, \n                                        \"'.'\", \"'...'\", \"'*'\", \"'('\", \"')'\", \n                                        \"','\", \"':'\", \"';'\", \"'**'\", \"'='\", \n                                        \"'['\", \"']'\", \"'|'\", \"'^'\", \"'&'\", \n                                        \"'<<'\", \"'>>'\", \"'+'\", \"'-'\", \"'/'\", \n                                        \"'%'\", \"'//'\", \"'~'\", \"'{'\", \"'}'\", \n                                        \"'<'\", \"'>'\", \"'=='\", \"'>='\", \"'<='\", \n                                        \"'<>'\", \"'!='\", \"'@'\", \"'->'\", \"'+='\", \n                                        \"'-='\", \"'*='\", \"'@='\", \"'/='\", \n                                        \"'%='\", \"'&='\", \"'|='\", \"'^='\", \n                                        \"'<<='\", \"'>>='\", \"'**='\", \"'//='\" ];\n\nPython3Lexer.prototype.symbolicNames = [ null, \"DEF\", \"RETURN\", \"RAISE\", \n                                         \"FROM\", \"IMPORT\", \"AS\", \"GLOBAL\", \n                                         \"NONLOCAL\", \"ASSERT\", \"IF\", \"ELIF\", \n                                         \"ELSE\", \"WHILE\", \"FOR\", \"IN\", \"TRY\", \n                                         \"FINALLY\", \"WITH\", \"EXCEPT\", \"LAMBDA\", \n                                         \"OR\", \"AND\", \"NOT\", \"IS\", \"NONE\", \n                                         \"TRUE\", \"FALSE\", \"CLASS\", \"YIELD\", \n                                         \"DEL\", \"PASS\", \"CONTINUE\", \"BREAK\", \n                                         \"NEWLINE\", \"NAME\", \"STRING_LITERAL\", \n                                         \"BYTES_LITERAL\", \"DECIMAL_INTEGER\", \n                                         \"OCT_INTEGER\", \"HEX_INTEGER\", \"BIN_INTEGER\", \n                                         \"FLOAT_NUMBER\", \"IMAG_NUMBER\", \n                                         \"DOT\", \"ELLIPSIS\", \"STAR\", \"OPEN_PAREN\", \n                                         \"CLOSE_PAREN\", \"COMMA\", \"COLON\", \n                                         \"SEMI_COLON\", \"POWER\", \"ASSIGN\", \n                                         \"OPEN_BRACK\", \"CLOSE_BRACK\", \"OR_OP\", \n                                         \"XOR\", \"AND_OP\", \"LEFT_SHIFT\", \n                                         \"RIGHT_SHIFT\", \"ADD\", \"MINUS\", \n                                         \"DIV\", \"MOD\", \"IDIV\", \"NOT_OP\", \n                                         \"OPEN_BRACE\", \"CLOSE_BRACE\", \"LESS_THAN\", \n                                         \"GREATER_THAN\", \"EQUALS\", \"GT_EQ\", \n                                         \"LT_EQ\", \"NOT_EQ_1\", \"NOT_EQ_2\", \n                                         \"AT\", \"ARROW\", \"ADD_ASSIGN\", \"SUB_ASSIGN\", \n                                         \"MULT_ASSIGN\", \"AT_ASSIGN\", \"DIV_ASSIGN\", \n                                         \"MOD_ASSIGN\", \"AND_ASSIGN\", \"OR_ASSIGN\", \n                                         \"XOR_ASSIGN\", \"LEFT_SHIFT_ASSIGN\", \n                                         \"RIGHT_SHIFT_ASSIGN\", \"POWER_ASSIGN\", \n                                         \"IDIV_ASSIGN\", \"SKIP_\", \"UNKNOWN_CHAR\" ];\n\nPython3Lexer.prototype.ruleNames = [ \"DEF\", \"RETURN\", \"RAISE\", \"FROM\", \"IMPORT\", \n                                     \"AS\", \"GLOBAL\", \"NONLOCAL\", \"ASSERT\", \n                                     \"IF\", \"ELIF\", \"ELSE\", \"WHILE\", \"FOR\", \n                                     \"IN\", \"TRY\", \"FINALLY\", \"WITH\", \"EXCEPT\", \n                                     \"LAMBDA\", \"OR\", \"AND\", \"NOT\", \"IS\", \n                                     \"NONE\", \"TRUE\", \"FALSE\", \"CLASS\", \"YIELD\", \n                                     \"DEL\", \"PASS\", \"CONTINUE\", \"BREAK\", \n                                     \"NEWLINE\", \"NAME\", \"STRING_LITERAL\", \n                                     \"BYTES_LITERAL\", \"DECIMAL_INTEGER\", \n                                     \"OCT_INTEGER\", \"HEX_INTEGER\", \"BIN_INTEGER\", \n                                     \"FLOAT_NUMBER\", \"IMAG_NUMBER\", \"DOT\", \n                                     \"ELLIPSIS\", \"STAR\", \"OPEN_PAREN\", \"CLOSE_PAREN\", \n                                     \"COMMA\", \"COLON\", \"SEMI_COLON\", \"POWER\", \n                                     \"ASSIGN\", \"OPEN_BRACK\", \"CLOSE_BRACK\", \n                                     \"OR_OP\", \"XOR\", \"AND_OP\", \"LEFT_SHIFT\", \n                                     \"RIGHT_SHIFT\", \"ADD\", \"MINUS\", \"DIV\", \n                                     \"MOD\", \"IDIV\", \"NOT_OP\", \"OPEN_BRACE\", \n                                     \"CLOSE_BRACE\", \"LESS_THAN\", \"GREATER_THAN\", \n                                     \"EQUALS\", \"GT_EQ\", \"LT_EQ\", \"NOT_EQ_1\", \n                                     \"NOT_EQ_2\", \"AT\", \"ARROW\", \"ADD_ASSIGN\", \n                                     \"SUB_ASSIGN\", \"MULT_ASSIGN\", \"AT_ASSIGN\", \n                                     \"DIV_ASSIGN\", \"MOD_ASSIGN\", \"AND_ASSIGN\", \n                                     \"OR_ASSIGN\", \"XOR_ASSIGN\", \"LEFT_SHIFT_ASSIGN\", \n                                     \"RIGHT_SHIFT_ASSIGN\", \"POWER_ASSIGN\", \n                                     \"IDIV_ASSIGN\", \"SKIP_\", \"UNKNOWN_CHAR\", \n                                     \"SHORT_STRING\", \"LONG_STRING\", \"LONG_STRING_ITEM\", \n                                     \"LONG_STRING_CHAR\", \"STRING_ESCAPE_SEQ\", \n                                     \"NON_ZERO_DIGIT\", \"DIGIT\", \"OCT_DIGIT\", \n                                     \"HEX_DIGIT\", \"BIN_DIGIT\", \"POINT_FLOAT\", \n                                     \"EXPONENT_FLOAT\", \"INT_PART\", \"FRACTION\", \n                                     \"EXPONENT\", \"SHORT_BYTES\", \"LONG_BYTES\", \n                                     \"LONG_BYTES_ITEM\", \"SHORT_BYTES_CHAR_NO_SINGLE_QUOTE\", \n                                     \"SHORT_BYTES_CHAR_NO_DOUBLE_QUOTE\", \n                                     \"LONG_BYTES_CHAR\", \"BYTES_ESCAPE_SEQ\", \n                                     \"SPACES\", \"COMMENT\", \"LINE_JOINING\", \n                                     \"ID_START\", \"ID_CONTINUE\" ];\n\nPython3Lexer.prototype.grammarFileName = \"Python3.g4\";\n\n\n\n  let CommonToken = require('antlr4/Token').CommonToken;\n  let Python3Parser = require('./Python3Parser').Python3Parser;\n\n  let old_lexer = Python3Lexer;\n  Python3Lexer = function() {\n    old_lexer.apply(this, arguments);\n    this.reset.call(this);\n  }\n\n  Python3Lexer.prototype = Object.create(old_lexer.prototype);\n  Python3Lexer.prototype.constructor = Python3Lexer;\n\n\n  Python3Lexer.prototype.reset = function() {\n    // A queue where extra tokens are pushed on (see the NEWLINE lexer rule).\n    this.token_queue = [];\n\n    // The stack that keeps track of the indentation level.\n    this.indents = [];\n\n    // The amount of opened braces, brackets and parenthesis.\n    this.opened = 0;\n\n    antlr4.Lexer.prototype.reset.call(this);\n  };\n\n  Python3Lexer.prototype.emitToken = function(token) {\n    this._token = token;\n    this.token_queue.push(token);\n  };\n\n  /**\n   * Return the next token from the character stream and records this last\n   * token in case it resides on the default channel. This recorded token\n   * is used to determine when the lexer could possibly match a regex\n   * literal.\n   *\n   */\n  Python3Lexer.prototype.nextToken = function() {\n    // Check if the end-of-file is ahead and there are still some DEDENTS expected.\n    if (this._input.LA(1) === Python3Parser.EOF && this.indents.length) {\n\n      // Remove any trailing EOF tokens from our buffer.\n      this.token_queue = this.token_queue.filter(function(val) {\n        return val.type !== Python3Parser.EOF;\n      });\n\n      // First emit an extra line break that serves as the end of the statement.\n      this.emitToken(this.commonToken(Python3Parser.NEWLINE, \"\\n\"));\n\n      // Now emit as much DEDENT tokens as needed.\n      while (this.indents.length) {\n        this.emitToken(this.createDedent());\n        this.indents.pop();\n      }\n\n      // Put the EOF back on the token stream.\n      this.emitToken(this.commonToken(Python3Parser.EOF, \"<EOF>\"));\n    }\n\n    let next = antlr4.Lexer.prototype.nextToken.call(this);\n    return this.token_queue.length ? this.token_queue.shift() : next;\n  };\n\n  Python3Lexer.prototype.createDedent = function() {\n    return this.commonToken(Python3Parser.DEDENT, \"\");\n  }\n\n  Python3Lexer.prototype.commonToken = function(type, text) {\n    let stop = this.getCharIndex() - 1;\n    let start = text.length ? stop - text.length + 1 : stop;\n    return new CommonToken(this._tokenFactorySourcePair, type, antlr4.Lexer.DEFAULT_TOKEN_CHANNEL, start, stop);\n  }\n\n  // Calculates the indentation of the provided spaces, taking the\n  // following rules into account:\n  //\n  // \"Tabs are replaced (from left to right) by one to eight spaces\n  //  such that the total number of characters up to and including\n  //  the replacement is a multiple of eight [...]\"\n  //\n  //  -- https://docs.python.org/3.1/reference/lexical_analysis.html#indentation\n  Python3Lexer.prototype.getIndentationCount = function(whitespace) {\n    let count = 0;\n    for (let i = 0; i < whitespace.length; i++) {\n      if (whitespace[i] === '\\t') {\n        count += 8 - count % 8;\n      } else {\n        count++;\n      }\n    }\n    return count;\n  }\n\n  Python3Lexer.prototype.atStartOfInput = function() {\n    return this.getCharIndex() === 0;\n  }\n\n\nPython3Lexer.prototype.action = function(localctx, ruleIndex, actionIndex) {\n\tswitch (ruleIndex) {\n\tcase 33:\n\t\tthis.NEWLINE_action(localctx, actionIndex);\n\t\tbreak;\n\tcase 46:\n\t\tthis.OPEN_PAREN_action(localctx, actionIndex);\n\t\tbreak;\n\tcase 47:\n\t\tthis.CLOSE_PAREN_action(localctx, actionIndex);\n\t\tbreak;\n\tcase 53:\n\t\tthis.OPEN_BRACK_action(localctx, actionIndex);\n\t\tbreak;\n\tcase 54:\n\t\tthis.CLOSE_BRACK_action(localctx, actionIndex);\n\t\tbreak;\n\tcase 66:\n\t\tthis.OPEN_BRACE_action(localctx, actionIndex);\n\t\tbreak;\n\tcase 67:\n\t\tthis.CLOSE_BRACE_action(localctx, actionIndex);\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + ruleIndex;\n\t}\n};\n\nPython3Lexer.prototype.NEWLINE_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 0:\n\n\t\t     let newLine = this.text.replace(/[^\\r\\n]+/g, '');\n\t\t     let spaces = this.text.replace(/[\\r\\n]+/g, '');\n\t\t     let next = this._input.LA(1);\n\n\t\t     if (this.opened > 0 || next === 13 /* '\\r' */ || next === 10 /* '\\n' */ || next === 35 /* '#' */) {\n\t\t       // If we're inside a list or on a blank line, ignore all indents,\n\t\t       // dedents and line breaks.\n\t\t       this.skip();\n\t\t     } else {\n\t\t       this.emitToken(this.commonToken(Python3Parser.NEWLINE, newLine));\n\n\t\t       let indent = this.getIndentationCount(spaces);\n\t\t       let previous = this.indents.length ? this.indents[this.indents.length - 1] : 0;\n\n\t\t       if (indent === previous) {\n\t\t         // skip indents of the same size as the present indent-size\n\t\t         this.skip();\n\t\t       } else if (indent > previous) {\n\t\t         this.indents.push(indent);\n\t\t         this.emitToken(this.commonToken(Python3Parser.INDENT, spaces));\n\t\t       } else {\n\t\t         // Possibly emit more than 1 DEDENT token.\n\t\t         while (this.indents.length && this.indents[this.indents.length - 1] > indent) {\n\t\t           this.emitToken(this.createDedent());\n\t\t           this.indents.pop();\n\t\t         }\n\t\t       }\n\t\t     }\n\t\t   \n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\n\nPython3Lexer.prototype.OPEN_PAREN_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 1:\n\t\tthis.opened++;\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\n\nPython3Lexer.prototype.CLOSE_PAREN_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 2:\n\t\tthis.opened--;\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\n\nPython3Lexer.prototype.OPEN_BRACK_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 3:\n\t\tthis.opened++;\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\n\nPython3Lexer.prototype.CLOSE_BRACK_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 4:\n\t\tthis.opened--;\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\n\nPython3Lexer.prototype.OPEN_BRACE_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 5:\n\t\tthis.opened++;\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\n\nPython3Lexer.prototype.CLOSE_BRACE_action = function(localctx , actionIndex) {\n\tswitch (actionIndex) {\n\tcase 6:\n\t\tthis.opened--;\n\t\tbreak;\n\tdefault:\n\t\tthrow \"No registered action for:\" + actionIndex;\n\t}\n};\nPython3Lexer.prototype.sempred = function(localctx, ruleIndex, predIndex) {\n\tswitch (ruleIndex) {\n\t\tcase 33:\n\t\t\treturn this.NEWLINE_sempred(localctx, predIndex);\n    \tdefault:\n    \t\tthrow \"No registered predicate for:\" + ruleIndex;\n    }\n};\n\nPython3Lexer.prototype.NEWLINE_sempred = function(localctx, predIndex) {\n\tswitch(predIndex) {\n\t\tcase 0:\n\t\t\treturn this.atStartOfInput();\n\t\tdefault:\n\t\t\tthrow \"No predicate with index:\" + predIndex;\n\t}\n};\n\n\n\nexports.Python3Lexer = Python3Lexer;\n\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Lexer.tokens",
    "content": "DEF=1\nRETURN=2\nRAISE=3\nFROM=4\nIMPORT=5\nAS=6\nGLOBAL=7\nNONLOCAL=8\nASSERT=9\nIF=10\nELIF=11\nELSE=12\nWHILE=13\nFOR=14\nIN=15\nTRY=16\nFINALLY=17\nWITH=18\nEXCEPT=19\nLAMBDA=20\nOR=21\nAND=22\nNOT=23\nIS=24\nNONE=25\nTRUE=26\nFALSE=27\nCLASS=28\nYIELD=29\nDEL=30\nPASS=31\nCONTINUE=32\nBREAK=33\nNEWLINE=34\nNAME=35\nSTRING_LITERAL=36\nBYTES_LITERAL=37\nDECIMAL_INTEGER=38\nOCT_INTEGER=39\nHEX_INTEGER=40\nBIN_INTEGER=41\nFLOAT_NUMBER=42\nIMAG_NUMBER=43\nDOT=44\nELLIPSIS=45\nSTAR=46\nOPEN_PAREN=47\nCLOSE_PAREN=48\nCOMMA=49\nCOLON=50\nSEMI_COLON=51\nPOWER=52\nASSIGN=53\nOPEN_BRACK=54\nCLOSE_BRACK=55\nOR_OP=56\nXOR=57\nAND_OP=58\nLEFT_SHIFT=59\nRIGHT_SHIFT=60\nADD=61\nMINUS=62\nDIV=63\nMOD=64\nIDIV=65\nNOT_OP=66\nOPEN_BRACE=67\nCLOSE_BRACE=68\nLESS_THAN=69\nGREATER_THAN=70\nEQUALS=71\nGT_EQ=72\nLT_EQ=73\nNOT_EQ_1=74\nNOT_EQ_2=75\nAT=76\nARROW=77\nADD_ASSIGN=78\nSUB_ASSIGN=79\nMULT_ASSIGN=80\nAT_ASSIGN=81\nDIV_ASSIGN=82\nMOD_ASSIGN=83\nAND_ASSIGN=84\nOR_ASSIGN=85\nXOR_ASSIGN=86\nLEFT_SHIFT_ASSIGN=87\nRIGHT_SHIFT_ASSIGN=88\nPOWER_ASSIGN=89\nIDIV_ASSIGN=90\nSKIP_=91\nUNKNOWN_CHAR=92\n'def'=1\n'return'=2\n'raise'=3\n'from'=4\n'import'=5\n'as'=6\n'global'=7\n'nonlocal'=8\n'assert'=9\n'if'=10\n'elif'=11\n'else'=12\n'while'=13\n'for'=14\n'in'=15\n'try'=16\n'finally'=17\n'with'=18\n'except'=19\n'lambda'=20\n'or'=21\n'and'=22\n'not'=23\n'is'=24\n'None'=25\n'True'=26\n'False'=27\n'class'=28\n'yield'=29\n'del'=30\n'pass'=31\n'continue'=32\n'break'=33\n'.'=44\n'...'=45\n'*'=46\n'('=47\n')'=48\n','=49\n':'=50\n';'=51\n'**'=52\n'='=53\n'['=54\n']'=55\n'|'=56\n'^'=57\n'&'=58\n'<<'=59\n'>>'=60\n'+'=61\n'-'=62\n'/'=63\n'%'=64\n'//'=65\n'~'=66\n'{'=67\n'}'=68\n'<'=69\n'>'=70\n'=='=71\n'>='=72\n'<='=73\n'<>'=74\n'!='=75\n'@'=76\n'->'=77\n'+='=78\n'-='=79\n'*='=80\n'@='=81\n'/='=82\n'%='=83\n'&='=84\n'|='=85\n'^='=86\n'<<='=87\n'>>='=88\n'**='=89\n'//='=90\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Listener.js",
    "content": "// Generated from ./lang/python/Python3.g4 by ANTLR 4.7\n// jshint ignore: start\nvar antlr4 = require('antlr4/index');\n\n// This class defines a complete listener for a parse tree produced by Python3Parser.\nfunction Python3Listener() {\n\tantlr4.tree.ParseTreeListener.call(this);\n\treturn this;\n}\n\nPython3Listener.prototype = Object.create(antlr4.tree.ParseTreeListener.prototype);\nPython3Listener.prototype.constructor = Python3Listener;\n\n// Enter a parse tree produced by Python3Parser#single_input.\nPython3Listener.prototype.enterSingle_input = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#single_input.\nPython3Listener.prototype.exitSingle_input = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#file_input.\nPython3Listener.prototype.enterFile_input = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#file_input.\nPython3Listener.prototype.exitFile_input = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#eval_input.\nPython3Listener.prototype.enterEval_input = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#eval_input.\nPython3Listener.prototype.exitEval_input = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#decorator.\nPython3Listener.prototype.enterDecorator = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#decorator.\nPython3Listener.prototype.exitDecorator = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#decorators.\nPython3Listener.prototype.enterDecorators = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#decorators.\nPython3Listener.prototype.exitDecorators = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#decorated.\nPython3Listener.prototype.enterDecorated = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#decorated.\nPython3Listener.prototype.exitDecorated = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#funcdef.\nPython3Listener.prototype.enterFuncdef = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#funcdef.\nPython3Listener.prototype.exitFuncdef = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#parameters.\nPython3Listener.prototype.enterParameters = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#parameters.\nPython3Listener.prototype.exitParameters = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#typedargslist.\nPython3Listener.prototype.enterTypedargslist = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#typedargslist.\nPython3Listener.prototype.exitTypedargslist = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#tfpdef.\nPython3Listener.prototype.enterTfpdef = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#tfpdef.\nPython3Listener.prototype.exitTfpdef = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#varargslist.\nPython3Listener.prototype.enterVarargslist = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#varargslist.\nPython3Listener.prototype.exitVarargslist = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#vfpdef.\nPython3Listener.prototype.enterVfpdef = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#vfpdef.\nPython3Listener.prototype.exitVfpdef = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#stmt.\nPython3Listener.prototype.enterStmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#stmt.\nPython3Listener.prototype.exitStmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#simple_stmt.\nPython3Listener.prototype.enterSimple_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#simple_stmt.\nPython3Listener.prototype.exitSimple_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#small_stmt.\nPython3Listener.prototype.enterSmall_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#small_stmt.\nPython3Listener.prototype.exitSmall_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#expr_stmt.\nPython3Listener.prototype.enterExpr_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#expr_stmt.\nPython3Listener.prototype.exitExpr_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#testlist_star_expr.\nPython3Listener.prototype.enterTestlist_star_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#testlist_star_expr.\nPython3Listener.prototype.exitTestlist_star_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#augassign.\nPython3Listener.prototype.enterAugassign = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#augassign.\nPython3Listener.prototype.exitAugassign = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#del_stmt.\nPython3Listener.prototype.enterDel_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#del_stmt.\nPython3Listener.prototype.exitDel_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#pass_stmt.\nPython3Listener.prototype.enterPass_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#pass_stmt.\nPython3Listener.prototype.exitPass_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#flow_stmt.\nPython3Listener.prototype.enterFlow_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#flow_stmt.\nPython3Listener.prototype.exitFlow_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#break_stmt.\nPython3Listener.prototype.enterBreak_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#break_stmt.\nPython3Listener.prototype.exitBreak_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#continue_stmt.\nPython3Listener.prototype.enterContinue_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#continue_stmt.\nPython3Listener.prototype.exitContinue_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#return_stmt.\nPython3Listener.prototype.enterReturn_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#return_stmt.\nPython3Listener.prototype.exitReturn_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#yield_stmt.\nPython3Listener.prototype.enterYield_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#yield_stmt.\nPython3Listener.prototype.exitYield_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#raise_stmt.\nPython3Listener.prototype.enterRaise_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#raise_stmt.\nPython3Listener.prototype.exitRaise_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#import_stmt.\nPython3Listener.prototype.enterImport_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#import_stmt.\nPython3Listener.prototype.exitImport_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#import_name.\nPython3Listener.prototype.enterImport_name = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#import_name.\nPython3Listener.prototype.exitImport_name = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#import_from.\nPython3Listener.prototype.enterImport_from = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#import_from.\nPython3Listener.prototype.exitImport_from = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#import_as_name.\nPython3Listener.prototype.enterImport_as_name = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#import_as_name.\nPython3Listener.prototype.exitImport_as_name = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#dotted_as_name.\nPython3Listener.prototype.enterDotted_as_name = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#dotted_as_name.\nPython3Listener.prototype.exitDotted_as_name = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#import_as_names.\nPython3Listener.prototype.enterImport_as_names = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#import_as_names.\nPython3Listener.prototype.exitImport_as_names = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#dotted_as_names.\nPython3Listener.prototype.enterDotted_as_names = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#dotted_as_names.\nPython3Listener.prototype.exitDotted_as_names = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#dotted_name.\nPython3Listener.prototype.enterDotted_name = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#dotted_name.\nPython3Listener.prototype.exitDotted_name = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#global_stmt.\nPython3Listener.prototype.enterGlobal_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#global_stmt.\nPython3Listener.prototype.exitGlobal_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#nonlocal_stmt.\nPython3Listener.prototype.enterNonlocal_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#nonlocal_stmt.\nPython3Listener.prototype.exitNonlocal_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#assert_stmt.\nPython3Listener.prototype.enterAssert_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#assert_stmt.\nPython3Listener.prototype.exitAssert_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#compound_stmt.\nPython3Listener.prototype.enterCompound_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#compound_stmt.\nPython3Listener.prototype.exitCompound_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#if_stmt.\nPython3Listener.prototype.enterIf_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#if_stmt.\nPython3Listener.prototype.exitIf_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#while_stmt.\nPython3Listener.prototype.enterWhile_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#while_stmt.\nPython3Listener.prototype.exitWhile_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#for_stmt.\nPython3Listener.prototype.enterFor_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#for_stmt.\nPython3Listener.prototype.exitFor_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#try_stmt.\nPython3Listener.prototype.enterTry_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#try_stmt.\nPython3Listener.prototype.exitTry_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#with_stmt.\nPython3Listener.prototype.enterWith_stmt = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#with_stmt.\nPython3Listener.prototype.exitWith_stmt = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#with_item.\nPython3Listener.prototype.enterWith_item = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#with_item.\nPython3Listener.prototype.exitWith_item = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#except_clause.\nPython3Listener.prototype.enterExcept_clause = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#except_clause.\nPython3Listener.prototype.exitExcept_clause = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#suite.\nPython3Listener.prototype.enterSuite = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#suite.\nPython3Listener.prototype.exitSuite = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#test.\nPython3Listener.prototype.enterTest = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#test.\nPython3Listener.prototype.exitTest = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#test_nocond.\nPython3Listener.prototype.enterTest_nocond = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#test_nocond.\nPython3Listener.prototype.exitTest_nocond = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#lambdef.\nPython3Listener.prototype.enterLambdef = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#lambdef.\nPython3Listener.prototype.exitLambdef = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#lambdef_nocond.\nPython3Listener.prototype.enterLambdef_nocond = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#lambdef_nocond.\nPython3Listener.prototype.exitLambdef_nocond = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#or_test.\nPython3Listener.prototype.enterOr_test = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#or_test.\nPython3Listener.prototype.exitOr_test = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#and_test.\nPython3Listener.prototype.enterAnd_test = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#and_test.\nPython3Listener.prototype.exitAnd_test = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#not_test.\nPython3Listener.prototype.enterNot_test = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#not_test.\nPython3Listener.prototype.exitNot_test = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#comparison.\nPython3Listener.prototype.enterComparison = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#comparison.\nPython3Listener.prototype.exitComparison = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#comp_op.\nPython3Listener.prototype.enterComp_op = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#comp_op.\nPython3Listener.prototype.exitComp_op = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#star_expr.\nPython3Listener.prototype.enterStar_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#star_expr.\nPython3Listener.prototype.exitStar_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#expr.\nPython3Listener.prototype.enterExpr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#expr.\nPython3Listener.prototype.exitExpr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#xor_expr.\nPython3Listener.prototype.enterXor_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#xor_expr.\nPython3Listener.prototype.exitXor_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#and_expr.\nPython3Listener.prototype.enterAnd_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#and_expr.\nPython3Listener.prototype.exitAnd_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#shift_expr.\nPython3Listener.prototype.enterShift_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#shift_expr.\nPython3Listener.prototype.exitShift_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#arith_expr.\nPython3Listener.prototype.enterArith_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#arith_expr.\nPython3Listener.prototype.exitArith_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#term.\nPython3Listener.prototype.enterTerm = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#term.\nPython3Listener.prototype.exitTerm = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#factor.\nPython3Listener.prototype.enterFactor = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#factor.\nPython3Listener.prototype.exitFactor = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#power.\nPython3Listener.prototype.enterPower = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#power.\nPython3Listener.prototype.exitPower = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#atom.\nPython3Listener.prototype.enterAtom = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#atom.\nPython3Listener.prototype.exitAtom = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#testlist_comp.\nPython3Listener.prototype.enterTestlist_comp = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#testlist_comp.\nPython3Listener.prototype.exitTestlist_comp = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#trailer.\nPython3Listener.prototype.enterTrailer = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#trailer.\nPython3Listener.prototype.exitTrailer = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#subscriptlist.\nPython3Listener.prototype.enterSubscriptlist = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#subscriptlist.\nPython3Listener.prototype.exitSubscriptlist = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#subscript.\nPython3Listener.prototype.enterSubscript = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#subscript.\nPython3Listener.prototype.exitSubscript = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#sliceop.\nPython3Listener.prototype.enterSliceop = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#sliceop.\nPython3Listener.prototype.exitSliceop = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#exprlist.\nPython3Listener.prototype.enterExprlist = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#exprlist.\nPython3Listener.prototype.exitExprlist = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#testlist.\nPython3Listener.prototype.enterTestlist = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#testlist.\nPython3Listener.prototype.exitTestlist = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#dictorsetmaker.\nPython3Listener.prototype.enterDictorsetmaker = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#dictorsetmaker.\nPython3Listener.prototype.exitDictorsetmaker = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#classdef.\nPython3Listener.prototype.enterClassdef = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#classdef.\nPython3Listener.prototype.exitClassdef = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#arglist.\nPython3Listener.prototype.enterArglist = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#arglist.\nPython3Listener.prototype.exitArglist = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#argument.\nPython3Listener.prototype.enterArgument = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#argument.\nPython3Listener.prototype.exitArgument = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#comp_iter.\nPython3Listener.prototype.enterComp_iter = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#comp_iter.\nPython3Listener.prototype.exitComp_iter = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#comp_for.\nPython3Listener.prototype.enterComp_for = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#comp_for.\nPython3Listener.prototype.exitComp_for = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#comp_if.\nPython3Listener.prototype.enterComp_if = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#comp_if.\nPython3Listener.prototype.exitComp_if = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#yield_expr.\nPython3Listener.prototype.enterYield_expr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#yield_expr.\nPython3Listener.prototype.exitYield_expr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#yield_arg.\nPython3Listener.prototype.enterYield_arg = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#yield_arg.\nPython3Listener.prototype.exitYield_arg = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#str.\nPython3Listener.prototype.enterStr = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#str.\nPython3Listener.prototype.exitStr = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#number.\nPython3Listener.prototype.enterNumber = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#number.\nPython3Listener.prototype.exitNumber = function(ctx) {\n};\n\n\n// Enter a parse tree produced by Python3Parser#integer.\nPython3Listener.prototype.enterInteger = function(ctx) {\n};\n\n// Exit a parse tree produced by Python3Parser#integer.\nPython3Listener.prototype.exitInteger = function(ctx) {\n};\n\n\n\nexports.Python3Listener = Python3Listener;"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Parser.js",
    "content": "// Generated from ./lang/python/Python3.g4 by ANTLR 4.7\n// jshint ignore: start\nvar antlr4 = require('antlr4/index');\nvar Python3Listener = require('./Python3Listener').Python3Listener;\nvar Python3Visitor = require('./Python3Visitor').Python3Visitor;\n\nvar grammarFileName = \"Python3.g4\";\n\nvar serializedATN = [\"\\u0003\\u608b\\ua72a\\u8133\\ub9ed\\u417c\\u3be7\\u7786\\u5964\",\n    \"\\u0003`\\u0422\\u0004\\u0002\\t\\u0002\\u0004\\u0003\\t\\u0003\\u0004\\u0004\\t\",\n    \"\\u0004\\u0004\\u0005\\t\\u0005\\u0004\\u0006\\t\\u0006\\u0004\\u0007\\t\\u0007\\u0004\",\n    \"\\b\\t\\b\\u0004\\t\\t\\t\\u0004\\n\\t\\n\\u0004\\u000b\\t\\u000b\\u0004\\f\\t\\f\\u0004\",\n    \"\\r\\t\\r\\u0004\\u000e\\t\\u000e\\u0004\\u000f\\t\\u000f\\u0004\\u0010\\t\\u0010\\u0004\",\n    \"\\u0011\\t\\u0011\\u0004\\u0012\\t\\u0012\\u0004\\u0013\\t\\u0013\\u0004\\u0014\\t\",\n    \"\\u0014\\u0004\\u0015\\t\\u0015\\u0004\\u0016\\t\\u0016\\u0004\\u0017\\t\\u0017\\u0004\",\n    \"\\u0018\\t\\u0018\\u0004\\u0019\\t\\u0019\\u0004\\u001a\\t\\u001a\\u0004\\u001b\\t\",\n    \"\\u001b\\u0004\\u001c\\t\\u001c\\u0004\\u001d\\t\\u001d\\u0004\\u001e\\t\\u001e\\u0004\",\n    \"\\u001f\\t\\u001f\\u0004 \\t \\u0004!\\t!\\u0004\\\"\\t\\\"\\u0004#\\t#\\u0004$\\t$\\u0004\",\n    \"%\\t%\\u0004&\\t&\\u0004\\'\\t\\'\\u0004(\\t(\\u0004)\\t)\\u0004*\\t*\\u0004+\\t+\\u0004\",\n    \",\\t,\\u0004-\\t-\\u0004.\\t.\\u0004/\\t/\\u00040\\t0\\u00041\\t1\\u00042\\t2\\u0004\",\n    \"3\\t3\\u00044\\t4\\u00045\\t5\\u00046\\t6\\u00047\\t7\\u00048\\t8\\u00049\\t9\\u0004\",\n    \":\\t:\\u0004;\\t;\\u0004<\\t<\\u0004=\\t=\\u0004>\\t>\\u0004?\\t?\\u0004@\\t@\\u0004\",\n    \"A\\tA\\u0004B\\tB\\u0004C\\tC\\u0004D\\tD\\u0004E\\tE\\u0004F\\tF\\u0004G\\tG\\u0004\",\n    \"H\\tH\\u0004I\\tI\\u0004J\\tJ\\u0004K\\tK\\u0004L\\tL\\u0004M\\tM\\u0004N\\tN\\u0004\",\n    \"O\\tO\\u0004P\\tP\\u0004Q\\tQ\\u0004R\\tR\\u0004S\\tS\\u0004T\\tT\\u0004U\\tU\\u0003\",\n    \"\\u0002\\u0003\\u0002\\u0003\\u0002\\u0003\\u0002\\u0003\\u0002\\u0005\\u0002\\u00b0\",\n    \"\\n\\u0002\\u0003\\u0003\\u0003\\u0003\\u0007\\u0003\\u00b4\\n\\u0003\\f\\u0003\\u000e\",\n    \"\\u0003\\u00b7\\u000b\\u0003\\u0003\\u0003\\u0003\\u0003\\u0003\\u0004\\u0003\\u0004\",\n    \"\\u0007\\u0004\\u00bd\\n\\u0004\\f\\u0004\\u000e\\u0004\\u00c0\\u000b\\u0004\\u0003\",\n    \"\\u0004\\u0003\\u0004\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0003\\u0005\\u0005\",\n    \"\\u0005\\u00c8\\n\\u0005\\u0003\\u0005\\u0005\\u0005\\u00cb\\n\\u0005\\u0003\\u0005\",\n    \"\\u0003\\u0005\\u0003\\u0006\\u0006\\u0006\\u00d0\\n\\u0006\\r\\u0006\\u000e\\u0006\",\n    \"\\u00d1\\u0003\\u0007\\u0003\\u0007\\u0003\\u0007\\u0005\\u0007\\u00d7\\n\\u0007\",\n    \"\\u0003\\b\\u0003\\b\\u0003\\b\\u0003\\b\\u0003\\b\\u0005\\b\\u00de\\n\\b\\u0003\\b\\u0003\",\n    \"\\b\\u0003\\b\\u0003\\t\\u0003\\t\\u0005\\t\\u00e5\\n\\t\\u0003\\t\\u0003\\t\\u0003\\n\",\n    \"\\u0003\\n\\u0003\\n\\u0005\\n\\u00ec\\n\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0005\",\n    \"\\n\\u00f2\\n\\n\\u0007\\n\\u00f4\\n\\n\\f\\n\\u000e\\n\\u00f7\\u000b\\n\\u0003\\n\\u0003\",\n    \"\\n\\u0003\\n\\u0005\\n\\u00fc\\n\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0005\\n\",\n    \"\\u0102\\n\\n\\u0007\\n\\u0104\\n\\n\\f\\n\\u000e\\n\\u0107\\u000b\\n\\u0003\\n\\u0003\",\n    \"\\n\\u0003\\n\\u0005\\n\\u010c\\n\\n\\u0003\\n\\u0003\\n\\u0005\\n\\u0110\\n\\n\\u0005\",\n    \"\\n\\u0112\\n\\n\\u0003\\n\\u0003\\n\\u0005\\n\\u0116\\n\\n\\u0003\\n\\u0003\\n\\u0003\",\n    \"\\n\\u0003\\n\\u0005\\n\\u011c\\n\\n\\u0007\\n\\u011e\\n\\n\\f\\n\\u000e\\n\\u0121\\u000b\",\n    \"\\n\\u0003\\n\\u0003\\n\\u0003\\n\\u0005\\n\\u0126\\n\\n\\u0003\\n\\u0003\\n\\u0005\\n\",\n    \"\\u012a\\n\\n\\u0003\\u000b\\u0003\\u000b\\u0003\\u000b\\u0005\\u000b\\u012f\\n\\u000b\",\n    \"\\u0003\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u0134\\n\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0003\",\n    \"\\f\\u0005\\f\\u013a\\n\\f\\u0007\\f\\u013c\\n\\f\\f\\f\\u000e\\f\\u013f\\u000b\\f\\u0003\",\n    \"\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u0144\\n\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0003\\f\",\n    \"\\u0005\\f\\u014a\\n\\f\\u0007\\f\\u014c\\n\\f\\f\\f\\u000e\\f\\u014f\\u000b\\f\\u0003\",\n    \"\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u0154\\n\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u0158\\n\",\n    \"\\f\\u0005\\f\\u015a\\n\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u015e\\n\\f\\u0003\\f\\u0003\",\n    \"\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u0164\\n\\f\\u0007\\f\\u0166\\n\\f\\f\\f\\u000e\\f\\u0169\",\n    \"\\u000b\\f\\u0003\\f\\u0003\\f\\u0003\\f\\u0005\\f\\u016e\\n\\f\\u0003\\f\\u0003\\f\\u0005\",\n    \"\\f\\u0172\\n\\f\\u0003\\r\\u0003\\r\\u0003\\u000e\\u0003\\u000e\\u0005\\u000e\\u0178\",\n    \"\\n\\u000e\\u0003\\u000f\\u0003\\u000f\\u0003\\u000f\\u0007\\u000f\\u017d\\n\\u000f\",\n    \"\\f\\u000f\\u000e\\u000f\\u0180\\u000b\\u000f\\u0003\\u000f\\u0005\\u000f\\u0183\",\n    \"\\n\\u000f\\u0003\\u000f\\u0003\\u000f\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\",\n    \"\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\\u0003\\u0010\\u0005\\u0010\",\n    \"\\u018f\\n\\u0010\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0005\",\n    \"\\u0011\\u0195\\n\\u0011\\u0003\\u0011\\u0003\\u0011\\u0003\\u0011\\u0005\\u0011\",\n    \"\\u019a\\n\\u0011\\u0007\\u0011\\u019c\\n\\u0011\\f\\u0011\\u000e\\u0011\\u019f\\u000b\",\n    \"\\u0011\\u0005\\u0011\\u01a1\\n\\u0011\\u0003\\u0012\\u0003\\u0012\\u0005\\u0012\",\n    \"\\u01a5\\n\\u0012\\u0003\\u0012\\u0003\\u0012\\u0003\\u0012\\u0005\\u0012\\u01aa\",\n    \"\\n\\u0012\\u0007\\u0012\\u01ac\\n\\u0012\\f\\u0012\\u000e\\u0012\\u01af\\u000b\\u0012\",\n    \"\\u0003\\u0012\\u0005\\u0012\\u01b2\\n\\u0012\\u0003\\u0013\\u0003\\u0013\\u0003\",\n    \"\\u0014\\u0003\\u0014\\u0003\\u0014\\u0003\\u0015\\u0003\\u0015\\u0003\\u0016\\u0003\",\n    \"\\u0016\\u0003\\u0016\\u0003\\u0016\\u0003\\u0016\\u0005\\u0016\\u01c0\\n\\u0016\",\n    \"\\u0003\\u0017\\u0003\\u0017\\u0003\\u0018\\u0003\\u0018\\u0003\\u0019\\u0003\\u0019\",\n    \"\\u0005\\u0019\\u01c8\\n\\u0019\\u0003\\u001a\\u0003\\u001a\\u0003\\u001b\\u0003\",\n    \"\\u001b\\u0003\\u001b\\u0003\\u001b\\u0005\\u001b\\u01d0\\n\\u001b\\u0005\\u001b\",\n    \"\\u01d2\\n\\u001b\\u0003\\u001c\\u0003\\u001c\\u0005\\u001c\\u01d6\\n\\u001c\\u0003\",\n    \"\\u001d\\u0003\\u001d\\u0003\\u001d\\u0003\\u001e\\u0003\\u001e\\u0007\\u001e\\u01dd\",\n    \"\\n\\u001e\\f\\u001e\\u000e\\u001e\\u01e0\\u000b\\u001e\\u0003\\u001e\\u0003\\u001e\",\n    \"\\u0006\\u001e\\u01e4\\n\\u001e\\r\\u001e\\u000e\\u001e\\u01e5\\u0005\\u001e\\u01e8\",\n    \"\\n\\u001e\\u0003\\u001e\\u0003\\u001e\\u0003\\u001e\\u0003\\u001e\\u0003\\u001e\",\n    \"\\u0003\\u001e\\u0003\\u001e\\u0005\\u001e\\u01f1\\n\\u001e\\u0003\\u001f\\u0003\",\n    \"\\u001f\\u0003\\u001f\\u0005\\u001f\\u01f6\\n\\u001f\\u0003 \\u0003 \\u0003 \\u0005\",\n    \" \\u01fb\\n \\u0003!\\u0003!\\u0003!\\u0007!\\u0200\\n!\\f!\\u000e!\\u0203\\u000b\",\n    \"!\\u0003!\\u0005!\\u0206\\n!\\u0003\\\"\\u0003\\\"\\u0003\\\"\\u0007\\\"\\u020b\\n\\\"\\f\",\n    \"\\\"\\u000e\\\"\\u020e\\u000b\\\"\\u0003#\\u0003#\\u0003#\\u0007#\\u0213\\n#\\f#\\u000e\",\n    \"#\\u0216\\u000b#\\u0003$\\u0003$\\u0003$\\u0003$\\u0007$\\u021c\\n$\\f$\\u000e\",\n    \"$\\u021f\\u000b$\\u0003%\\u0003%\\u0003%\\u0003%\\u0007%\\u0225\\n%\\f%\\u000e\",\n    \"%\\u0228\\u000b%\\u0003&\\u0003&\\u0003&\\u0003&\\u0005&\\u022e\\n&\\u0003\\'\\u0003\",\n    \"\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0003\\'\\u0005\\'\\u0238\\n\\'\",\n    \"\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0003(\\u0007\",\n    \"(\\u0243\\n(\\f(\\u000e(\\u0246\\u000b(\\u0003(\\u0003(\\u0003(\\u0005(\\u024b\",\n    \"\\n(\\u0003)\\u0003)\\u0003)\\u0003)\\u0003)\\u0003)\\u0003)\\u0005)\\u0254\\n\",\n    \")\\u0003*\\u0003*\\u0003*\\u0003*\\u0003*\\u0003*\\u0003*\\u0003*\\u0003*\\u0005\",\n    \"*\\u025f\\n*\\u0003+\\u0003+\\u0003+\\u0003+\\u0003+\\u0003+\\u0003+\\u0006+\\u0268\",\n    \"\\n+\\r+\\u000e+\\u0269\\u0003+\\u0003+\\u0003+\\u0005+\\u026f\\n+\\u0003+\\u0003\",\n    \"+\\u0003+\\u0005+\\u0274\\n+\\u0003+\\u0003+\\u0003+\\u0005+\\u0279\\n+\\u0003\",\n    \",\\u0003,\\u0003,\\u0003,\\u0007,\\u027f\\n,\\f,\\u000e,\\u0282\\u000b,\\u0003\",\n    \",\\u0003,\\u0003,\\u0003-\\u0003-\\u0003-\\u0005-\\u028a\\n-\\u0003.\\u0003.\\u0003\",\n    \".\\u0003.\\u0005.\\u0290\\n.\\u0005.\\u0292\\n.\\u0003/\\u0003/\\u0003/\\u0003\",\n    \"/\\u0006/\\u0298\\n/\\r/\\u000e/\\u0299\\u0003/\\u0003/\\u0005/\\u029e\\n/\\u0003\",\n    \"0\\u00030\\u00030\\u00030\\u00030\\u00030\\u00050\\u02a6\\n0\\u00030\\u00050\\u02a9\",\n    \"\\n0\\u00031\\u00031\\u00051\\u02ad\\n1\\u00032\\u00032\\u00052\\u02b1\\n2\\u0003\",\n    \"2\\u00032\\u00032\\u00033\\u00033\\u00053\\u02b8\\n3\\u00033\\u00033\\u00033\\u0003\",\n    \"4\\u00034\\u00034\\u00074\\u02c0\\n4\\f4\\u000e4\\u02c3\\u000b4\\u00035\\u0003\",\n    \"5\\u00035\\u00075\\u02c8\\n5\\f5\\u000e5\\u02cb\\u000b5\\u00036\\u00036\\u0003\",\n    \"6\\u00056\\u02d0\\n6\\u00037\\u00037\\u00037\\u00037\\u00077\\u02d6\\n7\\f7\\u000e\",\n    \"7\\u02d9\\u000b7\\u00038\\u00038\\u00038\\u00038\\u00038\\u00038\\u00038\\u0003\",\n    \"8\\u00038\\u00038\\u00038\\u00038\\u00038\\u00058\\u02e8\\n8\\u00039\\u00059\\u02eb\",\n    \"\\n9\\u00039\\u00039\\u0003:\\u0003:\\u0003:\\u0007:\\u02f2\\n:\\f:\\u000e:\\u02f5\",\n    \"\\u000b:\\u0003;\\u0003;\\u0003;\\u0007;\\u02fa\\n;\\f;\\u000e;\\u02fd\\u000b;\",\n    \"\\u0003<\\u0003<\\u0003<\\u0007<\\u0302\\n<\\f<\\u000e<\\u0305\\u000b<\\u0003=\",\n    \"\\u0003=\\u0003=\\u0003=\\u0003=\\u0007=\\u030c\\n=\\f=\\u000e=\\u030f\\u000b=\",\n    \"\\u0003>\\u0003>\\u0003>\\u0003>\\u0003>\\u0007>\\u0316\\n>\\f>\\u000e>\\u0319\",\n    \"\\u000b>\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003?\\u0003\",\n    \"?\\u0003?\\u0003?\\u0007?\\u0326\\n?\\f?\\u000e?\\u0329\\u000b?\\u0003@\\u0003\",\n    \"@\\u0003@\\u0003@\\u0003@\\u0003@\\u0003@\\u0005@\\u0332\\n@\\u0003A\\u0003A\\u0007\",\n    \"A\\u0336\\nA\\fA\\u000eA\\u0339\\u000bA\\u0003A\\u0003A\\u0005A\\u033d\\nA\\u0003\",\n    \"B\\u0003B\\u0003B\\u0005B\\u0342\\nB\\u0003B\\u0003B\\u0003B\\u0005B\\u0347\\n\",\n    \"B\\u0003B\\u0003B\\u0003B\\u0005B\\u034c\\nB\\u0003B\\u0003B\\u0003B\\u0003B\\u0006\",\n    \"B\\u0352\\nB\\rB\\u000eB\\u0353\\u0003B\\u0003B\\u0003B\\u0003B\\u0005B\\u035a\",\n    \"\\nB\\u0003C\\u0003C\\u0003C\\u0003C\\u0007C\\u0360\\nC\\fC\\u000eC\\u0363\\u000b\",\n    \"C\\u0003C\\u0005C\\u0366\\nC\\u0005C\\u0368\\nC\\u0003D\\u0003D\\u0005D\\u036c\",\n    \"\\nD\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0003D\\u0005D\\u0375\\n\",\n    \"D\\u0003E\\u0003E\\u0003E\\u0007E\\u037a\\nE\\fE\\u000eE\\u037d\\u000bE\\u0003\",\n    \"E\\u0005E\\u0380\\nE\\u0003F\\u0003F\\u0005F\\u0384\\nF\\u0003F\\u0003F\\u0005\",\n    \"F\\u0388\\nF\\u0003F\\u0005F\\u038b\\nF\\u0005F\\u038d\\nF\\u0003G\\u0003G\\u0005\",\n    \"G\\u0391\\nG\\u0003H\\u0003H\\u0003H\\u0007H\\u0396\\nH\\fH\\u000eH\\u0399\\u000b\",\n    \"H\\u0003H\\u0005H\\u039c\\nH\\u0003I\\u0003I\\u0003I\\u0007I\\u03a1\\nI\\fI\\u000e\",\n    \"I\\u03a4\\u000bI\\u0003I\\u0005I\\u03a7\\nI\\u0003J\\u0003J\\u0003J\\u0003J\\u0003\",\n    \"J\\u0003J\\u0003J\\u0003J\\u0003J\\u0007J\\u03b2\\nJ\\fJ\\u000eJ\\u03b5\\u000b\",\n    \"J\\u0003J\\u0005J\\u03b8\\nJ\\u0005J\\u03ba\\nJ\\u0003J\\u0003J\\u0003J\\u0003\",\n    \"J\\u0007J\\u03c0\\nJ\\fJ\\u000eJ\\u03c3\\u000bJ\\u0003J\\u0005J\\u03c6\\nJ\\u0005\",\n    \"J\\u03c8\\nJ\\u0005J\\u03ca\\nJ\\u0003K\\u0003K\\u0003K\\u0003K\\u0005K\\u03d0\",\n    \"\\nK\\u0003K\\u0005K\\u03d3\\nK\\u0003K\\u0003K\\u0003K\\u0003L\\u0003L\\u0003\",\n    \"L\\u0007L\\u03db\\nL\\fL\\u000eL\\u03de\\u000bL\\u0003L\\u0003L\\u0005L\\u03e2\",\n    \"\\nL\\u0003L\\u0003L\\u0003L\\u0003L\\u0007L\\u03e8\\nL\\fL\\u000eL\\u03eb\\u000b\",\n    \"L\\u0003L\\u0003L\\u0003L\\u0005L\\u03f0\\nL\\u0003L\\u0003L\\u0005L\\u03f4\\n\",\n    \"L\\u0003M\\u0003M\\u0005M\\u03f8\\nM\\u0003M\\u0003M\\u0003M\\u0003M\\u0005M\\u03fe\",\n    \"\\nM\\u0003N\\u0003N\\u0005N\\u0402\\nN\\u0003O\\u0003O\\u0003O\\u0003O\\u0003\",\n    \"O\\u0005O\\u0409\\nO\\u0003P\\u0003P\\u0003P\\u0005P\\u040e\\nP\\u0003Q\\u0003\",\n    \"Q\\u0005Q\\u0412\\nQ\\u0003R\\u0003R\\u0003R\\u0005R\\u0417\\nR\\u0003S\\u0003\",\n    \"S\\u0003T\\u0003T\\u0003T\\u0005T\\u041e\\nT\\u0003U\\u0003U\\u0003U\\u0002\\u0002\",\n    \"V\\u0002\\u0004\\u0006\\b\\n\\f\\u000e\\u0010\\u0012\\u0014\\u0016\\u0018\\u001a\",\n    \"\\u001c\\u001e \\\"$&(*,.02468:<>@BDFHJLNPRTVXZ\\\\^`bdfhjlnprtvxz|~\\u0080\",\n    \"\\u0082\\u0084\\u0086\\u0088\\u008a\\u008c\\u008e\\u0090\\u0092\\u0094\\u0096\\u0098\",\n    \"\\u009a\\u009c\\u009e\\u00a0\\u00a2\\u00a4\\u00a6\\u00a8\\u0002\\u0006\\u0003\\u0002\",\n    \"P\\\\\\u0003\\u0002./\\u0003\\u0002&\\'\\u0003\\u0002(+\\u0002\\u0492\\u0002\\u00af\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0004\\u00b5\\u0003\\u0002\\u0002\\u0002\\u0006\\u00ba\",\n    \"\\u0003\\u0002\\u0002\\u0002\\b\\u00c3\\u0003\\u0002\\u0002\\u0002\\n\\u00cf\\u0003\",\n    \"\\u0002\\u0002\\u0002\\f\\u00d3\\u0003\\u0002\\u0002\\u0002\\u000e\\u00d8\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0010\\u00e2\\u0003\\u0002\\u0002\\u0002\\u0012\\u0129\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0014\\u012b\\u0003\\u0002\\u0002\\u0002\\u0016\\u0171\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0018\\u0173\\u0003\\u0002\\u0002\\u0002\\u001a\\u0177\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u001c\\u0179\\u0003\\u0002\\u0002\\u0002\\u001e\\u018e\\u0003\",\n    \"\\u0002\\u0002\\u0002 \\u0190\\u0003\\u0002\\u0002\\u0002\\\"\\u01a4\\u0003\\u0002\",\n    \"\\u0002\\u0002$\\u01b3\\u0003\\u0002\\u0002\\u0002&\\u01b5\\u0003\\u0002\\u0002\",\n    \"\\u0002(\\u01b8\\u0003\\u0002\\u0002\\u0002*\\u01bf\\u0003\\u0002\\u0002\\u0002\",\n    \",\\u01c1\\u0003\\u0002\\u0002\\u0002.\\u01c3\\u0003\\u0002\\u0002\\u00020\\u01c5\",\n    \"\\u0003\\u0002\\u0002\\u00022\\u01c9\\u0003\\u0002\\u0002\\u00024\\u01cb\\u0003\",\n    \"\\u0002\\u0002\\u00026\\u01d5\\u0003\\u0002\\u0002\\u00028\\u01d7\\u0003\\u0002\",\n    \"\\u0002\\u0002:\\u01da\\u0003\\u0002\\u0002\\u0002<\\u01f2\\u0003\\u0002\\u0002\",\n    \"\\u0002>\\u01f7\\u0003\\u0002\\u0002\\u0002@\\u01fc\\u0003\\u0002\\u0002\\u0002\",\n    \"B\\u0207\\u0003\\u0002\\u0002\\u0002D\\u020f\\u0003\\u0002\\u0002\\u0002F\\u0217\",\n    \"\\u0003\\u0002\\u0002\\u0002H\\u0220\\u0003\\u0002\\u0002\\u0002J\\u0229\\u0003\",\n    \"\\u0002\\u0002\\u0002L\\u0237\\u0003\\u0002\\u0002\\u0002N\\u0239\\u0003\\u0002\",\n    \"\\u0002\\u0002P\\u024c\\u0003\\u0002\\u0002\\u0002R\\u0255\\u0003\\u0002\\u0002\",\n    \"\\u0002T\\u0260\\u0003\\u0002\\u0002\\u0002V\\u027a\\u0003\\u0002\\u0002\\u0002\",\n    \"X\\u0286\\u0003\\u0002\\u0002\\u0002Z\\u028b\\u0003\\u0002\\u0002\\u0002\\\\\\u029d\",\n    \"\\u0003\\u0002\\u0002\\u0002^\\u02a8\\u0003\\u0002\\u0002\\u0002`\\u02ac\\u0003\",\n    \"\\u0002\\u0002\\u0002b\\u02ae\\u0003\\u0002\\u0002\\u0002d\\u02b5\\u0003\\u0002\",\n    \"\\u0002\\u0002f\\u02bc\\u0003\\u0002\\u0002\\u0002h\\u02c4\\u0003\\u0002\\u0002\",\n    \"\\u0002j\\u02cf\\u0003\\u0002\\u0002\\u0002l\\u02d1\\u0003\\u0002\\u0002\\u0002\",\n    \"n\\u02e7\\u0003\\u0002\\u0002\\u0002p\\u02ea\\u0003\\u0002\\u0002\\u0002r\\u02ee\",\n    \"\\u0003\\u0002\\u0002\\u0002t\\u02f6\\u0003\\u0002\\u0002\\u0002v\\u02fe\\u0003\",\n    \"\\u0002\\u0002\\u0002x\\u0306\\u0003\\u0002\\u0002\\u0002z\\u0310\\u0003\\u0002\",\n    \"\\u0002\\u0002|\\u031a\\u0003\\u0002\\u0002\\u0002~\\u0331\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0080\\u0333\\u0003\\u0002\\u0002\\u0002\\u0082\\u0359\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0084\\u035b\\u0003\\u0002\\u0002\\u0002\\u0086\\u0374\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0088\\u0376\\u0003\\u0002\\u0002\\u0002\\u008a\\u038c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u008c\\u038e\\u0003\\u0002\\u0002\\u0002\\u008e\\u0392\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0090\\u039d\\u0003\\u0002\\u0002\\u0002\\u0092\\u03c9\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0094\\u03cb\\u0003\\u0002\\u0002\\u0002\\u0096\\u03dc\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0098\\u03fd\\u0003\\u0002\\u0002\\u0002\\u009a\\u0401\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u009c\\u0403\\u0003\\u0002\\u0002\\u0002\\u009e\\u040a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00a0\\u040f\\u0003\\u0002\\u0002\\u0002\\u00a2\\u0416\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00a4\\u0418\\u0003\\u0002\\u0002\\u0002\\u00a6\\u041d\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00a8\\u041f\\u0003\\u0002\\u0002\\u0002\\u00aa\\u00b0\\u0007$\\u0002\",\n    \"\\u0002\\u00ab\\u00b0\\u0005\\u001c\\u000f\\u0002\\u00ac\\u00ad\\u0005L\\'\\u0002\",\n    \"\\u00ad\\u00ae\\u0007$\\u0002\\u0002\\u00ae\\u00b0\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00af\\u00aa\\u0003\\u0002\\u0002\\u0002\\u00af\\u00ab\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00af\\u00ac\\u0003\\u0002\\u0002\\u0002\\u00b0\\u0003\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00b1\\u00b4\\u0007$\\u0002\\u0002\\u00b2\\u00b4\\u0005\\u001a\\u000e\\u0002\",\n    \"\\u00b3\\u00b1\\u0003\\u0002\\u0002\\u0002\\u00b3\\u00b2\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00b4\\u00b7\\u0003\\u0002\\u0002\\u0002\\u00b5\\u00b3\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00b5\\u00b6\\u0003\\u0002\\u0002\\u0002\\u00b6\\u00b8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00b7\\u00b5\\u0003\\u0002\\u0002\\u0002\\u00b8\\u00b9\\u0007\\u0002\\u0002\\u0003\",\n    \"\\u00b9\\u0005\\u0003\\u0002\\u0002\\u0002\\u00ba\\u00be\\u0005\\u0090I\\u0002\",\n    \"\\u00bb\\u00bd\\u0007$\\u0002\\u0002\\u00bc\\u00bb\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00bd\\u00c0\\u0003\\u0002\\u0002\\u0002\\u00be\\u00bc\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00be\\u00bf\\u0003\\u0002\\u0002\\u0002\\u00bf\\u00c1\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u00c0\\u00be\\u0003\\u0002\\u0002\\u0002\\u00c1\\u00c2\\u0007\\u0002\\u0002\\u0003\",\n    \"\\u00c2\\u0007\\u0003\\u0002\\u0002\\u0002\\u00c3\\u00c4\\u0007N\\u0002\\u0002\",\n    \"\\u00c4\\u00ca\\u0005D#\\u0002\\u00c5\\u00c7\\u00071\\u0002\\u0002\\u00c6\\u00c8\",\n    \"\\u0005\\u0096L\\u0002\\u00c7\\u00c6\\u0003\\u0002\\u0002\\u0002\\u00c7\\u00c8\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u00c8\\u00c9\\u0003\\u0002\\u0002\\u0002\\u00c9\\u00cb\",\n    \"\\u00072\\u0002\\u0002\\u00ca\\u00c5\\u0003\\u0002\\u0002\\u0002\\u00ca\\u00cb\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u00cb\\u00cc\\u0003\\u0002\\u0002\\u0002\\u00cc\\u00cd\",\n    \"\\u0007$\\u0002\\u0002\\u00cd\\t\\u0003\\u0002\\u0002\\u0002\\u00ce\\u00d0\\u0005\",\n    \"\\b\\u0005\\u0002\\u00cf\\u00ce\\u0003\\u0002\\u0002\\u0002\\u00d0\\u00d1\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00d1\\u00cf\\u0003\\u0002\\u0002\\u0002\\u00d1\\u00d2\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00d2\\u000b\\u0003\\u0002\\u0002\\u0002\\u00d3\\u00d6\\u0005\",\n    \"\\n\\u0006\\u0002\\u00d4\\u00d7\\u0005\\u0094K\\u0002\\u00d5\\u00d7\\u0005\\u000e\",\n    \"\\b\\u0002\\u00d6\\u00d4\\u0003\\u0002\\u0002\\u0002\\u00d6\\u00d5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u00d7\\r\\u0003\\u0002\\u0002\\u0002\\u00d8\\u00d9\\u0007\\u0003\",\n    \"\\u0002\\u0002\\u00d9\\u00da\\u0007%\\u0002\\u0002\\u00da\\u00dd\\u0005\\u0010\",\n    \"\\t\\u0002\\u00db\\u00dc\\u0007O\\u0002\\u0002\\u00dc\\u00de\\u0005^0\\u0002\\u00dd\",\n    \"\\u00db\\u0003\\u0002\\u0002\\u0002\\u00dd\\u00de\\u0003\\u0002\\u0002\\u0002\\u00de\",\n    \"\\u00df\\u0003\\u0002\\u0002\\u0002\\u00df\\u00e0\\u00074\\u0002\\u0002\\u00e0\",\n    \"\\u00e1\\u0005\\\\/\\u0002\\u00e1\\u000f\\u0003\\u0002\\u0002\\u0002\\u00e2\\u00e4\",\n    \"\\u00071\\u0002\\u0002\\u00e3\\u00e5\\u0005\\u0012\\n\\u0002\\u00e4\\u00e3\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00e4\\u00e5\\u0003\\u0002\\u0002\\u0002\\u00e5\\u00e6\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00e6\\u00e7\\u00072\\u0002\\u0002\\u00e7\\u0011\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u00e8\\u00eb\\u0005\\u0014\\u000b\\u0002\\u00e9\\u00ea\\u0007\",\n    \"7\\u0002\\u0002\\u00ea\\u00ec\\u0005^0\\u0002\\u00eb\\u00e9\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00eb\\u00ec\\u0003\\u0002\\u0002\\u0002\\u00ec\\u00f5\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u00ed\\u00ee\\u00073\\u0002\\u0002\\u00ee\\u00f1\\u0005\\u0014\\u000b\",\n    \"\\u0002\\u00ef\\u00f0\\u00077\\u0002\\u0002\\u00f0\\u00f2\\u0005^0\\u0002\\u00f1\",\n    \"\\u00ef\\u0003\\u0002\\u0002\\u0002\\u00f1\\u00f2\\u0003\\u0002\\u0002\\u0002\\u00f2\",\n    \"\\u00f4\\u0003\\u0002\\u0002\\u0002\\u00f3\\u00ed\\u0003\\u0002\\u0002\\u0002\\u00f4\",\n    \"\\u00f7\\u0003\\u0002\\u0002\\u0002\\u00f5\\u00f3\\u0003\\u0002\\u0002\\u0002\\u00f5\",\n    \"\\u00f6\\u0003\\u0002\\u0002\\u0002\\u00f6\\u0111\\u0003\\u0002\\u0002\\u0002\\u00f7\",\n    \"\\u00f5\\u0003\\u0002\\u0002\\u0002\\u00f8\\u010f\\u00073\\u0002\\u0002\\u00f9\",\n    \"\\u00fb\\u00070\\u0002\\u0002\\u00fa\\u00fc\\u0005\\u0014\\u000b\\u0002\\u00fb\",\n    \"\\u00fa\\u0003\\u0002\\u0002\\u0002\\u00fb\\u00fc\\u0003\\u0002\\u0002\\u0002\\u00fc\",\n    \"\\u0105\\u0003\\u0002\\u0002\\u0002\\u00fd\\u00fe\\u00073\\u0002\\u0002\\u00fe\",\n    \"\\u0101\\u0005\\u0014\\u000b\\u0002\\u00ff\\u0100\\u00077\\u0002\\u0002\\u0100\",\n    \"\\u0102\\u0005^0\\u0002\\u0101\\u00ff\\u0003\\u0002\\u0002\\u0002\\u0101\\u0102\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0102\\u0104\\u0003\\u0002\\u0002\\u0002\\u0103\\u00fd\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0104\\u0107\\u0003\\u0002\\u0002\\u0002\\u0105\\u0103\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0105\\u0106\\u0003\\u0002\\u0002\\u0002\\u0106\\u010b\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0107\\u0105\\u0003\\u0002\\u0002\\u0002\\u0108\\u0109\",\n    \"\\u00073\\u0002\\u0002\\u0109\\u010a\\u00076\\u0002\\u0002\\u010a\\u010c\\u0005\",\n    \"\\u0014\\u000b\\u0002\\u010b\\u0108\\u0003\\u0002\\u0002\\u0002\\u010b\\u010c\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u010c\\u0110\\u0003\\u0002\\u0002\\u0002\\u010d\\u010e\\u0007\",\n    \"6\\u0002\\u0002\\u010e\\u0110\\u0005\\u0014\\u000b\\u0002\\u010f\\u00f9\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u010f\\u010d\\u0003\\u0002\\u0002\\u0002\\u010f\\u0110\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0110\\u0112\\u0003\\u0002\\u0002\\u0002\\u0111\\u00f8\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0111\\u0112\\u0003\\u0002\\u0002\\u0002\\u0112\\u012a\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0113\\u0115\\u00070\\u0002\\u0002\\u0114\\u0116\\u0005\",\n    \"\\u0014\\u000b\\u0002\\u0115\\u0114\\u0003\\u0002\\u0002\\u0002\\u0115\\u0116\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0116\\u011f\\u0003\\u0002\\u0002\\u0002\\u0117\\u0118\\u0007\",\n    \"3\\u0002\\u0002\\u0118\\u011b\\u0005\\u0014\\u000b\\u0002\\u0119\\u011a\\u0007\",\n    \"7\\u0002\\u0002\\u011a\\u011c\\u0005^0\\u0002\\u011b\\u0119\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u011b\\u011c\\u0003\\u0002\\u0002\\u0002\\u011c\\u011e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u011d\\u0117\\u0003\\u0002\\u0002\\u0002\\u011e\\u0121\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u011f\\u011d\\u0003\\u0002\\u0002\\u0002\\u011f\\u0120\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0120\\u0125\\u0003\\u0002\\u0002\\u0002\\u0121\\u011f\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0122\\u0123\\u00073\\u0002\\u0002\\u0123\\u0124\\u00076\\u0002\\u0002\",\n    \"\\u0124\\u0126\\u0005\\u0014\\u000b\\u0002\\u0125\\u0122\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0125\\u0126\\u0003\\u0002\\u0002\\u0002\\u0126\\u012a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0127\\u0128\\u00076\\u0002\\u0002\\u0128\\u012a\\u0005\\u0014\\u000b\\u0002\",\n    \"\\u0129\\u00e8\\u0003\\u0002\\u0002\\u0002\\u0129\\u0113\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0129\\u0127\\u0003\\u0002\\u0002\\u0002\\u012a\\u0013\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u012b\\u012e\\u0007%\\u0002\\u0002\\u012c\\u012d\\u00074\\u0002\\u0002\\u012d\",\n    \"\\u012f\\u0005^0\\u0002\\u012e\\u012c\\u0003\\u0002\\u0002\\u0002\\u012e\\u012f\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u012f\\u0015\\u0003\\u0002\\u0002\\u0002\\u0130\\u0133\",\n    \"\\u0005\\u0018\\r\\u0002\\u0131\\u0132\\u00077\\u0002\\u0002\\u0132\\u0134\\u0005\",\n    \"^0\\u0002\\u0133\\u0131\\u0003\\u0002\\u0002\\u0002\\u0133\\u0134\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0134\\u013d\\u0003\\u0002\\u0002\\u0002\\u0135\\u0136\\u00073\",\n    \"\\u0002\\u0002\\u0136\\u0139\\u0005\\u0018\\r\\u0002\\u0137\\u0138\\u00077\\u0002\",\n    \"\\u0002\\u0138\\u013a\\u0005^0\\u0002\\u0139\\u0137\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0139\\u013a\\u0003\\u0002\\u0002\\u0002\\u013a\\u013c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u013b\\u0135\\u0003\\u0002\\u0002\\u0002\\u013c\\u013f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u013d\\u013b\\u0003\\u0002\\u0002\\u0002\\u013d\\u013e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u013e\\u0159\\u0003\\u0002\\u0002\\u0002\\u013f\\u013d\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0140\\u0157\\u00073\\u0002\\u0002\\u0141\\u0143\\u00070\\u0002\\u0002\\u0142\",\n    \"\\u0144\\u0005\\u0018\\r\\u0002\\u0143\\u0142\\u0003\\u0002\\u0002\\u0002\\u0143\",\n    \"\\u0144\\u0003\\u0002\\u0002\\u0002\\u0144\\u014d\\u0003\\u0002\\u0002\\u0002\\u0145\",\n    \"\\u0146\\u00073\\u0002\\u0002\\u0146\\u0149\\u0005\\u0018\\r\\u0002\\u0147\\u0148\",\n    \"\\u00077\\u0002\\u0002\\u0148\\u014a\\u0005^0\\u0002\\u0149\\u0147\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0149\\u014a\\u0003\\u0002\\u0002\\u0002\\u014a\\u014c\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u014b\\u0145\\u0003\\u0002\\u0002\\u0002\\u014c\\u014f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u014d\\u014b\\u0003\\u0002\\u0002\\u0002\\u014d\\u014e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u014e\\u0153\\u0003\\u0002\\u0002\\u0002\\u014f\\u014d\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0150\\u0151\\u00073\\u0002\\u0002\\u0151\\u0152\\u00076\\u0002\",\n    \"\\u0002\\u0152\\u0154\\u0005\\u0018\\r\\u0002\\u0153\\u0150\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0153\\u0154\\u0003\\u0002\\u0002\\u0002\\u0154\\u0158\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0155\\u0156\\u00076\\u0002\\u0002\\u0156\\u0158\\u0005\\u0018\\r\\u0002\",\n    \"\\u0157\\u0141\\u0003\\u0002\\u0002\\u0002\\u0157\\u0155\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0157\\u0158\\u0003\\u0002\\u0002\\u0002\\u0158\\u015a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0159\\u0140\\u0003\\u0002\\u0002\\u0002\\u0159\\u015a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u015a\\u0172\\u0003\\u0002\\u0002\\u0002\\u015b\\u015d\\u00070\\u0002\\u0002\",\n    \"\\u015c\\u015e\\u0005\\u0018\\r\\u0002\\u015d\\u015c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u015d\\u015e\\u0003\\u0002\\u0002\\u0002\\u015e\\u0167\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u015f\\u0160\\u00073\\u0002\\u0002\\u0160\\u0163\\u0005\\u0018\\r\\u0002\\u0161\",\n    \"\\u0162\\u00077\\u0002\\u0002\\u0162\\u0164\\u0005^0\\u0002\\u0163\\u0161\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0163\\u0164\\u0003\\u0002\\u0002\\u0002\\u0164\\u0166\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0165\\u015f\\u0003\\u0002\\u0002\\u0002\\u0166\\u0169\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0167\\u0165\\u0003\\u0002\\u0002\\u0002\\u0167\\u0168\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0168\\u016d\\u0003\\u0002\\u0002\\u0002\\u0169\\u0167\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u016a\\u016b\\u00073\\u0002\\u0002\\u016b\\u016c\\u0007\",\n    \"6\\u0002\\u0002\\u016c\\u016e\\u0005\\u0018\\r\\u0002\\u016d\\u016a\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u016d\\u016e\\u0003\\u0002\\u0002\\u0002\\u016e\\u0172\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u016f\\u0170\\u00076\\u0002\\u0002\\u0170\\u0172\\u0005\\u0018\",\n    \"\\r\\u0002\\u0171\\u0130\\u0003\\u0002\\u0002\\u0002\\u0171\\u015b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0171\\u016f\\u0003\\u0002\\u0002\\u0002\\u0172\\u0017\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0173\\u0174\\u0007%\\u0002\\u0002\\u0174\\u0019\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0175\\u0178\\u0005\\u001c\\u000f\\u0002\\u0176\\u0178\\u0005L\",\n    \"\\'\\u0002\\u0177\\u0175\\u0003\\u0002\\u0002\\u0002\\u0177\\u0176\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0178\\u001b\\u0003\\u0002\\u0002\\u0002\\u0179\\u017e\\u0005\\u001e\",\n    \"\\u0010\\u0002\\u017a\\u017b\\u00075\\u0002\\u0002\\u017b\\u017d\\u0005\\u001e\",\n    \"\\u0010\\u0002\\u017c\\u017a\\u0003\\u0002\\u0002\\u0002\\u017d\\u0180\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u017e\\u017c\\u0003\\u0002\\u0002\\u0002\\u017e\\u017f\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u017f\\u0182\\u0003\\u0002\\u0002\\u0002\\u0180\\u017e\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0181\\u0183\\u00075\\u0002\\u0002\\u0182\\u0181\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0182\\u0183\\u0003\\u0002\\u0002\\u0002\\u0183\\u0184\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0184\\u0185\\u0007$\\u0002\\u0002\\u0185\\u001d\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0186\\u018f\\u0005 \\u0011\\u0002\\u0187\\u018f\\u0005&\\u0014\",\n    \"\\u0002\\u0188\\u018f\\u0005(\\u0015\\u0002\\u0189\\u018f\\u0005*\\u0016\\u0002\",\n    \"\\u018a\\u018f\\u00056\\u001c\\u0002\\u018b\\u018f\\u0005F$\\u0002\\u018c\\u018f\",\n    \"\\u0005H%\\u0002\\u018d\\u018f\\u0005J&\\u0002\\u018e\\u0186\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u018e\\u0187\\u0003\\u0002\\u0002\\u0002\\u018e\\u0188\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u018e\\u0189\\u0003\\u0002\\u0002\\u0002\\u018e\\u018a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u018e\\u018b\\u0003\\u0002\\u0002\\u0002\\u018e\\u018c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u018e\\u018d\\u0003\\u0002\\u0002\\u0002\\u018f\\u001f\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0190\\u01a0\\u0005\\\"\\u0012\\u0002\\u0191\\u0194\\u0005$\\u0013\\u0002\",\n    \"\\u0192\\u0195\\u0005\\u00a0Q\\u0002\\u0193\\u0195\\u0005\\u0090I\\u0002\\u0194\",\n    \"\\u0192\\u0003\\u0002\\u0002\\u0002\\u0194\\u0193\\u0003\\u0002\\u0002\\u0002\\u0195\",\n    \"\\u01a1\\u0003\\u0002\\u0002\\u0002\\u0196\\u0199\\u00077\\u0002\\u0002\\u0197\",\n    \"\\u019a\\u0005\\u00a0Q\\u0002\\u0198\\u019a\\u0005\\\"\\u0012\\u0002\\u0199\\u0197\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0199\\u0198\\u0003\\u0002\\u0002\\u0002\\u019a\\u019c\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u019b\\u0196\\u0003\\u0002\\u0002\\u0002\\u019c\\u019f\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u019d\\u019b\\u0003\\u0002\\u0002\\u0002\\u019d\\u019e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u019e\\u01a1\\u0003\\u0002\\u0002\\u0002\\u019f\\u019d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01a0\\u0191\\u0003\\u0002\\u0002\\u0002\\u01a0\\u019d\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01a1!\\u0003\\u0002\\u0002\\u0002\\u01a2\\u01a5\",\n    \"\\u0005^0\\u0002\\u01a3\\u01a5\\u0005p9\\u0002\\u01a4\\u01a2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01a4\\u01a3\\u0003\\u0002\\u0002\\u0002\\u01a5\\u01ad\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01a6\\u01a9\\u00073\\u0002\\u0002\\u01a7\\u01aa\\u0005^0\\u0002\\u01a8\",\n    \"\\u01aa\\u0005p9\\u0002\\u01a9\\u01a7\\u0003\\u0002\\u0002\\u0002\\u01a9\\u01a8\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01aa\\u01ac\\u0003\\u0002\\u0002\\u0002\\u01ab\\u01a6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01ac\\u01af\\u0003\\u0002\\u0002\\u0002\\u01ad\\u01ab\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01ad\\u01ae\\u0003\\u0002\\u0002\\u0002\\u01ae\\u01b1\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01af\\u01ad\\u0003\\u0002\\u0002\\u0002\\u01b0\\u01b2\",\n    \"\\u00073\\u0002\\u0002\\u01b1\\u01b0\\u0003\\u0002\\u0002\\u0002\\u01b1\\u01b2\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01b2#\\u0003\\u0002\\u0002\\u0002\\u01b3\\u01b4\",\n    \"\\t\\u0002\\u0002\\u0002\\u01b4%\\u0003\\u0002\\u0002\\u0002\\u01b5\\u01b6\\u0007\",\n    \" \\u0002\\u0002\\u01b6\\u01b7\\u0005\\u008eH\\u0002\\u01b7\\'\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u01b8\\u01b9\\u0007!\\u0002\\u0002\\u01b9)\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01ba\\u01c0\\u0005,\\u0017\\u0002\\u01bb\\u01c0\\u0005.\\u0018\\u0002\\u01bc\",\n    \"\\u01c0\\u00050\\u0019\\u0002\\u01bd\\u01c0\\u00054\\u001b\\u0002\\u01be\\u01c0\",\n    \"\\u00052\\u001a\\u0002\\u01bf\\u01ba\\u0003\\u0002\\u0002\\u0002\\u01bf\\u01bb\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01bf\\u01bc\\u0003\\u0002\\u0002\\u0002\\u01bf\\u01bd\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01bf\\u01be\\u0003\\u0002\\u0002\\u0002\\u01c0+\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01c1\\u01c2\\u0007#\\u0002\\u0002\\u01c2-\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01c3\\u01c4\\u0007\\\"\\u0002\\u0002\\u01c4/\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01c5\\u01c7\\u0007\\u0004\\u0002\\u0002\\u01c6\\u01c8\\u0005\\u0090\",\n    \"I\\u0002\\u01c7\\u01c6\\u0003\\u0002\\u0002\\u0002\\u01c7\\u01c8\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01c81\\u0003\\u0002\\u0002\\u0002\\u01c9\\u01ca\\u0005\\u00a0\",\n    \"Q\\u0002\\u01ca3\\u0003\\u0002\\u0002\\u0002\\u01cb\\u01d1\\u0007\\u0005\\u0002\",\n    \"\\u0002\\u01cc\\u01cf\\u0005^0\\u0002\\u01cd\\u01ce\\u0007\\u0006\\u0002\\u0002\",\n    \"\\u01ce\\u01d0\\u0005^0\\u0002\\u01cf\\u01cd\\u0003\\u0002\\u0002\\u0002\\u01cf\",\n    \"\\u01d0\\u0003\\u0002\\u0002\\u0002\\u01d0\\u01d2\\u0003\\u0002\\u0002\\u0002\\u01d1\",\n    \"\\u01cc\\u0003\\u0002\\u0002\\u0002\\u01d1\\u01d2\\u0003\\u0002\\u0002\\u0002\\u01d2\",\n    \"5\\u0003\\u0002\\u0002\\u0002\\u01d3\\u01d6\\u00058\\u001d\\u0002\\u01d4\\u01d6\",\n    \"\\u0005:\\u001e\\u0002\\u01d5\\u01d3\\u0003\\u0002\\u0002\\u0002\\u01d5\\u01d4\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u01d67\\u0003\\u0002\\u0002\\u0002\\u01d7\\u01d8\",\n    \"\\u0007\\u0007\\u0002\\u0002\\u01d8\\u01d9\\u0005B\\\"\\u0002\\u01d99\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01da\\u01e7\\u0007\\u0006\\u0002\\u0002\\u01db\\u01dd\\t\\u0003\",\n    \"\\u0002\\u0002\\u01dc\\u01db\\u0003\\u0002\\u0002\\u0002\\u01dd\\u01e0\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01de\\u01dc\\u0003\\u0002\\u0002\\u0002\\u01de\\u01df\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01df\\u01e1\\u0003\\u0002\\u0002\\u0002\\u01e0\\u01de\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01e1\\u01e8\\u0005D#\\u0002\\u01e2\\u01e4\\t\\u0003\\u0002\\u0002\",\n    \"\\u01e3\\u01e2\\u0003\\u0002\\u0002\\u0002\\u01e4\\u01e5\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01e5\\u01e3\\u0003\\u0002\\u0002\\u0002\\u01e5\\u01e6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01e6\\u01e8\\u0003\\u0002\\u0002\\u0002\\u01e7\\u01de\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01e7\\u01e3\\u0003\\u0002\\u0002\\u0002\\u01e8\\u01e9\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01e9\\u01f0\\u0007\\u0007\\u0002\\u0002\\u01ea\\u01f1\\u00070\\u0002\\u0002\",\n    \"\\u01eb\\u01ec\\u00071\\u0002\\u0002\\u01ec\\u01ed\\u0005@!\\u0002\\u01ed\\u01ee\",\n    \"\\u00072\\u0002\\u0002\\u01ee\\u01f1\\u0003\\u0002\\u0002\\u0002\\u01ef\\u01f1\",\n    \"\\u0005@!\\u0002\\u01f0\\u01ea\\u0003\\u0002\\u0002\\u0002\\u01f0\\u01eb\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01f0\\u01ef\\u0003\\u0002\\u0002\\u0002\\u01f1;\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u01f2\\u01f5\\u0007%\\u0002\\u0002\\u01f3\\u01f4\\u0007\",\n    \"\\b\\u0002\\u0002\\u01f4\\u01f6\\u0007%\\u0002\\u0002\\u01f5\\u01f3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01f5\\u01f6\\u0003\\u0002\\u0002\\u0002\\u01f6=\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u01f7\\u01fa\\u0005D#\\u0002\\u01f8\\u01f9\\u0007\\b\\u0002\\u0002\",\n    \"\\u01f9\\u01fb\\u0007%\\u0002\\u0002\\u01fa\\u01f8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01fa\\u01fb\\u0003\\u0002\\u0002\\u0002\\u01fb?\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u01fc\\u0201\\u0005<\\u001f\\u0002\\u01fd\\u01fe\\u00073\\u0002\\u0002\\u01fe\",\n    \"\\u0200\\u0005<\\u001f\\u0002\\u01ff\\u01fd\\u0003\\u0002\\u0002\\u0002\\u0200\",\n    \"\\u0203\\u0003\\u0002\\u0002\\u0002\\u0201\\u01ff\\u0003\\u0002\\u0002\\u0002\\u0201\",\n    \"\\u0202\\u0003\\u0002\\u0002\\u0002\\u0202\\u0205\\u0003\\u0002\\u0002\\u0002\\u0203\",\n    \"\\u0201\\u0003\\u0002\\u0002\\u0002\\u0204\\u0206\\u00073\\u0002\\u0002\\u0205\",\n    \"\\u0204\\u0003\\u0002\\u0002\\u0002\\u0205\\u0206\\u0003\\u0002\\u0002\\u0002\\u0206\",\n    \"A\\u0003\\u0002\\u0002\\u0002\\u0207\\u020c\\u0005> \\u0002\\u0208\\u0209\\u0007\",\n    \"3\\u0002\\u0002\\u0209\\u020b\\u0005> \\u0002\\u020a\\u0208\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u020b\\u020e\\u0003\\u0002\\u0002\\u0002\\u020c\\u020a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u020c\\u020d\\u0003\\u0002\\u0002\\u0002\\u020dC\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u020e\\u020c\\u0003\\u0002\\u0002\\u0002\\u020f\\u0214\\u0007%\\u0002\",\n    \"\\u0002\\u0210\\u0211\\u0007.\\u0002\\u0002\\u0211\\u0213\\u0007%\\u0002\\u0002\",\n    \"\\u0212\\u0210\\u0003\\u0002\\u0002\\u0002\\u0213\\u0216\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0214\\u0212\\u0003\\u0002\\u0002\\u0002\\u0214\\u0215\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0215E\\u0003\\u0002\\u0002\\u0002\\u0216\\u0214\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0217\\u0218\\u0007\\t\\u0002\\u0002\\u0218\\u021d\\u0007%\\u0002\\u0002\\u0219\",\n    \"\\u021a\\u00073\\u0002\\u0002\\u021a\\u021c\\u0007%\\u0002\\u0002\\u021b\\u0219\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u021c\\u021f\\u0003\\u0002\\u0002\\u0002\\u021d\\u021b\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u021d\\u021e\\u0003\\u0002\\u0002\\u0002\\u021eG\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u021f\\u021d\\u0003\\u0002\\u0002\\u0002\\u0220\\u0221\",\n    \"\\u0007\\n\\u0002\\u0002\\u0221\\u0226\\u0007%\\u0002\\u0002\\u0222\\u0223\\u0007\",\n    \"3\\u0002\\u0002\\u0223\\u0225\\u0007%\\u0002\\u0002\\u0224\\u0222\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0225\\u0228\\u0003\\u0002\\u0002\\u0002\\u0226\\u0224\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0226\\u0227\\u0003\\u0002\\u0002\\u0002\\u0227I\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0228\\u0226\\u0003\\u0002\\u0002\\u0002\\u0229\\u022a\\u0007\\u000b\",\n    \"\\u0002\\u0002\\u022a\\u022d\\u0005^0\\u0002\\u022b\\u022c\\u00073\\u0002\\u0002\",\n    \"\\u022c\\u022e\\u0005^0\\u0002\\u022d\\u022b\\u0003\\u0002\\u0002\\u0002\\u022d\",\n    \"\\u022e\\u0003\\u0002\\u0002\\u0002\\u022eK\\u0003\\u0002\\u0002\\u0002\\u022f\",\n    \"\\u0238\\u0005N(\\u0002\\u0230\\u0238\\u0005P)\\u0002\\u0231\\u0238\\u0005R*\\u0002\",\n    \"\\u0232\\u0238\\u0005T+\\u0002\\u0233\\u0238\\u0005V,\\u0002\\u0234\\u0238\\u0005\",\n    \"\\u000e\\b\\u0002\\u0235\\u0238\\u0005\\u0094K\\u0002\\u0236\\u0238\\u0005\\f\\u0007\",\n    \"\\u0002\\u0237\\u022f\\u0003\\u0002\\u0002\\u0002\\u0237\\u0230\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0237\\u0231\\u0003\\u0002\\u0002\\u0002\\u0237\\u0232\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0237\\u0233\\u0003\\u0002\\u0002\\u0002\\u0237\\u0234\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0237\\u0235\\u0003\\u0002\\u0002\\u0002\\u0237\\u0236\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0238M\\u0003\\u0002\\u0002\\u0002\\u0239\\u023a\\u0007\\f\\u0002\\u0002\",\n    \"\\u023a\\u023b\\u0005^0\\u0002\\u023b\\u023c\\u00074\\u0002\\u0002\\u023c\\u0244\",\n    \"\\u0005\\\\/\\u0002\\u023d\\u023e\\u0007\\r\\u0002\\u0002\\u023e\\u023f\\u0005^0\",\n    \"\\u0002\\u023f\\u0240\\u00074\\u0002\\u0002\\u0240\\u0241\\u0005\\\\/\\u0002\\u0241\",\n    \"\\u0243\\u0003\\u0002\\u0002\\u0002\\u0242\\u023d\\u0003\\u0002\\u0002\\u0002\\u0243\",\n    \"\\u0246\\u0003\\u0002\\u0002\\u0002\\u0244\\u0242\\u0003\\u0002\\u0002\\u0002\\u0244\",\n    \"\\u0245\\u0003\\u0002\\u0002\\u0002\\u0245\\u024a\\u0003\\u0002\\u0002\\u0002\\u0246\",\n    \"\\u0244\\u0003\\u0002\\u0002\\u0002\\u0247\\u0248\\u0007\\u000e\\u0002\\u0002\\u0248\",\n    \"\\u0249\\u00074\\u0002\\u0002\\u0249\\u024b\\u0005\\\\/\\u0002\\u024a\\u0247\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u024a\\u024b\\u0003\\u0002\\u0002\\u0002\\u024bO\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u024c\\u024d\\u0007\\u000f\\u0002\\u0002\\u024d\\u024e\\u0005\",\n    \"^0\\u0002\\u024e\\u024f\\u00074\\u0002\\u0002\\u024f\\u0253\\u0005\\\\/\\u0002\\u0250\",\n    \"\\u0251\\u0007\\u000e\\u0002\\u0002\\u0251\\u0252\\u00074\\u0002\\u0002\\u0252\",\n    \"\\u0254\\u0005\\\\/\\u0002\\u0253\\u0250\\u0003\\u0002\\u0002\\u0002\\u0253\\u0254\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0254Q\\u0003\\u0002\\u0002\\u0002\\u0255\\u0256\",\n    \"\\u0007\\u0010\\u0002\\u0002\\u0256\\u0257\\u0005\\u008eH\\u0002\\u0257\\u0258\",\n    \"\\u0007\\u0011\\u0002\\u0002\\u0258\\u0259\\u0005\\u0090I\\u0002\\u0259\\u025a\",\n    \"\\u00074\\u0002\\u0002\\u025a\\u025e\\u0005\\\\/\\u0002\\u025b\\u025c\\u0007\\u000e\",\n    \"\\u0002\\u0002\\u025c\\u025d\\u00074\\u0002\\u0002\\u025d\\u025f\\u0005\\\\/\\u0002\",\n    \"\\u025e\\u025b\\u0003\\u0002\\u0002\\u0002\\u025e\\u025f\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u025fS\\u0003\\u0002\\u0002\\u0002\\u0260\\u0261\\u0007\\u0012\\u0002\\u0002\",\n    \"\\u0261\\u0262\\u00074\\u0002\\u0002\\u0262\\u0278\\u0005\\\\/\\u0002\\u0263\\u0264\",\n    \"\\u0005Z.\\u0002\\u0264\\u0265\\u00074\\u0002\\u0002\\u0265\\u0266\\u0005\\\\/\\u0002\",\n    \"\\u0266\\u0268\\u0003\\u0002\\u0002\\u0002\\u0267\\u0263\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0268\\u0269\\u0003\\u0002\\u0002\\u0002\\u0269\\u0267\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0269\\u026a\\u0003\\u0002\\u0002\\u0002\\u026a\\u026e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u026b\\u026c\\u0007\\u000e\\u0002\\u0002\\u026c\\u026d\\u00074\\u0002\\u0002\",\n    \"\\u026d\\u026f\\u0005\\\\/\\u0002\\u026e\\u026b\\u0003\\u0002\\u0002\\u0002\\u026e\",\n    \"\\u026f\\u0003\\u0002\\u0002\\u0002\\u026f\\u0273\\u0003\\u0002\\u0002\\u0002\\u0270\",\n    \"\\u0271\\u0007\\u0013\\u0002\\u0002\\u0271\\u0272\\u00074\\u0002\\u0002\\u0272\",\n    \"\\u0274\\u0005\\\\/\\u0002\\u0273\\u0270\\u0003\\u0002\\u0002\\u0002\\u0273\\u0274\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0274\\u0279\\u0003\\u0002\\u0002\\u0002\\u0275\\u0276\",\n    \"\\u0007\\u0013\\u0002\\u0002\\u0276\\u0277\\u00074\\u0002\\u0002\\u0277\\u0279\",\n    \"\\u0005\\\\/\\u0002\\u0278\\u0267\\u0003\\u0002\\u0002\\u0002\\u0278\\u0275\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0279U\\u0003\\u0002\\u0002\\u0002\\u027a\\u027b\\u0007\",\n    \"\\u0014\\u0002\\u0002\\u027b\\u0280\\u0005X-\\u0002\\u027c\\u027d\\u00073\\u0002\",\n    \"\\u0002\\u027d\\u027f\\u0005X-\\u0002\\u027e\\u027c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u027f\\u0282\\u0003\\u0002\\u0002\\u0002\\u0280\\u027e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0280\\u0281\\u0003\\u0002\\u0002\\u0002\\u0281\\u0283\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0282\\u0280\\u0003\\u0002\\u0002\\u0002\\u0283\\u0284\\u00074\\u0002\\u0002\",\n    \"\\u0284\\u0285\\u0005\\\\/\\u0002\\u0285W\\u0003\\u0002\\u0002\\u0002\\u0286\\u0289\",\n    \"\\u0005^0\\u0002\\u0287\\u0288\\u0007\\b\\u0002\\u0002\\u0288\\u028a\\u0005r:\\u0002\",\n    \"\\u0289\\u0287\\u0003\\u0002\\u0002\\u0002\\u0289\\u028a\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u028aY\\u0003\\u0002\\u0002\\u0002\\u028b\\u0291\\u0007\\u0015\\u0002\\u0002\",\n    \"\\u028c\\u028f\\u0005^0\\u0002\\u028d\\u028e\\u0007\\b\\u0002\\u0002\\u028e\\u0290\",\n    \"\\u0007%\\u0002\\u0002\\u028f\\u028d\\u0003\\u0002\\u0002\\u0002\\u028f\\u0290\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0290\\u0292\\u0003\\u0002\\u0002\\u0002\\u0291\\u028c\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0291\\u0292\\u0003\\u0002\\u0002\\u0002\\u0292[\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0293\\u029e\\u0005\\u001c\\u000f\\u0002\\u0294\\u0295\",\n    \"\\u0007$\\u0002\\u0002\\u0295\\u0297\\u0007_\\u0002\\u0002\\u0296\\u0298\\u0005\",\n    \"\\u001a\\u000e\\u0002\\u0297\\u0296\\u0003\\u0002\\u0002\\u0002\\u0298\\u0299\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0299\\u0297\\u0003\\u0002\\u0002\\u0002\\u0299\\u029a\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u029a\\u029b\\u0003\\u0002\\u0002\\u0002\\u029b\\u029c\\u0007\",\n    \"`\\u0002\\u0002\\u029c\\u029e\\u0003\\u0002\\u0002\\u0002\\u029d\\u0293\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u029d\\u0294\\u0003\\u0002\\u0002\\u0002\\u029e]\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u029f\\u02a5\\u0005f4\\u0002\\u02a0\\u02a1\\u0007\\f\\u0002\",\n    \"\\u0002\\u02a1\\u02a2\\u0005f4\\u0002\\u02a2\\u02a3\\u0007\\u000e\\u0002\\u0002\",\n    \"\\u02a3\\u02a4\\u0005^0\\u0002\\u02a4\\u02a6\\u0003\\u0002\\u0002\\u0002\\u02a5\",\n    \"\\u02a0\\u0003\\u0002\\u0002\\u0002\\u02a5\\u02a6\\u0003\\u0002\\u0002\\u0002\\u02a6\",\n    \"\\u02a9\\u0003\\u0002\\u0002\\u0002\\u02a7\\u02a9\\u0005b2\\u0002\\u02a8\\u029f\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02a8\\u02a7\\u0003\\u0002\\u0002\\u0002\\u02a9_\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02aa\\u02ad\\u0005f4\\u0002\\u02ab\\u02ad\\u0005\",\n    \"d3\\u0002\\u02ac\\u02aa\\u0003\\u0002\\u0002\\u0002\\u02ac\\u02ab\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02ada\\u0003\\u0002\\u0002\\u0002\\u02ae\\u02b0\\u0007\\u0016\",\n    \"\\u0002\\u0002\\u02af\\u02b1\\u0005\\u0016\\f\\u0002\\u02b0\\u02af\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02b0\\u02b1\\u0003\\u0002\\u0002\\u0002\\u02b1\\u02b2\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u02b2\\u02b3\\u00074\\u0002\\u0002\\u02b3\\u02b4\\u0005^0\\u0002\",\n    \"\\u02b4c\\u0003\\u0002\\u0002\\u0002\\u02b5\\u02b7\\u0007\\u0016\\u0002\\u0002\",\n    \"\\u02b6\\u02b8\\u0005\\u0016\\f\\u0002\\u02b7\\u02b6\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b7\\u02b8\\u0003\\u0002\\u0002\\u0002\\u02b8\\u02b9\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02b9\\u02ba\\u00074\\u0002\\u0002\\u02ba\\u02bb\\u0005`1\\u0002\\u02bbe\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02bc\\u02c1\\u0005h5\\u0002\\u02bd\\u02be\\u0007\\u0017\",\n    \"\\u0002\\u0002\\u02be\\u02c0\\u0005h5\\u0002\\u02bf\\u02bd\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02c0\\u02c3\\u0003\\u0002\\u0002\\u0002\\u02c1\\u02bf\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02c1\\u02c2\\u0003\\u0002\\u0002\\u0002\\u02c2g\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02c3\\u02c1\\u0003\\u0002\\u0002\\u0002\\u02c4\\u02c9\\u0005j6\\u0002\",\n    \"\\u02c5\\u02c6\\u0007\\u0018\\u0002\\u0002\\u02c6\\u02c8\\u0005j6\\u0002\\u02c7\",\n    \"\\u02c5\\u0003\\u0002\\u0002\\u0002\\u02c8\\u02cb\\u0003\\u0002\\u0002\\u0002\\u02c9\",\n    \"\\u02c7\\u0003\\u0002\\u0002\\u0002\\u02c9\\u02ca\\u0003\\u0002\\u0002\\u0002\\u02ca\",\n    \"i\\u0003\\u0002\\u0002\\u0002\\u02cb\\u02c9\\u0003\\u0002\\u0002\\u0002\\u02cc\",\n    \"\\u02cd\\u0007\\u0019\\u0002\\u0002\\u02cd\\u02d0\\u0005j6\\u0002\\u02ce\\u02d0\",\n    \"\\u0005l7\\u0002\\u02cf\\u02cc\\u0003\\u0002\\u0002\\u0002\\u02cf\\u02ce\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u02d0k\\u0003\\u0002\\u0002\\u0002\\u02d1\\u02d7\\u0005\",\n    \"p9\\u0002\\u02d2\\u02d3\\u0005n8\\u0002\\u02d3\\u02d4\\u0005p9\\u0002\\u02d4\\u02d6\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02d5\\u02d2\\u0003\\u0002\\u0002\\u0002\\u02d6\\u02d9\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02d7\\u02d5\\u0003\\u0002\\u0002\\u0002\\u02d7\\u02d8\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02d8m\\u0003\\u0002\\u0002\\u0002\\u02d9\\u02d7\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02da\\u02e8\\u0007G\\u0002\\u0002\\u02db\\u02e8\",\n    \"\\u0007H\\u0002\\u0002\\u02dc\\u02e8\\u0007I\\u0002\\u0002\\u02dd\\u02e8\\u0007\",\n    \"J\\u0002\\u0002\\u02de\\u02e8\\u0007K\\u0002\\u0002\\u02df\\u02e8\\u0007L\\u0002\",\n    \"\\u0002\\u02e0\\u02e8\\u0007M\\u0002\\u0002\\u02e1\\u02e8\\u0007\\u0011\\u0002\",\n    \"\\u0002\\u02e2\\u02e3\\u0007\\u0019\\u0002\\u0002\\u02e3\\u02e8\\u0007\\u0011\\u0002\",\n    \"\\u0002\\u02e4\\u02e8\\u0007\\u001a\\u0002\\u0002\\u02e5\\u02e6\\u0007\\u001a\\u0002\",\n    \"\\u0002\\u02e6\\u02e8\\u0007\\u0019\\u0002\\u0002\\u02e7\\u02da\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e7\\u02db\\u0003\\u0002\\u0002\\u0002\\u02e7\\u02dc\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e7\\u02dd\\u0003\\u0002\\u0002\\u0002\\u02e7\\u02de\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e7\\u02df\\u0003\\u0002\\u0002\\u0002\\u02e7\\u02e0\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e7\\u02e1\\u0003\\u0002\\u0002\\u0002\\u02e7\\u02e2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e7\\u02e4\\u0003\\u0002\\u0002\\u0002\\u02e7\\u02e5\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02e8o\\u0003\\u0002\\u0002\\u0002\\u02e9\\u02eb\\u00070\\u0002\\u0002\",\n    \"\\u02ea\\u02e9\\u0003\\u0002\\u0002\\u0002\\u02ea\\u02eb\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u02eb\\u02ec\\u0003\\u0002\\u0002\\u0002\\u02ec\\u02ed\\u0005r:\\u0002\\u02ed\",\n    \"q\\u0003\\u0002\\u0002\\u0002\\u02ee\\u02f3\\u0005t;\\u0002\\u02ef\\u02f0\\u0007\",\n    \":\\u0002\\u0002\\u02f0\\u02f2\\u0005t;\\u0002\\u02f1\\u02ef\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02f2\\u02f5\\u0003\\u0002\\u0002\\u0002\\u02f3\\u02f1\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02f3\\u02f4\\u0003\\u0002\\u0002\\u0002\\u02f4s\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u02f5\\u02f3\\u0003\\u0002\\u0002\\u0002\\u02f6\\u02fb\\u0005v<\\u0002\",\n    \"\\u02f7\\u02f8\\u0007;\\u0002\\u0002\\u02f8\\u02fa\\u0005v<\\u0002\\u02f9\\u02f7\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02fa\\u02fd\\u0003\\u0002\\u0002\\u0002\\u02fb\\u02f9\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02fb\\u02fc\\u0003\\u0002\\u0002\\u0002\\u02fcu\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u02fd\\u02fb\\u0003\\u0002\\u0002\\u0002\\u02fe\\u0303\",\n    \"\\u0005x=\\u0002\\u02ff\\u0300\\u0007<\\u0002\\u0002\\u0300\\u0302\\u0005x=\\u0002\",\n    \"\\u0301\\u02ff\\u0003\\u0002\\u0002\\u0002\\u0302\\u0305\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0303\\u0301\\u0003\\u0002\\u0002\\u0002\\u0303\\u0304\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0304w\\u0003\\u0002\\u0002\\u0002\\u0305\\u0303\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0306\\u030d\\u0005z>\\u0002\\u0307\\u0308\\u0007=\\u0002\\u0002\\u0308\\u030c\",\n    \"\\u0005z>\\u0002\\u0309\\u030a\\u0007>\\u0002\\u0002\\u030a\\u030c\\u0005z>\\u0002\",\n    \"\\u030b\\u0307\\u0003\\u0002\\u0002\\u0002\\u030b\\u0309\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u030c\\u030f\\u0003\\u0002\\u0002\\u0002\\u030d\\u030b\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u030d\\u030e\\u0003\\u0002\\u0002\\u0002\\u030ey\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u030f\\u030d\\u0003\\u0002\\u0002\\u0002\\u0310\\u0317\\u0005|?\\u0002\\u0311\",\n    \"\\u0312\\u0007?\\u0002\\u0002\\u0312\\u0316\\u0005|?\\u0002\\u0313\\u0314\\u0007\",\n    \"@\\u0002\\u0002\\u0314\\u0316\\u0005|?\\u0002\\u0315\\u0311\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0315\\u0313\\u0003\\u0002\\u0002\\u0002\\u0316\\u0319\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0317\\u0315\\u0003\\u0002\\u0002\\u0002\\u0317\\u0318\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0318{\\u0003\\u0002\\u0002\\u0002\\u0319\\u0317\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u031a\\u0327\\u0005~@\\u0002\\u031b\\u031c\\u00070\\u0002\\u0002\\u031c\",\n    \"\\u0326\\u0005~@\\u0002\\u031d\\u031e\\u0007A\\u0002\\u0002\\u031e\\u0326\\u0005\",\n    \"~@\\u0002\\u031f\\u0320\\u0007B\\u0002\\u0002\\u0320\\u0326\\u0005~@\\u0002\\u0321\",\n    \"\\u0322\\u0007C\\u0002\\u0002\\u0322\\u0326\\u0005~@\\u0002\\u0323\\u0324\\u0007\",\n    \"N\\u0002\\u0002\\u0324\\u0326\\u0005~@\\u0002\\u0325\\u031b\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0325\\u031d\\u0003\\u0002\\u0002\\u0002\\u0325\\u031f\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0325\\u0321\\u0003\\u0002\\u0002\\u0002\\u0325\\u0323\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0326\\u0329\\u0003\\u0002\\u0002\\u0002\\u0327\\u0325\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0327\\u0328\\u0003\\u0002\\u0002\\u0002\\u0328}\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0329\\u0327\\u0003\\u0002\\u0002\\u0002\\u032a\\u032b\\u0007?\\u0002\",\n    \"\\u0002\\u032b\\u0332\\u0005~@\\u0002\\u032c\\u032d\\u0007@\\u0002\\u0002\\u032d\",\n    \"\\u0332\\u0005~@\\u0002\\u032e\\u032f\\u0007D\\u0002\\u0002\\u032f\\u0332\\u0005\",\n    \"~@\\u0002\\u0330\\u0332\\u0005\\u0080A\\u0002\\u0331\\u032a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0331\\u032c\\u0003\\u0002\\u0002\\u0002\\u0331\\u032e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0331\\u0330\\u0003\\u0002\\u0002\\u0002\\u0332\\u007f\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0333\\u0337\\u0005\\u0082B\\u0002\\u0334\\u0336\\u0005\\u0086D\\u0002\",\n    \"\\u0335\\u0334\\u0003\\u0002\\u0002\\u0002\\u0336\\u0339\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0337\\u0335\\u0003\\u0002\\u0002\\u0002\\u0337\\u0338\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0338\\u033c\\u0003\\u0002\\u0002\\u0002\\u0339\\u0337\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u033a\\u033b\\u00076\\u0002\\u0002\\u033b\\u033d\\u0005~@\\u0002\\u033c\\u033a\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033c\\u033d\\u0003\\u0002\\u0002\\u0002\\u033d\\u0081\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u033e\\u0341\\u00071\\u0002\\u0002\\u033f\\u0342\",\n    \"\\u0005\\u00a0Q\\u0002\\u0340\\u0342\\u0005\\u0084C\\u0002\\u0341\\u033f\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0341\\u0340\\u0003\\u0002\\u0002\\u0002\\u0341\\u0342\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0342\\u0343\\u0003\\u0002\\u0002\\u0002\\u0343\\u035a\\u0007\",\n    \"2\\u0002\\u0002\\u0344\\u0346\\u00078\\u0002\\u0002\\u0345\\u0347\\u0005\\u0084\",\n    \"C\\u0002\\u0346\\u0345\\u0003\\u0002\\u0002\\u0002\\u0346\\u0347\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0347\\u0348\\u0003\\u0002\\u0002\\u0002\\u0348\\u035a\\u00079\",\n    \"\\u0002\\u0002\\u0349\\u034b\\u0007E\\u0002\\u0002\\u034a\\u034c\\u0005\\u0092\",\n    \"J\\u0002\\u034b\\u034a\\u0003\\u0002\\u0002\\u0002\\u034b\\u034c\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u034c\\u034d\\u0003\\u0002\\u0002\\u0002\\u034d\\u035a\\u0007F\",\n    \"\\u0002\\u0002\\u034e\\u035a\\u0007%\\u0002\\u0002\\u034f\\u035a\\u0005\\u00a6\",\n    \"T\\u0002\\u0350\\u0352\\u0005\\u00a4S\\u0002\\u0351\\u0350\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0352\\u0353\\u0003\\u0002\\u0002\\u0002\\u0353\\u0351\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0353\\u0354\\u0003\\u0002\\u0002\\u0002\\u0354\\u035a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0355\\u035a\\u0007/\\u0002\\u0002\\u0356\\u035a\\u0007\\u001b\\u0002\",\n    \"\\u0002\\u0357\\u035a\\u0007\\u001c\\u0002\\u0002\\u0358\\u035a\\u0007\\u001d\\u0002\",\n    \"\\u0002\\u0359\\u033e\\u0003\\u0002\\u0002\\u0002\\u0359\\u0344\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0359\\u0349\\u0003\\u0002\\u0002\\u0002\\u0359\\u034e\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0359\\u034f\\u0003\\u0002\\u0002\\u0002\\u0359\\u0351\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0359\\u0355\\u0003\\u0002\\u0002\\u0002\\u0359\\u0356\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0359\\u0357\\u0003\\u0002\\u0002\\u0002\\u0359\\u0358\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u035a\\u0083\\u0003\\u0002\\u0002\\u0002\\u035b\\u0367\\u0005^0\\u0002\",\n    \"\\u035c\\u0368\\u0005\\u009cO\\u0002\\u035d\\u035e\\u00073\\u0002\\u0002\\u035e\",\n    \"\\u0360\\u0005^0\\u0002\\u035f\\u035d\\u0003\\u0002\\u0002\\u0002\\u0360\\u0363\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0361\\u035f\\u0003\\u0002\\u0002\\u0002\\u0361\\u0362\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0362\\u0365\\u0003\\u0002\\u0002\\u0002\\u0363\\u0361\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0364\\u0366\\u00073\\u0002\\u0002\\u0365\\u0364\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0365\\u0366\\u0003\\u0002\\u0002\\u0002\\u0366\\u0368\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0367\\u035c\\u0003\\u0002\\u0002\\u0002\\u0367\\u0361\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0368\\u0085\\u0003\\u0002\\u0002\\u0002\\u0369\\u036b\",\n    \"\\u00071\\u0002\\u0002\\u036a\\u036c\\u0005\\u0096L\\u0002\\u036b\\u036a\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u036b\\u036c\\u0003\\u0002\\u0002\\u0002\\u036c\\u036d\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u036d\\u0375\\u00072\\u0002\\u0002\\u036e\\u036f\\u0007\",\n    \"8\\u0002\\u0002\\u036f\\u0370\\u0005\\u0088E\\u0002\\u0370\\u0371\\u00079\\u0002\",\n    \"\\u0002\\u0371\\u0375\\u0003\\u0002\\u0002\\u0002\\u0372\\u0373\\u0007.\\u0002\",\n    \"\\u0002\\u0373\\u0375\\u0007%\\u0002\\u0002\\u0374\\u0369\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0374\\u036e\\u0003\\u0002\\u0002\\u0002\\u0374\\u0372\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u0375\\u0087\\u0003\\u0002\\u0002\\u0002\\u0376\\u037b\\u0005\\u008aF\",\n    \"\\u0002\\u0377\\u0378\\u00073\\u0002\\u0002\\u0378\\u037a\\u0005\\u008aF\\u0002\",\n    \"\\u0379\\u0377\\u0003\\u0002\\u0002\\u0002\\u037a\\u037d\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u037b\\u0379\\u0003\\u0002\\u0002\\u0002\\u037b\\u037c\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u037c\\u037f\\u0003\\u0002\\u0002\\u0002\\u037d\\u037b\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u037e\\u0380\\u00073\\u0002\\u0002\\u037f\\u037e\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u037f\\u0380\\u0003\\u0002\\u0002\\u0002\\u0380\\u0089\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0381\\u038d\\u0005^0\\u0002\\u0382\\u0384\\u0005^0\\u0002\\u0383\\u0382\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0383\\u0384\\u0003\\u0002\\u0002\\u0002\\u0384\\u0385\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0385\\u0387\\u00074\\u0002\\u0002\\u0386\\u0388\\u0005\",\n    \"^0\\u0002\\u0387\\u0386\\u0003\\u0002\\u0002\\u0002\\u0387\\u0388\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0388\\u038a\\u0003\\u0002\\u0002\\u0002\\u0389\\u038b\\u0005\\u008c\",\n    \"G\\u0002\\u038a\\u0389\\u0003\\u0002\\u0002\\u0002\\u038a\\u038b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u038b\\u038d\\u0003\\u0002\\u0002\\u0002\\u038c\\u0381\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u038c\\u0383\\u0003\\u0002\\u0002\\u0002\\u038d\\u008b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u038e\\u0390\\u00074\\u0002\\u0002\\u038f\\u0391\\u0005^0\\u0002\",\n    \"\\u0390\\u038f\\u0003\\u0002\\u0002\\u0002\\u0390\\u0391\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0391\\u008d\\u0003\\u0002\\u0002\\u0002\\u0392\\u0397\\u0005p9\\u0002\\u0393\",\n    \"\\u0394\\u00073\\u0002\\u0002\\u0394\\u0396\\u0005p9\\u0002\\u0395\\u0393\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0396\\u0399\\u0003\\u0002\\u0002\\u0002\\u0397\\u0395\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0397\\u0398\\u0003\\u0002\\u0002\\u0002\\u0398\\u039b\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u0399\\u0397\\u0003\\u0002\\u0002\\u0002\\u039a\\u039c\\u0007\",\n    \"3\\u0002\\u0002\\u039b\\u039a\\u0003\\u0002\\u0002\\u0002\\u039b\\u039c\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u039c\\u008f\\u0003\\u0002\\u0002\\u0002\\u039d\\u03a2\\u0005\",\n    \"^0\\u0002\\u039e\\u039f\\u00073\\u0002\\u0002\\u039f\\u03a1\\u0005^0\\u0002\\u03a0\",\n    \"\\u039e\\u0003\\u0002\\u0002\\u0002\\u03a1\\u03a4\\u0003\\u0002\\u0002\\u0002\\u03a2\",\n    \"\\u03a0\\u0003\\u0002\\u0002\\u0002\\u03a2\\u03a3\\u0003\\u0002\\u0002\\u0002\\u03a3\",\n    \"\\u03a6\\u0003\\u0002\\u0002\\u0002\\u03a4\\u03a2\\u0003\\u0002\\u0002\\u0002\\u03a5\",\n    \"\\u03a7\\u00073\\u0002\\u0002\\u03a6\\u03a5\\u0003\\u0002\\u0002\\u0002\\u03a6\",\n    \"\\u03a7\\u0003\\u0002\\u0002\\u0002\\u03a7\\u0091\\u0003\\u0002\\u0002\\u0002\\u03a8\",\n    \"\\u03a9\\u0005^0\\u0002\\u03a9\\u03aa\\u00074\\u0002\\u0002\\u03aa\\u03b9\\u0005\",\n    \"^0\\u0002\\u03ab\\u03ba\\u0005\\u009cO\\u0002\\u03ac\\u03ad\\u00073\\u0002\\u0002\",\n    \"\\u03ad\\u03ae\\u0005^0\\u0002\\u03ae\\u03af\\u00074\\u0002\\u0002\\u03af\\u03b0\",\n    \"\\u0005^0\\u0002\\u03b0\\u03b2\\u0003\\u0002\\u0002\\u0002\\u03b1\\u03ac\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b2\\u03b5\\u0003\\u0002\\u0002\\u0002\\u03b3\\u03b1\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b3\\u03b4\\u0003\\u0002\\u0002\\u0002\\u03b4\\u03b7\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b5\\u03b3\\u0003\\u0002\\u0002\\u0002\\u03b6\\u03b8\\u0007\",\n    \"3\\u0002\\u0002\\u03b7\\u03b6\\u0003\\u0002\\u0002\\u0002\\u03b7\\u03b8\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b8\\u03ba\\u0003\\u0002\\u0002\\u0002\\u03b9\\u03ab\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03b9\\u03b3\\u0003\\u0002\\u0002\\u0002\\u03ba\\u03ca\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03bb\\u03c7\\u0005^0\\u0002\\u03bc\\u03c8\\u0005\\u009c\",\n    \"O\\u0002\\u03bd\\u03be\\u00073\\u0002\\u0002\\u03be\\u03c0\\u0005^0\\u0002\\u03bf\",\n    \"\\u03bd\\u0003\\u0002\\u0002\\u0002\\u03c0\\u03c3\\u0003\\u0002\\u0002\\u0002\\u03c1\",\n    \"\\u03bf\\u0003\\u0002\\u0002\\u0002\\u03c1\\u03c2\\u0003\\u0002\\u0002\\u0002\\u03c2\",\n    \"\\u03c5\\u0003\\u0002\\u0002\\u0002\\u03c3\\u03c1\\u0003\\u0002\\u0002\\u0002\\u03c4\",\n    \"\\u03c6\\u00073\\u0002\\u0002\\u03c5\\u03c4\\u0003\\u0002\\u0002\\u0002\\u03c5\",\n    \"\\u03c6\\u0003\\u0002\\u0002\\u0002\\u03c6\\u03c8\\u0003\\u0002\\u0002\\u0002\\u03c7\",\n    \"\\u03bc\\u0003\\u0002\\u0002\\u0002\\u03c7\\u03c1\\u0003\\u0002\\u0002\\u0002\\u03c8\",\n    \"\\u03ca\\u0003\\u0002\\u0002\\u0002\\u03c9\\u03a8\\u0003\\u0002\\u0002\\u0002\\u03c9\",\n    \"\\u03bb\\u0003\\u0002\\u0002\\u0002\\u03ca\\u0093\\u0003\\u0002\\u0002\\u0002\\u03cb\",\n    \"\\u03cc\\u0007\\u001e\\u0002\\u0002\\u03cc\\u03d2\\u0007%\\u0002\\u0002\\u03cd\",\n    \"\\u03cf\\u00071\\u0002\\u0002\\u03ce\\u03d0\\u0005\\u0096L\\u0002\\u03cf\\u03ce\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03cf\\u03d0\\u0003\\u0002\\u0002\\u0002\\u03d0\\u03d1\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03d1\\u03d3\\u00072\\u0002\\u0002\\u03d2\\u03cd\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03d2\\u03d3\\u0003\\u0002\\u0002\\u0002\\u03d3\\u03d4\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u03d4\\u03d5\\u00074\\u0002\\u0002\\u03d5\\u03d6\",\n    \"\\u0005\\\\/\\u0002\\u03d6\\u0095\\u0003\\u0002\\u0002\\u0002\\u03d7\\u03d8\\u0005\",\n    \"\\u0098M\\u0002\\u03d8\\u03d9\\u00073\\u0002\\u0002\\u03d9\\u03db\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03da\\u03d7\\u0003\\u0002\\u0002\\u0002\\u03db\\u03de\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03dc\\u03da\\u0003\\u0002\\u0002\\u0002\\u03dc\\u03dd\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03dd\\u03f3\\u0003\\u0002\\u0002\\u0002\\u03de\\u03dc\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03df\\u03e1\\u0005\\u0098M\\u0002\\u03e0\\u03e2\\u00073\\u0002\",\n    \"\\u0002\\u03e1\\u03e0\\u0003\\u0002\\u0002\\u0002\\u03e1\\u03e2\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u03e2\\u03f4\\u0003\\u0002\\u0002\\u0002\\u03e3\\u03e4\\u00070\\u0002\",\n    \"\\u0002\\u03e4\\u03e9\\u0005^0\\u0002\\u03e5\\u03e6\\u00073\\u0002\\u0002\\u03e6\",\n    \"\\u03e8\\u0005\\u0098M\\u0002\\u03e7\\u03e5\\u0003\\u0002\\u0002\\u0002\\u03e8\",\n    \"\\u03eb\\u0003\\u0002\\u0002\\u0002\\u03e9\\u03e7\\u0003\\u0002\\u0002\\u0002\\u03e9\",\n    \"\\u03ea\\u0003\\u0002\\u0002\\u0002\\u03ea\\u03ef\\u0003\\u0002\\u0002\\u0002\\u03eb\",\n    \"\\u03e9\\u0003\\u0002\\u0002\\u0002\\u03ec\\u03ed\\u00073\\u0002\\u0002\\u03ed\",\n    \"\\u03ee\\u00076\\u0002\\u0002\\u03ee\\u03f0\\u0005^0\\u0002\\u03ef\\u03ec\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03ef\\u03f0\\u0003\\u0002\\u0002\\u0002\\u03f0\\u03f4\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03f1\\u03f2\\u00076\\u0002\\u0002\\u03f2\\u03f4\\u0005\",\n    \"^0\\u0002\\u03f3\\u03df\\u0003\\u0002\\u0002\\u0002\\u03f3\\u03e3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03f3\\u03f1\\u0003\\u0002\\u0002\\u0002\\u03f4\\u0097\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u03f5\\u03f7\\u0005^0\\u0002\\u03f6\\u03f8\\u0005\\u009cO\\u0002\",\n    \"\\u03f7\\u03f6\\u0003\\u0002\\u0002\\u0002\\u03f7\\u03f8\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u03f8\\u03fe\\u0003\\u0002\\u0002\\u0002\\u03f9\\u03fa\\u0005^0\\u0002\\u03fa\",\n    \"\\u03fb\\u00077\\u0002\\u0002\\u03fb\\u03fc\\u0005^0\\u0002\\u03fc\\u03fe\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03fd\\u03f5\\u0003\\u0002\\u0002\\u0002\\u03fd\\u03f9\\u0003\",\n    \"\\u0002\\u0002\\u0002\\u03fe\\u0099\\u0003\\u0002\\u0002\\u0002\\u03ff\\u0402\\u0005\",\n    \"\\u009cO\\u0002\\u0400\\u0402\\u0005\\u009eP\\u0002\\u0401\\u03ff\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0401\\u0400\\u0003\\u0002\\u0002\\u0002\\u0402\\u009b\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0403\\u0404\\u0007\\u0010\\u0002\\u0002\\u0404\\u0405\\u0005\\u008e\",\n    \"H\\u0002\\u0405\\u0406\\u0007\\u0011\\u0002\\u0002\\u0406\\u0408\\u0005f4\\u0002\",\n    \"\\u0407\\u0409\\u0005\\u009aN\\u0002\\u0408\\u0407\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u0408\\u0409\\u0003\\u0002\\u0002\\u0002\\u0409\\u009d\\u0003\\u0002\\u0002\\u0002\",\n    \"\\u040a\\u040b\\u0007\\f\\u0002\\u0002\\u040b\\u040d\\u0005`1\\u0002\\u040c\\u040e\",\n    \"\\u0005\\u009aN\\u0002\\u040d\\u040c\\u0003\\u0002\\u0002\\u0002\\u040d\\u040e\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u040e\\u009f\\u0003\\u0002\\u0002\\u0002\\u040f\\u0411\",\n    \"\\u0007\\u001f\\u0002\\u0002\\u0410\\u0412\\u0005\\u00a2R\\u0002\\u0411\\u0410\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0411\\u0412\\u0003\\u0002\\u0002\\u0002\\u0412\\u00a1\",\n    \"\\u0003\\u0002\\u0002\\u0002\\u0413\\u0414\\u0007\\u0006\\u0002\\u0002\\u0414\\u0417\",\n    \"\\u0005^0\\u0002\\u0415\\u0417\\u0005\\u0090I\\u0002\\u0416\\u0413\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0416\\u0415\\u0003\\u0002\\u0002\\u0002\\u0417\\u00a3\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u0418\\u0419\\t\\u0004\\u0002\\u0002\\u0419\\u00a5\\u0003\\u0002\",\n    \"\\u0002\\u0002\\u041a\\u041e\\u0005\\u00a8U\\u0002\\u041b\\u041e\\u0007,\\u0002\",\n    \"\\u0002\\u041c\\u041e\\u0007-\\u0002\\u0002\\u041d\\u041a\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u041d\\u041b\\u0003\\u0002\\u0002\\u0002\\u041d\\u041c\\u0003\\u0002\\u0002\",\n    \"\\u0002\\u041e\\u00a7\\u0003\\u0002\\u0002\\u0002\\u041f\\u0420\\t\\u0005\\u0002\",\n    \"\\u0002\\u0420\\u00a9\\u0003\\u0002\\u0002\\u0002\\u0098\\u00af\\u00b3\\u00b5\\u00be\",\n    \"\\u00c7\\u00ca\\u00d1\\u00d6\\u00dd\\u00e4\\u00eb\\u00f1\\u00f5\\u00fb\\u0101\\u0105\",\n    \"\\u010b\\u010f\\u0111\\u0115\\u011b\\u011f\\u0125\\u0129\\u012e\\u0133\\u0139\\u013d\",\n    \"\\u0143\\u0149\\u014d\\u0153\\u0157\\u0159\\u015d\\u0163\\u0167\\u016d\\u0171\\u0177\",\n    \"\\u017e\\u0182\\u018e\\u0194\\u0199\\u019d\\u01a0\\u01a4\\u01a9\\u01ad\\u01b1\\u01bf\",\n    \"\\u01c7\\u01cf\\u01d1\\u01d5\\u01de\\u01e5\\u01e7\\u01f0\\u01f5\\u01fa\\u0201\\u0205\",\n    \"\\u020c\\u0214\\u021d\\u0226\\u022d\\u0237\\u0244\\u024a\\u0253\\u025e\\u0269\\u026e\",\n    \"\\u0273\\u0278\\u0280\\u0289\\u028f\\u0291\\u0299\\u029d\\u02a5\\u02a8\\u02ac\\u02b0\",\n    \"\\u02b7\\u02c1\\u02c9\\u02cf\\u02d7\\u02e7\\u02ea\\u02f3\\u02fb\\u0303\\u030b\\u030d\",\n    \"\\u0315\\u0317\\u0325\\u0327\\u0331\\u0337\\u033c\\u0341\\u0346\\u034b\\u0353\\u0359\",\n    \"\\u0361\\u0365\\u0367\\u036b\\u0374\\u037b\\u037f\\u0383\\u0387\\u038a\\u038c\\u0390\",\n    \"\\u0397\\u039b\\u03a2\\u03a6\\u03b3\\u03b7\\u03b9\\u03c1\\u03c5\\u03c7\\u03c9\\u03cf\",\n    \"\\u03d2\\u03dc\\u03e1\\u03e9\\u03ef\\u03f3\\u03f7\\u03fd\\u0401\\u0408\\u040d\\u0411\",\n    \"\\u0416\\u041d\"].join(\"\");\n\n\nvar atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN);\n\nvar decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); });\n\nvar sharedContextCache = new antlr4.PredictionContextCache();\n\nvar literalNames = [ null, \"'def'\", \"'return'\", \"'raise'\", \"'from'\", \"'import'\", \n                     \"'as'\", \"'global'\", \"'nonlocal'\", \"'assert'\", \"'if'\", \n                     \"'elif'\", \"'else'\", \"'while'\", \"'for'\", \"'in'\", \"'try'\", \n                     \"'finally'\", \"'with'\", \"'except'\", \"'lambda'\", \"'or'\", \n                     \"'and'\", \"'not'\", \"'is'\", \"'None'\", \"'True'\", \"'False'\", \n                     \"'class'\", \"'yield'\", \"'del'\", \"'pass'\", \"'continue'\", \n                     \"'break'\", null, null, null, null, null, null, null, \n                     null, null, null, \"'.'\", \"'...'\", \"'*'\", \"'('\", \"')'\", \n                     \"','\", \"':'\", \"';'\", \"'**'\", \"'='\", \"'['\", \"']'\", \"'|'\", \n                     \"'^'\", \"'&'\", \"'<<'\", \"'>>'\", \"'+'\", \"'-'\", \"'/'\", \n                     \"'%'\", \"'//'\", \"'~'\", \"'{'\", \"'}'\", \"'<'\", \"'>'\", \"'=='\", \n                     \"'>='\", \"'<='\", \"'<>'\", \"'!='\", \"'@'\", \"'->'\", \"'+='\", \n                     \"'-='\", \"'*='\", \"'@='\", \"'/='\", \"'%='\", \"'&='\", \"'|='\", \n                     \"'^='\", \"'<<='\", \"'>>='\", \"'**='\", \"'//='\" ];\n\nvar symbolicNames = [ null, \"DEF\", \"RETURN\", \"RAISE\", \"FROM\", \"IMPORT\", \n                      \"AS\", \"GLOBAL\", \"NONLOCAL\", \"ASSERT\", \"IF\", \"ELIF\", \n                      \"ELSE\", \"WHILE\", \"FOR\", \"IN\", \"TRY\", \"FINALLY\", \"WITH\", \n                      \"EXCEPT\", \"LAMBDA\", \"OR\", \"AND\", \"NOT\", \"IS\", \"NONE\", \n                      \"TRUE\", \"FALSE\", \"CLASS\", \"YIELD\", \"DEL\", \"PASS\", \n                      \"CONTINUE\", \"BREAK\", \"NEWLINE\", \"NAME\", \"STRING_LITERAL\", \n                      \"BYTES_LITERAL\", \"DECIMAL_INTEGER\", \"OCT_INTEGER\", \n                      \"HEX_INTEGER\", \"BIN_INTEGER\", \"FLOAT_NUMBER\", \"IMAG_NUMBER\", \n                      \"DOT\", \"ELLIPSIS\", \"STAR\", \"OPEN_PAREN\", \"CLOSE_PAREN\", \n                      \"COMMA\", \"COLON\", \"SEMI_COLON\", \"POWER\", \"ASSIGN\", \n                      \"OPEN_BRACK\", \"CLOSE_BRACK\", \"OR_OP\", \"XOR\", \"AND_OP\", \n                      \"LEFT_SHIFT\", \"RIGHT_SHIFT\", \"ADD\", \"MINUS\", \"DIV\", \n                      \"MOD\", \"IDIV\", \"NOT_OP\", \"OPEN_BRACE\", \"CLOSE_BRACE\", \n                      \"LESS_THAN\", \"GREATER_THAN\", \"EQUALS\", \"GT_EQ\", \"LT_EQ\", \n                      \"NOT_EQ_1\", \"NOT_EQ_2\", \"AT\", \"ARROW\", \"ADD_ASSIGN\", \n                      \"SUB_ASSIGN\", \"MULT_ASSIGN\", \"AT_ASSIGN\", \"DIV_ASSIGN\", \n                      \"MOD_ASSIGN\", \"AND_ASSIGN\", \"OR_ASSIGN\", \"XOR_ASSIGN\", \n                      \"LEFT_SHIFT_ASSIGN\", \"RIGHT_SHIFT_ASSIGN\", \"POWER_ASSIGN\", \n                      \"IDIV_ASSIGN\", \"SKIP_\", \"UNKNOWN_CHAR\", \"INDENT\", \n                      \"DEDENT\" ];\n\nvar ruleNames =  [ \"single_input\", \"file_input\", \"eval_input\", \"decorator\", \n                   \"decorators\", \"decorated\", \"funcdef\", \"parameters\", \"typedargslist\", \n                   \"tfpdef\", \"varargslist\", \"vfpdef\", \"stmt\", \"simple_stmt\", \n                   \"small_stmt\", \"expr_stmt\", \"testlist_star_expr\", \"augassign\", \n                   \"del_stmt\", \"pass_stmt\", \"flow_stmt\", \"break_stmt\", \"continue_stmt\", \n                   \"return_stmt\", \"yield_stmt\", \"raise_stmt\", \"import_stmt\", \n                   \"import_name\", \"import_from\", \"import_as_name\", \"dotted_as_name\", \n                   \"import_as_names\", \"dotted_as_names\", \"dotted_name\", \n                   \"global_stmt\", \"nonlocal_stmt\", \"assert_stmt\", \"compound_stmt\", \n                   \"if_stmt\", \"while_stmt\", \"for_stmt\", \"try_stmt\", \"with_stmt\", \n                   \"with_item\", \"except_clause\", \"suite\", \"test\", \"test_nocond\", \n                   \"lambdef\", \"lambdef_nocond\", \"or_test\", \"and_test\", \"not_test\", \n                   \"comparison\", \"comp_op\", \"star_expr\", \"expr\", \"xor_expr\", \n                   \"and_expr\", \"shift_expr\", \"arith_expr\", \"term\", \"factor\", \n                   \"power\", \"atom\", \"testlist_comp\", \"trailer\", \"subscriptlist\", \n                   \"subscript\", \"sliceop\", \"exprlist\", \"testlist\", \"dictorsetmaker\", \n                   \"classdef\", \"arglist\", \"argument\", \"comp_iter\", \"comp_for\", \n                   \"comp_if\", \"yield_expr\", \"yield_arg\", \"str\", \"number\", \n                   \"integer\" ];\n\nfunction Python3Parser (input) {\n\tantlr4.Parser.call(this, input);\n    this._interp = new antlr4.atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache);\n    this.ruleNames = ruleNames;\n    this.literalNames = literalNames;\n    this.symbolicNames = symbolicNames;\n    return this;\n}\n\nPython3Parser.prototype = Object.create(antlr4.Parser.prototype);\nPython3Parser.prototype.constructor = Python3Parser;\n\nObject.defineProperty(Python3Parser.prototype, \"atn\", {\n\tget : function() {\n\t\treturn atn;\n\t}\n});\n\nPython3Parser.EOF = antlr4.Token.EOF;\nPython3Parser.DEF = 1;\nPython3Parser.RETURN = 2;\nPython3Parser.RAISE = 3;\nPython3Parser.FROM = 4;\nPython3Parser.IMPORT = 5;\nPython3Parser.AS = 6;\nPython3Parser.GLOBAL = 7;\nPython3Parser.NONLOCAL = 8;\nPython3Parser.ASSERT = 9;\nPython3Parser.IF = 10;\nPython3Parser.ELIF = 11;\nPython3Parser.ELSE = 12;\nPython3Parser.WHILE = 13;\nPython3Parser.FOR = 14;\nPython3Parser.IN = 15;\nPython3Parser.TRY = 16;\nPython3Parser.FINALLY = 17;\nPython3Parser.WITH = 18;\nPython3Parser.EXCEPT = 19;\nPython3Parser.LAMBDA = 20;\nPython3Parser.OR = 21;\nPython3Parser.AND = 22;\nPython3Parser.NOT = 23;\nPython3Parser.IS = 24;\nPython3Parser.NONE = 25;\nPython3Parser.TRUE = 26;\nPython3Parser.FALSE = 27;\nPython3Parser.CLASS = 28;\nPython3Parser.YIELD = 29;\nPython3Parser.DEL = 30;\nPython3Parser.PASS = 31;\nPython3Parser.CONTINUE = 32;\nPython3Parser.BREAK = 33;\nPython3Parser.NEWLINE = 34;\nPython3Parser.NAME = 35;\nPython3Parser.STRING_LITERAL = 36;\nPython3Parser.BYTES_LITERAL = 37;\nPython3Parser.DECIMAL_INTEGER = 38;\nPython3Parser.OCT_INTEGER = 39;\nPython3Parser.HEX_INTEGER = 40;\nPython3Parser.BIN_INTEGER = 41;\nPython3Parser.FLOAT_NUMBER = 42;\nPython3Parser.IMAG_NUMBER = 43;\nPython3Parser.DOT = 44;\nPython3Parser.ELLIPSIS = 45;\nPython3Parser.STAR = 46;\nPython3Parser.OPEN_PAREN = 47;\nPython3Parser.CLOSE_PAREN = 48;\nPython3Parser.COMMA = 49;\nPython3Parser.COLON = 50;\nPython3Parser.SEMI_COLON = 51;\nPython3Parser.POWER = 52;\nPython3Parser.ASSIGN = 53;\nPython3Parser.OPEN_BRACK = 54;\nPython3Parser.CLOSE_BRACK = 55;\nPython3Parser.OR_OP = 56;\nPython3Parser.XOR = 57;\nPython3Parser.AND_OP = 58;\nPython3Parser.LEFT_SHIFT = 59;\nPython3Parser.RIGHT_SHIFT = 60;\nPython3Parser.ADD = 61;\nPython3Parser.MINUS = 62;\nPython3Parser.DIV = 63;\nPython3Parser.MOD = 64;\nPython3Parser.IDIV = 65;\nPython3Parser.NOT_OP = 66;\nPython3Parser.OPEN_BRACE = 67;\nPython3Parser.CLOSE_BRACE = 68;\nPython3Parser.LESS_THAN = 69;\nPython3Parser.GREATER_THAN = 70;\nPython3Parser.EQUALS = 71;\nPython3Parser.GT_EQ = 72;\nPython3Parser.LT_EQ = 73;\nPython3Parser.NOT_EQ_1 = 74;\nPython3Parser.NOT_EQ_2 = 75;\nPython3Parser.AT = 76;\nPython3Parser.ARROW = 77;\nPython3Parser.ADD_ASSIGN = 78;\nPython3Parser.SUB_ASSIGN = 79;\nPython3Parser.MULT_ASSIGN = 80;\nPython3Parser.AT_ASSIGN = 81;\nPython3Parser.DIV_ASSIGN = 82;\nPython3Parser.MOD_ASSIGN = 83;\nPython3Parser.AND_ASSIGN = 84;\nPython3Parser.OR_ASSIGN = 85;\nPython3Parser.XOR_ASSIGN = 86;\nPython3Parser.LEFT_SHIFT_ASSIGN = 87;\nPython3Parser.RIGHT_SHIFT_ASSIGN = 88;\nPython3Parser.POWER_ASSIGN = 89;\nPython3Parser.IDIV_ASSIGN = 90;\nPython3Parser.SKIP_ = 91;\nPython3Parser.UNKNOWN_CHAR = 92;\nPython3Parser.INDENT = 93;\nPython3Parser.DEDENT = 94;\n\nPython3Parser.RULE_single_input = 0;\nPython3Parser.RULE_file_input = 1;\nPython3Parser.RULE_eval_input = 2;\nPython3Parser.RULE_decorator = 3;\nPython3Parser.RULE_decorators = 4;\nPython3Parser.RULE_decorated = 5;\nPython3Parser.RULE_funcdef = 6;\nPython3Parser.RULE_parameters = 7;\nPython3Parser.RULE_typedargslist = 8;\nPython3Parser.RULE_tfpdef = 9;\nPython3Parser.RULE_varargslist = 10;\nPython3Parser.RULE_vfpdef = 11;\nPython3Parser.RULE_stmt = 12;\nPython3Parser.RULE_simple_stmt = 13;\nPython3Parser.RULE_small_stmt = 14;\nPython3Parser.RULE_expr_stmt = 15;\nPython3Parser.RULE_testlist_star_expr = 16;\nPython3Parser.RULE_augassign = 17;\nPython3Parser.RULE_del_stmt = 18;\nPython3Parser.RULE_pass_stmt = 19;\nPython3Parser.RULE_flow_stmt = 20;\nPython3Parser.RULE_break_stmt = 21;\nPython3Parser.RULE_continue_stmt = 22;\nPython3Parser.RULE_return_stmt = 23;\nPython3Parser.RULE_yield_stmt = 24;\nPython3Parser.RULE_raise_stmt = 25;\nPython3Parser.RULE_import_stmt = 26;\nPython3Parser.RULE_import_name = 27;\nPython3Parser.RULE_import_from = 28;\nPython3Parser.RULE_import_as_name = 29;\nPython3Parser.RULE_dotted_as_name = 30;\nPython3Parser.RULE_import_as_names = 31;\nPython3Parser.RULE_dotted_as_names = 32;\nPython3Parser.RULE_dotted_name = 33;\nPython3Parser.RULE_global_stmt = 34;\nPython3Parser.RULE_nonlocal_stmt = 35;\nPython3Parser.RULE_assert_stmt = 36;\nPython3Parser.RULE_compound_stmt = 37;\nPython3Parser.RULE_if_stmt = 38;\nPython3Parser.RULE_while_stmt = 39;\nPython3Parser.RULE_for_stmt = 40;\nPython3Parser.RULE_try_stmt = 41;\nPython3Parser.RULE_with_stmt = 42;\nPython3Parser.RULE_with_item = 43;\nPython3Parser.RULE_except_clause = 44;\nPython3Parser.RULE_suite = 45;\nPython3Parser.RULE_test = 46;\nPython3Parser.RULE_test_nocond = 47;\nPython3Parser.RULE_lambdef = 48;\nPython3Parser.RULE_lambdef_nocond = 49;\nPython3Parser.RULE_or_test = 50;\nPython3Parser.RULE_and_test = 51;\nPython3Parser.RULE_not_test = 52;\nPython3Parser.RULE_comparison = 53;\nPython3Parser.RULE_comp_op = 54;\nPython3Parser.RULE_star_expr = 55;\nPython3Parser.RULE_expr = 56;\nPython3Parser.RULE_xor_expr = 57;\nPython3Parser.RULE_and_expr = 58;\nPython3Parser.RULE_shift_expr = 59;\nPython3Parser.RULE_arith_expr = 60;\nPython3Parser.RULE_term = 61;\nPython3Parser.RULE_factor = 62;\nPython3Parser.RULE_power = 63;\nPython3Parser.RULE_atom = 64;\nPython3Parser.RULE_testlist_comp = 65;\nPython3Parser.RULE_trailer = 66;\nPython3Parser.RULE_subscriptlist = 67;\nPython3Parser.RULE_subscript = 68;\nPython3Parser.RULE_sliceop = 69;\nPython3Parser.RULE_exprlist = 70;\nPython3Parser.RULE_testlist = 71;\nPython3Parser.RULE_dictorsetmaker = 72;\nPython3Parser.RULE_classdef = 73;\nPython3Parser.RULE_arglist = 74;\nPython3Parser.RULE_argument = 75;\nPython3Parser.RULE_comp_iter = 76;\nPython3Parser.RULE_comp_for = 77;\nPython3Parser.RULE_comp_if = 78;\nPython3Parser.RULE_yield_expr = 79;\nPython3Parser.RULE_yield_arg = 80;\nPython3Parser.RULE_str = 81;\nPython3Parser.RULE_number = 82;\nPython3Parser.RULE_integer = 83;\n\nfunction Single_inputContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_single_input;\n    return this;\n}\n\nSingle_inputContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSingle_inputContext.prototype.constructor = Single_inputContext;\n\nSingle_inputContext.prototype.NEWLINE = function() {\n    return this.getToken(Python3Parser.NEWLINE, 0);\n};\n\nSingle_inputContext.prototype.simple_stmt = function() {\n    return this.getTypedRuleContext(Simple_stmtContext,0);\n};\n\nSingle_inputContext.prototype.compound_stmt = function() {\n    return this.getTypedRuleContext(Compound_stmtContext,0);\n};\n\nSingle_inputContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSingle_input(this);\n\t}\n};\n\nSingle_inputContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSingle_input(this);\n\t}\n};\n\nSingle_inputContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSingle_input(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Single_inputContext = Single_inputContext;\n\nPython3Parser.prototype.single_input = function() {\n\n    var localctx = new Single_inputContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 0, Python3Parser.RULE_single_input);\n    try {\n        this.state = 173;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.NEWLINE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 168;\n            this.match(Python3Parser.NEWLINE);\n            break;\n        case Python3Parser.RETURN:\n        case Python3Parser.RAISE:\n        case Python3Parser.FROM:\n        case Python3Parser.IMPORT:\n        case Python3Parser.GLOBAL:\n        case Python3Parser.NONLOCAL:\n        case Python3Parser.ASSERT:\n        case Python3Parser.LAMBDA:\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.YIELD:\n        case Python3Parser.DEL:\n        case Python3Parser.PASS:\n        case Python3Parser.CONTINUE:\n        case Python3Parser.BREAK:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 169;\n            this.simple_stmt();\n            break;\n        case Python3Parser.DEF:\n        case Python3Parser.IF:\n        case Python3Parser.WHILE:\n        case Python3Parser.FOR:\n        case Python3Parser.TRY:\n        case Python3Parser.WITH:\n        case Python3Parser.CLASS:\n        case Python3Parser.AT:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 170;\n            this.compound_stmt();\n            this.state = 171;\n            this.match(Python3Parser.NEWLINE);\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction File_inputContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_file_input;\n    return this;\n}\n\nFile_inputContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nFile_inputContext.prototype.constructor = File_inputContext;\n\nFile_inputContext.prototype.EOF = function() {\n    return this.getToken(Python3Parser.EOF, 0);\n};\n\nFile_inputContext.prototype.NEWLINE = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.NEWLINE);\n    } else {\n        return this.getToken(Python3Parser.NEWLINE, i);\n    }\n};\n\n\nFile_inputContext.prototype.stmt = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(StmtContext);\n    } else {\n        return this.getTypedRuleContext(StmtContext,i);\n    }\n};\n\nFile_inputContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterFile_input(this);\n\t}\n};\n\nFile_inputContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitFile_input(this);\n\t}\n};\n\nFile_inputContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitFile_input(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.File_inputContext = File_inputContext;\n\nPython3Parser.prototype.file_input = function() {\n\n    var localctx = new File_inputContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 2, Python3Parser.RULE_file_input);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 179;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 177;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.NEWLINE:\n                this.state = 175;\n                this.match(Python3Parser.NEWLINE);\n                break;\n            case Python3Parser.DEF:\n            case Python3Parser.RETURN:\n            case Python3Parser.RAISE:\n            case Python3Parser.FROM:\n            case Python3Parser.IMPORT:\n            case Python3Parser.GLOBAL:\n            case Python3Parser.NONLOCAL:\n            case Python3Parser.ASSERT:\n            case Python3Parser.IF:\n            case Python3Parser.WHILE:\n            case Python3Parser.FOR:\n            case Python3Parser.TRY:\n            case Python3Parser.WITH:\n            case Python3Parser.LAMBDA:\n            case Python3Parser.NOT:\n            case Python3Parser.NONE:\n            case Python3Parser.TRUE:\n            case Python3Parser.FALSE:\n            case Python3Parser.CLASS:\n            case Python3Parser.YIELD:\n            case Python3Parser.DEL:\n            case Python3Parser.PASS:\n            case Python3Parser.CONTINUE:\n            case Python3Parser.BREAK:\n            case Python3Parser.NAME:\n            case Python3Parser.STRING_LITERAL:\n            case Python3Parser.BYTES_LITERAL:\n            case Python3Parser.DECIMAL_INTEGER:\n            case Python3Parser.OCT_INTEGER:\n            case Python3Parser.HEX_INTEGER:\n            case Python3Parser.BIN_INTEGER:\n            case Python3Parser.FLOAT_NUMBER:\n            case Python3Parser.IMAG_NUMBER:\n            case Python3Parser.ELLIPSIS:\n            case Python3Parser.STAR:\n            case Python3Parser.OPEN_PAREN:\n            case Python3Parser.OPEN_BRACK:\n            case Python3Parser.ADD:\n            case Python3Parser.MINUS:\n            case Python3Parser.NOT_OP:\n            case Python3Parser.OPEN_BRACE:\n            case Python3Parser.AT:\n                this.state = 176;\n                this.stmt();\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            this.state = 181;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 182;\n        this.match(Python3Parser.EOF);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Eval_inputContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_eval_input;\n    return this;\n}\n\nEval_inputContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nEval_inputContext.prototype.constructor = Eval_inputContext;\n\nEval_inputContext.prototype.testlist = function() {\n    return this.getTypedRuleContext(TestlistContext,0);\n};\n\nEval_inputContext.prototype.EOF = function() {\n    return this.getToken(Python3Parser.EOF, 0);\n};\n\nEval_inputContext.prototype.NEWLINE = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.NEWLINE);\n    } else {\n        return this.getToken(Python3Parser.NEWLINE, i);\n    }\n};\n\n\nEval_inputContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterEval_input(this);\n\t}\n};\n\nEval_inputContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitEval_input(this);\n\t}\n};\n\nEval_inputContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitEval_input(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Eval_inputContext = Eval_inputContext;\n\nPython3Parser.prototype.eval_input = function() {\n\n    var localctx = new Eval_inputContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 4, Python3Parser.RULE_eval_input);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 184;\n        this.testlist();\n        this.state = 188;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.NEWLINE) {\n            this.state = 185;\n            this.match(Python3Parser.NEWLINE);\n            this.state = 190;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 191;\n        this.match(Python3Parser.EOF);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction DecoratorContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_decorator;\n    return this;\n}\n\nDecoratorContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDecoratorContext.prototype.constructor = DecoratorContext;\n\nDecoratorContext.prototype.dotted_name = function() {\n    return this.getTypedRuleContext(Dotted_nameContext,0);\n};\n\nDecoratorContext.prototype.NEWLINE = function() {\n    return this.getToken(Python3Parser.NEWLINE, 0);\n};\n\nDecoratorContext.prototype.arglist = function() {\n    return this.getTypedRuleContext(ArglistContext,0);\n};\n\nDecoratorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDecorator(this);\n\t}\n};\n\nDecoratorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDecorator(this);\n\t}\n};\n\nDecoratorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDecorator(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.DecoratorContext = DecoratorContext;\n\nPython3Parser.prototype.decorator = function() {\n\n    var localctx = new DecoratorContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 6, Python3Parser.RULE_decorator);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 193;\n        this.match(Python3Parser.AT);\n        this.state = 194;\n        this.dotted_name();\n        this.state = 200;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.OPEN_PAREN) {\n            this.state = 195;\n            this.match(Python3Parser.OPEN_PAREN);\n            this.state = 197;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 196;\n                this.arglist();\n            }\n\n            this.state = 199;\n            this.match(Python3Parser.CLOSE_PAREN);\n        }\n\n        this.state = 202;\n        this.match(Python3Parser.NEWLINE);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction DecoratorsContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_decorators;\n    return this;\n}\n\nDecoratorsContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDecoratorsContext.prototype.constructor = DecoratorsContext;\n\nDecoratorsContext.prototype.decorator = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(DecoratorContext);\n    } else {\n        return this.getTypedRuleContext(DecoratorContext,i);\n    }\n};\n\nDecoratorsContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDecorators(this);\n\t}\n};\n\nDecoratorsContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDecorators(this);\n\t}\n};\n\nDecoratorsContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDecorators(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.DecoratorsContext = DecoratorsContext;\n\nPython3Parser.prototype.decorators = function() {\n\n    var localctx = new DecoratorsContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 8, Python3Parser.RULE_decorators);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 205; \n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        do {\n            this.state = 204;\n            this.decorator();\n            this.state = 207; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        } while(_la===Python3Parser.AT);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction DecoratedContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_decorated;\n    return this;\n}\n\nDecoratedContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDecoratedContext.prototype.constructor = DecoratedContext;\n\nDecoratedContext.prototype.decorators = function() {\n    return this.getTypedRuleContext(DecoratorsContext,0);\n};\n\nDecoratedContext.prototype.classdef = function() {\n    return this.getTypedRuleContext(ClassdefContext,0);\n};\n\nDecoratedContext.prototype.funcdef = function() {\n    return this.getTypedRuleContext(FuncdefContext,0);\n};\n\nDecoratedContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDecorated(this);\n\t}\n};\n\nDecoratedContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDecorated(this);\n\t}\n};\n\nDecoratedContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDecorated(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.DecoratedContext = DecoratedContext;\n\nPython3Parser.prototype.decorated = function() {\n\n    var localctx = new DecoratedContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 10, Python3Parser.RULE_decorated);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 209;\n        this.decorators();\n        this.state = 212;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.CLASS:\n            this.state = 210;\n            this.classdef();\n            break;\n        case Python3Parser.DEF:\n            this.state = 211;\n            this.funcdef();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction FuncdefContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_funcdef;\n    return this;\n}\n\nFuncdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nFuncdefContext.prototype.constructor = FuncdefContext;\n\nFuncdefContext.prototype.DEF = function() {\n    return this.getToken(Python3Parser.DEF, 0);\n};\n\nFuncdefContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nFuncdefContext.prototype.parameters = function() {\n    return this.getTypedRuleContext(ParametersContext,0);\n};\n\nFuncdefContext.prototype.suite = function() {\n    return this.getTypedRuleContext(SuiteContext,0);\n};\n\nFuncdefContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nFuncdefContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterFuncdef(this);\n\t}\n};\n\nFuncdefContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitFuncdef(this);\n\t}\n};\n\nFuncdefContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitFuncdef(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.FuncdefContext = FuncdefContext;\n\nPython3Parser.prototype.funcdef = function() {\n\n    var localctx = new FuncdefContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 12, Python3Parser.RULE_funcdef);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 214;\n        this.match(Python3Parser.DEF);\n        this.state = 215;\n        this.match(Python3Parser.NAME);\n        this.state = 216;\n        this.parameters();\n        this.state = 219;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.ARROW) {\n            this.state = 217;\n            this.match(Python3Parser.ARROW);\n            this.state = 218;\n            this.test();\n        }\n\n        this.state = 221;\n        this.match(Python3Parser.COLON);\n        this.state = 222;\n        this.suite();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ParametersContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_parameters;\n    return this;\n}\n\nParametersContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nParametersContext.prototype.constructor = ParametersContext;\n\nParametersContext.prototype.typedargslist = function() {\n    return this.getTypedRuleContext(TypedargslistContext,0);\n};\n\nParametersContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterParameters(this);\n\t}\n};\n\nParametersContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitParameters(this);\n\t}\n};\n\nParametersContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitParameters(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ParametersContext = ParametersContext;\n\nPython3Parser.prototype.parameters = function() {\n\n    var localctx = new ParametersContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 14, Python3Parser.RULE_parameters);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 224;\n        this.match(Python3Parser.OPEN_PAREN);\n        this.state = 226;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(((((_la - 35)) & ~0x1f) == 0 && ((1 << (_la - 35)) & ((1 << (Python3Parser.NAME - 35)) | (1 << (Python3Parser.STAR - 35)) | (1 << (Python3Parser.POWER - 35)))) !== 0)) {\n            this.state = 225;\n            this.typedargslist();\n        }\n\n        this.state = 228;\n        this.match(Python3Parser.CLOSE_PAREN);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TypedargslistContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_typedargslist;\n    return this;\n}\n\nTypedargslistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTypedargslistContext.prototype.constructor = TypedargslistContext;\n\nTypedargslistContext.prototype.tfpdef = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TfpdefContext);\n    } else {\n        return this.getTypedRuleContext(TfpdefContext,i);\n    }\n};\n\nTypedargslistContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nTypedargslistContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTypedargslist(this);\n\t}\n};\n\nTypedargslistContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTypedargslist(this);\n\t}\n};\n\nTypedargslistContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTypedargslist(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.TypedargslistContext = TypedargslistContext;\n\nPython3Parser.prototype.typedargslist = function() {\n\n    var localctx = new TypedargslistContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 16, Python3Parser.RULE_typedargslist);\n    var _la = 0; // Token type\n    try {\n        this.state = 295;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.NAME:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 230;\n            this.tfpdef();\n            this.state = 233;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.ASSIGN) {\n                this.state = 231;\n                this.match(Python3Parser.ASSIGN);\n                this.state = 232;\n                this.test();\n            }\n\n            this.state = 243;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,12,this._ctx)\n            while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 235;\n                    this.match(Python3Parser.COMMA);\n                    this.state = 236;\n                    this.tfpdef();\n                    this.state = 239;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                    if(_la===Python3Parser.ASSIGN) {\n                        this.state = 237;\n                        this.match(Python3Parser.ASSIGN);\n                        this.state = 238;\n                        this.test();\n                    }\n             \n                }\n                this.state = 245;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,12,this._ctx);\n            }\n\n            this.state = 271;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 246;\n                this.match(Python3Parser.COMMA);\n                this.state = 269;\n                this._errHandler.sync(this);\n                switch (this._input.LA(1)) {\n                case Python3Parser.STAR:\n                \tthis.state = 247;\n                \tthis.match(Python3Parser.STAR);\n                \tthis.state = 249;\n                \tthis._errHandler.sync(this);\n                \t_la = this._input.LA(1);\n                \tif(_la===Python3Parser.NAME) {\n                \t    this.state = 248;\n                \t    this.tfpdef();\n                \t}\n\n                \tthis.state = 259;\n                \tthis._errHandler.sync(this);\n                \tvar _alt = this._interp.adaptivePredict(this._input,15,this._ctx)\n                \twhile(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                \t    if(_alt===1) {\n                \t        this.state = 251;\n                \t        this.match(Python3Parser.COMMA);\n                \t        this.state = 252;\n                \t        this.tfpdef();\n                \t        this.state = 255;\n                \t        this._errHandler.sync(this);\n                \t        _la = this._input.LA(1);\n                \t        if(_la===Python3Parser.ASSIGN) {\n                \t            this.state = 253;\n                \t            this.match(Python3Parser.ASSIGN);\n                \t            this.state = 254;\n                \t            this.test();\n                \t        }\n                \t \n                \t    }\n                \t    this.state = 261;\n                \t    this._errHandler.sync(this);\n                \t    _alt = this._interp.adaptivePredict(this._input,15,this._ctx);\n                \t}\n\n                \tthis.state = 265;\n                \tthis._errHandler.sync(this);\n                \t_la = this._input.LA(1);\n                \tif(_la===Python3Parser.COMMA) {\n                \t    this.state = 262;\n                \t    this.match(Python3Parser.COMMA);\n                \t    this.state = 263;\n                \t    this.match(Python3Parser.POWER);\n                \t    this.state = 264;\n                \t    this.tfpdef();\n                \t}\n\n                \tbreak;\n                case Python3Parser.POWER:\n                \tthis.state = 267;\n                \tthis.match(Python3Parser.POWER);\n                \tthis.state = 268;\n                \tthis.tfpdef();\n                \tbreak;\n                case Python3Parser.CLOSE_PAREN:\n                \tbreak;\n                default:\n                \tbreak;\n                }\n            }\n\n            break;\n        case Python3Parser.STAR:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 273;\n            this.match(Python3Parser.STAR);\n            this.state = 275;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.NAME) {\n                this.state = 274;\n                this.tfpdef();\n            }\n\n            this.state = 285;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,21,this._ctx)\n            while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 277;\n                    this.match(Python3Parser.COMMA);\n                    this.state = 278;\n                    this.tfpdef();\n                    this.state = 281;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                    if(_la===Python3Parser.ASSIGN) {\n                        this.state = 279;\n                        this.match(Python3Parser.ASSIGN);\n                        this.state = 280;\n                        this.test();\n                    }\n             \n                }\n                this.state = 287;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,21,this._ctx);\n            }\n\n            this.state = 291;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 288;\n                this.match(Python3Parser.COMMA);\n                this.state = 289;\n                this.match(Python3Parser.POWER);\n                this.state = 290;\n                this.tfpdef();\n            }\n\n            break;\n        case Python3Parser.POWER:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 293;\n            this.match(Python3Parser.POWER);\n            this.state = 294;\n            this.tfpdef();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TfpdefContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_tfpdef;\n    return this;\n}\n\nTfpdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTfpdefContext.prototype.constructor = TfpdefContext;\n\nTfpdefContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nTfpdefContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nTfpdefContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTfpdef(this);\n\t}\n};\n\nTfpdefContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTfpdef(this);\n\t}\n};\n\nTfpdefContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTfpdef(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.TfpdefContext = TfpdefContext;\n\nPython3Parser.prototype.tfpdef = function() {\n\n    var localctx = new TfpdefContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 18, Python3Parser.RULE_tfpdef);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 297;\n        this.match(Python3Parser.NAME);\n        this.state = 300;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COLON) {\n            this.state = 298;\n            this.match(Python3Parser.COLON);\n            this.state = 299;\n            this.test();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction VarargslistContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_varargslist;\n    return this;\n}\n\nVarargslistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nVarargslistContext.prototype.constructor = VarargslistContext;\n\nVarargslistContext.prototype.vfpdef = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(VfpdefContext);\n    } else {\n        return this.getTypedRuleContext(VfpdefContext,i);\n    }\n};\n\nVarargslistContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nVarargslistContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterVarargslist(this);\n\t}\n};\n\nVarargslistContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitVarargslist(this);\n\t}\n};\n\nVarargslistContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitVarargslist(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.VarargslistContext = VarargslistContext;\n\nPython3Parser.prototype.varargslist = function() {\n\n    var localctx = new VarargslistContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 20, Python3Parser.RULE_varargslist);\n    var _la = 0; // Token type\n    try {\n        this.state = 367;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.NAME:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 302;\n            this.vfpdef();\n            this.state = 305;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.ASSIGN) {\n                this.state = 303;\n                this.match(Python3Parser.ASSIGN);\n                this.state = 304;\n                this.test();\n            }\n\n            this.state = 315;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,27,this._ctx)\n            while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 307;\n                    this.match(Python3Parser.COMMA);\n                    this.state = 308;\n                    this.vfpdef();\n                    this.state = 311;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                    if(_la===Python3Parser.ASSIGN) {\n                        this.state = 309;\n                        this.match(Python3Parser.ASSIGN);\n                        this.state = 310;\n                        this.test();\n                    }\n             \n                }\n                this.state = 317;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,27,this._ctx);\n            }\n\n            this.state = 343;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 318;\n                this.match(Python3Parser.COMMA);\n                this.state = 341;\n                this._errHandler.sync(this);\n                switch (this._input.LA(1)) {\n                case Python3Parser.STAR:\n                \tthis.state = 319;\n                \tthis.match(Python3Parser.STAR);\n                \tthis.state = 321;\n                \tthis._errHandler.sync(this);\n                \t_la = this._input.LA(1);\n                \tif(_la===Python3Parser.NAME) {\n                \t    this.state = 320;\n                \t    this.vfpdef();\n                \t}\n\n                \tthis.state = 331;\n                \tthis._errHandler.sync(this);\n                \tvar _alt = this._interp.adaptivePredict(this._input,30,this._ctx)\n                \twhile(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                \t    if(_alt===1) {\n                \t        this.state = 323;\n                \t        this.match(Python3Parser.COMMA);\n                \t        this.state = 324;\n                \t        this.vfpdef();\n                \t        this.state = 327;\n                \t        this._errHandler.sync(this);\n                \t        _la = this._input.LA(1);\n                \t        if(_la===Python3Parser.ASSIGN) {\n                \t            this.state = 325;\n                \t            this.match(Python3Parser.ASSIGN);\n                \t            this.state = 326;\n                \t            this.test();\n                \t        }\n                \t \n                \t    }\n                \t    this.state = 333;\n                \t    this._errHandler.sync(this);\n                \t    _alt = this._interp.adaptivePredict(this._input,30,this._ctx);\n                \t}\n\n                \tthis.state = 337;\n                \tthis._errHandler.sync(this);\n                \t_la = this._input.LA(1);\n                \tif(_la===Python3Parser.COMMA) {\n                \t    this.state = 334;\n                \t    this.match(Python3Parser.COMMA);\n                \t    this.state = 335;\n                \t    this.match(Python3Parser.POWER);\n                \t    this.state = 336;\n                \t    this.vfpdef();\n                \t}\n\n                \tbreak;\n                case Python3Parser.POWER:\n                \tthis.state = 339;\n                \tthis.match(Python3Parser.POWER);\n                \tthis.state = 340;\n                \tthis.vfpdef();\n                \tbreak;\n                case Python3Parser.COLON:\n                \tbreak;\n                default:\n                \tbreak;\n                }\n            }\n\n            break;\n        case Python3Parser.STAR:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 345;\n            this.match(Python3Parser.STAR);\n            this.state = 347;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.NAME) {\n                this.state = 346;\n                this.vfpdef();\n            }\n\n            this.state = 357;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,36,this._ctx)\n            while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 349;\n                    this.match(Python3Parser.COMMA);\n                    this.state = 350;\n                    this.vfpdef();\n                    this.state = 353;\n                    this._errHandler.sync(this);\n                    _la = this._input.LA(1);\n                    if(_la===Python3Parser.ASSIGN) {\n                        this.state = 351;\n                        this.match(Python3Parser.ASSIGN);\n                        this.state = 352;\n                        this.test();\n                    }\n             \n                }\n                this.state = 359;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,36,this._ctx);\n            }\n\n            this.state = 363;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 360;\n                this.match(Python3Parser.COMMA);\n                this.state = 361;\n                this.match(Python3Parser.POWER);\n                this.state = 362;\n                this.vfpdef();\n            }\n\n            break;\n        case Python3Parser.POWER:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 365;\n            this.match(Python3Parser.POWER);\n            this.state = 366;\n            this.vfpdef();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction VfpdefContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_vfpdef;\n    return this;\n}\n\nVfpdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nVfpdefContext.prototype.constructor = VfpdefContext;\n\nVfpdefContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nVfpdefContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterVfpdef(this);\n\t}\n};\n\nVfpdefContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitVfpdef(this);\n\t}\n};\n\nVfpdefContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitVfpdef(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.VfpdefContext = VfpdefContext;\n\nPython3Parser.prototype.vfpdef = function() {\n\n    var localctx = new VfpdefContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 22, Python3Parser.RULE_vfpdef);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 369;\n        this.match(Python3Parser.NAME);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction StmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_stmt;\n    return this;\n}\n\nStmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nStmtContext.prototype.constructor = StmtContext;\n\nStmtContext.prototype.simple_stmt = function() {\n    return this.getTypedRuleContext(Simple_stmtContext,0);\n};\n\nStmtContext.prototype.compound_stmt = function() {\n    return this.getTypedRuleContext(Compound_stmtContext,0);\n};\n\nStmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterStmt(this);\n\t}\n};\n\nStmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitStmt(this);\n\t}\n};\n\nStmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitStmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.StmtContext = StmtContext;\n\nPython3Parser.prototype.stmt = function() {\n\n    var localctx = new StmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 24, Python3Parser.RULE_stmt);\n    try {\n        this.state = 373;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.RETURN:\n        case Python3Parser.RAISE:\n        case Python3Parser.FROM:\n        case Python3Parser.IMPORT:\n        case Python3Parser.GLOBAL:\n        case Python3Parser.NONLOCAL:\n        case Python3Parser.ASSERT:\n        case Python3Parser.LAMBDA:\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.YIELD:\n        case Python3Parser.DEL:\n        case Python3Parser.PASS:\n        case Python3Parser.CONTINUE:\n        case Python3Parser.BREAK:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 371;\n            this.simple_stmt();\n            break;\n        case Python3Parser.DEF:\n        case Python3Parser.IF:\n        case Python3Parser.WHILE:\n        case Python3Parser.FOR:\n        case Python3Parser.TRY:\n        case Python3Parser.WITH:\n        case Python3Parser.CLASS:\n        case Python3Parser.AT:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 372;\n            this.compound_stmt();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Simple_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_simple_stmt;\n    return this;\n}\n\nSimple_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSimple_stmtContext.prototype.constructor = Simple_stmtContext;\n\nSimple_stmtContext.prototype.small_stmt = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Small_stmtContext);\n    } else {\n        return this.getTypedRuleContext(Small_stmtContext,i);\n    }\n};\n\nSimple_stmtContext.prototype.NEWLINE = function() {\n    return this.getToken(Python3Parser.NEWLINE, 0);\n};\n\nSimple_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSimple_stmt(this);\n\t}\n};\n\nSimple_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSimple_stmt(this);\n\t}\n};\n\nSimple_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSimple_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Simple_stmtContext = Simple_stmtContext;\n\nPython3Parser.prototype.simple_stmt = function() {\n\n    var localctx = new Simple_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 26, Python3Parser.RULE_simple_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 375;\n        this.small_stmt();\n        this.state = 380;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,40,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 376;\n                this.match(Python3Parser.SEMI_COLON);\n                this.state = 377;\n                this.small_stmt(); \n            }\n            this.state = 382;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,40,this._ctx);\n        }\n\n        this.state = 384;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.SEMI_COLON) {\n            this.state = 383;\n            this.match(Python3Parser.SEMI_COLON);\n        }\n\n        this.state = 386;\n        this.match(Python3Parser.NEWLINE);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Small_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_small_stmt;\n    return this;\n}\n\nSmall_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSmall_stmtContext.prototype.constructor = Small_stmtContext;\n\nSmall_stmtContext.prototype.expr_stmt = function() {\n    return this.getTypedRuleContext(Expr_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.del_stmt = function() {\n    return this.getTypedRuleContext(Del_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.pass_stmt = function() {\n    return this.getTypedRuleContext(Pass_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.flow_stmt = function() {\n    return this.getTypedRuleContext(Flow_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.import_stmt = function() {\n    return this.getTypedRuleContext(Import_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.global_stmt = function() {\n    return this.getTypedRuleContext(Global_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.nonlocal_stmt = function() {\n    return this.getTypedRuleContext(Nonlocal_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.assert_stmt = function() {\n    return this.getTypedRuleContext(Assert_stmtContext,0);\n};\n\nSmall_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSmall_stmt(this);\n\t}\n};\n\nSmall_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSmall_stmt(this);\n\t}\n};\n\nSmall_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSmall_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Small_stmtContext = Small_stmtContext;\n\nPython3Parser.prototype.small_stmt = function() {\n\n    var localctx = new Small_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 28, Python3Parser.RULE_small_stmt);\n    try {\n        this.state = 396;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.LAMBDA:\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 388;\n            this.expr_stmt();\n            break;\n        case Python3Parser.DEL:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 389;\n            this.del_stmt();\n            break;\n        case Python3Parser.PASS:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 390;\n            this.pass_stmt();\n            break;\n        case Python3Parser.RETURN:\n        case Python3Parser.RAISE:\n        case Python3Parser.YIELD:\n        case Python3Parser.CONTINUE:\n        case Python3Parser.BREAK:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 391;\n            this.flow_stmt();\n            break;\n        case Python3Parser.FROM:\n        case Python3Parser.IMPORT:\n            this.enterOuterAlt(localctx, 5);\n            this.state = 392;\n            this.import_stmt();\n            break;\n        case Python3Parser.GLOBAL:\n            this.enterOuterAlt(localctx, 6);\n            this.state = 393;\n            this.global_stmt();\n            break;\n        case Python3Parser.NONLOCAL:\n            this.enterOuterAlt(localctx, 7);\n            this.state = 394;\n            this.nonlocal_stmt();\n            break;\n        case Python3Parser.ASSERT:\n            this.enterOuterAlt(localctx, 8);\n            this.state = 395;\n            this.assert_stmt();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Expr_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_expr_stmt;\n    return this;\n}\n\nExpr_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nExpr_stmtContext.prototype.constructor = Expr_stmtContext;\n\nExpr_stmtContext.prototype.testlist_star_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Testlist_star_exprContext);\n    } else {\n        return this.getTypedRuleContext(Testlist_star_exprContext,i);\n    }\n};\n\nExpr_stmtContext.prototype.augassign = function() {\n    return this.getTypedRuleContext(AugassignContext,0);\n};\n\nExpr_stmtContext.prototype.yield_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Yield_exprContext);\n    } else {\n        return this.getTypedRuleContext(Yield_exprContext,i);\n    }\n};\n\nExpr_stmtContext.prototype.testlist = function() {\n    return this.getTypedRuleContext(TestlistContext,0);\n};\n\nExpr_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterExpr_stmt(this);\n\t}\n};\n\nExpr_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitExpr_stmt(this);\n\t}\n};\n\nExpr_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitExpr_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Expr_stmtContext = Expr_stmtContext;\n\nPython3Parser.prototype.expr_stmt = function() {\n\n    var localctx = new Expr_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 30, Python3Parser.RULE_expr_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 398;\n        this.testlist_star_expr();\n        this.state = 414;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.ADD_ASSIGN:\n        case Python3Parser.SUB_ASSIGN:\n        case Python3Parser.MULT_ASSIGN:\n        case Python3Parser.AT_ASSIGN:\n        case Python3Parser.DIV_ASSIGN:\n        case Python3Parser.MOD_ASSIGN:\n        case Python3Parser.AND_ASSIGN:\n        case Python3Parser.OR_ASSIGN:\n        case Python3Parser.XOR_ASSIGN:\n        case Python3Parser.LEFT_SHIFT_ASSIGN:\n        case Python3Parser.RIGHT_SHIFT_ASSIGN:\n        case Python3Parser.POWER_ASSIGN:\n        case Python3Parser.IDIV_ASSIGN:\n            this.state = 399;\n            this.augassign();\n            this.state = 402;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.YIELD:\n                this.state = 400;\n                this.yield_expr();\n                break;\n            case Python3Parser.LAMBDA:\n            case Python3Parser.NOT:\n            case Python3Parser.NONE:\n            case Python3Parser.TRUE:\n            case Python3Parser.FALSE:\n            case Python3Parser.NAME:\n            case Python3Parser.STRING_LITERAL:\n            case Python3Parser.BYTES_LITERAL:\n            case Python3Parser.DECIMAL_INTEGER:\n            case Python3Parser.OCT_INTEGER:\n            case Python3Parser.HEX_INTEGER:\n            case Python3Parser.BIN_INTEGER:\n            case Python3Parser.FLOAT_NUMBER:\n            case Python3Parser.IMAG_NUMBER:\n            case Python3Parser.ELLIPSIS:\n            case Python3Parser.STAR:\n            case Python3Parser.OPEN_PAREN:\n            case Python3Parser.OPEN_BRACK:\n            case Python3Parser.ADD:\n            case Python3Parser.MINUS:\n            case Python3Parser.NOT_OP:\n            case Python3Parser.OPEN_BRACE:\n                this.state = 401;\n                this.testlist();\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            break;\n        case Python3Parser.NEWLINE:\n        case Python3Parser.SEMI_COLON:\n        case Python3Parser.ASSIGN:\n            this.state = 411;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===Python3Parser.ASSIGN) {\n                this.state = 404;\n                this.match(Python3Parser.ASSIGN);\n                this.state = 407;\n                this._errHandler.sync(this);\n                switch(this._input.LA(1)) {\n                case Python3Parser.YIELD:\n                    this.state = 405;\n                    this.yield_expr();\n                    break;\n                case Python3Parser.LAMBDA:\n                case Python3Parser.NOT:\n                case Python3Parser.NONE:\n                case Python3Parser.TRUE:\n                case Python3Parser.FALSE:\n                case Python3Parser.NAME:\n                case Python3Parser.STRING_LITERAL:\n                case Python3Parser.BYTES_LITERAL:\n                case Python3Parser.DECIMAL_INTEGER:\n                case Python3Parser.OCT_INTEGER:\n                case Python3Parser.HEX_INTEGER:\n                case Python3Parser.BIN_INTEGER:\n                case Python3Parser.FLOAT_NUMBER:\n                case Python3Parser.IMAG_NUMBER:\n                case Python3Parser.ELLIPSIS:\n                case Python3Parser.STAR:\n                case Python3Parser.OPEN_PAREN:\n                case Python3Parser.OPEN_BRACK:\n                case Python3Parser.ADD:\n                case Python3Parser.MINUS:\n                case Python3Parser.NOT_OP:\n                case Python3Parser.OPEN_BRACE:\n                    this.state = 406;\n                    this.testlist_star_expr();\n                    break;\n                default:\n                    throw new antlr4.error.NoViableAltException(this);\n                }\n                this.state = 413;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Testlist_star_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_testlist_star_expr;\n    return this;\n}\n\nTestlist_star_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTestlist_star_exprContext.prototype.constructor = Testlist_star_exprContext;\n\nTestlist_star_exprContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nTestlist_star_exprContext.prototype.star_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Star_exprContext);\n    } else {\n        return this.getTypedRuleContext(Star_exprContext,i);\n    }\n};\n\nTestlist_star_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTestlist_star_expr(this);\n\t}\n};\n\nTestlist_star_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTestlist_star_expr(this);\n\t}\n};\n\nTestlist_star_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTestlist_star_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Testlist_star_exprContext = Testlist_star_exprContext;\n\nPython3Parser.prototype.testlist_star_expr = function() {\n\n    var localctx = new Testlist_star_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 32, Python3Parser.RULE_testlist_star_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 418;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,47,this._ctx);\n        switch(la_) {\n        case 1:\n            this.state = 416;\n            this.test();\n            break;\n\n        case 2:\n            this.state = 417;\n            this.star_expr();\n            break;\n\n        }\n        this.state = 427;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,49,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 420;\n                this.match(Python3Parser.COMMA);\n                this.state = 423;\n                this._errHandler.sync(this);\n                var la_ = this._interp.adaptivePredict(this._input,48,this._ctx);\n                switch(la_) {\n                case 1:\n                    this.state = 421;\n                    this.test();\n                    break;\n\n                case 2:\n                    this.state = 422;\n                    this.star_expr();\n                    break;\n\n                } \n            }\n            this.state = 429;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,49,this._ctx);\n        }\n\n        this.state = 431;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COMMA) {\n            this.state = 430;\n            this.match(Python3Parser.COMMA);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction AugassignContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_augassign;\n    return this;\n}\n\nAugassignContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nAugassignContext.prototype.constructor = AugassignContext;\n\n\nAugassignContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterAugassign(this);\n\t}\n};\n\nAugassignContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitAugassign(this);\n\t}\n};\n\nAugassignContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitAugassign(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.AugassignContext = AugassignContext;\n\nPython3Parser.prototype.augassign = function() {\n\n    var localctx = new AugassignContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 34, Python3Parser.RULE_augassign);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 433;\n        _la = this._input.LA(1);\n        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))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Del_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_del_stmt;\n    return this;\n}\n\nDel_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDel_stmtContext.prototype.constructor = Del_stmtContext;\n\nDel_stmtContext.prototype.DEL = function() {\n    return this.getToken(Python3Parser.DEL, 0);\n};\n\nDel_stmtContext.prototype.exprlist = function() {\n    return this.getTypedRuleContext(ExprlistContext,0);\n};\n\nDel_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDel_stmt(this);\n\t}\n};\n\nDel_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDel_stmt(this);\n\t}\n};\n\nDel_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDel_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Del_stmtContext = Del_stmtContext;\n\nPython3Parser.prototype.del_stmt = function() {\n\n    var localctx = new Del_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 36, Python3Parser.RULE_del_stmt);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 435;\n        this.match(Python3Parser.DEL);\n        this.state = 436;\n        this.exprlist();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Pass_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_pass_stmt;\n    return this;\n}\n\nPass_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nPass_stmtContext.prototype.constructor = Pass_stmtContext;\n\nPass_stmtContext.prototype.PASS = function() {\n    return this.getToken(Python3Parser.PASS, 0);\n};\n\nPass_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterPass_stmt(this);\n\t}\n};\n\nPass_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitPass_stmt(this);\n\t}\n};\n\nPass_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitPass_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Pass_stmtContext = Pass_stmtContext;\n\nPython3Parser.prototype.pass_stmt = function() {\n\n    var localctx = new Pass_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 38, Python3Parser.RULE_pass_stmt);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 438;\n        this.match(Python3Parser.PASS);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Flow_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_flow_stmt;\n    return this;\n}\n\nFlow_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nFlow_stmtContext.prototype.constructor = Flow_stmtContext;\n\nFlow_stmtContext.prototype.break_stmt = function() {\n    return this.getTypedRuleContext(Break_stmtContext,0);\n};\n\nFlow_stmtContext.prototype.continue_stmt = function() {\n    return this.getTypedRuleContext(Continue_stmtContext,0);\n};\n\nFlow_stmtContext.prototype.return_stmt = function() {\n    return this.getTypedRuleContext(Return_stmtContext,0);\n};\n\nFlow_stmtContext.prototype.raise_stmt = function() {\n    return this.getTypedRuleContext(Raise_stmtContext,0);\n};\n\nFlow_stmtContext.prototype.yield_stmt = function() {\n    return this.getTypedRuleContext(Yield_stmtContext,0);\n};\n\nFlow_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterFlow_stmt(this);\n\t}\n};\n\nFlow_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitFlow_stmt(this);\n\t}\n};\n\nFlow_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitFlow_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Flow_stmtContext = Flow_stmtContext;\n\nPython3Parser.prototype.flow_stmt = function() {\n\n    var localctx = new Flow_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 40, Python3Parser.RULE_flow_stmt);\n    try {\n        this.state = 445;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.BREAK:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 440;\n            this.break_stmt();\n            break;\n        case Python3Parser.CONTINUE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 441;\n            this.continue_stmt();\n            break;\n        case Python3Parser.RETURN:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 442;\n            this.return_stmt();\n            break;\n        case Python3Parser.RAISE:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 443;\n            this.raise_stmt();\n            break;\n        case Python3Parser.YIELD:\n            this.enterOuterAlt(localctx, 5);\n            this.state = 444;\n            this.yield_stmt();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Break_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_break_stmt;\n    return this;\n}\n\nBreak_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nBreak_stmtContext.prototype.constructor = Break_stmtContext;\n\nBreak_stmtContext.prototype.BREAK = function() {\n    return this.getToken(Python3Parser.BREAK, 0);\n};\n\nBreak_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterBreak_stmt(this);\n\t}\n};\n\nBreak_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitBreak_stmt(this);\n\t}\n};\n\nBreak_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitBreak_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Break_stmtContext = Break_stmtContext;\n\nPython3Parser.prototype.break_stmt = function() {\n\n    var localctx = new Break_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 42, Python3Parser.RULE_break_stmt);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 447;\n        this.match(Python3Parser.BREAK);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Continue_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_continue_stmt;\n    return this;\n}\n\nContinue_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nContinue_stmtContext.prototype.constructor = Continue_stmtContext;\n\nContinue_stmtContext.prototype.CONTINUE = function() {\n    return this.getToken(Python3Parser.CONTINUE, 0);\n};\n\nContinue_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterContinue_stmt(this);\n\t}\n};\n\nContinue_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitContinue_stmt(this);\n\t}\n};\n\nContinue_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitContinue_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Continue_stmtContext = Continue_stmtContext;\n\nPython3Parser.prototype.continue_stmt = function() {\n\n    var localctx = new Continue_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 44, Python3Parser.RULE_continue_stmt);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 449;\n        this.match(Python3Parser.CONTINUE);\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Return_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_return_stmt;\n    return this;\n}\n\nReturn_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nReturn_stmtContext.prototype.constructor = Return_stmtContext;\n\nReturn_stmtContext.prototype.RETURN = function() {\n    return this.getToken(Python3Parser.RETURN, 0);\n};\n\nReturn_stmtContext.prototype.testlist = function() {\n    return this.getTypedRuleContext(TestlistContext,0);\n};\n\nReturn_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterReturn_stmt(this);\n\t}\n};\n\nReturn_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitReturn_stmt(this);\n\t}\n};\n\nReturn_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitReturn_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Return_stmtContext = Return_stmtContext;\n\nPython3Parser.prototype.return_stmt = function() {\n\n    var localctx = new Return_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 46, Python3Parser.RULE_return_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 451;\n        this.match(Python3Parser.RETURN);\n        this.state = 453;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 452;\n            this.testlist();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Yield_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_yield_stmt;\n    return this;\n}\n\nYield_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nYield_stmtContext.prototype.constructor = Yield_stmtContext;\n\nYield_stmtContext.prototype.yield_expr = function() {\n    return this.getTypedRuleContext(Yield_exprContext,0);\n};\n\nYield_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterYield_stmt(this);\n\t}\n};\n\nYield_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitYield_stmt(this);\n\t}\n};\n\nYield_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitYield_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Yield_stmtContext = Yield_stmtContext;\n\nPython3Parser.prototype.yield_stmt = function() {\n\n    var localctx = new Yield_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 48, Python3Parser.RULE_yield_stmt);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 455;\n        this.yield_expr();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Raise_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_raise_stmt;\n    return this;\n}\n\nRaise_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nRaise_stmtContext.prototype.constructor = Raise_stmtContext;\n\nRaise_stmtContext.prototype.RAISE = function() {\n    return this.getToken(Python3Parser.RAISE, 0);\n};\n\nRaise_stmtContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nRaise_stmtContext.prototype.FROM = function() {\n    return this.getToken(Python3Parser.FROM, 0);\n};\n\nRaise_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterRaise_stmt(this);\n\t}\n};\n\nRaise_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitRaise_stmt(this);\n\t}\n};\n\nRaise_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitRaise_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Raise_stmtContext = Raise_stmtContext;\n\nPython3Parser.prototype.raise_stmt = function() {\n\n    var localctx = new Raise_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 50, Python3Parser.RULE_raise_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 457;\n        this.match(Python3Parser.RAISE);\n        this.state = 463;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 458;\n            this.test();\n            this.state = 461;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.FROM) {\n                this.state = 459;\n                this.match(Python3Parser.FROM);\n                this.state = 460;\n                this.test();\n            }\n\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Import_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_import_stmt;\n    return this;\n}\n\nImport_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nImport_stmtContext.prototype.constructor = Import_stmtContext;\n\nImport_stmtContext.prototype.import_name = function() {\n    return this.getTypedRuleContext(Import_nameContext,0);\n};\n\nImport_stmtContext.prototype.import_from = function() {\n    return this.getTypedRuleContext(Import_fromContext,0);\n};\n\nImport_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterImport_stmt(this);\n\t}\n};\n\nImport_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitImport_stmt(this);\n\t}\n};\n\nImport_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitImport_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Import_stmtContext = Import_stmtContext;\n\nPython3Parser.prototype.import_stmt = function() {\n\n    var localctx = new Import_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 52, Python3Parser.RULE_import_stmt);\n    try {\n        this.state = 467;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.IMPORT:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 465;\n            this.import_name();\n            break;\n        case Python3Parser.FROM:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 466;\n            this.import_from();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Import_nameContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_import_name;\n    return this;\n}\n\nImport_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nImport_nameContext.prototype.constructor = Import_nameContext;\n\nImport_nameContext.prototype.IMPORT = function() {\n    return this.getToken(Python3Parser.IMPORT, 0);\n};\n\nImport_nameContext.prototype.dotted_as_names = function() {\n    return this.getTypedRuleContext(Dotted_as_namesContext,0);\n};\n\nImport_nameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterImport_name(this);\n\t}\n};\n\nImport_nameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitImport_name(this);\n\t}\n};\n\nImport_nameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitImport_name(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Import_nameContext = Import_nameContext;\n\nPython3Parser.prototype.import_name = function() {\n\n    var localctx = new Import_nameContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 54, Python3Parser.RULE_import_name);\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 469;\n        this.match(Python3Parser.IMPORT);\n        this.state = 470;\n        this.dotted_as_names();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Import_fromContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_import_from;\n    return this;\n}\n\nImport_fromContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nImport_fromContext.prototype.constructor = Import_fromContext;\n\nImport_fromContext.prototype.FROM = function() {\n    return this.getToken(Python3Parser.FROM, 0);\n};\n\nImport_fromContext.prototype.IMPORT = function() {\n    return this.getToken(Python3Parser.IMPORT, 0);\n};\n\nImport_fromContext.prototype.dotted_name = function() {\n    return this.getTypedRuleContext(Dotted_nameContext,0);\n};\n\nImport_fromContext.prototype.import_as_names = function() {\n    return this.getTypedRuleContext(Import_as_namesContext,0);\n};\n\nImport_fromContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterImport_from(this);\n\t}\n};\n\nImport_fromContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitImport_from(this);\n\t}\n};\n\nImport_fromContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitImport_from(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Import_fromContext = Import_fromContext;\n\nPython3Parser.prototype.import_from = function() {\n\n    var localctx = new Import_fromContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 56, Python3Parser.RULE_import_from);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 472;\n        this.match(Python3Parser.FROM);\n        this.state = 485;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,58,this._ctx);\n        switch(la_) {\n        case 1:\n            this.state = 476;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            while(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS) {\n                this.state = 473;\n                _la = this._input.LA(1);\n                if(!(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS)) {\n                this._errHandler.recoverInline(this);\n                }\n                else {\n                \tthis._errHandler.reportMatch(this);\n                    this.consume();\n                }\n                this.state = 478;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            }\n            this.state = 479;\n            this.dotted_name();\n            break;\n\n        case 2:\n            this.state = 481; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            do {\n                this.state = 480;\n                _la = this._input.LA(1);\n                if(!(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS)) {\n                this._errHandler.recoverInline(this);\n                }\n                else {\n                \tthis._errHandler.reportMatch(this);\n                    this.consume();\n                }\n                this.state = 483; \n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            } while(_la===Python3Parser.DOT || _la===Python3Parser.ELLIPSIS);\n            break;\n\n        }\n        this.state = 487;\n        this.match(Python3Parser.IMPORT);\n        this.state = 494;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.STAR:\n            this.state = 488;\n            this.match(Python3Parser.STAR);\n            break;\n        case Python3Parser.OPEN_PAREN:\n            this.state = 489;\n            this.match(Python3Parser.OPEN_PAREN);\n            this.state = 490;\n            this.import_as_names();\n            this.state = 491;\n            this.match(Python3Parser.CLOSE_PAREN);\n            break;\n        case Python3Parser.NAME:\n            this.state = 493;\n            this.import_as_names();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Import_as_nameContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_import_as_name;\n    return this;\n}\n\nImport_as_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nImport_as_nameContext.prototype.constructor = Import_as_nameContext;\n\nImport_as_nameContext.prototype.NAME = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.NAME);\n    } else {\n        return this.getToken(Python3Parser.NAME, i);\n    }\n};\n\n\nImport_as_nameContext.prototype.AS = function() {\n    return this.getToken(Python3Parser.AS, 0);\n};\n\nImport_as_nameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterImport_as_name(this);\n\t}\n};\n\nImport_as_nameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitImport_as_name(this);\n\t}\n};\n\nImport_as_nameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitImport_as_name(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Import_as_nameContext = Import_as_nameContext;\n\nPython3Parser.prototype.import_as_name = function() {\n\n    var localctx = new Import_as_nameContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 58, Python3Parser.RULE_import_as_name);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 496;\n        this.match(Python3Parser.NAME);\n        this.state = 499;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.AS) {\n            this.state = 497;\n            this.match(Python3Parser.AS);\n            this.state = 498;\n            this.match(Python3Parser.NAME);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Dotted_as_nameContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_dotted_as_name;\n    return this;\n}\n\nDotted_as_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDotted_as_nameContext.prototype.constructor = Dotted_as_nameContext;\n\nDotted_as_nameContext.prototype.dotted_name = function() {\n    return this.getTypedRuleContext(Dotted_nameContext,0);\n};\n\nDotted_as_nameContext.prototype.AS = function() {\n    return this.getToken(Python3Parser.AS, 0);\n};\n\nDotted_as_nameContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nDotted_as_nameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDotted_as_name(this);\n\t}\n};\n\nDotted_as_nameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDotted_as_name(this);\n\t}\n};\n\nDotted_as_nameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDotted_as_name(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Dotted_as_nameContext = Dotted_as_nameContext;\n\nPython3Parser.prototype.dotted_as_name = function() {\n\n    var localctx = new Dotted_as_nameContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 60, Python3Parser.RULE_dotted_as_name);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 501;\n        this.dotted_name();\n        this.state = 504;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.AS) {\n            this.state = 502;\n            this.match(Python3Parser.AS);\n            this.state = 503;\n            this.match(Python3Parser.NAME);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Import_as_namesContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_import_as_names;\n    return this;\n}\n\nImport_as_namesContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nImport_as_namesContext.prototype.constructor = Import_as_namesContext;\n\nImport_as_namesContext.prototype.import_as_name = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Import_as_nameContext);\n    } else {\n        return this.getTypedRuleContext(Import_as_nameContext,i);\n    }\n};\n\nImport_as_namesContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterImport_as_names(this);\n\t}\n};\n\nImport_as_namesContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitImport_as_names(this);\n\t}\n};\n\nImport_as_namesContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitImport_as_names(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Import_as_namesContext = Import_as_namesContext;\n\nPython3Parser.prototype.import_as_names = function() {\n\n    var localctx = new Import_as_namesContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 62, Python3Parser.RULE_import_as_names);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 506;\n        this.import_as_name();\n        this.state = 511;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,62,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 507;\n                this.match(Python3Parser.COMMA);\n                this.state = 508;\n                this.import_as_name(); \n            }\n            this.state = 513;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,62,this._ctx);\n        }\n\n        this.state = 515;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COMMA) {\n            this.state = 514;\n            this.match(Python3Parser.COMMA);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Dotted_as_namesContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_dotted_as_names;\n    return this;\n}\n\nDotted_as_namesContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDotted_as_namesContext.prototype.constructor = Dotted_as_namesContext;\n\nDotted_as_namesContext.prototype.dotted_as_name = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Dotted_as_nameContext);\n    } else {\n        return this.getTypedRuleContext(Dotted_as_nameContext,i);\n    }\n};\n\nDotted_as_namesContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDotted_as_names(this);\n\t}\n};\n\nDotted_as_namesContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDotted_as_names(this);\n\t}\n};\n\nDotted_as_namesContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDotted_as_names(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Dotted_as_namesContext = Dotted_as_namesContext;\n\nPython3Parser.prototype.dotted_as_names = function() {\n\n    var localctx = new Dotted_as_namesContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 64, Python3Parser.RULE_dotted_as_names);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 517;\n        this.dotted_as_name();\n        this.state = 522;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.COMMA) {\n            this.state = 518;\n            this.match(Python3Parser.COMMA);\n            this.state = 519;\n            this.dotted_as_name();\n            this.state = 524;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Dotted_nameContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_dotted_name;\n    return this;\n}\n\nDotted_nameContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDotted_nameContext.prototype.constructor = Dotted_nameContext;\n\nDotted_nameContext.prototype.NAME = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.NAME);\n    } else {\n        return this.getToken(Python3Parser.NAME, i);\n    }\n};\n\n\nDotted_nameContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDotted_name(this);\n\t}\n};\n\nDotted_nameContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDotted_name(this);\n\t}\n};\n\nDotted_nameContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDotted_name(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Dotted_nameContext = Dotted_nameContext;\n\nPython3Parser.prototype.dotted_name = function() {\n\n    var localctx = new Dotted_nameContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 66, Python3Parser.RULE_dotted_name);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 525;\n        this.match(Python3Parser.NAME);\n        this.state = 530;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.DOT) {\n            this.state = 526;\n            this.match(Python3Parser.DOT);\n            this.state = 527;\n            this.match(Python3Parser.NAME);\n            this.state = 532;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Global_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_global_stmt;\n    return this;\n}\n\nGlobal_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nGlobal_stmtContext.prototype.constructor = Global_stmtContext;\n\nGlobal_stmtContext.prototype.GLOBAL = function() {\n    return this.getToken(Python3Parser.GLOBAL, 0);\n};\n\nGlobal_stmtContext.prototype.NAME = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.NAME);\n    } else {\n        return this.getToken(Python3Parser.NAME, i);\n    }\n};\n\n\nGlobal_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterGlobal_stmt(this);\n\t}\n};\n\nGlobal_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitGlobal_stmt(this);\n\t}\n};\n\nGlobal_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitGlobal_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Global_stmtContext = Global_stmtContext;\n\nPython3Parser.prototype.global_stmt = function() {\n\n    var localctx = new Global_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 68, Python3Parser.RULE_global_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 533;\n        this.match(Python3Parser.GLOBAL);\n        this.state = 534;\n        this.match(Python3Parser.NAME);\n        this.state = 539;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.COMMA) {\n            this.state = 535;\n            this.match(Python3Parser.COMMA);\n            this.state = 536;\n            this.match(Python3Parser.NAME);\n            this.state = 541;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Nonlocal_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_nonlocal_stmt;\n    return this;\n}\n\nNonlocal_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nNonlocal_stmtContext.prototype.constructor = Nonlocal_stmtContext;\n\nNonlocal_stmtContext.prototype.NONLOCAL = function() {\n    return this.getToken(Python3Parser.NONLOCAL, 0);\n};\n\nNonlocal_stmtContext.prototype.NAME = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.NAME);\n    } else {\n        return this.getToken(Python3Parser.NAME, i);\n    }\n};\n\n\nNonlocal_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterNonlocal_stmt(this);\n\t}\n};\n\nNonlocal_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitNonlocal_stmt(this);\n\t}\n};\n\nNonlocal_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitNonlocal_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Nonlocal_stmtContext = Nonlocal_stmtContext;\n\nPython3Parser.prototype.nonlocal_stmt = function() {\n\n    var localctx = new Nonlocal_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 70, Python3Parser.RULE_nonlocal_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 542;\n        this.match(Python3Parser.NONLOCAL);\n        this.state = 543;\n        this.match(Python3Parser.NAME);\n        this.state = 548;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.COMMA) {\n            this.state = 544;\n            this.match(Python3Parser.COMMA);\n            this.state = 545;\n            this.match(Python3Parser.NAME);\n            this.state = 550;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Assert_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_assert_stmt;\n    return this;\n}\n\nAssert_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nAssert_stmtContext.prototype.constructor = Assert_stmtContext;\n\nAssert_stmtContext.prototype.ASSERT = function() {\n    return this.getToken(Python3Parser.ASSERT, 0);\n};\n\nAssert_stmtContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nAssert_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterAssert_stmt(this);\n\t}\n};\n\nAssert_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitAssert_stmt(this);\n\t}\n};\n\nAssert_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitAssert_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Assert_stmtContext = Assert_stmtContext;\n\nPython3Parser.prototype.assert_stmt = function() {\n\n    var localctx = new Assert_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 72, Python3Parser.RULE_assert_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 551;\n        this.match(Python3Parser.ASSERT);\n        this.state = 552;\n        this.test();\n        this.state = 555;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COMMA) {\n            this.state = 553;\n            this.match(Python3Parser.COMMA);\n            this.state = 554;\n            this.test();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Compound_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_compound_stmt;\n    return this;\n}\n\nCompound_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nCompound_stmtContext.prototype.constructor = Compound_stmtContext;\n\nCompound_stmtContext.prototype.if_stmt = function() {\n    return this.getTypedRuleContext(If_stmtContext,0);\n};\n\nCompound_stmtContext.prototype.while_stmt = function() {\n    return this.getTypedRuleContext(While_stmtContext,0);\n};\n\nCompound_stmtContext.prototype.for_stmt = function() {\n    return this.getTypedRuleContext(For_stmtContext,0);\n};\n\nCompound_stmtContext.prototype.try_stmt = function() {\n    return this.getTypedRuleContext(Try_stmtContext,0);\n};\n\nCompound_stmtContext.prototype.with_stmt = function() {\n    return this.getTypedRuleContext(With_stmtContext,0);\n};\n\nCompound_stmtContext.prototype.funcdef = function() {\n    return this.getTypedRuleContext(FuncdefContext,0);\n};\n\nCompound_stmtContext.prototype.classdef = function() {\n    return this.getTypedRuleContext(ClassdefContext,0);\n};\n\nCompound_stmtContext.prototype.decorated = function() {\n    return this.getTypedRuleContext(DecoratedContext,0);\n};\n\nCompound_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterCompound_stmt(this);\n\t}\n};\n\nCompound_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitCompound_stmt(this);\n\t}\n};\n\nCompound_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitCompound_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Compound_stmtContext = Compound_stmtContext;\n\nPython3Parser.prototype.compound_stmt = function() {\n\n    var localctx = new Compound_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 74, Python3Parser.RULE_compound_stmt);\n    try {\n        this.state = 565;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.IF:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 557;\n            this.if_stmt();\n            break;\n        case Python3Parser.WHILE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 558;\n            this.while_stmt();\n            break;\n        case Python3Parser.FOR:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 559;\n            this.for_stmt();\n            break;\n        case Python3Parser.TRY:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 560;\n            this.try_stmt();\n            break;\n        case Python3Parser.WITH:\n            this.enterOuterAlt(localctx, 5);\n            this.state = 561;\n            this.with_stmt();\n            break;\n        case Python3Parser.DEF:\n            this.enterOuterAlt(localctx, 6);\n            this.state = 562;\n            this.funcdef();\n            break;\n        case Python3Parser.CLASS:\n            this.enterOuterAlt(localctx, 7);\n            this.state = 563;\n            this.classdef();\n            break;\n        case Python3Parser.AT:\n            this.enterOuterAlt(localctx, 8);\n            this.state = 564;\n            this.decorated();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction If_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_if_stmt;\n    return this;\n}\n\nIf_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nIf_stmtContext.prototype.constructor = If_stmtContext;\n\nIf_stmtContext.prototype.IF = function() {\n    return this.getToken(Python3Parser.IF, 0);\n};\n\nIf_stmtContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nIf_stmtContext.prototype.suite = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SuiteContext);\n    } else {\n        return this.getTypedRuleContext(SuiteContext,i);\n    }\n};\n\nIf_stmtContext.prototype.ELIF = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.ELIF);\n    } else {\n        return this.getToken(Python3Parser.ELIF, i);\n    }\n};\n\n\nIf_stmtContext.prototype.ELSE = function() {\n    return this.getToken(Python3Parser.ELSE, 0);\n};\n\nIf_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterIf_stmt(this);\n\t}\n};\n\nIf_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitIf_stmt(this);\n\t}\n};\n\nIf_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitIf_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.If_stmtContext = If_stmtContext;\n\nPython3Parser.prototype.if_stmt = function() {\n\n    var localctx = new If_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 76, Python3Parser.RULE_if_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 567;\n        this.match(Python3Parser.IF);\n        this.state = 568;\n        this.test();\n        this.state = 569;\n        this.match(Python3Parser.COLON);\n        this.state = 570;\n        this.suite();\n        this.state = 578;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.ELIF) {\n            this.state = 571;\n            this.match(Python3Parser.ELIF);\n            this.state = 572;\n            this.test();\n            this.state = 573;\n            this.match(Python3Parser.COLON);\n            this.state = 574;\n            this.suite();\n            this.state = 580;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 584;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.ELSE) {\n            this.state = 581;\n            this.match(Python3Parser.ELSE);\n            this.state = 582;\n            this.match(Python3Parser.COLON);\n            this.state = 583;\n            this.suite();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction While_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_while_stmt;\n    return this;\n}\n\nWhile_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nWhile_stmtContext.prototype.constructor = While_stmtContext;\n\nWhile_stmtContext.prototype.WHILE = function() {\n    return this.getToken(Python3Parser.WHILE, 0);\n};\n\nWhile_stmtContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nWhile_stmtContext.prototype.suite = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SuiteContext);\n    } else {\n        return this.getTypedRuleContext(SuiteContext,i);\n    }\n};\n\nWhile_stmtContext.prototype.ELSE = function() {\n    return this.getToken(Python3Parser.ELSE, 0);\n};\n\nWhile_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterWhile_stmt(this);\n\t}\n};\n\nWhile_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitWhile_stmt(this);\n\t}\n};\n\nWhile_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitWhile_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.While_stmtContext = While_stmtContext;\n\nPython3Parser.prototype.while_stmt = function() {\n\n    var localctx = new While_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 78, Python3Parser.RULE_while_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 586;\n        this.match(Python3Parser.WHILE);\n        this.state = 587;\n        this.test();\n        this.state = 588;\n        this.match(Python3Parser.COLON);\n        this.state = 589;\n        this.suite();\n        this.state = 593;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.ELSE) {\n            this.state = 590;\n            this.match(Python3Parser.ELSE);\n            this.state = 591;\n            this.match(Python3Parser.COLON);\n            this.state = 592;\n            this.suite();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction For_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_for_stmt;\n    return this;\n}\n\nFor_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nFor_stmtContext.prototype.constructor = For_stmtContext;\n\nFor_stmtContext.prototype.FOR = function() {\n    return this.getToken(Python3Parser.FOR, 0);\n};\n\nFor_stmtContext.prototype.exprlist = function() {\n    return this.getTypedRuleContext(ExprlistContext,0);\n};\n\nFor_stmtContext.prototype.IN = function() {\n    return this.getToken(Python3Parser.IN, 0);\n};\n\nFor_stmtContext.prototype.testlist = function() {\n    return this.getTypedRuleContext(TestlistContext,0);\n};\n\nFor_stmtContext.prototype.suite = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SuiteContext);\n    } else {\n        return this.getTypedRuleContext(SuiteContext,i);\n    }\n};\n\nFor_stmtContext.prototype.ELSE = function() {\n    return this.getToken(Python3Parser.ELSE, 0);\n};\n\nFor_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterFor_stmt(this);\n\t}\n};\n\nFor_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitFor_stmt(this);\n\t}\n};\n\nFor_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitFor_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.For_stmtContext = For_stmtContext;\n\nPython3Parser.prototype.for_stmt = function() {\n\n    var localctx = new For_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 80, Python3Parser.RULE_for_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 595;\n        this.match(Python3Parser.FOR);\n        this.state = 596;\n        this.exprlist();\n        this.state = 597;\n        this.match(Python3Parser.IN);\n        this.state = 598;\n        this.testlist();\n        this.state = 599;\n        this.match(Python3Parser.COLON);\n        this.state = 600;\n        this.suite();\n        this.state = 604;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.ELSE) {\n            this.state = 601;\n            this.match(Python3Parser.ELSE);\n            this.state = 602;\n            this.match(Python3Parser.COLON);\n            this.state = 603;\n            this.suite();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Try_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_try_stmt;\n    return this;\n}\n\nTry_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTry_stmtContext.prototype.constructor = Try_stmtContext;\n\nTry_stmtContext.prototype.TRY = function() {\n    return this.getToken(Python3Parser.TRY, 0);\n};\n\nTry_stmtContext.prototype.suite = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SuiteContext);\n    } else {\n        return this.getTypedRuleContext(SuiteContext,i);\n    }\n};\n\nTry_stmtContext.prototype.FINALLY = function() {\n    return this.getToken(Python3Parser.FINALLY, 0);\n};\n\nTry_stmtContext.prototype.except_clause = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Except_clauseContext);\n    } else {\n        return this.getTypedRuleContext(Except_clauseContext,i);\n    }\n};\n\nTry_stmtContext.prototype.ELSE = function() {\n    return this.getToken(Python3Parser.ELSE, 0);\n};\n\nTry_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTry_stmt(this);\n\t}\n};\n\nTry_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTry_stmt(this);\n\t}\n};\n\nTry_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTry_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Try_stmtContext = Try_stmtContext;\n\nPython3Parser.prototype.try_stmt = function() {\n\n    var localctx = new Try_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 82, Python3Parser.RULE_try_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 606;\n        this.match(Python3Parser.TRY);\n        this.state = 607;\n        this.match(Python3Parser.COLON);\n        this.state = 608;\n        this.suite();\n        this.state = 630;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.EXCEPT:\n            this.state = 613; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            do {\n                this.state = 609;\n                this.except_clause();\n                this.state = 610;\n                this.match(Python3Parser.COLON);\n                this.state = 611;\n                this.suite();\n                this.state = 615; \n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            } while(_la===Python3Parser.EXCEPT);\n            this.state = 620;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.ELSE) {\n                this.state = 617;\n                this.match(Python3Parser.ELSE);\n                this.state = 618;\n                this.match(Python3Parser.COLON);\n                this.state = 619;\n                this.suite();\n            }\n\n            this.state = 625;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.FINALLY) {\n                this.state = 622;\n                this.match(Python3Parser.FINALLY);\n                this.state = 623;\n                this.match(Python3Parser.COLON);\n                this.state = 624;\n                this.suite();\n            }\n\n            break;\n        case Python3Parser.FINALLY:\n            this.state = 627;\n            this.match(Python3Parser.FINALLY);\n            this.state = 628;\n            this.match(Python3Parser.COLON);\n            this.state = 629;\n            this.suite();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction With_stmtContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_with_stmt;\n    return this;\n}\n\nWith_stmtContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nWith_stmtContext.prototype.constructor = With_stmtContext;\n\nWith_stmtContext.prototype.WITH = function() {\n    return this.getToken(Python3Parser.WITH, 0);\n};\n\nWith_stmtContext.prototype.with_item = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(With_itemContext);\n    } else {\n        return this.getTypedRuleContext(With_itemContext,i);\n    }\n};\n\nWith_stmtContext.prototype.suite = function() {\n    return this.getTypedRuleContext(SuiteContext,0);\n};\n\nWith_stmtContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterWith_stmt(this);\n\t}\n};\n\nWith_stmtContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitWith_stmt(this);\n\t}\n};\n\nWith_stmtContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitWith_stmt(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.With_stmtContext = With_stmtContext;\n\nPython3Parser.prototype.with_stmt = function() {\n\n    var localctx = new With_stmtContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 84, Python3Parser.RULE_with_stmt);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 632;\n        this.match(Python3Parser.WITH);\n        this.state = 633;\n        this.with_item();\n        this.state = 638;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.COMMA) {\n            this.state = 634;\n            this.match(Python3Parser.COMMA);\n            this.state = 635;\n            this.with_item();\n            this.state = 640;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 641;\n        this.match(Python3Parser.COLON);\n        this.state = 642;\n        this.suite();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction With_itemContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_with_item;\n    return this;\n}\n\nWith_itemContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nWith_itemContext.prototype.constructor = With_itemContext;\n\nWith_itemContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nWith_itemContext.prototype.AS = function() {\n    return this.getToken(Python3Parser.AS, 0);\n};\n\nWith_itemContext.prototype.expr = function() {\n    return this.getTypedRuleContext(ExprContext,0);\n};\n\nWith_itemContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterWith_item(this);\n\t}\n};\n\nWith_itemContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitWith_item(this);\n\t}\n};\n\nWith_itemContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitWith_item(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.With_itemContext = With_itemContext;\n\nPython3Parser.prototype.with_item = function() {\n\n    var localctx = new With_itemContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 86, Python3Parser.RULE_with_item);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 644;\n        this.test();\n        this.state = 647;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.AS) {\n            this.state = 645;\n            this.match(Python3Parser.AS);\n            this.state = 646;\n            this.expr();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Except_clauseContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_except_clause;\n    return this;\n}\n\nExcept_clauseContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nExcept_clauseContext.prototype.constructor = Except_clauseContext;\n\nExcept_clauseContext.prototype.EXCEPT = function() {\n    return this.getToken(Python3Parser.EXCEPT, 0);\n};\n\nExcept_clauseContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nExcept_clauseContext.prototype.AS = function() {\n    return this.getToken(Python3Parser.AS, 0);\n};\n\nExcept_clauseContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nExcept_clauseContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterExcept_clause(this);\n\t}\n};\n\nExcept_clauseContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitExcept_clause(this);\n\t}\n};\n\nExcept_clauseContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitExcept_clause(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Except_clauseContext = Except_clauseContext;\n\nPython3Parser.prototype.except_clause = function() {\n\n    var localctx = new Except_clauseContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 88, Python3Parser.RULE_except_clause);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 649;\n        this.match(Python3Parser.EXCEPT);\n        this.state = 655;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 650;\n            this.test();\n            this.state = 653;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.AS) {\n                this.state = 651;\n                this.match(Python3Parser.AS);\n                this.state = 652;\n                this.match(Python3Parser.NAME);\n            }\n\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SuiteContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_suite;\n    return this;\n}\n\nSuiteContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSuiteContext.prototype.constructor = SuiteContext;\n\nSuiteContext.prototype.simple_stmt = function() {\n    return this.getTypedRuleContext(Simple_stmtContext,0);\n};\n\nSuiteContext.prototype.NEWLINE = function() {\n    return this.getToken(Python3Parser.NEWLINE, 0);\n};\n\nSuiteContext.prototype.INDENT = function() {\n    return this.getToken(Python3Parser.INDENT, 0);\n};\n\nSuiteContext.prototype.DEDENT = function() {\n    return this.getToken(Python3Parser.DEDENT, 0);\n};\n\nSuiteContext.prototype.stmt = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(StmtContext);\n    } else {\n        return this.getTypedRuleContext(StmtContext,i);\n    }\n};\n\nSuiteContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSuite(this);\n\t}\n};\n\nSuiteContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSuite(this);\n\t}\n};\n\nSuiteContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSuite(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.SuiteContext = SuiteContext;\n\nPython3Parser.prototype.suite = function() {\n\n    var localctx = new SuiteContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 90, Python3Parser.RULE_suite);\n    var _la = 0; // Token type\n    try {\n        this.state = 667;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.RETURN:\n        case Python3Parser.RAISE:\n        case Python3Parser.FROM:\n        case Python3Parser.IMPORT:\n        case Python3Parser.GLOBAL:\n        case Python3Parser.NONLOCAL:\n        case Python3Parser.ASSERT:\n        case Python3Parser.LAMBDA:\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.YIELD:\n        case Python3Parser.DEL:\n        case Python3Parser.PASS:\n        case Python3Parser.CONTINUE:\n        case Python3Parser.BREAK:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 657;\n            this.simple_stmt();\n            break;\n        case Python3Parser.NEWLINE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 658;\n            this.match(Python3Parser.NEWLINE);\n            this.state = 659;\n            this.match(Python3Parser.INDENT);\n            this.state = 661; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            do {\n                this.state = 660;\n                this.stmt();\n                this.state = 663; \n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            } 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));\n            this.state = 665;\n            this.match(Python3Parser.DEDENT);\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TestContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_test;\n    return this;\n}\n\nTestContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTestContext.prototype.constructor = TestContext;\n\nTestContext.prototype.or_test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Or_testContext);\n    } else {\n        return this.getTypedRuleContext(Or_testContext,i);\n    }\n};\n\nTestContext.prototype.IF = function() {\n    return this.getToken(Python3Parser.IF, 0);\n};\n\nTestContext.prototype.ELSE = function() {\n    return this.getToken(Python3Parser.ELSE, 0);\n};\n\nTestContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nTestContext.prototype.lambdef = function() {\n    return this.getTypedRuleContext(LambdefContext,0);\n};\n\nTestContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTest(this);\n\t}\n};\n\nTestContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTest(this);\n\t}\n};\n\nTestContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTest(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.TestContext = TestContext;\n\nPython3Parser.prototype.test = function() {\n\n    var localctx = new TestContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 92, Python3Parser.RULE_test);\n    var _la = 0; // Token type\n    try {\n        this.state = 678;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 669;\n            this.or_test();\n            this.state = 675;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.IF) {\n                this.state = 670;\n                this.match(Python3Parser.IF);\n                this.state = 671;\n                this.or_test();\n                this.state = 672;\n                this.match(Python3Parser.ELSE);\n                this.state = 673;\n                this.test();\n            }\n\n            break;\n        case Python3Parser.LAMBDA:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 677;\n            this.lambdef();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Test_nocondContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_test_nocond;\n    return this;\n}\n\nTest_nocondContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTest_nocondContext.prototype.constructor = Test_nocondContext;\n\nTest_nocondContext.prototype.or_test = function() {\n    return this.getTypedRuleContext(Or_testContext,0);\n};\n\nTest_nocondContext.prototype.lambdef_nocond = function() {\n    return this.getTypedRuleContext(Lambdef_nocondContext,0);\n};\n\nTest_nocondContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTest_nocond(this);\n\t}\n};\n\nTest_nocondContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTest_nocond(this);\n\t}\n};\n\nTest_nocondContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTest_nocond(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Test_nocondContext = Test_nocondContext;\n\nPython3Parser.prototype.test_nocond = function() {\n\n    var localctx = new Test_nocondContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 94, Python3Parser.RULE_test_nocond);\n    try {\n        this.state = 682;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 680;\n            this.or_test();\n            break;\n        case Python3Parser.LAMBDA:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 681;\n            this.lambdef_nocond();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction LambdefContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_lambdef;\n    return this;\n}\n\nLambdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nLambdefContext.prototype.constructor = LambdefContext;\n\nLambdefContext.prototype.LAMBDA = function() {\n    return this.getToken(Python3Parser.LAMBDA, 0);\n};\n\nLambdefContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nLambdefContext.prototype.varargslist = function() {\n    return this.getTypedRuleContext(VarargslistContext,0);\n};\n\nLambdefContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterLambdef(this);\n\t}\n};\n\nLambdefContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitLambdef(this);\n\t}\n};\n\nLambdefContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitLambdef(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.LambdefContext = LambdefContext;\n\nPython3Parser.prototype.lambdef = function() {\n\n    var localctx = new LambdefContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 96, Python3Parser.RULE_lambdef);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 684;\n        this.match(Python3Parser.LAMBDA);\n        this.state = 686;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(((((_la - 35)) & ~0x1f) == 0 && ((1 << (_la - 35)) & ((1 << (Python3Parser.NAME - 35)) | (1 << (Python3Parser.STAR - 35)) | (1 << (Python3Parser.POWER - 35)))) !== 0)) {\n            this.state = 685;\n            this.varargslist();\n        }\n\n        this.state = 688;\n        this.match(Python3Parser.COLON);\n        this.state = 689;\n        this.test();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Lambdef_nocondContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_lambdef_nocond;\n    return this;\n}\n\nLambdef_nocondContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nLambdef_nocondContext.prototype.constructor = Lambdef_nocondContext;\n\nLambdef_nocondContext.prototype.LAMBDA = function() {\n    return this.getToken(Python3Parser.LAMBDA, 0);\n};\n\nLambdef_nocondContext.prototype.test_nocond = function() {\n    return this.getTypedRuleContext(Test_nocondContext,0);\n};\n\nLambdef_nocondContext.prototype.varargslist = function() {\n    return this.getTypedRuleContext(VarargslistContext,0);\n};\n\nLambdef_nocondContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterLambdef_nocond(this);\n\t}\n};\n\nLambdef_nocondContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitLambdef_nocond(this);\n\t}\n};\n\nLambdef_nocondContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitLambdef_nocond(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Lambdef_nocondContext = Lambdef_nocondContext;\n\nPython3Parser.prototype.lambdef_nocond = function() {\n\n    var localctx = new Lambdef_nocondContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 98, Python3Parser.RULE_lambdef_nocond);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 691;\n        this.match(Python3Parser.LAMBDA);\n        this.state = 693;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(((((_la - 35)) & ~0x1f) == 0 && ((1 << (_la - 35)) & ((1 << (Python3Parser.NAME - 35)) | (1 << (Python3Parser.STAR - 35)) | (1 << (Python3Parser.POWER - 35)))) !== 0)) {\n            this.state = 692;\n            this.varargslist();\n        }\n\n        this.state = 695;\n        this.match(Python3Parser.COLON);\n        this.state = 696;\n        this.test_nocond();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Or_testContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_or_test;\n    return this;\n}\n\nOr_testContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nOr_testContext.prototype.constructor = Or_testContext;\n\nOr_testContext.prototype.and_test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(And_testContext);\n    } else {\n        return this.getTypedRuleContext(And_testContext,i);\n    }\n};\n\nOr_testContext.prototype.OR = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.OR);\n    } else {\n        return this.getToken(Python3Parser.OR, i);\n    }\n};\n\n\nOr_testContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterOr_test(this);\n\t}\n};\n\nOr_testContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitOr_test(this);\n\t}\n};\n\nOr_testContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitOr_test(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Or_testContext = Or_testContext;\n\nPython3Parser.prototype.or_test = function() {\n\n    var localctx = new Or_testContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 100, Python3Parser.RULE_or_test);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 698;\n        this.and_test();\n        this.state = 703;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.OR) {\n            this.state = 699;\n            this.match(Python3Parser.OR);\n            this.state = 700;\n            this.and_test();\n            this.state = 705;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction And_testContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_and_test;\n    return this;\n}\n\nAnd_testContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nAnd_testContext.prototype.constructor = And_testContext;\n\nAnd_testContext.prototype.not_test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Not_testContext);\n    } else {\n        return this.getTypedRuleContext(Not_testContext,i);\n    }\n};\n\nAnd_testContext.prototype.AND = function(i) {\n\tif(i===undefined) {\n\t\ti = null;\n\t}\n    if(i===null) {\n        return this.getTokens(Python3Parser.AND);\n    } else {\n        return this.getToken(Python3Parser.AND, i);\n    }\n};\n\n\nAnd_testContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterAnd_test(this);\n\t}\n};\n\nAnd_testContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitAnd_test(this);\n\t}\n};\n\nAnd_testContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitAnd_test(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.And_testContext = And_testContext;\n\nPython3Parser.prototype.and_test = function() {\n\n    var localctx = new And_testContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 102, Python3Parser.RULE_and_test);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 706;\n        this.not_test();\n        this.state = 711;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.AND) {\n            this.state = 707;\n            this.match(Python3Parser.AND);\n            this.state = 708;\n            this.not_test();\n            this.state = 713;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Not_testContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_not_test;\n    return this;\n}\n\nNot_testContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nNot_testContext.prototype.constructor = Not_testContext;\n\nNot_testContext.prototype.NOT = function() {\n    return this.getToken(Python3Parser.NOT, 0);\n};\n\nNot_testContext.prototype.not_test = function() {\n    return this.getTypedRuleContext(Not_testContext,0);\n};\n\nNot_testContext.prototype.comparison = function() {\n    return this.getTypedRuleContext(ComparisonContext,0);\n};\n\nNot_testContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterNot_test(this);\n\t}\n};\n\nNot_testContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitNot_test(this);\n\t}\n};\n\nNot_testContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitNot_test(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Not_testContext = Not_testContext;\n\nPython3Parser.prototype.not_test = function() {\n\n    var localctx = new Not_testContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 104, Python3Parser.RULE_not_test);\n    try {\n        this.state = 717;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.NOT:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 714;\n            this.match(Python3Parser.NOT);\n            this.state = 715;\n            this.not_test();\n            break;\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 716;\n            this.comparison();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ComparisonContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_comparison;\n    return this;\n}\n\nComparisonContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nComparisonContext.prototype.constructor = ComparisonContext;\n\nComparisonContext.prototype.star_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Star_exprContext);\n    } else {\n        return this.getTypedRuleContext(Star_exprContext,i);\n    }\n};\n\nComparisonContext.prototype.comp_op = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Comp_opContext);\n    } else {\n        return this.getTypedRuleContext(Comp_opContext,i);\n    }\n};\n\nComparisonContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterComparison(this);\n\t}\n};\n\nComparisonContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitComparison(this);\n\t}\n};\n\nComparisonContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitComparison(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ComparisonContext = ComparisonContext;\n\nPython3Parser.prototype.comparison = function() {\n\n    var localctx = new ComparisonContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 106, Python3Parser.RULE_comparison);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 719;\n        this.star_expr();\n        this.state = 725;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 720;\n            this.comp_op();\n            this.state = 721;\n            this.star_expr();\n            this.state = 727;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Comp_opContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_comp_op;\n    return this;\n}\n\nComp_opContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nComp_opContext.prototype.constructor = Comp_opContext;\n\nComp_opContext.prototype.IN = function() {\n    return this.getToken(Python3Parser.IN, 0);\n};\n\nComp_opContext.prototype.NOT = function() {\n    return this.getToken(Python3Parser.NOT, 0);\n};\n\nComp_opContext.prototype.IS = function() {\n    return this.getToken(Python3Parser.IS, 0);\n};\n\nComp_opContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterComp_op(this);\n\t}\n};\n\nComp_opContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitComp_op(this);\n\t}\n};\n\nComp_opContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitComp_op(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Comp_opContext = Comp_opContext;\n\nPython3Parser.prototype.comp_op = function() {\n\n    var localctx = new Comp_opContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 108, Python3Parser.RULE_comp_op);\n    try {\n        this.state = 741;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,93,this._ctx);\n        switch(la_) {\n        case 1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 728;\n            this.match(Python3Parser.LESS_THAN);\n            break;\n\n        case 2:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 729;\n            this.match(Python3Parser.GREATER_THAN);\n            break;\n\n        case 3:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 730;\n            this.match(Python3Parser.EQUALS);\n            break;\n\n        case 4:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 731;\n            this.match(Python3Parser.GT_EQ);\n            break;\n\n        case 5:\n            this.enterOuterAlt(localctx, 5);\n            this.state = 732;\n            this.match(Python3Parser.LT_EQ);\n            break;\n\n        case 6:\n            this.enterOuterAlt(localctx, 6);\n            this.state = 733;\n            this.match(Python3Parser.NOT_EQ_1);\n            break;\n\n        case 7:\n            this.enterOuterAlt(localctx, 7);\n            this.state = 734;\n            this.match(Python3Parser.NOT_EQ_2);\n            break;\n\n        case 8:\n            this.enterOuterAlt(localctx, 8);\n            this.state = 735;\n            this.match(Python3Parser.IN);\n            break;\n\n        case 9:\n            this.enterOuterAlt(localctx, 9);\n            this.state = 736;\n            this.match(Python3Parser.NOT);\n            this.state = 737;\n            this.match(Python3Parser.IN);\n            break;\n\n        case 10:\n            this.enterOuterAlt(localctx, 10);\n            this.state = 738;\n            this.match(Python3Parser.IS);\n            break;\n\n        case 11:\n            this.enterOuterAlt(localctx, 11);\n            this.state = 739;\n            this.match(Python3Parser.IS);\n            this.state = 740;\n            this.match(Python3Parser.NOT);\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Star_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_star_expr;\n    return this;\n}\n\nStar_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nStar_exprContext.prototype.constructor = Star_exprContext;\n\nStar_exprContext.prototype.expr = function() {\n    return this.getTypedRuleContext(ExprContext,0);\n};\n\nStar_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterStar_expr(this);\n\t}\n};\n\nStar_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitStar_expr(this);\n\t}\n};\n\nStar_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitStar_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Star_exprContext = Star_exprContext;\n\nPython3Parser.prototype.star_expr = function() {\n\n    var localctx = new Star_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 110, Python3Parser.RULE_star_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 744;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.STAR) {\n            this.state = 743;\n            this.match(Python3Parser.STAR);\n        }\n\n        this.state = 746;\n        this.expr();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ExprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_expr;\n    return this;\n}\n\nExprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nExprContext.prototype.constructor = ExprContext;\n\nExprContext.prototype.xor_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Xor_exprContext);\n    } else {\n        return this.getTypedRuleContext(Xor_exprContext,i);\n    }\n};\n\nExprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterExpr(this);\n\t}\n};\n\nExprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitExpr(this);\n\t}\n};\n\nExprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitExpr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ExprContext = ExprContext;\n\nPython3Parser.prototype.expr = function() {\n\n    var localctx = new ExprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 112, Python3Parser.RULE_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 748;\n        this.xor_expr();\n        this.state = 753;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.OR_OP) {\n            this.state = 749;\n            this.match(Python3Parser.OR_OP);\n            this.state = 750;\n            this.xor_expr();\n            this.state = 755;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Xor_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_xor_expr;\n    return this;\n}\n\nXor_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nXor_exprContext.prototype.constructor = Xor_exprContext;\n\nXor_exprContext.prototype.and_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(And_exprContext);\n    } else {\n        return this.getTypedRuleContext(And_exprContext,i);\n    }\n};\n\nXor_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterXor_expr(this);\n\t}\n};\n\nXor_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitXor_expr(this);\n\t}\n};\n\nXor_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitXor_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Xor_exprContext = Xor_exprContext;\n\nPython3Parser.prototype.xor_expr = function() {\n\n    var localctx = new Xor_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 114, Python3Parser.RULE_xor_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 756;\n        this.and_expr();\n        this.state = 761;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.XOR) {\n            this.state = 757;\n            this.match(Python3Parser.XOR);\n            this.state = 758;\n            this.and_expr();\n            this.state = 763;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction And_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_and_expr;\n    return this;\n}\n\nAnd_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nAnd_exprContext.prototype.constructor = And_exprContext;\n\nAnd_exprContext.prototype.shift_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Shift_exprContext);\n    } else {\n        return this.getTypedRuleContext(Shift_exprContext,i);\n    }\n};\n\nAnd_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterAnd_expr(this);\n\t}\n};\n\nAnd_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitAnd_expr(this);\n\t}\n};\n\nAnd_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitAnd_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.And_exprContext = And_exprContext;\n\nPython3Parser.prototype.and_expr = function() {\n\n    var localctx = new And_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 116, Python3Parser.RULE_and_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 764;\n        this.shift_expr();\n        this.state = 769;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.AND_OP) {\n            this.state = 765;\n            this.match(Python3Parser.AND_OP);\n            this.state = 766;\n            this.shift_expr();\n            this.state = 771;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Shift_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_shift_expr;\n    return this;\n}\n\nShift_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nShift_exprContext.prototype.constructor = Shift_exprContext;\n\nShift_exprContext.prototype.arith_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Arith_exprContext);\n    } else {\n        return this.getTypedRuleContext(Arith_exprContext,i);\n    }\n};\n\nShift_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterShift_expr(this);\n\t}\n};\n\nShift_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitShift_expr(this);\n\t}\n};\n\nShift_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitShift_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Shift_exprContext = Shift_exprContext;\n\nPython3Parser.prototype.shift_expr = function() {\n\n    var localctx = new Shift_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 118, Python3Parser.RULE_shift_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 772;\n        this.arith_expr();\n        this.state = 779;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.LEFT_SHIFT || _la===Python3Parser.RIGHT_SHIFT) {\n            this.state = 777;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.LEFT_SHIFT:\n                this.state = 773;\n                this.match(Python3Parser.LEFT_SHIFT);\n                this.state = 774;\n                this.arith_expr();\n                break;\n            case Python3Parser.RIGHT_SHIFT:\n                this.state = 775;\n                this.match(Python3Parser.RIGHT_SHIFT);\n                this.state = 776;\n                this.arith_expr();\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            this.state = 781;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Arith_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_arith_expr;\n    return this;\n}\n\nArith_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nArith_exprContext.prototype.constructor = Arith_exprContext;\n\nArith_exprContext.prototype.term = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TermContext);\n    } else {\n        return this.getTypedRuleContext(TermContext,i);\n    }\n};\n\nArith_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterArith_expr(this);\n\t}\n};\n\nArith_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitArith_expr(this);\n\t}\n};\n\nArith_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitArith_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Arith_exprContext = Arith_exprContext;\n\nPython3Parser.prototype.arith_expr = function() {\n\n    var localctx = new Arith_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 120, Python3Parser.RULE_arith_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 782;\n        this.term();\n        this.state = 789;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(_la===Python3Parser.ADD || _la===Python3Parser.MINUS) {\n            this.state = 787;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.ADD:\n                this.state = 783;\n                this.match(Python3Parser.ADD);\n                this.state = 784;\n                this.term();\n                break;\n            case Python3Parser.MINUS:\n                this.state = 785;\n                this.match(Python3Parser.MINUS);\n                this.state = 786;\n                this.term();\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            this.state = 791;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TermContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_term;\n    return this;\n}\n\nTermContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTermContext.prototype.constructor = TermContext;\n\nTermContext.prototype.factor = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(FactorContext);\n    } else {\n        return this.getTypedRuleContext(FactorContext,i);\n    }\n};\n\nTermContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTerm(this);\n\t}\n};\n\nTermContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTerm(this);\n\t}\n};\n\nTermContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTerm(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.TermContext = TermContext;\n\nPython3Parser.prototype.term = function() {\n\n    var localctx = new TermContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 122, Python3Parser.RULE_term);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 792;\n        this.factor();\n        this.state = 805;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 803;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.STAR:\n                this.state = 793;\n                this.match(Python3Parser.STAR);\n                this.state = 794;\n                this.factor();\n                break;\n            case Python3Parser.DIV:\n                this.state = 795;\n                this.match(Python3Parser.DIV);\n                this.state = 796;\n                this.factor();\n                break;\n            case Python3Parser.MOD:\n                this.state = 797;\n                this.match(Python3Parser.MOD);\n                this.state = 798;\n                this.factor();\n                break;\n            case Python3Parser.IDIV:\n                this.state = 799;\n                this.match(Python3Parser.IDIV);\n                this.state = 800;\n                this.factor();\n                break;\n            case Python3Parser.AT:\n                this.state = 801;\n                this.match(Python3Parser.AT);\n                this.state = 802;\n                this.factor();\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            this.state = 807;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction FactorContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_factor;\n    return this;\n}\n\nFactorContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nFactorContext.prototype.constructor = FactorContext;\n\nFactorContext.prototype.factor = function() {\n    return this.getTypedRuleContext(FactorContext,0);\n};\n\nFactorContext.prototype.power = function() {\n    return this.getTypedRuleContext(PowerContext,0);\n};\n\nFactorContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterFactor(this);\n\t}\n};\n\nFactorContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitFactor(this);\n\t}\n};\n\nFactorContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitFactor(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.FactorContext = FactorContext;\n\nPython3Parser.prototype.factor = function() {\n\n    var localctx = new FactorContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 124, Python3Parser.RULE_factor);\n    try {\n        this.state = 815;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.ADD:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 808;\n            this.match(Python3Parser.ADD);\n            this.state = 809;\n            this.factor();\n            break;\n        case Python3Parser.MINUS:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 810;\n            this.match(Python3Parser.MINUS);\n            this.state = 811;\n            this.factor();\n            break;\n        case Python3Parser.NOT_OP:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 812;\n            this.match(Python3Parser.NOT_OP);\n            this.state = 813;\n            this.factor();\n            break;\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 814;\n            this.power();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction PowerContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_power;\n    return this;\n}\n\nPowerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nPowerContext.prototype.constructor = PowerContext;\n\nPowerContext.prototype.atom = function() {\n    return this.getTypedRuleContext(AtomContext,0);\n};\n\nPowerContext.prototype.trailer = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TrailerContext);\n    } else {\n        return this.getTypedRuleContext(TrailerContext,i);\n    }\n};\n\nPowerContext.prototype.factor = function() {\n    return this.getTypedRuleContext(FactorContext,0);\n};\n\nPowerContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterPower(this);\n\t}\n};\n\nPowerContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitPower(this);\n\t}\n};\n\nPowerContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitPower(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.PowerContext = PowerContext;\n\nPython3Parser.prototype.power = function() {\n\n    var localctx = new PowerContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 126, Python3Parser.RULE_power);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 817;\n        this.atom();\n        this.state = 821;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        while(((((_la - 44)) & ~0x1f) == 0 && ((1 << (_la - 44)) & ((1 << (Python3Parser.DOT - 44)) | (1 << (Python3Parser.OPEN_PAREN - 44)) | (1 << (Python3Parser.OPEN_BRACK - 44)))) !== 0)) {\n            this.state = 818;\n            this.trailer();\n            this.state = 823;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n        }\n        this.state = 826;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.POWER) {\n            this.state = 824;\n            this.match(Python3Parser.POWER);\n            this.state = 825;\n            this.factor();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction AtomContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_atom;\n    return this;\n}\n\nAtomContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nAtomContext.prototype.constructor = AtomContext;\n\nAtomContext.prototype.yield_expr = function() {\n    return this.getTypedRuleContext(Yield_exprContext,0);\n};\n\nAtomContext.prototype.testlist_comp = function() {\n    return this.getTypedRuleContext(Testlist_compContext,0);\n};\n\nAtomContext.prototype.dictorsetmaker = function() {\n    return this.getTypedRuleContext(DictorsetmakerContext,0);\n};\n\nAtomContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nAtomContext.prototype.number = function() {\n    return this.getTypedRuleContext(NumberContext,0);\n};\n\nAtomContext.prototype.str = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(StrContext);\n    } else {\n        return this.getTypedRuleContext(StrContext,i);\n    }\n};\n\nAtomContext.prototype.NONE = function() {\n    return this.getToken(Python3Parser.NONE, 0);\n};\n\nAtomContext.prototype.TRUE = function() {\n    return this.getToken(Python3Parser.TRUE, 0);\n};\n\nAtomContext.prototype.FALSE = function() {\n    return this.getToken(Python3Parser.FALSE, 0);\n};\n\nAtomContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterAtom(this);\n\t}\n};\n\nAtomContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitAtom(this);\n\t}\n};\n\nAtomContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitAtom(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.AtomContext = AtomContext;\n\nPython3Parser.prototype.atom = function() {\n\n    var localctx = new AtomContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 128, Python3Parser.RULE_atom);\n    var _la = 0; // Token type\n    try {\n        this.state = 855;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.OPEN_PAREN:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 828;\n            this.match(Python3Parser.OPEN_PAREN);\n            this.state = 831;\n            this._errHandler.sync(this);\n            switch (this._input.LA(1)) {\n            case Python3Parser.YIELD:\n            \tthis.state = 829;\n            \tthis.yield_expr();\n            \tbreak;\n            case Python3Parser.LAMBDA:\n            case Python3Parser.NOT:\n            case Python3Parser.NONE:\n            case Python3Parser.TRUE:\n            case Python3Parser.FALSE:\n            case Python3Parser.NAME:\n            case Python3Parser.STRING_LITERAL:\n            case Python3Parser.BYTES_LITERAL:\n            case Python3Parser.DECIMAL_INTEGER:\n            case Python3Parser.OCT_INTEGER:\n            case Python3Parser.HEX_INTEGER:\n            case Python3Parser.BIN_INTEGER:\n            case Python3Parser.FLOAT_NUMBER:\n            case Python3Parser.IMAG_NUMBER:\n            case Python3Parser.ELLIPSIS:\n            case Python3Parser.STAR:\n            case Python3Parser.OPEN_PAREN:\n            case Python3Parser.OPEN_BRACK:\n            case Python3Parser.ADD:\n            case Python3Parser.MINUS:\n            case Python3Parser.NOT_OP:\n            case Python3Parser.OPEN_BRACE:\n            \tthis.state = 830;\n            \tthis.testlist_comp();\n            \tbreak;\n            case Python3Parser.CLOSE_PAREN:\n            \tbreak;\n            default:\n            \tbreak;\n            }\n            this.state = 833;\n            this.match(Python3Parser.CLOSE_PAREN);\n            break;\n        case Python3Parser.OPEN_BRACK:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 834;\n            this.match(Python3Parser.OPEN_BRACK);\n            this.state = 836;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 835;\n                this.testlist_comp();\n            }\n\n            this.state = 838;\n            this.match(Python3Parser.CLOSE_BRACK);\n            break;\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 839;\n            this.match(Python3Parser.OPEN_BRACE);\n            this.state = 841;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 840;\n                this.dictorsetmaker();\n            }\n\n            this.state = 843;\n            this.match(Python3Parser.CLOSE_BRACE);\n            break;\n        case Python3Parser.NAME:\n            this.enterOuterAlt(localctx, 4);\n            this.state = 844;\n            this.match(Python3Parser.NAME);\n            break;\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n            this.enterOuterAlt(localctx, 5);\n            this.state = 845;\n            this.number();\n            break;\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n            this.enterOuterAlt(localctx, 6);\n            this.state = 847; \n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            do {\n                this.state = 846;\n                this.str();\n                this.state = 849; \n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n            } while(_la===Python3Parser.STRING_LITERAL || _la===Python3Parser.BYTES_LITERAL);\n            break;\n        case Python3Parser.ELLIPSIS:\n            this.enterOuterAlt(localctx, 7);\n            this.state = 851;\n            this.match(Python3Parser.ELLIPSIS);\n            break;\n        case Python3Parser.NONE:\n            this.enterOuterAlt(localctx, 8);\n            this.state = 852;\n            this.match(Python3Parser.NONE);\n            break;\n        case Python3Parser.TRUE:\n            this.enterOuterAlt(localctx, 9);\n            this.state = 853;\n            this.match(Python3Parser.TRUE);\n            break;\n        case Python3Parser.FALSE:\n            this.enterOuterAlt(localctx, 10);\n            this.state = 854;\n            this.match(Python3Parser.FALSE);\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Testlist_compContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_testlist_comp;\n    return this;\n}\n\nTestlist_compContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTestlist_compContext.prototype.constructor = Testlist_compContext;\n\nTestlist_compContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nTestlist_compContext.prototype.comp_for = function() {\n    return this.getTypedRuleContext(Comp_forContext,0);\n};\n\nTestlist_compContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTestlist_comp(this);\n\t}\n};\n\nTestlist_compContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTestlist_comp(this);\n\t}\n};\n\nTestlist_compContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTestlist_comp(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Testlist_compContext = Testlist_compContext;\n\nPython3Parser.prototype.testlist_comp = function() {\n\n    var localctx = new Testlist_compContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 130, Python3Parser.RULE_testlist_comp);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 857;\n        this.test();\n        this.state = 869;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.FOR:\n            this.state = 858;\n            this.comp_for();\n            break;\n        case Python3Parser.CLOSE_PAREN:\n        case Python3Parser.COMMA:\n        case Python3Parser.CLOSE_BRACK:\n            this.state = 863;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,112,this._ctx)\n            while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 859;\n                    this.match(Python3Parser.COMMA);\n                    this.state = 860;\n                    this.test(); \n                }\n                this.state = 865;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,112,this._ctx);\n            }\n\n            this.state = 867;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 866;\n                this.match(Python3Parser.COMMA);\n            }\n\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TrailerContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_trailer;\n    return this;\n}\n\nTrailerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTrailerContext.prototype.constructor = TrailerContext;\n\nTrailerContext.prototype.arglist = function() {\n    return this.getTypedRuleContext(ArglistContext,0);\n};\n\nTrailerContext.prototype.subscriptlist = function() {\n    return this.getTypedRuleContext(SubscriptlistContext,0);\n};\n\nTrailerContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nTrailerContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTrailer(this);\n\t}\n};\n\nTrailerContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTrailer(this);\n\t}\n};\n\nTrailerContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTrailer(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.TrailerContext = TrailerContext;\n\nPython3Parser.prototype.trailer = function() {\n\n    var localctx = new TrailerContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 132, Python3Parser.RULE_trailer);\n    var _la = 0; // Token type\n    try {\n        this.state = 882;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.OPEN_PAREN:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 871;\n            this.match(Python3Parser.OPEN_PAREN);\n            this.state = 873;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 872;\n                this.arglist();\n            }\n\n            this.state = 875;\n            this.match(Python3Parser.CLOSE_PAREN);\n            break;\n        case Python3Parser.OPEN_BRACK:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 876;\n            this.match(Python3Parser.OPEN_BRACK);\n            this.state = 877;\n            this.subscriptlist();\n            this.state = 878;\n            this.match(Python3Parser.CLOSE_BRACK);\n            break;\n        case Python3Parser.DOT:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 880;\n            this.match(Python3Parser.DOT);\n            this.state = 881;\n            this.match(Python3Parser.NAME);\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SubscriptlistContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_subscriptlist;\n    return this;\n}\n\nSubscriptlistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSubscriptlistContext.prototype.constructor = SubscriptlistContext;\n\nSubscriptlistContext.prototype.subscript = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(SubscriptContext);\n    } else {\n        return this.getTypedRuleContext(SubscriptContext,i);\n    }\n};\n\nSubscriptlistContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSubscriptlist(this);\n\t}\n};\n\nSubscriptlistContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSubscriptlist(this);\n\t}\n};\n\nSubscriptlistContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSubscriptlist(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.SubscriptlistContext = SubscriptlistContext;\n\nPython3Parser.prototype.subscriptlist = function() {\n\n    var localctx = new SubscriptlistContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 134, Python3Parser.RULE_subscriptlist);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 884;\n        this.subscript();\n        this.state = 889;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,117,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 885;\n                this.match(Python3Parser.COMMA);\n                this.state = 886;\n                this.subscript(); \n            }\n            this.state = 891;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,117,this._ctx);\n        }\n\n        this.state = 893;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COMMA) {\n            this.state = 892;\n            this.match(Python3Parser.COMMA);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SubscriptContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_subscript;\n    return this;\n}\n\nSubscriptContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSubscriptContext.prototype.constructor = SubscriptContext;\n\nSubscriptContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nSubscriptContext.prototype.sliceop = function() {\n    return this.getTypedRuleContext(SliceopContext,0);\n};\n\nSubscriptContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSubscript(this);\n\t}\n};\n\nSubscriptContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSubscript(this);\n\t}\n};\n\nSubscriptContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSubscript(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.SubscriptContext = SubscriptContext;\n\nPython3Parser.prototype.subscript = function() {\n\n    var localctx = new SubscriptContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 136, Python3Parser.RULE_subscript);\n    var _la = 0; // Token type\n    try {\n        this.state = 906;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,122,this._ctx);\n        switch(la_) {\n        case 1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 895;\n            this.test();\n            break;\n\n        case 2:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 897;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 896;\n                this.test();\n            }\n\n            this.state = 899;\n            this.match(Python3Parser.COLON);\n            this.state = 901;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 900;\n                this.test();\n            }\n\n            this.state = 904;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COLON) {\n                this.state = 903;\n                this.sliceop();\n            }\n\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction SliceopContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_sliceop;\n    return this;\n}\n\nSliceopContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nSliceopContext.prototype.constructor = SliceopContext;\n\nSliceopContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nSliceopContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterSliceop(this);\n\t}\n};\n\nSliceopContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitSliceop(this);\n\t}\n};\n\nSliceopContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitSliceop(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.SliceopContext = SliceopContext;\n\nPython3Parser.prototype.sliceop = function() {\n\n    var localctx = new SliceopContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 138, Python3Parser.RULE_sliceop);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 908;\n        this.match(Python3Parser.COLON);\n        this.state = 910;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 909;\n            this.test();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ExprlistContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_exprlist;\n    return this;\n}\n\nExprlistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nExprlistContext.prototype.constructor = ExprlistContext;\n\nExprlistContext.prototype.star_expr = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(Star_exprContext);\n    } else {\n        return this.getTypedRuleContext(Star_exprContext,i);\n    }\n};\n\nExprlistContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterExprlist(this);\n\t}\n};\n\nExprlistContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitExprlist(this);\n\t}\n};\n\nExprlistContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitExprlist(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ExprlistContext = ExprlistContext;\n\nPython3Parser.prototype.exprlist = function() {\n\n    var localctx = new ExprlistContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 140, Python3Parser.RULE_exprlist);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 912;\n        this.star_expr();\n        this.state = 917;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,124,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 913;\n                this.match(Python3Parser.COMMA);\n                this.state = 914;\n                this.star_expr(); \n            }\n            this.state = 919;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,124,this._ctx);\n        }\n\n        this.state = 921;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COMMA) {\n            this.state = 920;\n            this.match(Python3Parser.COMMA);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction TestlistContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_testlist;\n    return this;\n}\n\nTestlistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nTestlistContext.prototype.constructor = TestlistContext;\n\nTestlistContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nTestlistContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterTestlist(this);\n\t}\n};\n\nTestlistContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitTestlist(this);\n\t}\n};\n\nTestlistContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitTestlist(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.TestlistContext = TestlistContext;\n\nPython3Parser.prototype.testlist = function() {\n\n    var localctx = new TestlistContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 142, Python3Parser.RULE_testlist);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 923;\n        this.test();\n        this.state = 928;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,126,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 924;\n                this.match(Python3Parser.COMMA);\n                this.state = 925;\n                this.test(); \n            }\n            this.state = 930;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,126,this._ctx);\n        }\n\n        this.state = 932;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.COMMA) {\n            this.state = 931;\n            this.match(Python3Parser.COMMA);\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction DictorsetmakerContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_dictorsetmaker;\n    return this;\n}\n\nDictorsetmakerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nDictorsetmakerContext.prototype.constructor = DictorsetmakerContext;\n\nDictorsetmakerContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nDictorsetmakerContext.prototype.comp_for = function() {\n    return this.getTypedRuleContext(Comp_forContext,0);\n};\n\nDictorsetmakerContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterDictorsetmaker(this);\n\t}\n};\n\nDictorsetmakerContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitDictorsetmaker(this);\n\t}\n};\n\nDictorsetmakerContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitDictorsetmaker(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.DictorsetmakerContext = DictorsetmakerContext;\n\nPython3Parser.prototype.dictorsetmaker = function() {\n\n    var localctx = new DictorsetmakerContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 144, Python3Parser.RULE_dictorsetmaker);\n    var _la = 0; // Token type\n    try {\n        this.state = 967;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,134,this._ctx);\n        switch(la_) {\n        case 1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 934;\n            this.test();\n            this.state = 935;\n            this.match(Python3Parser.COLON);\n            this.state = 936;\n            this.test();\n            this.state = 951;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.FOR:\n                this.state = 937;\n                this.comp_for();\n                break;\n            case Python3Parser.COMMA:\n            case Python3Parser.CLOSE_BRACE:\n                this.state = 945;\n                this._errHandler.sync(this);\n                var _alt = this._interp.adaptivePredict(this._input,128,this._ctx)\n                while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                    if(_alt===1) {\n                        this.state = 938;\n                        this.match(Python3Parser.COMMA);\n                        this.state = 939;\n                        this.test();\n                        this.state = 940;\n                        this.match(Python3Parser.COLON);\n                        this.state = 941;\n                        this.test(); \n                    }\n                    this.state = 947;\n                    this._errHandler.sync(this);\n                    _alt = this._interp.adaptivePredict(this._input,128,this._ctx);\n                }\n\n                this.state = 949;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                if(_la===Python3Parser.COMMA) {\n                    this.state = 948;\n                    this.match(Python3Parser.COMMA);\n                }\n\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            break;\n\n        case 2:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 953;\n            this.test();\n            this.state = 965;\n            this._errHandler.sync(this);\n            switch(this._input.LA(1)) {\n            case Python3Parser.FOR:\n                this.state = 954;\n                this.comp_for();\n                break;\n            case Python3Parser.COMMA:\n            case Python3Parser.CLOSE_BRACE:\n                this.state = 959;\n                this._errHandler.sync(this);\n                var _alt = this._interp.adaptivePredict(this._input,131,this._ctx)\n                while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                    if(_alt===1) {\n                        this.state = 955;\n                        this.match(Python3Parser.COMMA);\n                        this.state = 956;\n                        this.test(); \n                    }\n                    this.state = 961;\n                    this._errHandler.sync(this);\n                    _alt = this._interp.adaptivePredict(this._input,131,this._ctx);\n                }\n\n                this.state = 963;\n                this._errHandler.sync(this);\n                _la = this._input.LA(1);\n                if(_la===Python3Parser.COMMA) {\n                    this.state = 962;\n                    this.match(Python3Parser.COMMA);\n                }\n\n                break;\n            default:\n                throw new antlr4.error.NoViableAltException(this);\n            }\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ClassdefContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_classdef;\n    return this;\n}\n\nClassdefContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nClassdefContext.prototype.constructor = ClassdefContext;\n\nClassdefContext.prototype.CLASS = function() {\n    return this.getToken(Python3Parser.CLASS, 0);\n};\n\nClassdefContext.prototype.NAME = function() {\n    return this.getToken(Python3Parser.NAME, 0);\n};\n\nClassdefContext.prototype.suite = function() {\n    return this.getTypedRuleContext(SuiteContext,0);\n};\n\nClassdefContext.prototype.arglist = function() {\n    return this.getTypedRuleContext(ArglistContext,0);\n};\n\nClassdefContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterClassdef(this);\n\t}\n};\n\nClassdefContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitClassdef(this);\n\t}\n};\n\nClassdefContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitClassdef(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ClassdefContext = ClassdefContext;\n\nPython3Parser.prototype.classdef = function() {\n\n    var localctx = new ClassdefContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 146, Python3Parser.RULE_classdef);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 969;\n        this.match(Python3Parser.CLASS);\n        this.state = 970;\n        this.match(Python3Parser.NAME);\n        this.state = 976;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.OPEN_PAREN) {\n            this.state = 971;\n            this.match(Python3Parser.OPEN_PAREN);\n            this.state = 973;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            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)) {\n                this.state = 972;\n                this.arglist();\n            }\n\n            this.state = 975;\n            this.match(Python3Parser.CLOSE_PAREN);\n        }\n\n        this.state = 978;\n        this.match(Python3Parser.COLON);\n        this.state = 979;\n        this.suite();\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ArglistContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_arglist;\n    return this;\n}\n\nArglistContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nArglistContext.prototype.constructor = ArglistContext;\n\nArglistContext.prototype.argument = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(ArgumentContext);\n    } else {\n        return this.getTypedRuleContext(ArgumentContext,i);\n    }\n};\n\nArglistContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nArglistContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterArglist(this);\n\t}\n};\n\nArglistContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitArglist(this);\n\t}\n};\n\nArglistContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitArglist(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ArglistContext = ArglistContext;\n\nPython3Parser.prototype.arglist = function() {\n\n    var localctx = new ArglistContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 148, Python3Parser.RULE_arglist);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 986;\n        this._errHandler.sync(this);\n        var _alt = this._interp.adaptivePredict(this._input,137,this._ctx)\n        while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n            if(_alt===1) {\n                this.state = 981;\n                this.argument();\n                this.state = 982;\n                this.match(Python3Parser.COMMA); \n            }\n            this.state = 988;\n            this._errHandler.sync(this);\n            _alt = this._interp.adaptivePredict(this._input,137,this._ctx);\n        }\n\n        this.state = 1009;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,141,this._ctx);\n        switch(la_) {\n        case 1:\n            this.state = 989;\n            this.argument();\n            this.state = 991;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 990;\n                this.match(Python3Parser.COMMA);\n            }\n\n            break;\n\n        case 2:\n            this.state = 993;\n            this.match(Python3Parser.STAR);\n            this.state = 994;\n            this.test();\n            this.state = 999;\n            this._errHandler.sync(this);\n            var _alt = this._interp.adaptivePredict(this._input,139,this._ctx)\n            while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) {\n                if(_alt===1) {\n                    this.state = 995;\n                    this.match(Python3Parser.COMMA);\n                    this.state = 996;\n                    this.argument(); \n                }\n                this.state = 1001;\n                this._errHandler.sync(this);\n                _alt = this._interp.adaptivePredict(this._input,139,this._ctx);\n            }\n\n            this.state = 1005;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.COMMA) {\n                this.state = 1002;\n                this.match(Python3Parser.COMMA);\n                this.state = 1003;\n                this.match(Python3Parser.POWER);\n                this.state = 1004;\n                this.test();\n            }\n\n            break;\n\n        case 3:\n            this.state = 1007;\n            this.match(Python3Parser.POWER);\n            this.state = 1008;\n            this.test();\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction ArgumentContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_argument;\n    return this;\n}\n\nArgumentContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nArgumentContext.prototype.constructor = ArgumentContext;\n\nArgumentContext.prototype.test = function(i) {\n    if(i===undefined) {\n        i = null;\n    }\n    if(i===null) {\n        return this.getTypedRuleContexts(TestContext);\n    } else {\n        return this.getTypedRuleContext(TestContext,i);\n    }\n};\n\nArgumentContext.prototype.comp_for = function() {\n    return this.getTypedRuleContext(Comp_forContext,0);\n};\n\nArgumentContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterArgument(this);\n\t}\n};\n\nArgumentContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitArgument(this);\n\t}\n};\n\nArgumentContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitArgument(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.ArgumentContext = ArgumentContext;\n\nPython3Parser.prototype.argument = function() {\n\n    var localctx = new ArgumentContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 150, Python3Parser.RULE_argument);\n    var _la = 0; // Token type\n    try {\n        this.state = 1019;\n        this._errHandler.sync(this);\n        var la_ = this._interp.adaptivePredict(this._input,143,this._ctx);\n        switch(la_) {\n        case 1:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1011;\n            this.test();\n            this.state = 1013;\n            this._errHandler.sync(this);\n            _la = this._input.LA(1);\n            if(_la===Python3Parser.FOR) {\n                this.state = 1012;\n                this.comp_for();\n            }\n\n            break;\n\n        case 2:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1015;\n            this.test();\n            this.state = 1016;\n            this.match(Python3Parser.ASSIGN);\n            this.state = 1017;\n            this.test();\n            break;\n\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Comp_iterContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_comp_iter;\n    return this;\n}\n\nComp_iterContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nComp_iterContext.prototype.constructor = Comp_iterContext;\n\nComp_iterContext.prototype.comp_for = function() {\n    return this.getTypedRuleContext(Comp_forContext,0);\n};\n\nComp_iterContext.prototype.comp_if = function() {\n    return this.getTypedRuleContext(Comp_ifContext,0);\n};\n\nComp_iterContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterComp_iter(this);\n\t}\n};\n\nComp_iterContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitComp_iter(this);\n\t}\n};\n\nComp_iterContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitComp_iter(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Comp_iterContext = Comp_iterContext;\n\nPython3Parser.prototype.comp_iter = function() {\n\n    var localctx = new Comp_iterContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 152, Python3Parser.RULE_comp_iter);\n    try {\n        this.state = 1023;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.FOR:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1021;\n            this.comp_for();\n            break;\n        case Python3Parser.IF:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1022;\n            this.comp_if();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Comp_forContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_comp_for;\n    return this;\n}\n\nComp_forContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nComp_forContext.prototype.constructor = Comp_forContext;\n\nComp_forContext.prototype.FOR = function() {\n    return this.getToken(Python3Parser.FOR, 0);\n};\n\nComp_forContext.prototype.exprlist = function() {\n    return this.getTypedRuleContext(ExprlistContext,0);\n};\n\nComp_forContext.prototype.IN = function() {\n    return this.getToken(Python3Parser.IN, 0);\n};\n\nComp_forContext.prototype.or_test = function() {\n    return this.getTypedRuleContext(Or_testContext,0);\n};\n\nComp_forContext.prototype.comp_iter = function() {\n    return this.getTypedRuleContext(Comp_iterContext,0);\n};\n\nComp_forContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterComp_for(this);\n\t}\n};\n\nComp_forContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitComp_for(this);\n\t}\n};\n\nComp_forContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitComp_for(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Comp_forContext = Comp_forContext;\n\nPython3Parser.prototype.comp_for = function() {\n\n    var localctx = new Comp_forContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 154, Python3Parser.RULE_comp_for);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1025;\n        this.match(Python3Parser.FOR);\n        this.state = 1026;\n        this.exprlist();\n        this.state = 1027;\n        this.match(Python3Parser.IN);\n        this.state = 1028;\n        this.or_test();\n        this.state = 1030;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.IF || _la===Python3Parser.FOR) {\n            this.state = 1029;\n            this.comp_iter();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Comp_ifContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_comp_if;\n    return this;\n}\n\nComp_ifContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nComp_ifContext.prototype.constructor = Comp_ifContext;\n\nComp_ifContext.prototype.IF = function() {\n    return this.getToken(Python3Parser.IF, 0);\n};\n\nComp_ifContext.prototype.test_nocond = function() {\n    return this.getTypedRuleContext(Test_nocondContext,0);\n};\n\nComp_ifContext.prototype.comp_iter = function() {\n    return this.getTypedRuleContext(Comp_iterContext,0);\n};\n\nComp_ifContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterComp_if(this);\n\t}\n};\n\nComp_ifContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitComp_if(this);\n\t}\n};\n\nComp_ifContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitComp_if(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Comp_ifContext = Comp_ifContext;\n\nPython3Parser.prototype.comp_if = function() {\n\n    var localctx = new Comp_ifContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 156, Python3Parser.RULE_comp_if);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1032;\n        this.match(Python3Parser.IF);\n        this.state = 1033;\n        this.test_nocond();\n        this.state = 1035;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        if(_la===Python3Parser.IF || _la===Python3Parser.FOR) {\n            this.state = 1034;\n            this.comp_iter();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Yield_exprContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_yield_expr;\n    return this;\n}\n\nYield_exprContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nYield_exprContext.prototype.constructor = Yield_exprContext;\n\nYield_exprContext.prototype.YIELD = function() {\n    return this.getToken(Python3Parser.YIELD, 0);\n};\n\nYield_exprContext.prototype.yield_arg = function() {\n    return this.getTypedRuleContext(Yield_argContext,0);\n};\n\nYield_exprContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterYield_expr(this);\n\t}\n};\n\nYield_exprContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitYield_expr(this);\n\t}\n};\n\nYield_exprContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitYield_expr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Yield_exprContext = Yield_exprContext;\n\nPython3Parser.prototype.yield_expr = function() {\n\n    var localctx = new Yield_exprContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 158, Python3Parser.RULE_yield_expr);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1037;\n        this.match(Python3Parser.YIELD);\n        this.state = 1039;\n        this._errHandler.sync(this);\n        _la = this._input.LA(1);\n        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)) {\n            this.state = 1038;\n            this.yield_arg();\n        }\n\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction Yield_argContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_yield_arg;\n    return this;\n}\n\nYield_argContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nYield_argContext.prototype.constructor = Yield_argContext;\n\nYield_argContext.prototype.FROM = function() {\n    return this.getToken(Python3Parser.FROM, 0);\n};\n\nYield_argContext.prototype.test = function() {\n    return this.getTypedRuleContext(TestContext,0);\n};\n\nYield_argContext.prototype.testlist = function() {\n    return this.getTypedRuleContext(TestlistContext,0);\n};\n\nYield_argContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterYield_arg(this);\n\t}\n};\n\nYield_argContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitYield_arg(this);\n\t}\n};\n\nYield_argContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitYield_arg(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.Yield_argContext = Yield_argContext;\n\nPython3Parser.prototype.yield_arg = function() {\n\n    var localctx = new Yield_argContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 160, Python3Parser.RULE_yield_arg);\n    try {\n        this.state = 1044;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.FROM:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1041;\n            this.match(Python3Parser.FROM);\n            this.state = 1042;\n            this.test();\n            break;\n        case Python3Parser.LAMBDA:\n        case Python3Parser.NOT:\n        case Python3Parser.NONE:\n        case Python3Parser.TRUE:\n        case Python3Parser.FALSE:\n        case Python3Parser.NAME:\n        case Python3Parser.STRING_LITERAL:\n        case Python3Parser.BYTES_LITERAL:\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n        case Python3Parser.FLOAT_NUMBER:\n        case Python3Parser.IMAG_NUMBER:\n        case Python3Parser.ELLIPSIS:\n        case Python3Parser.STAR:\n        case Python3Parser.OPEN_PAREN:\n        case Python3Parser.OPEN_BRACK:\n        case Python3Parser.ADD:\n        case Python3Parser.MINUS:\n        case Python3Parser.NOT_OP:\n        case Python3Parser.OPEN_BRACE:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1043;\n            this.testlist();\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction StrContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_str;\n    return this;\n}\n\nStrContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nStrContext.prototype.constructor = StrContext;\n\nStrContext.prototype.STRING_LITERAL = function() {\n    return this.getToken(Python3Parser.STRING_LITERAL, 0);\n};\n\nStrContext.prototype.BYTES_LITERAL = function() {\n    return this.getToken(Python3Parser.BYTES_LITERAL, 0);\n};\n\nStrContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterStr(this);\n\t}\n};\n\nStrContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitStr(this);\n\t}\n};\n\nStrContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitStr(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.StrContext = StrContext;\n\nPython3Parser.prototype.str = function() {\n\n    var localctx = new StrContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 162, Python3Parser.RULE_str);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1046;\n        _la = this._input.LA(1);\n        if(!(_la===Python3Parser.STRING_LITERAL || _la===Python3Parser.BYTES_LITERAL)) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction NumberContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_number;\n    return this;\n}\n\nNumberContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nNumberContext.prototype.constructor = NumberContext;\n\nNumberContext.prototype.integer = function() {\n    return this.getTypedRuleContext(IntegerContext,0);\n};\n\nNumberContext.prototype.FLOAT_NUMBER = function() {\n    return this.getToken(Python3Parser.FLOAT_NUMBER, 0);\n};\n\nNumberContext.prototype.IMAG_NUMBER = function() {\n    return this.getToken(Python3Parser.IMAG_NUMBER, 0);\n};\n\nNumberContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterNumber(this);\n\t}\n};\n\nNumberContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitNumber(this);\n\t}\n};\n\nNumberContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitNumber(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.NumberContext = NumberContext;\n\nPython3Parser.prototype.number = function() {\n\n    var localctx = new NumberContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 164, Python3Parser.RULE_number);\n    try {\n        this.state = 1051;\n        this._errHandler.sync(this);\n        switch(this._input.LA(1)) {\n        case Python3Parser.DECIMAL_INTEGER:\n        case Python3Parser.OCT_INTEGER:\n        case Python3Parser.HEX_INTEGER:\n        case Python3Parser.BIN_INTEGER:\n            this.enterOuterAlt(localctx, 1);\n            this.state = 1048;\n            this.integer();\n            break;\n        case Python3Parser.FLOAT_NUMBER:\n            this.enterOuterAlt(localctx, 2);\n            this.state = 1049;\n            this.match(Python3Parser.FLOAT_NUMBER);\n            break;\n        case Python3Parser.IMAG_NUMBER:\n            this.enterOuterAlt(localctx, 3);\n            this.state = 1050;\n            this.match(Python3Parser.IMAG_NUMBER);\n            break;\n        default:\n            throw new antlr4.error.NoViableAltException(this);\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\nfunction IntegerContext(parser, parent, invokingState) {\n\tif(parent===undefined) {\n\t    parent = null;\n\t}\n\tif(invokingState===undefined || invokingState===null) {\n\t\tinvokingState = -1;\n\t}\n\tantlr4.ParserRuleContext.call(this, parent, invokingState);\n    this.parser = parser;\n    this.ruleIndex = Python3Parser.RULE_integer;\n    return this;\n}\n\nIntegerContext.prototype = Object.create(antlr4.ParserRuleContext.prototype);\nIntegerContext.prototype.constructor = IntegerContext;\n\nIntegerContext.prototype.DECIMAL_INTEGER = function() {\n    return this.getToken(Python3Parser.DECIMAL_INTEGER, 0);\n};\n\nIntegerContext.prototype.OCT_INTEGER = function() {\n    return this.getToken(Python3Parser.OCT_INTEGER, 0);\n};\n\nIntegerContext.prototype.HEX_INTEGER = function() {\n    return this.getToken(Python3Parser.HEX_INTEGER, 0);\n};\n\nIntegerContext.prototype.BIN_INTEGER = function() {\n    return this.getToken(Python3Parser.BIN_INTEGER, 0);\n};\n\nIntegerContext.prototype.enterRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.enterInteger(this);\n\t}\n};\n\nIntegerContext.prototype.exitRule = function(listener) {\n    if(listener instanceof Python3Listener ) {\n        listener.exitInteger(this);\n\t}\n};\n\nIntegerContext.prototype.accept = function(visitor) {\n    if ( visitor instanceof Python3Visitor ) {\n        return visitor.visitInteger(this);\n    } else {\n        return visitor.visitChildren(this);\n    }\n};\n\n\n\n\nPython3Parser.IntegerContext = IntegerContext;\n\nPython3Parser.prototype.integer = function() {\n\n    var localctx = new IntegerContext(this, this._ctx, this.state);\n    this.enterRule(localctx, 166, Python3Parser.RULE_integer);\n    var _la = 0; // Token type\n    try {\n        this.enterOuterAlt(localctx, 1);\n        this.state = 1053;\n        _la = this._input.LA(1);\n        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))) {\n        this._errHandler.recoverInline(this);\n        }\n        else {\n        \tthis._errHandler.reportMatch(this);\n            this.consume();\n        }\n    } catch (re) {\n    \tif(re instanceof antlr4.error.RecognitionException) {\n\t        localctx.exception = re;\n\t        this._errHandler.reportError(this, re);\n\t        this._errHandler.recover(this, re);\n\t    } else {\n\t    \tthrow re;\n\t    }\n    } finally {\n        this.exitRule();\n    }\n    return localctx;\n};\n\n\nexports.Python3Parser = Python3Parser;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/Python3Visitor.js",
    "content": "// Generated from ./lang/python/Python3.g4 by ANTLR 4.7\n// jshint ignore: start\nvar antlr4 = require('antlr4/index');\n\n// This class defines a complete generic visitor for a parse tree produced by Python3Parser.\n\nfunction Python3Visitor() {\n\tantlr4.tree.ParseTreeVisitor.call(this);\n\treturn this;\n}\n\nPython3Visitor.prototype = Object.create(antlr4.tree.ParseTreeVisitor.prototype);\nPython3Visitor.prototype.constructor = Python3Visitor;\n\n// Visit a parse tree produced by Python3Parser#single_input.\nPython3Visitor.prototype.visitSingle_input = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#file_input.\nPython3Visitor.prototype.visitFile_input = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#eval_input.\nPython3Visitor.prototype.visitEval_input = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#decorator.\nPython3Visitor.prototype.visitDecorator = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#decorators.\nPython3Visitor.prototype.visitDecorators = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#decorated.\nPython3Visitor.prototype.visitDecorated = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#funcdef.\nPython3Visitor.prototype.visitFuncdef = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#parameters.\nPython3Visitor.prototype.visitParameters = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#typedargslist.\nPython3Visitor.prototype.visitTypedargslist = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#tfpdef.\nPython3Visitor.prototype.visitTfpdef = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#varargslist.\nPython3Visitor.prototype.visitVarargslist = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#vfpdef.\nPython3Visitor.prototype.visitVfpdef = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#stmt.\nPython3Visitor.prototype.visitStmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#simple_stmt.\nPython3Visitor.prototype.visitSimple_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#small_stmt.\nPython3Visitor.prototype.visitSmall_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#expr_stmt.\nPython3Visitor.prototype.visitExpr_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#testlist_star_expr.\nPython3Visitor.prototype.visitTestlist_star_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#augassign.\nPython3Visitor.prototype.visitAugassign = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#del_stmt.\nPython3Visitor.prototype.visitDel_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#pass_stmt.\nPython3Visitor.prototype.visitPass_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#flow_stmt.\nPython3Visitor.prototype.visitFlow_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#break_stmt.\nPython3Visitor.prototype.visitBreak_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#continue_stmt.\nPython3Visitor.prototype.visitContinue_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#return_stmt.\nPython3Visitor.prototype.visitReturn_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#yield_stmt.\nPython3Visitor.prototype.visitYield_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#raise_stmt.\nPython3Visitor.prototype.visitRaise_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#import_stmt.\nPython3Visitor.prototype.visitImport_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#import_name.\nPython3Visitor.prototype.visitImport_name = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#import_from.\nPython3Visitor.prototype.visitImport_from = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#import_as_name.\nPython3Visitor.prototype.visitImport_as_name = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#dotted_as_name.\nPython3Visitor.prototype.visitDotted_as_name = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#import_as_names.\nPython3Visitor.prototype.visitImport_as_names = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#dotted_as_names.\nPython3Visitor.prototype.visitDotted_as_names = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#dotted_name.\nPython3Visitor.prototype.visitDotted_name = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#global_stmt.\nPython3Visitor.prototype.visitGlobal_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#nonlocal_stmt.\nPython3Visitor.prototype.visitNonlocal_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#assert_stmt.\nPython3Visitor.prototype.visitAssert_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#compound_stmt.\nPython3Visitor.prototype.visitCompound_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#if_stmt.\nPython3Visitor.prototype.visitIf_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#while_stmt.\nPython3Visitor.prototype.visitWhile_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#for_stmt.\nPython3Visitor.prototype.visitFor_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#try_stmt.\nPython3Visitor.prototype.visitTry_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#with_stmt.\nPython3Visitor.prototype.visitWith_stmt = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#with_item.\nPython3Visitor.prototype.visitWith_item = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#except_clause.\nPython3Visitor.prototype.visitExcept_clause = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#suite.\nPython3Visitor.prototype.visitSuite = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#test.\nPython3Visitor.prototype.visitTest = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#test_nocond.\nPython3Visitor.prototype.visitTest_nocond = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#lambdef.\nPython3Visitor.prototype.visitLambdef = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#lambdef_nocond.\nPython3Visitor.prototype.visitLambdef_nocond = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#or_test.\nPython3Visitor.prototype.visitOr_test = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#and_test.\nPython3Visitor.prototype.visitAnd_test = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#not_test.\nPython3Visitor.prototype.visitNot_test = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#comparison.\nPython3Visitor.prototype.visitComparison = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#comp_op.\nPython3Visitor.prototype.visitComp_op = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#star_expr.\nPython3Visitor.prototype.visitStar_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#expr.\nPython3Visitor.prototype.visitExpr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#xor_expr.\nPython3Visitor.prototype.visitXor_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#and_expr.\nPython3Visitor.prototype.visitAnd_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#shift_expr.\nPython3Visitor.prototype.visitShift_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#arith_expr.\nPython3Visitor.prototype.visitArith_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#term.\nPython3Visitor.prototype.visitTerm = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#factor.\nPython3Visitor.prototype.visitFactor = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#power.\nPython3Visitor.prototype.visitPower = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#atom.\nPython3Visitor.prototype.visitAtom = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#testlist_comp.\nPython3Visitor.prototype.visitTestlist_comp = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#trailer.\nPython3Visitor.prototype.visitTrailer = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#subscriptlist.\nPython3Visitor.prototype.visitSubscriptlist = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#subscript.\nPython3Visitor.prototype.visitSubscript = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#sliceop.\nPython3Visitor.prototype.visitSliceop = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#exprlist.\nPython3Visitor.prototype.visitExprlist = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#testlist.\nPython3Visitor.prototype.visitTestlist = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#dictorsetmaker.\nPython3Visitor.prototype.visitDictorsetmaker = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#classdef.\nPython3Visitor.prototype.visitClassdef = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#arglist.\nPython3Visitor.prototype.visitArglist = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#argument.\nPython3Visitor.prototype.visitArgument = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#comp_iter.\nPython3Visitor.prototype.visitComp_iter = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#comp_for.\nPython3Visitor.prototype.visitComp_for = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#comp_if.\nPython3Visitor.prototype.visitComp_if = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#yield_expr.\nPython3Visitor.prototype.visitYield_expr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#yield_arg.\nPython3Visitor.prototype.visitYield_arg = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#str.\nPython3Visitor.prototype.visitStr = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#number.\nPython3Visitor.prototype.visitNumber = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n// Visit a parse tree produced by Python3Parser#integer.\nPython3Visitor.prototype.visitInteger = function(ctx) {\n  return this.visitChildren(ctx);\n};\n\n\n\nexports.Python3Visitor = Python3Visitor;"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-grammar/lang/python/index.js",
    "content": "exports.Python3Lexer = require('./lang/python/Python3Lexer');\nexports.Python3Listener = require('./lang/prpythonesto/Python3Listener');\nexports.Python3Parser = require('./lang/python/Python3Parser');\nexports.Python3Visitor = require('./lang/python/Python3Visitor');"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/index.ts",
    "content": "import {PythonWebWorkerMngr} from './web-worker/web-worker-manager';\nexport {PythonWebWorkerMngr};\n\ndeclare var window: any;\nif (typeof window !== 'undefined') {\n  window.biPythonParser = {PythonWebWorkerMngr};\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/parser/errors-listener.ts",
    "content": "import * as antlr4 from 'antlr4';\n\nexport interface IErrorAnnotation {\n  row: number;\n  column: number;\n  text: string;\n  type: string;\n}\n\nexport class PythonErrorListener extends antlr4.error.ErrorListener {\n  private readonly annotations: IErrorAnnotation[] = [];\n\n  getErrors = () => this.annotations;\n\n  syntaxError(recognizer, offendingSymbol, line, column, msg, e) {\n    this.annotations.push({\n      row: line - 1,\n      column,\n      text: msg,\n      type: 'error'\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/parser/index.ts",
    "content": "import {Python3Parser} from '../../python-grammar/lang/python/Python3Parser';\nimport {createTokenizer} from '../tokenizer/index';\nimport {PythonErrorListener, IErrorAnnotation} from './errors-listener';\n\nexport const createParser = (input: string): any => {\n  const tokens = createTokenizer(input);\n  return new Python3Parser(tokens);\n};\n\nexport const getPythonErrors = (input: string) => {\n  const parser = createParser(input);\n  const listener = new PythonErrorListener();\n  parser.removeErrorListeners();\n  parser.addErrorListener(listener);\n  parser.file_input();\n  return listener.getErrors();\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/parser/parser.spec.ts",
    "content": "import {expect} from 'chai';\nimport {getPythonErrors} from './';\n\ndescribe('python parser', () => {\n  it('should pass leagal code:', () => {\n    const code = `\ndef greet(name):\n  print ('Hello', name)\ngreet('Jack')\ngreet('Jill')\ngreet('Bob')\n`;\n    const errors = getPythonErrors(code);\n    expect(errors).to.eqls([]);\n  });\n\n  it('should handle indent error:', () => {\n    const code = `\ndef greet(name):\nprint ('Hello', name)\ngreet('Jack')\ngreet('Jill')\ngreet('Bob')\n`;\n    const errors = getPythonErrors(code);\n    expect(errors.length).to.be.greaterThan(0);\n    expect(errors[0]).to.eql({column: 0, row: 2, text: `missing INDENT at 'print'`, type: 'error'});\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/parser/types.ts",
    "content": "export interface ContextNode {\n  children: Array<ContextNode | Terminal>;\n  exception: any;\n  invokingState: number;\n  parentCtx: ContextNode;\n  parser: any;\n  ruleIndex: number;\n  start: CommonToken;\n  stop: CommonToken;\n}\n\nexport interface Terminal {\n  invokingState: number;\n  parentCtx: ContextNode;\n  symbol: CommonToken;\n}\n\nexport interface CommonToken {\n  channel: number;\n  column: number;\n  line: number;\n  start: number;\n  stop: number;\n  source: any[];\n  tokenIndex: number;\n  type: number; //token type from SqlBase.tokens\n  text: string;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/tokenizer/index.ts",
    "content": "import antlr4 from 'antlr4';\nimport {Python3Lexer} from '../../python-grammar/lang/python/Python3Lexer';\nimport last from 'lodash/last';\nimport {CommonToken} from '../types/index';\n\nexport const createTokenizer = (input: string) => {\n  const stream = new antlr4.InputStream(input);\n  const lexer = new Python3Lexer(stream);\n  const tokenizer = new antlr4.CommonTokenStream(lexer);\n  return tokenizer;\n};\n\nconst generateTokens = (tokenizer: any) => {\n  do {\n    tokenizer.consume();\n  }\n  while (last<any>(tokenizer.tokens).type !== -1);\n\n  return tokenizer.tokens as CommonToken[];\n};\n\nexport function tokenize(input: string) {\n  const tokenizer = createTokenizer(input);\n  return generateTokens(tokenizer);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/types/3rd-party.d.ts",
    "content": "declare module 'antlr4' {\n  const _a: any;\n  export = _a;\n}\n\ndeclare module 'tiny-worker' {\n  export = Worker;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/types/index.ts",
    "content": "export type TokensMap = number;\nexport interface CommonToken {\n  channel: number;\n  column: number;\n  line: number;\n  start: number;\n  stop: number;\n  source: any[];\n  tokenIndex: number;\n  type: TokensMap;\n  text: string;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/types.ts",
    "content": "import {WorkerFunctionsMap, RequestTypeToResponseTypeMap} from '../../../web-worker-infra/web-worker';\nimport {IErrorAnnotation} from '../parser/errors-listener';\n\nexport interface WorkerRequest {\n  'getErrors': string;\n}\n\nexport interface WorkerResponse {\n  'errorsDone': IErrorAnnotation[];\n}\n\nexport interface RequestToResponseMap {\n  'getErrors': 'errorsDone';\n}\n\nexport const RequestToResponseMap: WorkerRqstToResposneMapType = {\n  getErrors: 'errorsDone'\n};\n\nexport type WorkerRqstToResposneMapType =\n  RequestTypeToResponseTypeMap<WorkerRequest, WorkerResponse, RequestToResponseMap>;\n\nexport type PythonWorkerFunctionsMap =\n  WorkerFunctionsMap<WorkerRequest, WorkerResponse, RequestToResponseMap>;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/web-worker-entry.ts",
    "content": "import webWorkerFunc from './web-worker';\n/* tslint:disable */\nwebWorkerFunc(self as any);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/web-worker-manager.ts",
    "content": "import {\n  WorkerRequest,\n  RequestToResponseMap,\n  WorkerResponse\n} from './types';\nimport {TypedWorkerManager} from '../../../web-worker-infra/web-worker-manager';\n\nexport class PythonWebWorkerMngr extends TypedWorkerManager<WorkerRequest, WorkerResponse, RequestToResponseMap> {\n  getErrors(pythonCode: string) {\n    return this.sendMsg({type: 'getErrors', data: pythonCode});\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/python-parser/web-worker/web-worker.ts",
    "content": "import {\n  WorkerRequest,\n  RequestToResponseMap,\n  WorkerResponse,\n  PythonWorkerFunctionsMap\n} from './types';\nimport {getPythonErrors} from '../parser/index';\nimport {TypedWorkerFactory} from '../../../web-worker-infra/web-worker';\n\nconst functionMap: PythonWorkerFunctionsMap = {\n  getErrors: getPythonErrors,\n};\n\nconst pythonWorker =\n  TypedWorkerFactory<WorkerRequest, WorkerResponse, RequestToResponseMap>(RequestToResponseMap, functionMap);\n\nexport default pythonWorker;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/auto-format/index.ts",
    "content": "import SqlFormatter from 'sql-formatter/lib/languages/StandardSqlFormatter.js';\n\nexport const formatSql = (query: string) => new SqlFormatter().format(query);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/index.ts",
    "content": "import {BiSqlWebWorkerMngr} from './web-worker/web-worker-manager';\nexport {BiSqlWebWorkerMngrCtor, BiSqlWebWorkerMngr} from './web-worker/web-worker-manager';\n\ndeclare var window: any;\nif (typeof window !== 'undefined') {\n  window.biSqlParser = {BiSqlWebWorkerMngr};\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/parser/errors-listener.ts",
    "content": "import antlr4 from 'antlr4';\n\nexport interface IErrorAnnotation {\n  row: number;\n  column: number;\n  text: string;\n  type: string;\n}\n\nexport class PrestoErrorListener extends antlr4.error.ErrorListener {\n  private readonly annotations: IErrorAnnotation[] = [];\n\n  getErrors = () => this.annotations;\n\n  syntaxError(recognizer, offendingSymbol, line, column, msg, e) {\n    this.annotations.push({\n      row: line - 1,\n      column,\n      text: msg,\n      type: 'error'\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/parser/index.ts",
    "content": "import antlr4 from 'antlr4';\nimport { SqlBaseParser } from '../../presto-grammar';\nimport { createTokenizer } from '../tokenizer/index';\nimport { PrestoListener } from './presto-listener';\nimport { PrestoErrorListener } from './errors-listener';\n\nexport const createParser = (input: string): any => {\n  const tokens = createTokenizer(input);\n  return new SqlBaseParser(tokens);\n};\n\nexport const createPrestoSyntaxTree = (input: string): any => {\n  const parser = createParser(input);\n  parser.removeErrorListeners();\n  return parser.multiStatement();\n};\n\nexport const parsePrestoSql = (input: string) => {\n  const tree = createPrestoSyntaxTree(input);\n  const prestoListener = new PrestoListener();\n  antlr4.tree.ParseTreeWalker.DEFAULT.walk(prestoListener, tree);\n  return prestoListener.parseResults();\n};\n\nexport const getErrorsPrestoSql = (input: string) => {\n  const parser = createParser(input);\n  const listener = new PrestoErrorListener();\n  parser.removeErrorListeners();\n  parser.addErrorListener(listener);\n  parser.multiStatement();\n  return listener.getErrors();\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/parser/parser.spec.ts",
    "content": "import {expect} from 'chai';\nimport {parsePrestoSql, getErrorsPrestoSql} from './';\n\ndescribe('presto sql basic parser', () => {\n  const defaultTestCase = `select foo,bar from table111 where foo = 'value'`;\n\n  it('should get table name', () => {\n    const results = parsePrestoSql(defaultTestCase);\n    expect(results.tables).to.deep.equal(['table111']);\n  });\n\n  it('should get *qualified* table name', () => {\n    const testCase = `select foo,bar from catalog1.table1 where foo = 'value'`;\n    const results = parsePrestoSql(testCase);\n    expect(results.tables).to.deep.equal(['catalog1.table1']);\n  });\n\n  it('should get column name', () => {\n    const results = parsePrestoSql(defaultTestCase);\n    expect(results.columns).to.deep.equal(['foo', 'bar']);\n  });\n\n  it('should get column name, column is qualified name', () => {\n    const results = parsePrestoSql('select foo.bar from sometable where base.col > 4');\n    expect(results.columns).to.deep.equal(['foo.bar', 'base.col']);\n  });\n\n  it('should have no duplicates', () => {\n    const testcase = `select foo,bar from table111 where foo = 'value' and bar = 'value'`;\n    const results = parsePrestoSql(testcase);\n    expect(results.strings).to.deep.equal([`'value'`]);\n  });\n\n  it('should get subqueries', () => {\n    const testcase = `WITH x AS (SELECT a, MAX(b) AS b FROM t GROUP BY a) SELECT a, b FROM x`;\n    const results = parsePrestoSql(testcase);\n\n    expect(results.subQueries).to.deep.equal(['x']);\n    expect(results.tables).to.deep.equal(['t']);\n  });\n\n  it('should get subqueries, sql not valid', () => {\n    const testcase = `WITH x AS (SELECT a`;\n    const results = parsePrestoSql(testcase);\n    expect(results.subQueries).to.deep.equal(['x']);\n    expect(results.columns).to.deep.equal(['a']);\n  });\n\n  it('should parse multiple queries', () => {\n    const testcase = `select foo from bar; select aa from bb;`;\n    const results = parsePrestoSql(testcase);\n    expect(results.tables).to.deep.equal(['bar', 'bb']);\n  });\n\n  it('should parse alias table', () => {\n    const testcase = `select foo from bar as b; select aa from aaa as a;`;\n    const results = parsePrestoSql(testcase);\n    expect(results.tableAlias).to.deep.equal(['b', 'a']);\n  });\n\n  describe('string constants', () => {\n    it('should get string constants', () => {\n      const results = parsePrestoSql(defaultTestCase);\n      expect(results.strings).to.deep.equal([`'value'`]);\n    });\n\n    it('should get string constants 2', () => {\n      const testcase = `select\n      evid evid_open\n      ,esi esi_open\n      , uuid uuid_open\n      , date_created date_open\n      from users_38\n      where\n      ((evid = 429))\n      and\n      date_created between date '2017-03-01' and  current_date`;\n      const results = parsePrestoSql(testcase);\n      expect(results.strings).to.deep.equal([`'2017-03-01'`]);\n    });\n  });\n});\n\ndescribe('error annotation', () => {\n  const testcase = `\n  select * from where a > 4\n  `;\n\n  it('should get errors', () => {\n    const errors = getErrorsPrestoSql(testcase);\n    expect(errors.length).to.be.at.least(1);\n    expect(errors[0].row).to.be.eq(1);\n    expect(errors[0].text).to.contain('extraneous input \\'where\\' expecting');\n  });\n\n  it('should get errors, query with new lines', () => {\n    const errors = getErrorsPrestoSql(`select *\n\n\n    from b where a > 4;\n\n    select foo\n\n    from where a > 5;\n`);\n    expect(errors.length).to.be.at.least(1);\n    expect(errors[0].row).to.be.eq(7);\n    expect(errors[0].text).to.contain('extraneous input \\'where\\' expecting');\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/parser/presto-listener.ts",
    "content": "import { SqlBaseListener } from '../../presto-grammar';\nimport { ContextNode, Terminal } from './types';\n\nexport class PrestoListener extends SqlBaseListener {\n  private readonly strings: Set<string> = new Set();\n  private readonly tables: Set<string> = new Set();\n  private readonly columns: Set<string> = new Set();\n  private readonly subQueries: Set<string> = new Set();\n  private readonly tableAlias: Set<string> = new Set();\n\n  private allowColumnReference = true;\n\n  parseResults() {\n    const strings = [...this.strings];\n    const columns = [...this.columns];\n    const subQueries = [...this.subQueries];\n    for (const sq of subQueries) {\n      this.tables.delete(sq);\n    }\n    const tables = [...this.tables];\n    const tableAlias = [...this.tableAlias];\n\n    return { strings, tables, columns, subQueries, tableAlias };\n  }\n\n  enterStringLiteral(ctx: ContextNode & { children: [Terminal] }) {\n    this.strings.add(ctx.children[0].symbol.text);\n  }\n\n  enterTableName(ctx: ContextNode) {\n    this.tables.add((ctx as any).qualifiedName().getText());\n  }\n\n  enterColumnReference(ctx: ContextNode) {\n    if (this.allowColumnReference) {\n      this.columns.add(ctx.start.text);\n    }\n  }\n\n  enterDereference(ctx: ContextNode) {\n    this.columns.add((ctx as any).getText());\n    this.allowColumnReference = false;\n  }\n\n  exitDereference(ctx: ContextNode) {\n    this.allowColumnReference = true;\n  }\n\n  enterNamedQuery(ctx: ContextNode) {\n    this.subQueries.add((ctx as any).identifier().getText());\n  }\n\n  enterAliasedRelation(ctx: any) {\n    if (ctx.alias) {\n      this.tableAlias.add(ctx.alias.getText());\n    }\n  }\n  enterSelectSingle(ctx: any) {\n    const identifier = ctx.identifier();\n    if (identifier) {\n      this.columns.add(identifier.getText());\n    }\n  }\n\n  enterTypeConstructor(ctx: any) {\n    this.strings.add(ctx.STRING().getText());\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/parser/types.ts",
    "content": "export interface ContextNode {\n  children: (ContextNode | Terminal)[];\n  exception: any;\n  invokingState: number;\n  parentCtx: ContextNode;\n  parser: any;\n  ruleIndex: number;\n  start: CommonToken;\n  stop: CommonToken;\n}\n\nexport interface Terminal {\n  invokingState: number;\n  parentCtx: ContextNode;\n  symbol: CommonToken;\n}\n\nexport interface CommonToken {\n  channel: number;\n  column: number;\n  line: number;\n  start: number;\n  stop: number;\n  source: any[];\n  tokenIndex: number;\n  type: number; //token type from SqlBase.tokens\n  text: string;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/tokenizer/index.ts",
    "content": "import { TokensMap } from './tokensMap';\nimport antlr4 from 'antlr4';\nimport { SqlBaseLexer } from '../../presto-grammar';\nimport { last, mapValues } from 'lodash';\nimport { CommonToken } from '../types/index';\n\nexport const createTokenizer = (input: string) => {\n  const stream = new antlr4.InputStream(input);\n  const lexer = new SqlBaseLexer(stream);\n  const tokenizer = new antlr4.CommonTokenStream(lexer);\n  return tokenizer;\n};\n\nconst generateTokens = (tokenizer: any) => {\n  do {\n    tokenizer.consume();\n  } while (last<any>(tokenizer.tokens).type !== -1);\n\n  return tokenizer.tokens as CommonToken[];\n};\n\nexport function tokenize(input: string) {\n  const tokenizer = createTokenizer(input);\n  return generateTokens(tokenizer);\n}\n\nexport interface GetIdentifersResult {\n  identifiers: string[];\n  strings: string[];\n}\n\nconst TokenTypeToPropNameMap = new Map<TokensMap, keyof GetIdentifersResult>([\n  [TokensMap.IDENTIFIER, 'identifiers'],\n  [TokensMap.STRING, 'strings'],\n]);\n\nexport function getIdentifiers(tokens: CommonToken[]): GetIdentifersResult {\n  const res = { identifiers: {}, strings: {} };\n\n  tokens.forEach((token) => {\n    const prop = TokenTypeToPropNameMap.get(token.type);\n\n    if (prop) {\n      res[prop][token.text] = true;\n    }\n  });\n\n  return mapValues(res, (t) => Object.keys(t)) as any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/tokenizer/tokenizer.spec.ts",
    "content": "import {expect} from 'chai';\nimport {tokenize, getIdentifiers} from './';\n\ndescribe('presto sql tokenizer', () => {\n  const testCase1 = `select foo,bar from table111 where bla = 'value'`;\n  const testCase2 = `select foo,bar from table111 where foo = 'value'`;\n\n  it('should return identifiers and strings', () => {\n    const tokens = tokenize(testCase1);\n    const identifersAndStrings = getIdentifiers(tokens);\n    expect(identifersAndStrings.identifiers).to.eql(['foo', 'bar', 'table111', 'bla']);\n    expect(identifersAndStrings.strings).to.eql([`'value'`]);\n  });\n\n  it('should return a list without duplicates', () => {\n    const tokens = tokenize(testCase2);\n    const identifersAndStrings = getIdentifiers(tokens);\n    expect(identifersAndStrings.identifiers).to.eql(['foo', 'bar', 'table111']);\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/tokenizer/tokensMap.ts",
    "content": "export enum TokensMap {\n  EOF = -1,\n  T__0 = 1,\n  T__1 = 2,\n  T__2 = 3,\n  T__3 = 4,\n  T__4 = 5,\n  T__5 = 6,\n  T__6 = 7,\n  T__7 = 8,\n  T__8 = 9,\n  SELECT = 10,\n  FROM = 11,\n  ADD = 12,\n  AS = 13,\n  ALL = 14,\n  SOME = 15,\n  ANY = 16,\n  DISTINCT = 17,\n  WHERE = 18,\n  GROUP = 19,\n  BY = 20,\n  GROUPING = 21,\n  SETS = 22,\n  CUBE = 23,\n  ROLLUP = 24,\n  ORDER = 25,\n  HAVING = 26,\n  LIMIT = 27,\n  AT = 28,\n  OR = 29,\n  AND = 30,\n  IN = 31,\n  NOT = 32,\n  NO = 33,\n  EXISTS = 34,\n  BETWEEN = 35,\n  LIKE = 36,\n  IS = 37,\n  NULL = 38,\n  TRUE = 39,\n  FALSE = 40,\n  NULLS = 41,\n  FIRST = 42,\n  LAST = 43,\n  ESCAPE = 44,\n  ASC = 45,\n  DESC = 46,\n  SUBSTRING = 47,\n  POSITION = 48,\n  FOR = 49,\n  TINYINT = 50,\n  SMALLINT = 51,\n  INTEGER = 52,\n  DATE = 53,\n  TIME = 54,\n  TIMESTAMP = 55,\n  INTERVAL = 56,\n  YEAR = 57,\n  MONTH = 58,\n  DAY = 59,\n  HOUR = 60,\n  MINUTE = 61,\n  SECOND = 62,\n  ZONE = 63,\n  CURRENT_DATE = 64,\n  CURRENT_TIME = 65,\n  CURRENT_TIMESTAMP = 66,\n  LOCALTIME = 67,\n  LOCALTIMESTAMP = 68,\n  EXTRACT = 69,\n  CASE = 70,\n  WHEN = 71,\n  THEN = 72,\n  ELSE = 73,\n  END = 74,\n  JOIN = 75,\n  CROSS = 76,\n  OUTER = 77,\n  INNER = 78,\n  LEFT = 79,\n  RIGHT = 80,\n  FULL = 81,\n  NATURAL = 82,\n  USING = 83,\n  ON = 84,\n  FILTER = 85,\n  OVER = 86,\n  PARTITION = 87,\n  RANGE = 88,\n  ROWS = 89,\n  UNBOUNDED = 90,\n  PRECEDING = 91,\n  FOLLOWING = 92,\n  CURRENT = 93,\n  ROW = 94,\n  WITH = 95,\n  RECURSIVE = 96,\n  VALUES = 97,\n  CREATE = 98,\n  SCHEMA = 99,\n  TABLE = 100,\n  VIEW = 101,\n  REPLACE = 102,\n  INSERT = 103,\n  DELETE = 104,\n  INTO = 105,\n  CONSTRAINT = 106,\n  DESCRIBE = 107,\n  GRANT = 108,\n  REVOKE = 109,\n  PRIVILEGES = 110,\n  PUBLIC = 111,\n  OPTION = 112,\n  EXPLAIN = 113,\n  ANALYZE = 114,\n  FORMAT = 115,\n  TYPE = 116,\n  TEXT = 117,\n  GRAPHVIZ = 118,\n  LOGICAL = 119,\n  DISTRIBUTED = 120,\n  CAST = 121,\n  TRY_CAST = 122,\n  SHOW = 123,\n  TABLES = 124,\n  SCHEMAS = 125,\n  CATALOGS = 126,\n  COLUMNS = 127,\n  COLUMN = 128,\n  USE = 129,\n  PARTITIONS = 130,\n  FUNCTIONS = 131,\n  DROP = 132,\n  UNION = 133,\n  EXCEPT = 134,\n  INTERSECT = 135,\n  TO = 136,\n  SYSTEM = 137,\n  BERNOULLI = 138,\n  POISSONIZED = 139,\n  TABLESAMPLE = 140,\n  ALTER = 141,\n  RENAME = 142,\n  UNNEST = 143,\n  ORDINALITY = 144,\n  ARRAY = 145,\n  MAP = 146,\n  SET = 147,\n  RESET = 148,\n  SESSION = 149,\n  DATA = 150,\n  START = 151,\n  TRANSACTION = 152,\n  COMMIT = 153,\n  ROLLBACK = 154,\n  WORK = 155,\n  ISOLATION = 156,\n  LEVEL = 157,\n  SERIALIZABLE = 158,\n  REPEATABLE = 159,\n  COMMITTED = 160,\n  UNCOMMITTED = 161,\n  READ = 162,\n  WRITE = 163,\n  ONLY = 164,\n  CALL = 165,\n  PREPARE = 166,\n  DEALLOCATE = 167,\n  EXECUTE = 168,\n  INPUT = 169,\n  OUTPUT = 170,\n  CASCADE = 171,\n  RESTRICT = 172,\n  INCLUDING = 173,\n  EXCLUDING = 174,\n  PROPERTIES = 175,\n  NORMALIZE = 176,\n  NFD = 177,\n  NFC = 178,\n  NFKD = 179,\n  NFKC = 180,\n  IF = 181,\n  NULLIF = 182,\n  COALESCE = 183,\n  EQ = 184,\n  NEQ = 185,\n  LT = 186,\n  LTE = 187,\n  GT = 188,\n  GTE = 189,\n  PLUS = 190,\n  MINUS = 191,\n  ASTERISK = 192,\n  SLASH = 193,\n  PERCENT = 194,\n  CONCAT = 195,\n  STRING = 196,\n  BINARY_LITERAL = 197,\n  INTEGER_VALUE = 198,\n  DECIMAL_VALUE = 199,\n  IDENTIFIER = 200,\n  DIGIT_IDENTIFIER = 201,\n  QUOTED_IDENTIFIER = 202,\n  BACKQUOTED_IDENTIFIER = 203,\n  TIME_WITH_TIME_ZONE = 204,\n  TIMESTAMP_WITH_TIME_ZONE = 205,\n  DOUBLE_PRECISION = 206,\n  SIMPLE_COMMENT = 207,\n  BRACKETED_COMMENT = 208,\n  WS = 209,\n  UNRECOGNIZED = 210,\n  DELIMITER = 211,\n  '.' = 1,\n  '(' = 2,\n  ',' = 3,\n  ')' = 4,\n  '?' = 5,\n  '->' = 6,\n  '[' = 7,\n  ']' = 8,\n  '=>' = 9,\n  '=' = 184,\n  '<' = 186,\n  '<=' = 187,\n  '>' = 188,\n  '>=' = 189,\n  '+' = 190,\n  '-' = 191,\n  '*' = 192,\n  '/' = 193,\n  '%' = 194,\n  '||' = 195,\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/types/3rd-party.d.ts",
    "content": "declare module 'antlr4';\ndeclare module 'tiny-worker' {\n  export = Worker;\n}\n\ndeclare module 'sql-formatter/lib/languages/StandardSqlFormatter.js' {\n  export interface SqlFormatterCfg {\n    indent?: number;\n    params?: Record<string, string>\n  }\n  export default class StandardSqlFormatter {\n    constructor(cfg?: SqlFormatterCfg);\n    format(query: string): string;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/types/index.ts",
    "content": "import {TokensMap} from '../tokenizer/tokensMap';\n\nexport interface CommonToken {\n  channel: number;\n  column: number;\n  line: number;\n  start: number;\n  stop: number;\n  source: any[];\n  tokenIndex: number;\n  type: TokensMap; //token type from SqlBase.tokens\n  text: string;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/types.ts",
    "content": "import {WorkerFunctionsMap, RequestTypeToResponseTypeMap} from '../../../web-worker-infra/web-worker';\nimport {IErrorAnnotation} from '../parser/errors-listener';\n\nexport interface SqlRequest {\n  'getIdentifiers': string,\n  'parse': string;\n  'getErrors': string;\n  'autoFormat': string;\n}\n\nexport interface SqlResponse {\n  'getIdentifiersDone': {identifiers: string[]; strings: string[]};\n  'parseDone': {strings: string[]; tables: string[]; subQueries: string[]; columns: string[]};\n  'errorsDone': IErrorAnnotation[];\n  'autoFormatDone': string;\n}\n\nexport interface RequestToResponseMap {\n  'getIdentifiers': 'getIdentifiersDone';\n  'parse': 'parseDone';\n  'getErrors': 'errorsDone';\n  'autoFormat': 'autoFormatDone';\n}\n\nexport const RequestToResponseMap: SqlRqstToResposneMapType = {\n  getIdentifiers: 'getIdentifiersDone',\n  parse: 'parseDone',\n  getErrors: 'errorsDone',\n  autoFormat: 'autoFormatDone'\n};\n\nexport type SqlRqstToResposneMapType =\n  RequestTypeToResponseTypeMap<SqlRequest, SqlResponse, RequestToResponseMap>;\n\nexport type SqlWorkerFunctionsMap =\n  WorkerFunctionsMap<SqlRequest, SqlResponse, RequestToResponseMap>;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/web-worker-entry.ts",
    "content": "import webWorkerFunc from './web-worker';\n/* tslint:disable */\nwebWorkerFunc(self as any);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/web-worker-manager.ts",
    "content": "import {\n  SqlRequest,\n  RequestToResponseMap,\n  SqlResponse\n} from './types';\nimport {TypedWorkerManager} from '../../../web-worker-infra/web-worker-manager';\n\nexport type BiSqlWebWorkerMngrCtor = typeof BiSqlWebWorkerMngr;\n\nexport class BiSqlWebWorkerMngr extends TypedWorkerManager<SqlRequest, SqlResponse, RequestToResponseMap> {\n\n  getIdentifiers(sqlQuery: string) {\n    return this.sendMsg({type: 'getIdentifiers', data: sqlQuery});\n  }\n\n  getErrors(sqlQuery: string) {\n    return this.sendMsg({type: 'getErrors', data: sqlQuery});\n  }\n\n  parse(sqlQuery: string) {\n    return this.sendMsg({type: 'parse', data: sqlQuery});\n  }\n\n  autoFormat(sqlQuery: string) {\n    return this.sendMsg({type: 'autoFormat', data: sqlQuery});\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/language-parsers/sql-parser/web-worker/web-worker.ts",
    "content": "import * as tokenizer from '../tokenizer';\nimport {\n  SqlRequest,\n  RequestToResponseMap,\n  SqlResponse,\n  SqlWorkerFunctionsMap\n} from './types';\nimport {getErrorsPrestoSql, parsePrestoSql} from '../parser/index';\nimport {TypedWorkerFactory} from '../../../web-worker-infra/web-worker';\nimport {formatSql} from '../auto-format';\n\nconst functionMap: SqlWorkerFunctionsMap = {\n  getErrors: getErrorsPrestoSql,\n  parse: parsePrestoSql,\n  getIdentifiers: (query) => {\n    const tokens = tokenizer.tokenize(query);\n    return tokenizer.getIdentifiers(tokens);\n  },\n  autoFormat: (query) => formatSql(query)\n};\n\nconst sqlWorker =\n  TypedWorkerFactory<SqlRequest, SqlResponse, RequestToResponseMap>(RequestToResponseMap, functionMap);\n\nexport default sqlWorker;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/bootstrap.ts",
    "content": "import angular from 'angular';\nimport 'angular-resource';\nimport 'angular-sanitize';\nimport 'ng-csv';\nimport '../ui';\nimport '../code-editor';\nimport '../viz';\n\nexport default angular.module('bi.runner', [\n  'ngResource',\n  'ngSanitize',\n  'ngCsv',\n  'bi.codeEditor',\n  'bi.ui',\n  'bi.viz'\n]);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/config/index.ts",
    "content": "import {Config} from '../../core';\n\nexport const config = new Config<{\n  executeBaseUrl: string;\n  apiBasePath: string;\n}>();\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/index.ts",
    "content": "export {default as runner} from './runner/runner';\nexport {default as sqlRunner} from './sql-runner/sql-runner';\nexport {default as pythonRunner} from './python-runner/python-runner';\nexport {default as consoleResult} from './results/console/console-result';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/python-runner/python-runner-init.ts",
    "content": "import {last} from 'lodash';\nimport moment from 'moment';\nimport {Runner} from '../../services/runner-service';\nimport {RunnerComponentInstance} from '../runner/runner';\n\nfunction initConsoleEvents(runner: Runner) {\n  const state = runner.getState();\n  const events = runner.getEvents();\n  const id = 'console';\n\n  events.register('log', data => {\n    data = {...data, timestamp: moment().format('HH:mm:ss')};\n\n    const fields = Object.keys(data);\n    const values = [...fields.map(field => data[field])];\n\n    if (!state.getQueryById(id).getFields().length) {\n      events.apply('fields', {id, fields}, {});\n    }\n\n    events.apply('row', {id, values}, {});\n\n    return data;\n  });\n\n  events\n    .append('start', data => {\n      events.apply('query-start', {id}, {});\n      events.apply('query-details', {id, code: 'console'}, {});\n\n      return data;\n    })\n    .prepend('end', data => {\n      state.getQueryById(id) && events.apply('query-end', {id}, {});\n\n      return data;\n    });\n}\n\nfunction initResultEvents(runner: Runner) {\n  const state = runner.getState();\n  const events = runner.getEvents();\n\n  events.append('query-start', () => {\n    state.setTotalNumOfQueries(state.getTotalNumOfQueries() + 1);\n  });\n\n  events.register('query-details', data => {\n    runner.getState().getQueryById(data.id).setTitle(data.id);\n\n    return data;\n  });\n}\n\nfunction initRunnerComponent(runner: Runner, runnerComponentDeferred: Promise<RunnerComponentInstance>) {\n  runner.on('finish', () => {\n    return runnerComponentDeferred.then(runnerComponent => {\n      if (runner.getTotalNumOfQueries() > 1) {\n        runnerComponent.setCurrentQuery(last(runner.getQueries()));\n      }\n    });\n  }, true);\n}\n\nexport default (runner: Runner, runnerComponentDeferred: Promise<RunnerComponentInstance>) => {\n  initConsoleEvents(runner);\n  initResultEvents(runner);\n  initRunnerComponent(runner, runnerComponentDeferred);\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/python-runner/python-runner.html",
    "content": "<bi-runner\n  ng-if=\"vm.enabled\"\n  data=\"model.value\"\n  version=\"version\"\n  runner=\"runner\"\n  br-options=\"{\n    type: type,\n    buttonText: vm.runnerOptions.buttonText,\n    autoRun: options.autoRun,\n  }\"\n  on-run=\"events.onRun(runner)\"\n  on-runner-created=\"events.onRunnerCreated(runner)\"\n  on-runner-destroyed=\"events.onRunnerDestroyed(runner)\"\n  on-load=\"events.onRunnerLoad(instance)\"\n  table-formatter=\"tableFormatter()\"\n  download-file-name=\"downloadFileName({query: query, runner: runner})\"\n>\n  <editor class=\"bi-c-h\">\n    <bi-code-editor\n      class=\"bi-c-h\"\n      ng-model=\"model.value\"\n      bce-options=\"::{\n        focus: options.focus,\n        params: options.params,\n        customParams: options.customParams,\n        fitContent: options.fitContent,\n        shareParams: options.shareParams,\n        dateFormat: options.dateFormat,\n        ace: {mode: 'ace/mode/python'}\n      }\"\n      on-save=\"onSave()\"\n      on-load=\"events.onEditorLoad(instance)\"\n      on-params-share=\"onParamsShare({params: params})\"\n      readonly=\"readonly\"\n    ></bi-code-editor>\n  </editor>\n\n  <result>\n    <bi-console-result ng-if=\"::query.id === 'console'\" query=\"query\"></bi-console-result>\n\n    <bi-viz\n      ng-if=\"::query.id !== 'console'\"\n      class=\"bi-c-h bi-grow\"\n      data=\"query.getResults().buffer\"\n      table-data=\"query.getResults()\"\n      fields=\"query.getRawFields()\"\n      table-fields=\"query.getFields()\"\n      is-partial=\"query.running\"\n      bv-options=\"::{picker: true}\"\n    ></bi-viz>\n  </result>\n\n  <run-hint>\n    <quix-note-hints ng-if=\"vm.hint.run.enabled && !readonly\"></quix-note-hints>\n  </run-hint>\n</bi-runner>"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/python-runner/python-runner.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n@import '../../../ui/assets/css/def/flex.def';\n\nbi-python-runner {\n  @include flex(column);\n\n  width: 100%;\n  flex-grow: 1;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/python-runner/python-runner.ts",
    "content": "import './python-runner.scss';\nimport template from './python-runner.html';\n\nimport {CodeEditorInstance} from '../../../code-editor';\nimport {createNgModel, initNgScope, inject} from '../../../core';\nimport createRunner, {Runner} from '../../services/runner-service';\nimport {attachErrorHandler} from '../../services/syntax-valdator/syntax-validator-service';\nimport {initPythonWorker} from '../../services/workers/python-parser-worker';\nimport {RunnerComponentInstance} from '../runner/runner';\nimport initPythonRunner from './python-runner-init';\n\nfunction initEditorComponentInstance(scope, editorComponentInstance: CodeEditorInstance, runnerComponentDeferred) {\n  runnerComponentDeferred.then((runnerComponentInstance: RunnerComponentInstance) => {\n    editorComponentInstance.addShortcut('Ctrl-Enter', 'Command-Enter', () => runnerComponentInstance.run(), scope);\n    editorComponentInstance.getSelection()\n      .on('select', text => {\n        scope.vm.selection = text;\n        scope.vm.runnerOptions.buttonText = 'Run selection';\n      })\n      .on('deselect', () => {\n        scope.vm.selection = null;\n        scope.vm.runnerOptions.buttonText = null;\n      });\n\n    runnerComponentInstance.on('error', (rowNumber, msg) => editorComponentInstance.getAnnotator().showError(rowNumber, msg));\n\n    if (editorComponentInstance.getParams().hasParams()) {\n      const code = editorComponentInstance.getParams().formatEmbed({runCustom: true});\n\n      createRunner('python', scope)\n        .run(code)\n        .on('finish', (runner: Runner) => {\n          runner.getCurrentQuery().getResults().buffer.forEach(({k, o}) => {\n            const options = JSON.parse(o);\n            editorComponentInstance.getParams().overrideParam(k, {options});\n          });\n        });\n    }\n  });\n\n  return editorComponentInstance;\n}\n\nfunction initRunnerComponentInstance(scope, runnerComponentInstance: RunnerComponentInstance, editorComponentDeferred) {\n  editorComponentDeferred.then((editorComponentInstance: CodeEditorInstance) => {\n    runnerComponentInstance.setRequestTransformer(() => {\n      const params = editorComponentInstance.getParams();\n\n      const user = params.format(scope.vm.selection || scope.model.value);\n      const autogenerated = params.formatEmbed();\n\n      return `${autogenerated}\\n${user}`;\n    });\n  });\n\n  return runnerComponentInstance;\n}\n\nfunction initRunner(runner: Runner, runnerComponentDeferred, editorComponentDeferred) {\n  runner\n    .on('success', () => editorComponentDeferred.then((editorComponentInstance: CodeEditorInstance) => editorComponentInstance.setValid(true)), true)\n    .on('error', () => editorComponentDeferred.then((editorComponentInstance: CodeEditorInstance) => editorComponentInstance.setValid(false)), true);\n\n  initPythonRunner(runner, runnerComponentDeferred);\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    require: 'ngModel',\n    scope: {\n      runner: '=',\n      version: '=',\n      type: '=',\n      bprOptions: '=',\n      onEditorLoad: '&',\n      onRunnerLoad: '&',\n      onSave: '&',\n      onRun: '&',\n      onRunnerCreated: '&',\n      onRunnerDestroyed: '&',\n      onParamsShare: '&',\n      downloadFileName: '&',\n      readonly: '='\n    },\n\n    link: {\n      pre(scope, element, attrs, ngModel) {\n        const q = inject('$q');\n        const runnerComponentDeferred = q.defer();\n        const editorComponentDeferred = q.defer();\n\n        const componentInstances = inject('$q').all({\n          runnerComponentInstance: runnerComponentDeferred.promise,\n          editorComponentInstance: editorComponentDeferred.promise,\n        });\n\n        const modelConf = createNgModel(scope, ngModel)\n          .formatWith(model => ({value: model}))\n          .parseWith(({value}) => value)\n          .watchDeep(true)\n          .then(() => scope.vm.toggle(true));\n\n        initNgScope(scope)\n          .withOptions('bprOptions', {\n            focus: false,\n            params: false,\n            autoParams: true,\n            customParams: true,\n            showSyntaxErrors: true,\n            fitContent: false,\n            shareParams: false,\n            autoRun: false,\n            dateFormat: null,\n          })\n          .withVM({\n            selection: null,\n            runnerOptions: {\n              buttonText: null\n            },\n            hint: {\n              run: {\n                enabled: true\n              }\n            },\n            viz: {\n              $init() {\n                this.queries = this.createItemsVm({\n                  type: null,\n                  setCurrent(type) {\n                    this.type = type;\n                  },\n                  $init() {\n                    this.setCurrent('table');\n                  }\n                });\n              }\n            }\n          })\n          .withEvents({\n            onRunnerLoad(instance: RunnerComponentInstance) {\n              runnerComponentDeferred.resolve(initRunnerComponentInstance(scope, instance, editorComponentDeferred.promise));\n              scope.onRunnerLoad({instance});\n            },\n            onEditorLoad(instance: CodeEditorInstance) {\n              editorComponentDeferred.resolve(initEditorComponentInstance(scope, instance, runnerComponentDeferred.promise));\n\n              if (!scope.readonly && scope.options.showSyntaxErrors) {\n                attachErrorHandler(initPythonWorker, instance, modelConf).catch(console.error)\n              }\n\n              scope.onEditorLoad({instance});\n            },\n            onRunnerCreated(runner: Runner) {\n              initRunner(runner, runnerComponentDeferred.promise, editorComponentDeferred.promise);\n\n              scope.vm.hint.run.toggle(false);\n              scope.onRunnerCreated({runner});\n            },\n            onRunnerDestroyed(runner) {\n              componentInstances.then(({editorComponentInstance}) => {\n                editorComponentInstance.setValid(null);\n                editorComponentInstance.getAnnotator().hideAll();\n              });\n\n              scope.vm.hint.run.toggle(true);\n              scope.onRunnerDestroyed({runner});\n            },\n            onRun(runner) {\n              scope.onRun({runner});\n            }\n          });\n\n        scope.getCtrlKeyName = () => {\n          return navigator.platform === 'MacIntel' ? 'Command' : 'Ctrl';\n        };\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/results/console/console-result-testkit.ts",
    "content": "import { Testkit } from '../../../../../../test/e2e/driver';\n\nconst enum Hooks {\n  Result = 'console-result-timestamp',\n  ValueRow = 'console-result-value-row'\n}\n\nexport class ConsoleResultTestkit extends Testkit {\n  async getTimestampsCount() {\n    return (await this.query.hooks(Hooks.Result)).length;\n  }\n\n  async getValueRowsCount() {\n    return (await this.query.hooks(Hooks.ValueRow)).length;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/results/console/console-result.html",
    "content": "<div class=\"bi-c bi-theme--darker\" data-hook=\"console-result\"> \n  <div \n    ng-if=\"isTimestampVisible(row.timestamp, $index, $first, $last)\"\n    ng-repeat-start=\"row in query.getResults().buffer\"\n    class=\"console-result-timestamp bi-s-v--x2\"\n    data-hook=\"console-result-timestamp\"\n  >\n    <span class=\"bi-no-select console-result-timestamp-value\">{{::row.timestamp}}</span>\n    <bi-copy-to-clipboard lazy-text=\"groupTextByTimestamp(row.timestamp)\"></bi-copy-to-clipboard>\n  </div>\n  <pre\n    class=\"bi-fade-in\"\n    ng-class=\"::{\n      'bi-white': row.level === 'INFO',\n      'bi-danger': row.level === 'ERROR'\n    }\"\n    ng-repeat-end\n    data-hook=\"console-result-value-row\"\n  >\n    <span class=\"console-result-value\">{{::row.line}}</span>\n  </pre>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/results/console/console-result.scss",
    "content": "@import '../../../../ui/assets/css/def/colors.def';\n@import '../../../../ui/assets/css/def/flex.def';\n\nbi-console-result {\n  @include flex(column);\n\n  height: 100%;\n  padding: 15px;\n  font-family: 'Courier';\n  font-size: 12px;\n  color: $white;\n  background-color: $darker-bg;\n  overflow-y: auto;\n\n  pre {\n    white-space: nowrap;\n    min-height: 17px;\n  }\n\n  bi-copy-to-clipboard {\n    position: absolute;\n    right: 0;\n    top: 0;\n  }\n\n  .console-result-timestamp {\n    position: relative;\n    margin: 0 0 12px 0;\n\n    &:not(:first-child) {\n      margin: 10px 0;\n    }\n\n    &::after {\n      content: '';\n      width: 100%;\n      position: absolute;\n      left: 0;\n      top: 50%;\n      z-index: 1;\n      border-top: 1px solid lighten($darker-bg, 20);\n    }\n\n    .console-result-timestamp-value {\n      $gap-width: 10px;\n      \n      font-size: 0.85em;  \n      padding: 1px $gap-width;\n      position: relative;\n      color: lighten($darker-bg, 80);\n      background-color: lighten($darker-bg, 20);\n      z-index: 2;\n      margin-left: $gap-width + 20px;\n      border-radius: 3px;\n\n      &::before {\n        content: '';\n        position: absolute;\n        width: $gap-width;\n        height: 100%;\n        background-color: $darker-bg;\n        z-index: 2;\n        left: -$gap-width;\n      }\n\n      &::after {\n        content: '';\n        position: absolute;\n        width: $gap-width;\n        height: 100%;\n        background-color: $darker-bg;\n        z-index: 2;\n        right: -$gap-width;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/results/console/console-result.ts",
    "content": "import {IScope} from './console-types';\nimport template from './console-result.html';\nimport './console-result.scss';\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      query: '<',\n    },\n    link: {\n      async pre(scope: IScope) {\n        scope.isTimestampVisible = (timestamp, index, isFirst, isLast) => {\n          return (\n            isFirst ||\n            isLast ||\n            scope.query.getResults().buffer[index - 1].timestamp !== timestamp\n          );\n        };\n\n        scope.groupTextByTimestamp = (timestamp) => {\n          return scope.query\n            .getResults()\n            .buffer.filter(r => r.timestamp === timestamp)\n            .map(r => r.line)\n            .join('\\n');\n        };\n      },\n    },\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/results/console/console-types.ts",
    "content": "import {IScope as ngIScope} from 'angular';\nimport {RunnerQuery} from '../../..';\n\nexport interface IScope extends ngIScope {\n  query: RunnerQuery;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/runner/runner.html",
    "content": "<div class=\"bi-c-h bi-grow\" ng-show=\"options.showEditor\" ng-transclude=\"editor\"></div>\n\n<div class=\"bi-spread bi-s-h--x3 bi-dont-shrink\">\n  <div class=\"bi-r-i bi-align bi-s-h\">\n    <div class=\"bi-button-group\">\n      <button\n        class=\"br-run-toggle bi-button--secondary bi-center\"\n        data-hook=\"runner-toggle-run\"\n        type=\"button\"\n        data-hook=\"runner-toggle-run\"\n        ng-class=\"{'bi-button--danger': vm.runner.enabled}\"\n        ng-click=\"events.onToggleRun()\"\n      >\n        {{vm.runner.enabled ? 'stop' : options.buttonText || 'Run'}}\n      </button>\n\n      <bi-dropdown\n        class=\"br-custom-actions-toggle\"\n        ng-if=\"vm.customActions.enabled && !options.disableCustomActions && !vm.runner.enabled\"\n        bd-options=\"::{align: 'left'}\"\n      >\n        <bi-toggle>\n          <button class=\"bi-button--secondary bi-center bi-caret\"></button>\n        </bi-toggle>\n\n        <div ng-transclude=\"actions\"></div>\n      </bi-dropdown>\n    </div>\n\n    <bi-progress-gauge class=\"bi-fade-in\" ng-if=\"vm.runner.enabled\" value=\"runner.progress\"></bi-progress-gauge>\n\n    <span ng-if=\"!vm.runner.enabled && vm.result.enabled\">\n      <i\n        class=\"br-download-action bi-button--success bi-icon--sm bi-fade-in\"\n        ng-if=\"!vm.result.current.error\"\n        ng-csv=\"::actions.getCsvRows()\"\n        csv-header=\"::actions.getCsvFields()\"\n        filename=\"{{vm.result.csvFileName}}\"\n        quote-strings=\"true\"\n        add-bom=\"true\"\n        lazy-load=\"true\"\n        title=\"Download CSV\"\n      >file_download</i>\n\n      <button class=\"br-download-action bi-button bi-center\" ng-if=\"vm.result.current.error\" disabled=\"disabled\">\n        <i\n          class=\"bi-icon--sm\"\n          title=\"Download CSV\"\n          disabled=\"disabled\"\n        >file_download</i>\n      </button>\n    </span>\n\n    <div class=\"bi-align bi-s-h--x15 bi-muted bi-fade-in\" ng-if=\"vm.runner.enabled || vm.result.enabled\">\n      <div class=\"bi-c bi-fade-in\" ng-if=\"vm.result.current.elapsedTime\">\n        <span class=\"bi-text--sm\">Elapsed time</span>\n        <div class=\"bi-r-i bi-align bi-s-h--x05\">\n          <i class=\"bi-icon--xs\">timer</i>\n          <b class=\"bi-text--sm\">{{vm.result.current.elapsedTime}}</b>\n        </div>\n      </div>\n\n      <div\n        class=\"bi-c bi-fade-in\"\n        ng-if=\"vm.result.current.finished\"\n        title=\"{{vm.result.current.startTime | biDate:'MMM dd, yyyy HH:mm'}}\"\n      >\n        <span class=\"bi-text--sm\">Start time</span>\n        <div class=\"bi-align bi-s-h--x05\">\n          <i class=\"bi-icon--xs\">access_time</i>\n          <b class=\"bi-text--sm\">{{vm.result.current.startTime | biDate:'HH:mm'}}</b>\n        </div>\n      </div>\n\n      <div class=\"bi-c bi-fade-in\" ng-if=\"vm.result.current.getResults().bufferSize() > 0 || vm.result.enabled\">\n        <span class=\"bi-text--sm\">Rows</span>\n        <b class=\"bi-text--sm\">{{vm.result.current.getResults().bufferSize()}}</b>\n      </div>\n\n      <div>\n        <div ng-if=\"vm.stats.enabled && vm.result.current.finished\" ng-transclude=\"stats\"></div>\n      </div>\n    </div>\n\n    <div class=\"bi-fade-in\" ng-if=\"!vm.runner.enabled\" ng-transclude=\"runHint\"></div>\n  </div>\n\n  <div class=\"bi-grow\" ng-transclude=\"controls\" ng-if=\"runner.running && !vm.tabs.isEnabled()\"></div>\n\n  <div class=\"br-tabs bi-r bi-fade-in\" ng-if=\"vm.tabs.isEnabled()\">\n    <div\n      class=\"br-tab bi-fade-in\"\n      ng-class=\"{'bi-active': query.getId() === vm.result.current.getId()}\"\n      ng-repeat=\"query in runner.getQueries()\"\n      ng-click=\"events.onSelectQuery(query)\"\n      title=\"{{::query.getTitle()}}\"\n    >{{::query.getTitle()}}</div>\n  </div>\n\n  <i class=\"bi-action bi-icon bi-fade-in\" ng-if=\"vm.result.enabled\" ng-click=\"events.onCloseResult()\">close</i>\n</div>\n\n<div \n  class=\"br-result bi-c-h bi-dont-shrink bi-dont-grow\"\n  ng-class=\"{'br-result-with-tabs': vm.tabs.isEnabled()}\" ng-if=\"vm.result.enabled\"\n>\n  <div\n    class=\"bi-dont-shrink bi-fade-in\"\n    ng-if=\"vm.result.queries.get(query).enabled\"\n    ng-show=\"query.getId() === vm.result.current.getId()\"\n    ng-repeat=\"query in runner.getQueries()\"\n  >\n    <div \n      class=\"bi-c-h bi-grow\"\n      ng-if=\"!query.getError() && query.getResults().bufferSize() > 0\"\n      bi-html=\"renderResult(scope, query)\"\n    ></div>\n\n    <div \n      class=\"bi-c-h bi-grow bi-align bi-center\"\n      ng-if=\"query.finished && !query.getError() && query.getResults().bufferSize() === 0\"\n    >\n      <div class=\"bi-empty-state\" ng-if=\"::runner.getMode() === 'stream'\">\n        <div class=\"bi-empty-state-icon\">\n          <i class=\"bi-icon\">sentiment_dissatisfied</i>\n        </div>\n        <div class=\"bi-empty-state-header\">No results</div>\n      </div>\n\n      <div class=\"bi-empty-state\" ng-if=\"::runner.getMode() === 'download'\">\n        <div class=\"bi-empty-state-icon\">\n          <i class=\"bi-icon\">file_download</i>\n        </div>\n        <div class=\"bi-empty-state-header\">See downloaded file</div>\n        <div class=\"bi-empty-state-content\">{{::vm.result.csvFileName}}</div>\n      </div>\n    </div>\n\n    <div \n      class=\"bi-c-h bi-grow bi-align bi-center\"\n      ng-if=\"query.finished && query.getError()\"\n    >\n      <div class=\"bi-empty-state\" ng-if=\"::!vm.result.queries.get(query).errorType\">\n        <div class=\"bi-empty-state-icon\">\n          <i class=\"bi-icon bi-danger\">warning</i>\n        </div>\n\n        <pre class=\"bi-empty-state-content bi-danger\">{{::query.getError().msg}}</pre>\n      </div>\n\n      <div class=\"bi-empty-state\" ng-if=\"::vm.result.queries.get(query).errorType === 'timeout'\">\n        <div class=\"bi-empty-state-icon\">\n          <i class=\"bi-icon bi-danger\">error_outline</i>\n        </div>\n        <div class=\"bi-empty-state-header\">{{::options.type | biToHumanCase}} seems to be down at the moment</div>\n        <div class=\"bi-empty-state-content\">Please try again in 5 minutes</div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/runner/runner.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n@import '../../../ui/assets/css/def/flex.def';\n@import '../../../ui/assets/css/def/space.def';\n\nbi-runner {\n  @include flex(column);\n  @include space-v__inner(15px !important);\n\n  width: 100%;\n  flex-grow: 1;\n  overflow: hidden;\n\n  editor,\n  editor > * {\n    @include flex(column);\n\n    flex-grow: 1;\n  }\n\n  .br-run-toggle {\n    min-width: 52px;\n  }\n\n  .br-custom-actions-toggle {\n    margin-left: -1px;\n\n    button {\n      width: 30px;\n      padding: 0;\n    }\n  }\n\n  .br-download-action {\n    width: 30px;\n    padding: 7px;\n    border-radius: 30px !important;\n  }\n\n  .br-download-action[disabled=\"disabled\"] {\n    i {\n      color: $grey--600;\n    }\n  }\n\n  .br-tabs {\n    .br-tab {\n      position: relative;\n      max-width: 150px;\n      height: 40px;\n      margin-left: -1px;\n      margin-bottom: -11px;\n      padding: 5px 10px;\n      flex-shrink: 3;\n      line-height: 28px;\n      color: $muted;\n      border: 1px solid $grey--300;\n      background-color: $grey--50;\n      white-space: nowrap;\n      overflow: hidden;\n      text-overflow: ellipsis;\n      cursor: pointer;\n\n      &.bi-active {\n        color: $black;\n        background-color: $white !important;\n        border-bottom: $white;\n      }\n\n      &:hover {\n        color: $black;\n        background-color: $white;\n      }\n    }\n  }\n\n  .br-result {\n    flex-basis: 300px;\n\n    > *,\n    result {\n      display: flex;\n      height: 300px;\n      flex-direction: column;\n\n      .bi-empty-state-content.bi-danger {\n        white-space: pre-wrap;\n        overflow-y: auto;\n      }\n    }\n\n    &.br-result-with-tabs {\n      margin-top: 10px !important;\n      padding-top: 10px;\n      border-top: 1px solid $grey--300;\n      flex-basis: 311px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/runner/runner.ts",
    "content": "import {initNgScope, inject, srv} from '../../../core';\nimport {default as createRunner} from '../../services/runner-service';\n\nimport template from './runner.html';\nimport './runner.scss';\n\nfunction downloadFile(url, fileName) {\n  const a = window.document.createElement('A');\n\n  a.setAttribute('href', encodeURI(url));\n  a.setAttribute('type', 'text/csv');\n  a.setAttribute('target', '_blank');\n  a.setAttribute('rel', 'noopener noreferrer');\n  a.setAttribute('download', fileName);\n\n  // needed for firefox\n  window.document.body.appendChild(a);\n  a.click();\n  window.document.body.removeChild(a);\n}\n\nfunction initRunner(scope, instance: RunnerComponentInstance, mode = 'stream') {\n  scope.vm.runner.toggle(true);\n\n  scope.runner = (scope.runner || createRunner(scope.options.type, scope, {\n    version: scope.version,\n    mode,\n    executeBaseUrl: instance.getExecuteBaseUrl()\n  })\n  .transformRequest(instance.getDataTransformer())\n  .transformResponse(instance.getResponseTransformer())\n)\n  .on('queryCreated', (runner, query) => {\n    if (!scope.vm.result.current) {\n      scope.vm.result.setCurrent(query);\n    }\n\n    query.on('firstResultReceived', () => {\n      scope.vm.result.toggle(true);\n    });\n\n    query.on('error', (q, {message}) => {\n      q.setErrorMessage(instance.getErrorTransformer()(runner, q, message));\n\n      if (message === 'Presto can\\'t be reached, please try later. Underlying exception name is SocketTimeoutException') {\n        scope.vm.result.queries.get(q).errorType = 'timeout';\n      }\n\n      scope.vm.result.setCurrent(q);\n      scope.vm.result.toggle(true);\n    }, true);\n  }, true)\n  .on('downloadFile', (url, runner, query) => {\n    downloadFile(url, scope.downloadFileName({query, runner}) || 'export.csv');\n  })\n  .on('finish', runner => {\n    scope.vm.runner.toggle(false);\n\n    if (!runner.getState().getStatus().killed) {\n      scope.vm.result.toggle(true);\n    }\n  }, true);\n\n  scope.onRunnerCreated({runner: scope.runner, component: instance});\n\n  return scope.runner;\n}\n\nfunction destroyRunner(scope) {\n  kill(scope);\n\n  scope.onRunnerDestroyed({runner: scope.runner});\n  scope.runner = null;\n}\n\nfunction destroyResult(scope) {\n  scope.vm.result.toggle(false);\n  scope.vm.result.reset();\n}\n\nfunction destroy(scope) {\n  destroyRunner(scope);\n  destroyResult(scope);\n}\n\nfunction kill(scope, notify = false) {\n  if (scope.runner) {\n    scope.runner.kill();\n\n    if (notify) {\n      scope.onRunnerKilled({runner: scope.runner});\n    }\n  }\n\n  scope.vm.runner.toggle(false);\n}\n\nfunction renderResult(scope, queryScope, query, tableFormatter, transclude) {\n  if (!transclude.isSlotFilled('result')) {\n    queryScope.options = scope.options;\n    queryScope.query = query;\n    queryScope.tableFormatter = tableFormatter;\n\n    return inject('$compile')(`\n      <bi-viz\n        class=\"bi-c-h bi-grow\"\n        type=\"{{::options.vizType}}\"\n        data=\"query.getResults().buffer\"\n        table-data=\"query.getResults()\"\n        fields=\"query.getRawFields()\"\n        table-fields=\"query.getFields()\"\n        is-partial=\"query.running\"\n        bv-options=\"::{\n          picker: options.vizPicker,\n          filter: options.vizFilter,\n          types: options.vizTypes\n        }\"\n        table-formatter=\"tableFormatter()\"\n        $state=\"$state\"\n      ></bi-viz>\n    `)(queryScope);\n  }\n\n  return transclude((_, _scope) => _scope.query = query, null, 'result');\n}\n\nexport class RunnerComponentInstance extends srv.eventEmitter.EventEmitter {\n  private user;\n  private dataTransformer: Function;\n  private responseTransformer: Function;\n  private errorTransformer: Function = (runner, query, error) => error;\n  private executeBaseUrl: string;\n\n  constructor(private readonly scope) {\n    super();\n  }\n\n  run(mode: 'stream' | 'download' = 'stream') {\n    return this.scope.events.onToggleRun(mode);\n  }\n\n  getDataTransformer() {\n    return this.dataTransformer;\n  }\n\n  getResponseTransformer() {\n    return this.responseTransformer;\n  }\n\n  getErrorTransformer() {\n    return this.errorTransformer;\n  }\n\n  getExecuteBaseUrl() {\n    return this.executeBaseUrl;\n  }\n\n  setRequestTransformer(fn: (code) => typeof code) {\n    this.dataTransformer = fn;\n  }\n\n  setResponseTransformer(fn: (response) => typeof response) {\n    this.responseTransformer = fn;\n  }\n\n  setErrorTransformer(fn: (runner, query, error) => typeof error) {\n    this.errorTransformer = (runner, query, error) => fn(runner, query, error);\n  }\n\n  setExecuteBaseUrl(baseUrl: string) {\n    this.executeBaseUrl = baseUrl;\n  }\n\n  setCurrentQuery(query) {\n    this.scope.vm.result.setCurrent(query);\n  }\n\n  getCurrentQuery() {\n    return this.scope.vm.result.current;\n  }\n\n  getUser() {\n    return this.user;\n  }\n\n  setUser(user) {\n    this.user = user;\n  }\n\n  load(runner) {\n    destroy(this.scope);\n    this.scope.runner = runner;\n    initRunner(this.scope, this);\n  }\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    transclude: {\n      editor: 'editor',\n      actions: '?actions',\n      result: '?result',\n      runHint: '?runHint',\n      controls: '?controls',\n      stats: '?stats',\n    },\n    scope: {\n      data: '=',\n      version: '=',\n      runner: '<',\n      brOptions: '<',\n      onRun: '&',\n      onRunnerCreated: '&',\n      onRunnerKilled: '&',\n      onRunnerDestroyed: '&',\n      onLoad: '&',\n      tableFormatter: '&',\n      downloadFileName: '&',\n      $state: '<'\n    },\n\n    link: {\n      pre(scope, element, attrs, ctrl, transclude) {\n        const instance = new RunnerComponentInstance(scope);\n\n        initNgScope(scope)\n          .withOptions('brOptions', {\n            type: 'presto',\n            buttonText: 'Run',\n            disableCustomActions: false,\n            vizType: 'table',\n            vizTypes: [],\n            vizPicker: true,\n            vizFilter: true,\n            autoRun: false,\n            showEditor: true,\n          }, true)\n          .withVM({\n            runner: {},\n            result: {\n              csvFileName: null,\n              $init() {\n                this.current = null;\n                this.queries = this.createItemsVm({\n                  errorType: null\n                });\n              },\n              setCurrent(query) {\n                this.current = query;\n                this.queries.get(query).toggle(true);\n                this.csvFileName = scope.downloadFileName({query, runner: scope.runner}) || 'export.csv';\n              },\n              reset() {\n                this.$init();\n              }\n            },\n            tabs: {\n              isEnabled() {\n                return scope.vm.result.enabled && scope.runner.getTotalNumOfQueries() > 1;\n              }\n            },\n            customActions: {\n              $init() {\n                this.toggle(transclude.isSlotFilled('actions'));\n              }\n            },\n            stats: {\n              enabled: true,\n            },\n          })\n          .withEvents({\n            onSelectQuery(query) {\n              scope.vm.result.setCurrent(query);\n              scope.vm.stats.reload();\n            },\n            onToggleRun(mode) {\n              if (scope.vm.runner.enabled) {\n                kill(scope, true);\n              } else {\n                destroy(scope);\n                const runner = initRunner(scope, instance, mode).run(scope.data, instance.getUser());\n\n                scope.onRun({runner});\n\n                return runner;\n              }\n            },\n            onCloseResult() {\n              destroy(scope);\n            }\n          })\n          .withActions({\n            getCsvFields() {\n              return scope.vm.result.current.getFields().map(field => field.name);\n            },\n            getCsvRows() {\n              const fields = scope.vm.result.current.getFields();\n              return scope.vm.result.current.getResults().buffer.map(row => fields.map(field => row[field.name]));\n            }\n          });\n\n        if (scope.runner) {\n          initRunner(scope, instance);\n        }\n\n        scope.renderResult = (queryScope, query) => ({html: renderResult(scope, queryScope, query, scope.tableFormatter, transclude)});\n\n        scope.onLoad({instance});\n\n        if (scope.options.autoRun) {\n          instance.run('stream');\n        }\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/sql-runner/sql-runner.html",
    "content": "<bi-runner\n  ng-if=\"vm.enabled\"\n  data=\"model.value\"\n  version=\"version\"\n  runner=\"runner\"\n  br-options=\"{\n    type: type,\n    buttonText: vm.runnerOptions.buttonText,\n    disableCustomActions: options.disableCustomActions,\n    autoRun: options.autoRun,\n    showEditor: options.showEditor,\n  }\"\n  on-run=\"events.onRun(runner)\"\n  on-runner-created=\"events.onRunnerCreated(runner)\"\n  on-runner-destroyed=\"events.onRunnerDestroyed(runner)\"\n  on-load=\"events.onRunnerLoad(instance)\"\n  table-formatter=\"tableFormatter()\"\n  download-file-name=\"downloadFileName({query: query, runner: runner})\"\n  $state=\"$state\"\n>\n  <editor class=\"bi-c-h\">\n    <bi-code-editor\n      class=\"bi-c-h\"\n      ng-model=\"model.value\"\n      bce-options=\"::{\n        focus: options.focus,\n        params: options.params,\n        customParams: options.customParams,\n        fitContent: options.fitContent,\n        shareParams: options.shareParams,\n        dateFormat: options.dateFormat\n      }\"\n      on-save=\"onSave()\"\n      on-load=\"events.onEditorLoad(instance)\"\n      on-params-share=\"onParamsShare({params: params})\"\n      readonly=\"readonly\"\n    ></bi-code-editor>\n  </editor>\n\n  <actions bi-html=\"renderActions()\"></actions>\n  <stats ng-transclude=\"stats\"></stats>\n\n  <run-hint>\n    <quix-note-hints ng-if=\"vm.hint.run.enabled && !readonly\"></quix-note-hints>\n  </run-hint>\n\n  <controls ng-transclude=\"controls\"></controls>\n</bi-runner>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/sql-runner/sql-runner.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n@import '../../../ui/assets/css/def/flex.def';\n\nbi-sql-runner {\n  @include flex(column);\n\n  width: 100%;\n  flex-grow: 1;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/directives/sql-runner/sql-runner.ts",
    "content": "import './sql-runner.scss';\nimport template from './sql-runner.html';\n\nimport {CodeEditorInstance} from '../../../code-editor';\nimport {createNgModel, initNgScope, inject} from '../../../core';\nimport {setupCompleters} from '../../services/autocomplete/autocomplete-service';\nimport {attachErrorHandler, getParamsOffset} from '../../services/syntax-valdator/syntax-validator-service';\nimport {initSqlWorker} from '../../services/workers/sql-parser-worker';\nimport {RunnerComponentInstance} from '../runner/runner';\nimport {requestCredentials, isPermissionError} from '../../services/permissions/permissions-service';\nimport {config} from '../../config';\nimport { AUTO_PARAMS, AUTO_PARAM_TYPES } from '../../../code-editor/services/param-parser/param-types';\n\nfunction renderActions(scope, editorComponentInstance, runnerComponentInstance, transclude: ng.ITranscludeFunction) {\n  if (!transclude.isSlotFilled('actions')) {\n    return inject('$compile')(`\n      <ul class=\"bi-dropdown-menu\">\n        <li class=\"bi-align bi-s-h--x05\" ng-click=\"events.onRunAndDownload()\">\n          <i class=\"bi-icon\">file_download</i>\n          <div>Run and download</div>\n        </li>\n      </ul>\n    `)(scope);\n  }\n\n  return transclude((_, s) => {\n    s.editorComponentInstance = editorComponentInstance;\n    s.runnerComponentInstance = runnerComponentInstance;\n  }, null, 'actions');\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    require: 'ngModel',\n    transclude: {\n      actions: '?actions',\n      controls: '?controls',\n      stats: '?stats',\n    },\n    scope: {\n      version: '=',\n      type: '=',\n      runner: '=',\n      bsrOptions: '=',\n      onEditorLoad: '&',\n      onRunnerLoad: '&',\n      onSave: '&',\n      onRun: '&',\n      onRunnerCreated: '&',\n      onRunnerDestroyed: '&',\n      onParamsShare: '&',\n      tableFormatter: '&',\n      downloadFileName: '&',\n      readonly: '=',\n      $state: '<',\n      autocompleteDbFetchers: '<'\n    },\n\n    link: {\n      pre(scope, element, attrs, ngModel, transclude) {\n        let editorInstance: CodeEditorInstance, runnerInstance: RunnerComponentInstance;\n        const deferredEditor = inject('$q').defer();\n\n        const modelConf = createNgModel(scope, ngModel)\n          .formatWith(model => ({value: model}))\n          .parseWith(({value}) => value)\n          .watchDeep(true)\n          .then(() => scope.vm.toggle(true));\n\n        initNgScope(scope)\n          .withOptions('bsrOptions', {\n            focus: false,\n            params: false,\n            autoParams: true,\n            customParams: true,\n            useAutocomplete: true,\n            showSyntaxErrors: true,\n            promptOnPermissionError: true,\n            disableCustomActions: false,\n            fitContent: false,\n            shareParams: false,\n            autoRun: false,\n            dateFormat: null,\n          })\n          .withVM({\n            selection: null,\n            password: null,\n            runnerOptions: {\n              buttonText: null\n            },\n            hint: {\n              run: {\n                enabled: true\n              }\n            },\n            viz: {\n              $init() {\n                this.queries = this.createItemsVm({\n                  type: null,\n                  setCurrent(type) {\n                    this.type = type;\n                  },\n                  $init() {\n                    this.setCurrent('table');\n                  }\n                });\n              }\n            }\n          })\n          .withEvents({\n            onRunnerLoad(instance: RunnerComponentInstance) {\n              runnerInstance = instance;\n\n              runnerInstance.setRequestTransformer(() => editorInstance.getParams().format(scope.vm.selection || scope.model.value));\n\n              runnerInstance.setErrorTransformer((runner, query, msg) => {\n                if (isPermissionError(msg) && scope.options.promptOnPermissionError) {\n                  requestCredentials(scope, runnerInstance).then(() => runnerInstance.run());\n                } else {\n                  const match = msg.match(/^line (\\d+)\\:\\d+/);\n\n                  if (match) {\n                    const queryOffset: number = runner.getQueries().reduce((res, _query) => {\n                      if (_query !== query) {\n                        res += _query.meta('numOfRows');\n                      }\n\n                      return res;\n                    }, getParamsOffset(editorInstance));\n\n                    const rowNumber = queryOffset + parseInt(match[1], 10) + (editorInstance.getSelection().getOffset() as number);\n                    msg = msg.replace(/^(line )(\\d+)(\\:\\d+)/, `$1${rowNumber}$3`);\n\n                    editorInstance.getAnnotator().showError(rowNumber, msg);\n                  }\n                }\n\n                return msg;\n              });\n\n              scope.onRunnerLoad({instance});\n            },\n            onEditorLoad(instance: CodeEditorInstance) {\n              editorInstance = instance;\n              deferredEditor.resolve(instance);\n\n              editorInstance.addShortcut('Ctrl-Enter', 'Command-Enter', () => runnerInstance.run(), scope);\n              editorInstance.getSelection()\n                .on('select', text => {\n                  scope.vm.selection = text;\n                  scope.vm.runnerOptions.buttonText = 'Run selection';\n                })\n                .on('deselect', () => {\n                  scope.vm.selection = null;\n                  scope.vm.runnerOptions.buttonText = null;\n                });\n\n              if (scope.options.params) {\n                editorInstance.addLiveCompleter('$', prefix => {\n                  let completions = [];\n                  const params = editorInstance.getParams();\n\n                  if (scope.options.autoParams) {\n                    completions = [\n                      ...completions,\n                      ...AUTO_PARAMS\n                        .map(name => ({name, meta: AUTO_PARAM_TYPES[name]}))\n                        .map(({name, meta}) => ({\n                          caption: name,\n                          value: params.getParser().getSerializer().serialize({\n                            match: null,\n                            key: name,\n                            type: null,\n                            value: null,\n                            isAutoParam: true,\n                            isKeyOnlyParam: false,\n                            options: null\n                          }),\n                        meta,\n                        completer: {\n                          insertMatch(editor) {\n                            editor.insert(name);\n                            editorInstance.getParams().addAutoParam(name);\n                          }\n                        }\n                      }))\n                    ];\n                  }\n\n                  if (scope.options.customParams) {\n                    completions = [\n                      ...completions,\n                      ...params.getParams().filter(({isAutoParam}) => !isAutoParam).map(({key, type, value}) => {\n                        return {\n                          caption: key,\n                          value: params.getParser().getSerializer().serialize({\n                            match: null,\n                            key,\n                            type,\n                            value,\n                            isAutoParam: false,\n                            isKeyOnlyParam: true,\n                            options: null\n                          }), meta: type\n                        };\n                      })\n                    ];\n                  }\n\n                  return completions;\n                });\n              }\n\n              runnerInstance.on('error', (rowNumber, msg) => editorInstance.getAnnotator().showError(rowNumber, msg));\n\n              if (!scope.readonly && scope.options.useAutocomplete) {\n                setupCompleters(editorInstance, scope.type, config.get().apiBasePath, scope.autocompleteDbFetchers).catch(console.error);\n              }\n\n              if (!scope.readonly && scope.options.showSyntaxErrors) {\n                attachErrorHandler(initSqlWorker, editorInstance, modelConf).catch(console.error);\n              }\n\n              scope.onEditorLoad({instance});\n            },\n            onRunnerCreated(runner) {\n              runner\n                .on('success', () => deferredEditor.promise.then((editor: CodeEditorInstance) => editor.setValid(true), true))\n                .on('error', () => deferredEditor.promise.then((editor: CodeEditorInstance) => editor.setValid(false), true));\n\n              runner.getEvents().register('query-details', data => {\n                const code = data && data.code || '';\n                const lines = code.trim().split('\\n');\n\n                runner.getCurrentQuery().meta('numOfRows', lines.length);\n                runner.getCurrentQuery().setTitle(lines[0] ? lines[0].replace('--', '').trim() : 'query');\n\n                return data;\n              });\n\n              scope.vm.hint.run.toggle(false);\n              scope.onRunnerCreated({runner});\n            },\n            onRunnerDestroyed(runner) {\n              deferredEditor.promise.then(() => {\n                editorInstance.setValid(null);\n                editorInstance.getAnnotator().hideAll();\n              });\n\n              scope.vm.hint.run.toggle(true);\n              scope.onRunnerDestroyed({runner});\n            },\n            onRun(runner) {\n              scope.onRun({runner});\n            },\n            onRunAndDownload() {\n              runnerInstance.run('download');\n            }\n          });\n\n        scope.renderActions = () => ({html: renderActions(scope, editorInstance, runnerInstance, transclude)});\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/index.ts",
    "content": "import ngApp from './bootstrap';\nimport init from './init';\n\ninit(ngApp);\n\nexport {default as createRunner, Runner} from './services/runner-service';\nexport {default as RunnerQuery} from './services/runner-query';\nexport {config} from './config';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/init.ts",
    "content": "import {forEach} from 'lodash';\nimport * as directives from './directives';\n\nfunction toDirectiveName(name: string) {\n  return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`;\n}\n\nexport default function init(ngApp: angular.IModule) {\n  forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any));\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/autocomplete/autocomplete-service.ts",
    "content": "import { CodeEditorInstance } from '../../../code-editor';\n// import { ICompleterItem as AceCompletion } from '../../../code-editor/services/code-editor-completer';\nimport { SqlAutocompleter } from \"../../../sql-autocomplete/adapter/sql-autocomplete-adapter\";\nimport {\n  highlightAndScore\n} from \"./highlight-and-score\";\n// import { BiSqlWebWorkerMngr } from '../../../language-parsers/sql-parser';\n// import { initSqlWorker } from '../workers/sql-parser-worker';\nimport {\n  getKeywordsCompletions,\n  getQueryAndCursorPositionFromEditor,\n  getSuggestions,\n  isSearchInObject,\n} from './autocomplete-utils';\nimport { IDbInfoConfig } from '../../../sql-autocomplete/db-info';\n// import { DbInfoService } from '../../../sql-autocomplete/db-info';\nimport {\n  evaluateContextFromPosition,\n  QueryContext,\n} from '../../../sql-autocomplete/sql-context-evaluator';\nimport { IEditSession } from 'brace';\nimport { setupOldCompleter } from './old-autocomplete-service';\n\n/* tslint:disable:no-shadowed-variable */\nexport async function setupCompleters(\n  editorInstance: CodeEditorInstance,\n  type: string,\n  apiBasePath = '',\n  dbInfoService?: IDbInfoConfig\n) {\n  // in order to run locally comment out\n  if (!dbInfoService) {\n    setupOldCompleter(editorInstance, type, apiBasePath);\n    return;\n  }\n\n  // dbInfoService = dbInfoService ?? new DbInfoService(type, apiBasePath);\n  const sqlAutocompleter = new SqlAutocompleter(dbInfoService, type);\n\n  editorInstance.setLiveAutocompletion(true);\n\n  const keywordsCompletions = getKeywordsCompletions();\n\n  const completerFn = async (prefix: string, session: IEditSession) => {\n\n    const { query, position } = getQueryAndCursorPositionFromEditor(\n      editorInstance,\n      session\n    );\n\n    const queryContext: QueryContext = evaluateContextFromPosition(\n      query,\n      position\n    );\n\n    const searchInObject = await isSearchInObject(queryContext, sqlAutocompleter)\n    let autocompletionSuggestions = await getSuggestions(queryContext, keywordsCompletions, sqlAutocompleter, searchInObject);\n\n    if (prefix) {\n      autocompletionSuggestions = highlightAndScore(\n        autocompletionSuggestions,\n        queryContext,\n        searchInObject\n      )\n    }\n\n    return autocompletionSuggestions.sort((a, b) => a.value.localeCompare(b.value));\n  };\n\n  editorInstance.addOnDemandCompleter(/[\\w.]+/, completerFn as any, {\n    acceptEmptyString: true,\n  });\n  // editorInstance.addOnDemandCompleter(/[\\s]+/, completerFn as any);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/autocomplete/autocomplete-utils.ts",
    "content": "/* tslint:disable:no-bitwise */\n\nimport { IEditSession } from 'brace';\nimport { CodeEditorInstance } from '../../../code-editor';\nimport { ICompleterItem } from '../../../code-editor/services/code-editor-completer';\nimport { reservedPrestoWords } from '../../../sql-autocomplete/languge/reserved-words';\nimport { ContextType } from '../../../sql-autocomplete/sql-context-evaluator/types';\n\nlet keywords: ICompleterItem[];\n\nexport const getKeywordsCompletions = (): ICompleterItem[] => {\n  // TODO: FIND A WAY TO FETCH KEYWORDS FROM ANTLR GRAMMAR\n  keywords =\n    keywords ??\n    reservedPrestoWords.map((keyword) =>\n      makeCompletionItem(keyword, 'keyword')\n    );\n  return keywords;\n};\n\n/**\n * create an array of bitmaps.\n *  if ((bit j of array[i]) === 1) means that the character i*31 + j should be marked in UI\n *\n * @param {number | number[]} start\n * @param {number} length\n * @returns {number[]}\n */\nexport const createMatchMask = (\n  start: number | number[],\n  length: number\n): number[] => {\n  const res = [];\n\n  start = Array.isArray(start) ? start : [start];\n  start.forEach((startElement) => {\n    for (let i = startElement; i < startElement + length; i++) {\n      const index = i % 31;\n      const offset = i - 31 * index;\n      res[index] = res[index] || 0;\n      res[index] = res[index] | (1 << offset);\n    }\n  });\n\n  return res;\n};\n\nexport async function getSuggestions(queryContext, keywordsCompletions, sqlAutocompleter, searchInObject) {\n  if (queryContext.contextType === ContextType.Undefined) {\n    return keywordsCompletions.filter(obj => obj.value.toLowerCase().includes(queryContext.prefix.toLowerCase()));\n  }\n\n  return searchInObject\n    ? sqlAutocompleter.getCompletionItemsFromQueryContextColumn(\n      queryContext\n    )\n    : sqlAutocompleter.getCompletionItemsFromQueryContext(\n      queryContext\n    );\n\n}\n\nexport async function isSearchInObject(queryContext, sqlAutocompleter) {\n  if (queryContext.contextType === ContextType.Column && queryContext.prefix) {\n    const completions = await sqlAutocompleter.getCompletionItemsFromQueryContext(\n      queryContext\n    )\n    const filteredCompletions = completions.filter(c => c.value.toLowerCase().includes(queryContext.prefix));\n    return filteredCompletions.length === 0;\n  }\n  return false\n}\n\n\nexport function createCaption(str: string) {\n  const maxCaptionLength = 60;\n  const maxSubCaptionLength = 57;\n\n  if (str.length > maxCaptionLength) {\n    return str.substring(0, maxSubCaptionLength) + \"...\";\n  }\n\n  return str;\n}\n\nexport const makeCompletionItem = (\n  value: string,\n  meta: string,\n  caption?: string,\n  matchMask?: number[],\n  score?: number\n): ICompleterItem => {\n  const completer = {\n    value,\n    meta,\n    ...(caption ? { caption } : {}),\n    ...(matchMask ? { matchMask } : {}),\n    ...(score ? { score } : {}),\n  };\n\n  return completer;\n};\n\nexport const getQueryAndCursorPositionFromEditor = (\n  editorInstance: CodeEditorInstance,\n  session: IEditSession\n) => {\n  let query: string = session\n    .getDocument()\n    .getAllLines()\n    .join('\\n');\n  let position: number = session\n    .getDocument()\n    .positionToIndex(session.selection.getCursor(), 0);\n\n  if (editorInstance.getParams().hasParams()) {\n    const tempQuery =\n      query.slice(0, position) + '@REPLACE_ME@' + query.slice(position);\n    query = editorInstance.getParams().format(tempQuery);\n    position = query.indexOf('@REPLACE_ME@');\n    query = query.replace('@REPLACE_ME@', '');\n  }\n\n  return { query, position };\n};\n\nexport const findAllIndexOf = (haystack: string, needle: string) => {\n  const indexes: number[] = [];\n  if (needle === '') {\n    return indexes;\n  }\n  haystack = haystack.toLowerCase();\n  needle = needle.toLowerCase();\n\n  let index = 0;\n  while (index !== -1) {\n    index = haystack.indexOf(needle, index);\n    if (index !== -1) {\n      indexes.push(index);\n      index++;\n    }\n  }\n\n  return indexes;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/autocomplete/highlight-and-score.ts",
    "content": "import {\n  createCaption,\n  createMatchMask,\n  findAllIndexOf,\n} from './autocomplete-utils';\nimport { findColumnPathForPrefix } from \"../../../sql-autocomplete/adapter/sql-autocomplete-adapter-utills\";\nimport { ICompleterItem as AceCompletion } from '../../../code-editor/services/code-editor-completer';\nimport { QueryContext } from '../../../sql-autocomplete/sql-context-evaluator';\n\nconst PERFECT_SCORE = 10000;\n\nexport function highlightAndScore(\n  autocompletionSuggestions,\n  queryContext,\n  searchInObject\n) {\n  const lowerCasedPrefix = queryContext.prefix.trim().toLowerCase();\n  return searchInObject\n    ? enrichCompletionForObject(queryContext.prefix, autocompletionSuggestions, queryContext, lowerCasedPrefix)\n    : enrichCompletionItem(autocompletionSuggestions, lowerCasedPrefix);\n}\n\nfunction enrichCompletionItemAfterDotObject(all: AceCompletion[]): AceCompletion[] {\n  const indexes = [0];\n  return all.map(completionItem => ({\n    ...completionItem,\n    matchMask: createMatchMask(indexes, 0),\n    score: PERFECT_SCORE,\n  }));\n}\n\nfunction enrichCompletionForObject(prefix: string, autocompletionSuggestions: any, queryContext: QueryContext, lowerCasedPrefix: string) {\n  return prefix.endsWith('.')\n    ? enrichCompletionItemAfterDotObject(autocompletionSuggestions)\n    : enrichCompletionItemInObjectSearch(autocompletionSuggestions, queryContext, lowerCasedPrefix);\n}\n\nfunction enrichCompletionItemInObjectSearch(all: AceCompletion[], queryContext: QueryContext, prefix: string): AceCompletion[] {\n  return all.reduce((resultArr, completionItem) => {\n    const columnPathForPrefix = findColumnPathForPrefix(queryContext.tables, prefix.split('.')).slice(0, -1);\n    const lastDotIndex = findLastDotIndex(columnPathForPrefix);\n    const startOfSearch = lastDotIndex >= 0 ? columnPathForPrefix.slice(0, lastDotIndex + 1) : columnPathForPrefix;\n    const searchPart = columnPathForPrefix.replace(startOfSearch, '');\n    const indexes = findAllIndexOf(completionItem.caption, searchPart);\n\n    updateCompletionItem(completionItem, indexes, searchPart, resultArr);\n\n    return resultArr;\n  }, []);\n}\n\n\nfunction enrichCompletionItem(all: AceCompletion[], lowerCasedPrefix: string): AceCompletion[] {\n  return all.reduce((resultArr, completionItem) => {\n    const indexes = findAllIndexOf(completionItem.value, lowerCasedPrefix);\n    updateCompletionItem(completionItem, indexes, lowerCasedPrefix, resultArr);\n    return resultArr;\n  }, []);\n}\n\nfunction updateCompletionItem(\n  completionItem: AceCompletion,\n  indexes: number[],\n  searchPart: string,\n  resultArr: AceCompletion[]\n): void {\n  if (indexes.length > 0) {\n    completionItem.matchMask = createMatchMask(\n      indexes,\n      searchPart.length\n    );\n    completionItem.score = PERFECT_SCORE - indexes[0];\n    resultArr.push(completionItem);\n  }\n  completionItem.caption = createCaption(completionItem.caption || completionItem.value);\n}\n\nexport function findLastDotIndex(prefix: string): number {\n  return prefix.lastIndexOf('.');\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/autocomplete/old-autocomplete-service.ts",
    "content": "import {CodeEditorInstance} from '../../../code-editor';\nimport {ICompleterItem as AceCompletion} from '../../../code-editor/services/code-editor-completer';\nimport {BiSqlWebWorkerMngr} from '../../../language-parsers/sql-parser';\nimport {DbInfo} from '../db/db-service';\nimport {initSqlWorker} from '../workers/sql-parser-worker';\nimport {createMatchMask, makeCompletionItem} from './autocomplete-utils';\n\nconst sqlContextGroups = ['subQueries', 'tableAlias', 'strings', 'tables', 'columns'];\n\nlet sqlParser: BiSqlWebWorkerMngr;\nlet keywords: Promise<AceCompletion[]>; // All Completions\nlet tables: Promise<AceCompletion[]>;\n\nasync function getTablesCompletions(dbInfoService: DbInfo): Promise<AceCompletion[]> {\n  keywords = keywords || dbInfoService.fetchAllKeywords();\n  const completions = await keywords;\n  return completions.filter(completion => completion.meta === 'table');\n}\n\n/* tslint:disable:no-shadowed-variable */\nexport async function setupOldCompleter(editorInstance: CodeEditorInstance, type: string, apiBasePath = '') {\n  sqlParser = await initSqlWorker();\n  const dbInfoService = new DbInfo(type, apiBasePath);\n\n  keywords = keywords || dbInfoService.fetchAllKeywords();\n  tables = tables || getTablesCompletions(dbInfoService);\n\n  editorInstance.addOnDemandCompleter(/[\\w.]+/, ((prefix, session) => {\n    let contextCompletions: Promise<AceCompletion[]>;\n\n    if (sqlParser) {\n      const text = session.getDocument().getAllLines().join('\\n');\n      contextCompletions = sqlParser.parse(text)\n        .then(parseResults =>\n          sqlContextGroups.reduce<AceCompletion[]>((sum, groupName) =>\n            sum.concat(parseResults[groupName]\n              .map(item => makeCompletionItem(item, groupName))),\n            []));\n    } else {\n      contextCompletions = Promise.resolve([]);\n    }\n\n    return Promise.all([tables, contextCompletions])\n      .then(([tableCompletions, contextCompletions]) => {\n        let all = contextCompletions.concat(tableCompletions);\n\n        if (prefix) {\n          all = all.reduce((resultArr: AceCompletion[], completion) => {\n            const index = completion.value.indexOf(prefix);\n\n            if (index !== -1) {\n              completion.matchMask = createMatchMask(index, prefix.length);\n              resultArr.push(completion);\n            }\n\n            return resultArr;\n          }, []);\n        }\n        return all;\n      });\n  }) as any, {acceptEmptyString: true});\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/db/db-service.ts",
    "content": "'use strict';\nimport {inject} from '../../../core';\nimport angular from 'angular';\n\nexport interface IAutocomplete {\n  value: string;\n  meta: string;\n}\n\nexport interface IDbNode {\n  name: string;\n  type: string;\n  children: IDbNode[];\n}\n\nexport class DbInfo {\n  private readonly $http: angular.IHttpService = inject('$http');\n\n  constructor(private readonly type: string, private readonly apiBasePath = '') {}\n\n  fetchAllKeywords(): Promise<IAutocomplete[]> {\n    return this.$http<any>({\n      url: `${this.apiBasePath}/api/autocomplete/${this.type}`,\n      method: 'GET'\n    })\n      .then(({data}) => data)\n      .catch(e => console.log(e)) as any;\n  }\n\n  fetchSchema(): Promise<IDbNode[]> {\n    return this.$http<any>({\n      url: `${this.apiBasePath}/api/db/${this.type}/explore`,\n      method: 'GET'\n    })\n      .then(({data}) => data)\n      .catch(e => []) as any;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/permissions/permissions-service.ts",
    "content": "import {confirm} from '../../../../lib/ui';\nimport {RunnerComponentInstance} from '../../directives/runner/runner';\n\nconst PERMISSION_ERROR_PATTERNS = [\n  'permission denied',\n  'permission was denied',\n  'you do not have permission',\n  'under the current security context',\n  'Login failed. The login is from an untrusted domain and cannot be used with Windows authentication'\n];\n\nexport const isPermissionError = (msg: string) => {\n  return PERMISSION_ERROR_PATTERNS.some(pattern => msg.indexOf(pattern) !== -1);\n}\n\nexport const requestCredentials = (scope, runnerInstance: RunnerComponentInstance) => {\n  const user = runnerInstance.getUser();\n\n  if (!user) {\n    throw new Error('To use promptOnPermissionError please call runnerComponentInstance.setUser(user)');\n  }\n\n  user.getPermission().deelevate();\n\n  return confirm({\n    title: `Permission denied`,\n    actionType: 'neutral',\n    icon: 'gpp_bad',\n    yes: 'Submit',\n    resolveOnEnter: true,\n    html: `\n      <div class=\"bi-c-h bi-s-v--x05\">\n        <span class=\"bi-text--sm bi-muted\">Please enter your password to access restricted data</span>\n        <input type=\"password\" class=\"bi-input\" ng-model=\"model.password\" placeholder=\"Password\" required=\"true\" bi-focus/>\n      </div>\n    `\n  }, scope, {model: {password: null}}).then(({model}) => {\n    user.getPermission().elevate(model.password);\n  });\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/runner-event.ts",
    "content": "export default class RunnerEvent {\n  private readonly handlers = [];\n  private readonly status = {\n    callCount: 0\n  };\n\n  constructor (private readonly name, private readonly options = {dontDigest: false}) { }\n\n  public getName() {\n    return this.name;\n  }\n\n  public getOptions() {\n    return this.options;\n  }\n\n  public append(handler) {\n    this.handlers.push(handler);\n  }\n\n  public prepend(handler) {\n    this.handlers.unshift(handler);\n  }\n\n  public apply(data, meta) {\n    this.status.callCount++;\n\n    this.handlers.every(handler => {\n      data = handler(data, meta, this.status);\n\n      // break if data is false\n      if (data === false) {\n        return false;\n      }\n      return true;\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/runner-events.ts",
    "content": "import {values} from 'lodash';\nimport RunnerEvent from './runner-event';\n\nexport default class RunnerEvents {\n  private readonly handlers: {[eventName: string]: RunnerEvent} = {};\n\n  constructor(private readonly runner) {\n\n  }\n\n  public register(eventName, handler, options = {dontDigest: false}) {\n    const event = this.handlers[eventName] = new RunnerEvent(eventName, options);\n\n    event.append(handler);\n\n    return this;\n  }\n\n  public getRegisteredEvents(): RunnerEvent[] {\n    return values<RunnerEvent>(this.handlers);\n  }\n\n  public append(eventName, handler): RunnerEvents {\n    this.handlers[eventName].append(handler);\n    return this;\n  }\n\n  public prepend(eventName, handler): RunnerEvents {\n    this.handlers[eventName].prepend(handler);\n    return this;\n  }\n\n  public apply(eventName, data, meta): RunnerEvents {\n    if (this.runner.getState().getStatus().killed) {\n      return;\n    }\n\n    this.handlers[eventName].apply(data, meta);\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/runner-query.ts",
    "content": "import {zipObject} from 'lodash';\nimport moment from 'moment';\nimport {srv, inject} from '../../core';\n\nexport interface IField {\n  name: string;\n  title?: string;\n}\n\nexport interface IError {\n  msg: string;\n  details: Object;\n}\n\nexport interface ITime {\n  elapsed: string;\n  started: number;\n  interval;\n}\n\nexport interface IStatus {\n  running: boolean;\n  success: boolean;\n  finished: boolean;\n  error: boolean;\n  killed: boolean;\n}\n\nfunction getFieldName(field: string, fieldNames: Record<string, number>) {\n  fieldNames[field] = fieldNames[field] || 0;\n\n  return field + `${fieldNames[field]++ ? `_${fieldNames[field]}` : ''}`;\n}\n\nfunction startDurationCount(): ITime {\n  const res: ITime = {\n    elapsed: '00:00',\n    started: Date.now(),\n    interval: null\n  };\n\n  res.interval = inject('$interval')(() => {\n    const now = moment();\n    res.elapsed = now.subtract(res.started).format('mm:ss');\n  }, 1000);\n\n  return res;\n}\n\nfunction stopDurationCount(time) {\n  inject('$interval').cancel(time.interval);\n}\n\nexport default class RunnerQuery extends srv.eventEmitter.EventEmitter {\n  private details = {};\n  private readonly metadata = {};\n  private title;\n  private _fields: IField[] = [];\n  private _rawFields: string[] = [];\n  private readonly _results = new srv.collections.BufferedCollection().setChunkSize(20);\n  private fastForwardPromise = null;\n  private error: IError;\n  private stats: {[key: string]: any};\n  private time: ITime = {\n    elapsed: null,\n    started: null,\n    interval: null\n  };\n  private readonly status: IStatus = {\n    running: false,\n    success: false,\n    finished: false,\n    error: false,\n    killed: false\n  };\n\n  constructor(private readonly id, private readonly index) {\n    super();\n  }\n\n  public meta(name, value?) {\n    if (value) {\n      this.metadata[name] = value;\n      return this;\n    }\n    return this.metadata[name];\n  }\n\n  public setDetails(details) {\n    this.details = details;\n    return this;\n  }\n\n  public getDetails() {\n    return this.details;\n  }\n\n  public get results(): any {\n    return this.getResults();\n  }\n\n  public get fields(): IField[] {\n    return this.getFields();\n  }\n\n  public get running(): boolean {\n    return this.status.running;\n  }\n\n  public get success(): boolean {\n    return this.status.success;\n  }\n\n  public get finished(): boolean {\n    return this.status.finished;\n  }\n\n  public get elapsedTime(): string {\n    return this.getTime().elapsed;\n  }\n\n  public get startTime(): number {\n    return this.getTime().started;\n  }\n\n  public getId(): string {\n    return this.id;\n  }\n\n  public getIndex(): number {\n    return this.index;\n  }\n\n  public getResults(): any {\n    return this._results;\n  }\n\n  public getFields(): IField[] {\n    return this._fields;\n  }\n\n  public getRawFields(): string[] {\n    return this._rawFields;\n  }\n\n  public getError(): IError {\n    return this.error;\n  }\n\n  public getTime(): ITime {\n    return this.time;\n  }\n\n  public getTitle() {\n    return this.title;\n  }\n\n  public setTitle(title: string): RunnerQuery {\n    this.title = title;\n    return this;\n  }\n\n  public setFields(fields: string[]): RunnerQuery {\n    const fieldNames = {};\n\n    this._fields = fields.map(name => ({\n      name: getFieldName(name, fieldNames),\n    }));\n\n\n    this._rawFields = this._fields.map(({name}) => name);\n\n    return this;\n  }\n\n  public addRow(row): Object {\n    this._results.feed(zipObject(this._rawFields, row));\n\n    if (this.getResults().bufferSize() === 1) {\n      this.fire('firstResultReceived', this);\n    } else if (this.getResults().bufferSize() === 2) {\n      this.fire('moreResultReceived', this);\n    }\n\n\n    // Fast-forward slow rows\n    if (this._results.size() < this._results.getChunkSize()) {\n      this.fastForwardPromise = this.fastForwardPromise ? this.fastForwardPromise.then(() => {\n        if (this._results.size() < this._results.getChunkSize()) {\n          return this._results.more();\n        }\n      }) : this._results.more();   \n    }\n\n    return this;\n  }\n\n  public setError(error): RunnerQuery {\n    this.error = error;\n    this.fire('error', this, error);\n\n    return this;\n  }\n\n  public setErrorMessage(msg) {\n    this.error.msg = msg;\n  }\n\n  public getStats() {\n    return this.stats;\n  }\n\n  public setStats(stats: {[key: string]: any}) {\n    this.stats = stats;\n  }\n\n  public start(): RunnerQuery {\n    this._results.fetch();\n    this.status.running = true;\n    this.status.success = true;\n\n    this.time = startDurationCount();\n\n    return this;\n  }\n\n  public end(): RunnerQuery {\n    this._results.seal();\n    this.status.running = false;\n    this.status.finished = true;\n\n    stopDurationCount(this.time);\n\n    this.fire('finish', this);\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/runner-service.ts",
    "content": "import {inject, srv} from '../../core';\nimport {RunnerSocket} from './runner-socket';\nimport RunnerEvents from './runner-events';\nimport RunnerState from './runner-state';\nimport RunnerQuery from './runner-query';\nimport {RunnerType} from '../typings/runner-types';\nimport { config } from '../config';\n\nfunction initSocket(socket: RunnerSocket, events: RunnerEvents, transformers, scope, log: boolean = false) {\n  events.getRegisteredEvents().forEach(event => {\n    const eventName = event.getName();\n\n    socket.on(eventName, ({data, meta}) => {\n      if (log) {\n        /* tslint:disable-next-line:no-console */\n        console.log(eventName, data, meta);\n      }\n\n      if (event.getOptions().dontDigest) {\n        events.apply(eventName, data, meta);\n      } else {\n        scope.$apply(() => {\n          events.apply(eventName, data, meta);\n        });\n      }\n    });\n  });\n\n  socket.transformResponse(transformers.response);\n}\n\nfunction sendSocketData(socket, code, user, transformers, mode = 'stream') {\n  const session: any = {mode};\n\n  if (user && user.getPermission() && user.getPermission().isElevated()) {\n    session['user.password'] = user.getPermission().getPassword();\n  }\n\n  socket.on('open', async () => {\n    code = await transformers.request(code);\n\n    socket.send({\n      event: 'execute',\n      data: {code, session}\n    });\n  });\n}\n\nexport class Runner extends srv.eventEmitter.EventEmitter {\n  private readonly mode: string;\n  private readonly version: number;\n  private readonly executeBaseUrl: string;\n  private socket: RunnerSocket;\n  private readonly events: RunnerEvents;\n  private readonly state = new RunnerState();\n  private code = null;\n  private logEvents: boolean = false;\n  private keepAliveInterval;\n  private numOfRetries = 0;\n\n  private readonly transformers = {\n    request: request => request,\n    response: response => response\n  };\n\n  constructor(private readonly type: RunnerType, private readonly scope, options) {\n    super();\n\n    this.mode = options.mode;\n    this.version = options.version || 1;\n    this.executeBaseUrl = options.executeBaseUrl;\n    this.events = new RunnerEvents(this);\n\n    this.events\n      .register('start', data => {\n        this.getState()\n          .setId(data.id)\n          .setTotalNumOfQueries(data.numOfQueries);\n\n        this.fire('start', this);\n\n        return data;\n      })\n\n      .register('end', data => {\n        this.finish();\n\n        return data;\n      })\n\n      .register('query-start', (data) => {\n        this.getState()\n          .startQuery(data.id);\n\n        this.stream('queryCreated', this, this.getState().getCurrentQuery());\n\n        return data;\n      });\n\n      this.getEvents().register('query-download', (data) => {\n        if (data.url) {\n          this.fire('downloadFile', `${this.executeBaseUrl}${data.url}`, this, this.getCurrentQuery());\n        }\n      })\n\n      .register('query-end', data => {\n        this.getCurrentQuery().setStats(data.statistics);\n        this.getState().endQuery(data.id);\n\n        return data;\n      })\n\n      .register('percentage', (data, meta, status) => {\n        const totalQueries = this.getTotalNumOfQueries();\n        const percentagePerQuery = 100 / totalQueries;\n        const totalQueriesUntilNow = this.getState().getQueries().length - 1;\n        const percentageUntilNow = totalQueriesUntilNow * percentagePerQuery;\n        const thisQueryPercentage = data.percentage * percentagePerQuery / 100;\n\n        this.getState()\n          .setProgress(Math.round(percentageUntilNow + thisQueryPercentage))\n          .setSuccessStatus(true);\n\n        if (status.callCount === 1) {\n          this.fire('success', this, this.getCurrentQuery());\n        }\n\n        return data;\n      })\n\n      .register('error', (data) => {\n        if (!this.getState().getCurrentQuery()) {\n          // error happened in a very early stage of execution, some events need to be simulated\n          this.events\n            .apply('start', {id: 1}, {})\n            .apply('query-start', {id: 1}, {})\n            .apply('query-end', {id: 1}, {});\n        }\n\n        const query = this.getState()\n          .setErrorStatus(true)\n          .getCurrentQuery().setError(data);\n\n        this.fire('error', this, data, query);\n\n        return data;\n      })\n\n      .register('fields', data => {\n        const query = data.id ? this.getState().getQueryById(data.id) : this.getState().getCurrentQuery();\n\n        query.setFields(data.fields);\n\n        return data;\n      })\n\n      .register('row', (data, meta, status) => {\n        const query = data.id ? this.getState().getQueryById(data.id) : this.getState().getCurrentQuery();\n\n        query.addRow(data.values);\n\n        if (status.callCount === 1) {\n          this.fire('firstResultReceived', this);\n        } else if (status.callCount === 2) {\n          this.fire('moreResultReceived', this);\n        }\n\n        return data;\n      }, {dontDigest: true});\n  }\n\n  protected log(value: boolean) {\n    this.logEvents = value;\n  }\n\n  protected start() {\n    this.getState().setRunningStatus(true);\n    \n    if (this.numOfRetries === 0) {\n      this.getState().startDurationCount();\n      this.keepAliveInterval = inject('$interval')(() => this.getSocket().send({\n        event: 'ping'\n      }), 15 * 1000);\n    }\n  }\n\n  protected finish() {\n    inject('$interval').cancel(this.keepAliveInterval);\n\n    this.getSocket().close();\n\n    this.getState()\n      .setRunningStatus(false)\n      .setFinishedStatus(true)\n      .stopDurationCount();\n\n    this.getState().getQueries().forEach(query => {\n      if (!query.finished) {\n        this.getState().endQuery(query.getId());\n      }\n    });\n\n    this.fire('finish', this);\n  }\n\n  public getScope() {\n    return this.scope;\n  }\n\n  public getSocket() {\n    return this.socket;\n  }\n\n  public getEvents() {\n    return this.events;\n  }\n\n  public getState() {\n    return this.state;\n  }\n\n  public getQueries(): RunnerQuery[] {\n    return this.getState().getQueries();\n  }\n\n  public getTotalNumOfQueries(): number {\n    return this.getState().getTotalNumOfQueries();\n  }\n\n  public getCurrentQuery(): RunnerQuery {\n    return this.getState().getCurrentQuery();\n  }\n\n  public getMode(): string {\n    return this.mode;\n  }\n\n  public get error() {\n    return this.getState().getError();\n  }\n\n  public get progress() {\n    return this.getState().getProgress();\n  }\n\n  public get elapsedTime() {\n    return this.getState().getTime().elapsed;\n  }\n\n  public get running() {\n    return this.getState().getStatus().running;\n  }\n\n  public getCode() {\n    return this.code;\n  }\n\n  public transformRequest(transformer): Runner {\n    this.transformers.request = transformer || this.transformers.request;\n\n    return this;\n  }\n\n  public transformResponse(transformer): Runner {\n    this.transformers.response = transformer || this.transformers.response;\n\n    return this;\n  }\n\n  public run(code, user?): Runner {\n    this.socket = new RunnerSocket(this.type, this.version, this.executeBaseUrl);\n    this.code = code;\n\n    initSocket(this.socket, this.events, this.transformers, this.scope, this.logEvents);\n    sendSocketData(this.socket, code, user, this.transformers, this.mode);\n\n    this.socket.on('close', () => {\n      if (this.getState().getStatus().finished) {\n        return;\n      }\n\n      const connectionId = this.getState().getId();\n\n      if (\n        this.numOfRetries < 10 &&\n        (!connectionId || (\n          this.getQueries().length === 1\n          && !this.getCurrentQuery().getResults().bufferSize()\n        ))\n      ) {\n        this.numOfRetries++;\n        this.run(code, user);\n        return;\n      }\n\n      this.getScope().$apply(() => {\n        this.getEvents().apply('error', {\n          message: this.getConnectionErrorMessage(connectionId),\n        }, {});\n\n        this.finish();\n      });\n    });\n\n    this.start();\n\n    return this;\n  }\n\n  public kill() {\n    this.getState().setKilledStatus(true);\n\n    if (!this.running) {\n      return;\n    }\n\n    this.finish();\n  }\n\n  getConnectionErrorMessage(connectionId) {\n    return `Connection failed after (${this.numOfRetries}) retries, please rerun your query manually.   \nThis is most likely a transient network error and not a problem with the ${inject('$filter')('biToHumanCase')(this.type)} engine.\n-------------------------------------------------------------------------------------------------\nConnection ID: ${connectionId}\nConnection start time: ${inject('$filter')('biDate')(this.getState().getTime().started, 'seconds')}\nConnection elapsed time: ${this.getState().getTime().elapsed}\n-------------------------------------------------------------------------------------------------\n${this.getCurrentQuery() ? `Query ID: ${this.getCurrentQuery().getId()}` : ''}\n${this.getCurrentQuery() ? `Query start time: ${inject('$filter')('biDate')(this.getCurrentQuery().getTime().started, 'seconds')}` : ``}\n${this.getCurrentQuery() ? `Query elapsed time: ${this.getCurrentQuery().getTime().elapsed}` : ``}\n${this.getCurrentQuery() ? `Fetched rows: ${this.getCurrentQuery().getResults().bufferSize()}` : ``}\n`\n  }\n}\n\nexport default function create(type: RunnerType, scope, {\n  mode = 'stream',\n  version = null,\n  executeBaseUrl = config.get().executeBaseUrl,\n} = {\n    mode: 'stream',\n    version: null,\n    executeBaseUrl: config.get().executeBaseUrl,\n}) {\n  if (!executeBaseUrl) {\n    throw new Error('Missing execute url definition');\n  }\n\n  return new Runner(type, scope, {mode, version, executeBaseUrl});\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/runner-socket.ts",
    "content": "import {srv} from '../../core';\nimport {RunnerType} from '../typings/runner-types';\n\nfunction attachProtocol(url: string) {\n  if (url.startsWith('http://')) {\n    return url.replace('http://', 'ws://');\n  }\n  if (url.startsWith('https://')) {\n    return url.replace('https://', 'wss://');\n  }\n  return (window.location.protocol === 'https:' ? 'wss:' : 'ws:') + url;\n}\n\nfunction getEndpoint(type: string, version: number) {\n  return `/api/v${version}/execute/${type}`;\n}\n\nexport class RunnerSocket extends srv.Socket {\n  private readonly transformers = {\n    response: response => response\n  };\n\n  constructor (\n    type: RunnerType = 'sql',\n    version: number = null,\n    baseUrl = '',\n    url: string = `${baseUrl}${getEndpoint(type, version)}`\n  ) {\n    super(attachProtocol(url));\n\n    this.on('event', (socket, eventName = '__unknown__', data) => {\n      this.fire(eventName, this.transformers.response(data), data.payload);\n    });\n  }\n\n  public send(payload): RunnerSocket {\n    super.send(payload);\n    return this;\n  }\n\n  public transformResponse(transformer): RunnerSocket {\n    this.transformers.response = transformer;\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/runner-state.ts",
    "content": "import moment from 'moment';\nimport {last, find} from 'lodash';\nimport {inject} from '../../core';\nimport {default as RunnerQuery, IStatus, ITime, IField} from './runner-query';\n\n// no actual runner logic should be handled here, just setters/getters\nexport default class State {\n  private readonly state = {\n    id: null,\n    queries: [],\n    progress: 0,\n    totalNumOfQueries: 0,\n    status: {\n      running: false,\n      success: false,\n      finished: false,\n      error: false,\n      killed: false\n    } as IStatus,\n    time: {\n      elapsed: '00:00',\n      started: null,\n      interval: null\n    } as ITime\n  };\n\n  public getId(): string {\n    return this.state.id;\n  }\n\n  public setId(id): State {\n    this.state.id = id;\n    return this;\n  }\n\n  public getFields(): IField[] {\n    return this.state.queries.length && this.getCurrentQuery().getFields();\n  }\n\n  public getResults() {\n    return this.state.queries.length && this.getCurrentQuery().getResults();\n  }\n\n  public getError() {\n    return this.state.queries.length && this.getCurrentQuery().getError();\n  }\n\n  public hasQueries(): boolean {\n    return !!this.getQueries().length;\n  }\n\n  public getQueries(): RunnerQuery[] {\n    return this.state.queries;\n  }\n\n  public getCurrentQuery(): RunnerQuery {\n    // if (!this.state.queries.length) {\n    //   throw 'Runner.state: there are 0 queries in the pool';\n    // }\n\n    return last(this.state.queries);\n  }\n\n  public getQueryById(id): RunnerQuery {\n    return find(this.state.queries, query => query.getId() === id);\n  }\n\n  public startQuery(id): State {\n    this.state.queries.push(new RunnerQuery(id, this.state.queries.length).start());\n    return this;\n  }\n\n  public endQuery(id): State {\n    this.getQueryById(id).end();\n    return this;\n  }\n\n  public getTotalNumOfQueries() {\n    return this.state.totalNumOfQueries;\n  }\n\n  public setTotalNumOfQueries(num) {\n    return this.state.totalNumOfQueries = num;\n  }\n\n  public getProgress(): number {\n    return this.state.progress;\n  }\n\n  public setProgress(progress): State {\n    this.state.progress = progress;\n    return this;\n  }\n\n  public getStatus(): IStatus {\n    return this.state.status;\n  }\n\n  public startDurationCount() {\n    this.state.time.started = Date.now();\n\n    this.state.time.interval = inject('$interval')(() => {\n      const now = moment();\n      this.state.time.elapsed = now.subtract(this.state.time.started).format('mm:ss');\n    }, 1000);\n\n    return this;\n  }\n\n  public stopDurationCount() {\n    inject('$interval').cancel(this.state.time.interval);\n    return this;\n  }\n\n  public getTime(): ITime {\n    return this.state.time;\n  }\n\n  public setRunningStatus(value: boolean): State {\n    this.state.status.running = value;\n    return this;\n  }\n\n  public setSuccessStatus(value: boolean): State {\n    this.state.status.success = value;\n    return this;\n  }\n\n  public setFinishedStatus(value: boolean): State {\n    this.state.status.finished = value;\n    return this;\n  }\n\n  public setErrorStatus(value: boolean): State {\n    this.state.status.error = value;\n    return this;\n  }\n\n  public setKilledStatus(value: boolean): State {\n    this.state.status.killed = value;\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/syntax-valdator/syntax-validator-service.ts",
    "content": "import {IErrorAnnotation} from '../../../language-parsers/sql-parser/parser/errors-listener';\nimport {CodeEditorInstance} from '../../../code-editor';\nimport {ModelConf} from '../../../core/ang/srv/ng-model/ng-model';\nexport interface HasGetErrorsMethod {\n  getErrors(s: string): Promise<IErrorAnnotation[]>;\n}\n\nexport function getParamsOffset(editorInstance: CodeEditorInstance) {\n  if (editorInstance.getParams().hasParams()) {\n    const locked = editorInstance.getLockedRange();\n    return (locked[locked.length - 1][1] as number) + 1; /* casting because of tslint... */\n  }\n  return 0;\n}\n\nexport const attachErrorHandler =\n  async (initWorker: () => Promise<HasGetErrorsMethod>, editorInstance: CodeEditorInstance, modelConf: ModelConf) => {\n    const worker = await initWorker();\n\n    modelConf.watchWith(({value}) => {\n      worker.getErrors(editorInstance.getParams().format(value))\n        .then(errors => {\n          editorInstance.getAnnotator().hideAll();\n          if (errors.length) {\n            const e = errors[0];\n            const offset = getParamsOffset(editorInstance);\n            editorInstance.getAnnotator().showError(e.row + offset + 1, e.text);\n          }\n        }).catch(e => null);\n    });\n  };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/workers/python-parser-worker.ts",
    "content": "import {PythonWebWorkerMngr} from '../../../language-parsers/python-parser';\n\nconst workerUrl = 'https://static.parastorage.com/unpkg-semver/bi-python-parser/web-worker.bundle.js';\nlet pythonParserPromise: Promise<PythonWebWorkerMngr>;\n\nexport const initPythonWorker = async (): Promise<PythonWebWorkerMngr | null> => {\n  pythonParserPromise = pythonParserPromise || PythonWebWorkerMngr.createFromUrl(workerUrl, 86400);\n  return pythonParserPromise;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/services/workers/sql-parser-worker.ts",
    "content": "import {BiSqlWebWorkerMngr} from '../../../language-parsers/sql-parser';\n\nconst workerUrl = 'https://static.parastorage.com/unpkg/@wix/bi-sql-parser@1.0.43/dist/statics/web-worker.bundle.min.js';\nlet sqlParserPromise: Promise<BiSqlWebWorkerMngr>;\n\nexport const initSqlWorker = async (): Promise<BiSqlWebWorkerMngr | null> => {\n  sqlParserPromise = sqlParserPromise || BiSqlWebWorkerMngr.createFromUrl(workerUrl, 86400);\n  return sqlParserPromise;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/typings/angular-promise.d.ts",
    "content": "/// <reference types=\"angular\" />\nimport * as angular from 'angular';\n\ndeclare module 'angular' {\n  export interface IPromise<T> {\n    then<TResult = T, TResult2 = never>(successCallback: (promiseValue: T) => PromiseLike<TResult> | TResult, errorCallback?: (reason: any) => TResult2, notifyCallback?: (state: any) => any): IPromise<TResult | TResult2>;\n    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/typings/runner-types.ts",
    "content": "export type RunnerType = 'sql' | 'python' | 'native';"
  },
  {
    "path": "quix-frontend/client/src/lib/runner/typings/types.d.ts",
    "content": "declare module '*.scss';\ndeclare module '*.html';\ninterface DedicatedWorkerGlobalScope {}\ninterface Promise<T> {\n  finally(finallyCallback: () => any): Promise<T>; /* lets pretend we have this in es6, makes it comptabile with ng.Ipromise */\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/sql-autocomplete-adapter-utills.ts",
    "content": "import { findLastDotIndex } from \"../../runner/services/autocomplete/highlight-and-score\";\nimport { Column } from \"../db-info\";\nimport { TableInfo } from \"../sql-context-evaluator\";\nimport { trinoToJs } from \"./trinoToJs\"\n\ninterface ObjectChild {\n  name: string;\n  dataType: any;\n}\n\nexport function getObjectChildren(obj: Record<string, any>, parentName = ''): ObjectChild[] {\n  const children: ObjectChild[] = [];\n\n  for (const key in obj) {\n    const childName = parentName ? `${parentName}.${key}` : key;\n    if (typeof obj[key] === 'object' && obj[key] !== null) {\n      children.push({ name: childName, dataType: obj[key] });\n      children.push(...getObjectChildren(obj[key], childName));\n    } else {\n      children.push({ name: childName, dataType: obj[key] });\n    }\n  }\n  return children;\n}\n\nexport function findColumnPathForPrefix(tables: TableInfo[], brokenPrefix: string[]): string {\n  const relevantPrefixes: string[] = [];\n\n  for (const table of tables) {\n    for (const column of table.columns) {\n      let found = false;\n      let gotRelevantPartOfPrefix = false;\n      let currentPrefix = '';\n\n      brokenPrefix.forEach(item => {\n        if (found) {\n          currentPrefix += item + '.';\n        }\n        if (typeof column === 'object' && !gotRelevantPartOfPrefix && item === column.name) {\n          found = true;\n          gotRelevantPartOfPrefix = true;\n          currentPrefix += item + '.';\n        }\n      });\n\n      if (currentPrefix) {\n        relevantPrefixes.push(currentPrefix);\n      }\n    }\n  }\n\n  if (relevantPrefixes.length === 0) {\n    return ''; // No relevant prefixes found\n  }\n\n  // Find the longest relevant prefix\n  let longestPrefix = relevantPrefixes[0];\n  for (const prefix of relevantPrefixes) {\n    if (prefix.length > longestPrefix.length) {\n      longestPrefix = prefix;\n    }\n  }\n\n  return longestPrefix\n}\n\n\n\nfunction getAllChildrenOfTables(tables: TableInfo[]) {\n  const allChildren = [];\n\n  for (const extractedTable of tables) {\n    const { columns } = extractedTable;\n\n    (columns.filter(c => typeof c === 'object') as Column[])\n      .forEach(({ name, dataType }) => {\n        if (typeof dataType === 'string') {\n          dataType = trinoToJs(dataType, 0);\n        }\n        if (typeof dataType === 'object') {\n          allChildren.push(...getObjectChildren(dataType, name));\n        }\n      });\n  }\n\n  return allChildren;\n}\n\n\n\n\nexport function getSearchCompletion(tables: TableInfo[], prefix: string | undefined): any {\n  if (!prefix.includes('.')) {\n    return [];\n  }\n  const columnPathForPrefix = findColumnPathForPrefix(tables, prefix.split('.')).slice(0, -1);\n  if (!columnPathForPrefix) {\n    return []\n  }\n  const filteredChildren = getAllChildrenOfTables(tables).filter(byPrefix(columnPathForPrefix));\n  const prefixUntilLastDot = extractPrefixUntilLastDot(columnPathForPrefix);\n  const completionArray = filteredChildren.map(({ name, dataType }) => ({\n    value: name,\n    meta: typeof dataType === 'object' ? 'row' : dataType,\n    caption: name.slice(prefixUntilLastDot.length + 1)\n  }));\n  return completionArray;\n}\n\nfunction byPrefix(relevantPartOfPrefix: string) {\n  return ({ name }) => {\n    const startOfSearch = findLastDotIndex(relevantPartOfPrefix) >= 0 ? relevantPartOfPrefix.slice(0, findLastDotIndex(relevantPartOfPrefix) + 1) : relevantPartOfPrefix;\n    const searchPart = relevantPartOfPrefix.replace(startOfSearch, '')\n    const parts = name.toLowerCase().split('.');\n\n    if (parts.length <= 1) { return false }\n\n    const substringAfterFirstDot = parts.slice(1).join('.');\n    const criteria = doesSubstringMatchInHierarchy(substringAfterFirstDot, searchPart.toLowerCase());\n    const filterIfInDifferentColumn = name.startsWith(relevantPartOfPrefix.split('.')[0]);\n\n    return name.includes(startOfSearch) && substringAfterFirstDot.includes(searchPart.toLowerCase()) && criteria && filterIfInDifferentColumn;\n  };\n}\n\nexport function getNextLevel(tables: TableInfo[], prefix: string | undefined): any {\n  const columnPathForPrefix = findColumnPathForPrefix(tables, prefix.split('.')).slice(0, -1);\n  const siblings = getAllChildrenOfTables(tables).filter(({ name }) => {\n    const dotCount = name.split('.').length - 1;\n    return name.startsWith(columnPathForPrefix) && dotCount === columnPathForPrefix.split('.').length - 1;\n  });\n  return siblings.map(({ name, dataType }) => ({\n    value: prefix.replace(columnPathForPrefix, '') + name,\n    meta: typeof dataType === 'object' ? 'row' : dataType,\n    caption: name.slice(columnPathForPrefix.length)\n  }));\n}\n\nfunction doesSubstringMatchInHierarchy(substringAfterFirstDot, searchPart) {\n  const lastDotIndex = findLastDotIndex(substringAfterFirstDot);\n  return lastDotIndex >= 0 ? substringAfterFirstDot.substring(lastDotIndex + 1).includes(searchPart) : substringAfterFirstDot.includes(searchPart);\n}\n\n\nfunction extractPrefixUntilLastDot(inputString: string) {\n  const lastDotIndex = findLastDotIndex(inputString);\n\n  return lastDotIndex >= 0 ?\n    inputString.substring(0, lastDotIndex) :\n    inputString\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/sql-autocomplete-adapter.ts",
    "content": "import { uniqBy } from 'lodash';\nimport { ICompleterItem } from '../../code-editor/services/code-editor-completer';\nimport { IAutocompleter } from './types';\nimport {\n  ContextType,\n  QueryContext,\n  TableInfo,\n  TableType,\n} from '../sql-context-evaluator';\nimport { getNextLevel, getSearchCompletion } from \"./sql-autocomplete-adapter-utills\";\nimport { trinoToJs } from \"./trinoToJs\";\nimport { IDbInfoConfig } from '../db-info';\nimport { BaseEntity, Column } from '../db-info/types';\n\ninterface ComplexCompleterItem extends ICompleterItem {\n  dataType?: string | object\n}\n\nexport class SqlAutocompleter implements IAutocompleter {\n  private prefix: string;\n  private lastCompleters: ICompleterItem[] = [];\n\n  constructor(\n    private readonly config: IDbInfoConfig,\n    private readonly type?: string\n  ) {\n    this.config.preFetch(this.type);\n  }\n\n  // methods\n\n  /**\n   * Extract columns and tables from the queryContext\n   * @param {QueryContext} queryContext\n   * @return {ICompleterItem[]}\n   */\n  public async getCompletionItemsFromQueryContext(queryContext: QueryContext) {\n    const { contextType, tables, prefix } = queryContext;\n    switch (contextType) {\n      case ContextType.Column:\n        return this.getQueryContextColumns(tables);\n      case ContextType.Table:\n        const tablesCompleters = this.getQueryContextTables(tables);\n        if (prefix !== this.prefix) {\n          const [dbEntitiesCompleters, dbCompleters] = await Promise.all([\n            this.getEntitiesCompletersFromDbBasedOnPrefix(prefix),\n            this.searchEntitiesFromDb(prefix),\n          ]);\n          this.lastCompleters = [...dbEntitiesCompleters, ...dbCompleters];\n        }\n        this.prefix = prefix;\n        return [...this.lastCompleters, ...tablesCompleters];\n      default:\n        return [];\n    }\n  }\n\n  public async getCompletionItemsFromQueryContextColumn(queryContext: QueryContext) {\n    switch (queryContext.contextType) {\n      case ContextType.Column:\n        return this.translateAndGetQueryContextColumns(queryContext.tables, queryContext.prefix);\n      default:\n        return [];\n    }    \n  }\n\n  public async translateAndGetQueryContextColumns(tables: TableInfo[], prefix?: string) {\n    const extractedTables = await this.extractColumnsFromTable(tables);\n    if (prefix.endsWith('.')) {\n      return getNextLevel(extractedTables, prefix);\n    }\n    return getSearchCompletion(extractedTables, prefix);\n  }\n\n  private async extractColumnsFromTable(tables: TableInfo[]) {\n    const tablesPromises: Promise<TableInfo>[] = [];\n    for (const table of tables) {\n      tablesPromises.push(this.extractTableColumns(table));\n    }\n    return Promise.all(tablesPromises);\n  }\n\n  /**\n   * Extract the tables from the queryContext\n   * @param {TableInfo[]} tables\n   * @return {ICompleterItem[]}\n   */\n  private getQueryContextTables(tables: TableInfo[]) {\n    return tables.map((table) => this.createCompleterItem(table.name, 'table'));\n  }\n\n  /**\n   * Extract the columns from the queryContext\n   * @param {TableInfo[]} tables\n   * @return {Promise<ICompleterItem[]>}\n   */\n  private async getQueryContextColumns(tables: TableInfo[]) {\n    const extractedTables = await this.extractColumnsFromTable(tables);\n    const result: ComplexCompleterItem[] = [];\n\n    for (const extractedTable of extractedTables) {\n      const { name, alias, columns } = extractedTable;\n      const includeTablePrefix = tables.length > 1;\n      columns.forEach((column) => {\n        if (typeof column === 'object' && typeof column.dataType === 'string') {\n          column.dataType = trinoToJs(column.dataType, 0);\n        }\n\n        let meta: string | undefined;\n        if (typeof column === 'object' && 'dataType' in column) {\n          const objectInTrino = 'row';\n          meta = typeof column.dataType === 'object' ? objectInTrino : column.dataType;\n        }\n\n        const getColumnDisplayName = (inputColumn: Column | string) => {\n          return inputColumn instanceof Object ? inputColumn.name : inputColumn;\n        };\n\n        let value: string;\n        if (alias) {\n          value = `${alias}.${getColumnDisplayName(column)}`;\n        } else if (includeTablePrefix) {\n          value = `${name}.${getColumnDisplayName(column)}`;\n        } else {\n          value = getColumnDisplayName(column);\n        }\n\n        if (typeof column === 'string') {\n          result.push({ value: column, meta: 'column' });\n          if (alias || extractedTable.name) {\n            const prefix = alias || extractedTable.name;\n            result.push({ value: `${prefix}.${column}`, meta: 'column' });\n          }\n        } else {\n          result.push({ meta, value });\n          result.push({ meta, value: column instanceof Object ? column.name : column });\n        }\n      });\n    }\n\n    return uniqBy(result, (obj) => `${obj.meta}-${obj.value}-${obj.caption}` )\n  }\n\n  /**\n   * Extract the columns from the table\n   * @param {TableInfo} table\n   * @return {Promise<TableInfo>}\n   */\n  private async extractTableColumns(table: TableInfo) {\n    const tablesToExtract = [...table.tableRefs];\n    if (table.type === TableType.External) {\n      tablesToExtract.push(table.name);\n    }\n\n    const columnsByTablesPromises: Promise<Column[]>[] = [];\n    for (const tableFullName of tablesToExtract) {\n      const [catalog, schema, tableName] = tableFullName.split('.');\n      columnsByTablesPromises.push(\n        this.config.getColumnsByTable(catalog, schema, tableName, this.type)\n      );\n    }\n    const columnsByTables = await Promise.all(columnsByTablesPromises);\n    for (const columnsByTable of columnsByTables) {\n      table.columns.push(...columnsByTable);\n    }\n\n    return table;\n  }\n\n  private createCompleterItem(value: string, meta: string): ICompleterItem {\n    return { value, meta };\n  }\n\n  private async getEntitiesCompletersFromDbBasedOnPrefix(prefix: string) {\n    const prefixArray = prefix.split('.') || [];\n    prefixArray.pop();\n    prefix = prefixArray.join('.');\n\n    let entities: BaseEntity[] = [];\n    switch (prefixArray.length) {\n      case 0:\n        entities = await this.config.getCatalogs(this.type);\n        break;\n      case 1:\n        entities = await this.config.getSchemasByCatalog(prefix, this.type);\n        break;\n      case 2:\n        entities = await this.config.getTablesBySchema(\n          prefixArray[0],\n          prefixArray[1],\n          this.type\n        );\n        break;\n      default:\n        entities = [];\n    }\n    return entities.map((entity) =>\n      this.createCompleterItem(\n        prefix ? `${prefix}.${entity.name}` : entity.name,\n        entity.type\n      )\n    );\n  }\n\n  private async searchEntitiesFromDb(\n    prefix: string\n  ): Promise<ICompleterItem[]> {\n    const allCompleters = [];\n\n    if (prefix?.length > 1) {\n      const schemaCompleters: Set<string> = new Set();\n      const tableCompleters: Set<string> = new Set();\n\n      const dbTree = await this.config.getCatalogs(this.type);\n\n      dbTree.forEach((catalog) => {\n        catalog.children.forEach((schema) => {\n          if (schema.name.indexOf(prefix) !== -1) {\n            schemaCompleters.add(`${catalog.name}.${schema.name}`);\n          }\n\n          schema.children.forEach((table) => {\n            if (table.name.indexOf(prefix) !== -1) {\n              tableCompleters.add(\n                `${catalog.name}.${schema.name}.${table.name}`\n              );\n            }\n          });\n        });\n      });\n\n      [...schemaCompleters].forEach((completer) =>\n        allCompleters.push(this.createCompleterItem(completer, 'schema'))\n      );\n      [...tableCompleters].forEach((completer) =>\n        allCompleters.push(this.createCompleterItem(completer, 'table'))\n      );\n    }\n\n    return allCompleters;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/expected-results.ts",
    "content": "import { makeCompletionItem } from '../../../../runner/services/autocomplete/autocomplete-utils';\n\nexport const expectedResult = {\n  empty: [],\n  twoColumns: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n  ],\n  twoColumnsWithAlias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblAlias1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblAlias1.col2', 'column'),\n  ],\n  twoColumnsWithNameAndAlias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n    makeCompletionItem('tblAlias1.col1', 'column'),\n    makeCompletionItem('tblAlias1.col2', 'column'),\n  ],\n  twoColumnsWithAliasAfter: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblAlias1.col1', 'column'),\n    makeCompletionItem('tblAlias1.col2', 'column'),\n  ],\n  twoColumnsWithNameAfter: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n  ],\n  twoColumnsWithName: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n  ],\n  twoColumnsWithTwoAliases: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblAlias1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblAlias1.col2', 'column'),\n    makeCompletionItem('tblAlias2.col1', 'column'),\n    makeCompletionItem('tblAlias2.col2', 'column'),\n  ],\n  fourColumnsWithTwoAliases: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblAlias1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblAlias1.col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('tblAlias2.col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('tblAlias2.col4', 'column'),\n  ],\n  fourColumnsWithNameAndAlias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('tblAlias1.col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('tblAlias1.col4', 'column'),\n  ],\n  fourColumnsWith1Alias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('tblAlias1.col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('tblAlias1.col4', 'column'),\n  ],\n  fourColumnsWith1Name: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('tblName1.col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('tblName1.col4', 'column'),\n  ],\n  sixColumnsWithName1: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('col5', 'column'),\n    makeCompletionItem('col6', 'column'),\n  ],\n  sixColumnsWithNameAndAlias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('tblAlias1.col3', 'column'),\n    makeCompletionItem('tblAlias1.col4', 'column'),\n  ],\n  sixColumnsWithNameAnd2Alias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n    makeCompletionItem('col3', 'column'),\n    makeCompletionItem('tblAlias1.col3', 'column'),\n    makeCompletionItem('col4', 'column'),\n    makeCompletionItem('tblAlias1.col4', 'column'),\n    makeCompletionItem('tblAlias2.col3', 'column'),\n    makeCompletionItem('tblAlias2.col4', 'column'),\n  ],\n  tableRefsColumnsAndExtColumns: [\n    makeCompletionItem('tblName1.col1_of_tblRef1', 'varchar'),\n    makeCompletionItem('col1_of_tblRef1', 'varchar'),\n    makeCompletionItem('tblName1.col2_of_tblRef1', 'varchar'),\n    makeCompletionItem('col2_of_tblRef1', 'varchar'),\n    makeCompletionItem('tblName1.col1_of_tblRef2', 'varchar'),\n    makeCompletionItem('col1_of_tblRef2', 'varchar'),\n    makeCompletionItem('tblName1.col2_of_tblRef2', 'varchar'),\n    makeCompletionItem('col2_of_tblRef2', 'varchar'),\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName1.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName1.col2', 'column'),\n    makeCompletionItem('ctl1.schm1.extTbl1.col1_of_extTbl1', 'varchar'),\n    makeCompletionItem('col1_of_extTbl1', 'varchar'),\n    makeCompletionItem('ctl1.schm1.extTbl1.col2_of_extTbl1', 'varchar'),\n    makeCompletionItem('col2_of_extTbl1', 'varchar'),\n  ],\n  threeTbl1Wtwithcolumns12AndTblRef1Ext1ExtwithAlias: [\n    makeCompletionItem('col1', 'column'),\n    makeCompletionItem('tblName2.col1', 'column'),\n    makeCompletionItem('col2', 'column'),\n    makeCompletionItem('tblName2.col2', 'column'),\n    makeCompletionItem('tblName2.col1_of_tblRef1', 'varchar'),\n    makeCompletionItem('col1_of_tblRef1', 'varchar'),\n    makeCompletionItem('tblName2.col2_of_tblRef1', 'varchar'),\n    makeCompletionItem('col2_of_tblRef1', 'varchar'),\n    makeCompletionItem('ctl1.schm1.extTbl1.col1_of_extTbl1', 'varchar'),\n    makeCompletionItem('col1_of_extTbl1', 'varchar'),\n    makeCompletionItem('ctl1.schm1.extTbl1.col2_of_extTbl1', 'varchar'),\n    makeCompletionItem('col2_of_extTbl1', 'varchar'),\n    makeCompletionItem('tblAlias1.col1_of_extTbl1', 'varchar'),\n    makeCompletionItem('tblAlias1.col2_of_extTbl1', 'varchar'),\n  ],\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/get-completion-Items.spec.ts",
    "content": "import { testInputQueryContext } from './test-inputs/input-query-context';\nimport { expectedResult } from './expected-results';\nimport { ContextType } from '../../../sql-context-evaluator/types';\nimport { runAdapterGetCompletersTest } from '../test-utils/tests-utils';\n\ndescribe('when reciving queryContext', () => {\n  runAdapterGetCompletersTest(\n    1,\n    testInputQueryContext[ContextType.Column].empty,\n    expectedResult.empty\n  );\n  runAdapterGetCompletersTest(\n    2,\n    testInputQueryContext[ContextType.Column].nestedTable,\n    expectedResult.twoColumns\n  );\n  runAdapterGetCompletersTest(\n    3,\n    testInputQueryContext[ContextType.Column].nestedTableWithAlias,\n    expectedResult.twoColumnsWithAlias\n  );\n  runAdapterGetCompletersTest(\n    4,\n    testInputQueryContext[ContextType.Column].withTable,\n    expectedResult.twoColumnsWithName\n  );\n  runAdapterGetCompletersTest(\n    5,\n    testInputQueryContext[ContextType.Column]\n      .twoTables1Nested1NestedWithAliasSameColumns,\n    expectedResult.twoColumnsWithAliasAfter\n  );\n  runAdapterGetCompletersTest(\n    6,\n    testInputQueryContext[ContextType.Column]\n      .twoTables1NestedWithAlias1NestedWithAlias2SameColumns,\n    expectedResult.twoColumnsWithTwoAliases\n  );\n  runAdapterGetCompletersTest(\n    7,\n    testInputQueryContext[ContextType.Column]\n      .twoTables1NestedWithAlias1NestedWithAlias2,\n    expectedResult.fourColumnsWithTwoAliases\n  );\n  runAdapterGetCompletersTest(\n    8,\n    testInputQueryContext[ContextType.Column].twoTables1Nested1NestedWithAlias,\n    expectedResult.fourColumnsWith1Alias\n  );\n  runAdapterGetCompletersTest(\n    9,\n    testInputQueryContext[ContextType.Column].twoTables1Nested1WtSameColumns,\n    expectedResult.twoColumnsWithNameAfter\n  );\n  runAdapterGetCompletersTest(\n    10,\n    testInputQueryContext[ContextType.Column].twoTables1Nested1Wt,\n    expectedResult.fourColumnsWith1Name\n  );\n  runAdapterGetCompletersTest(\n    11,\n    testInputQueryContext[ContextType.Column]\n      .twoTables1Wt1WithAlias1NestedSameColumns,\n    expectedResult.twoColumnsWithNameAndAlias\n  );\n  runAdapterGetCompletersTest(\n    12,\n    testInputQueryContext[ContextType.Column].twoTables1Wt1NestedWithAlias,\n    expectedResult.fourColumnsWithNameAndAlias\n  );\n  runAdapterGetCompletersTest(\n    13,\n    testInputQueryContext[ContextType.Column]\n      .threeTables1WtWith2Columns2NestedWith2Columns,\n    expectedResult.sixColumnsWithName1\n  );\n  runAdapterGetCompletersTest(\n    14,\n    testInputQueryContext[ContextType.Column]\n      .threeTables1WtWith2Columns121NestedWithColumns341NestedWithColumns34AndAlias,\n    expectedResult.sixColumnsWithNameAndAlias\n  );\n  runAdapterGetCompletersTest(\n    15,\n    testInputQueryContext[ContextType.Column]\n      .threeTables1WtWith2Columns121NestedWithColumns34Alias1NestedWithColumns34Alias2,\n    expectedResult.sixColumnsWithNameAnd2Alias\n  );\n  runAdapterGetCompletersTest(\n    16,\n    testInputQueryContext[ContextType.Column]\n      .threeTables1Ext1WtColumns121Wt2Refs,\n    expectedResult.tableRefsColumnsAndExtColumns\n  );\n  runAdapterGetCompletersTest(\n    17,\n    testInputQueryContext[ContextType.Column].threeTables2Ext1Wt1Refs2Columns,\n    expectedResult.threeTbl1Wtwithcolumns12AndTblRef1Ext1ExtwithAlias\n  );\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/test-inputs/input-query-context.ts",
    "content": "import { BasicQueryContextOption } from '../../../../sql-context-evaluator/tests/result-options/utils';\nimport {\n  ContextType,\n  QueryContext,\n  TableInfo,\n} from '../../../../sql-context-evaluator/types';\nimport { testTable } from './input-table';\n\nexport const createQueryContextObject = (\n  contextType: ContextType.Column | ContextType.Table | ContextType.Undefined,\n  tables: TableInfo[],\n  queryContext?: QueryContext\n) => {\n  return {\n    ...queryContext,\n    contextType: contextType,\n    tables: tables,\n  } as QueryContext;\n};\n\nexport const testInputQueryContext: BasicQueryContextOption = {\n  [ContextType.Column]: {\n    empty: createQueryContextObject(ContextType.Column, []),\n    nestedTable: createQueryContextObject(ContextType.Column, [\n      testTable.nested.unnamedWith2Columns12,\n    ]),\n    nestedTableWithAlias: createQueryContextObject(ContextType.Column, [\n      testTable.nested.unnamedWith2Columns12AndAlias,\n    ]),\n    withTable: createQueryContextObject(ContextType.Column, [\n      testTable.withTable.namedWith2Columns12,\n    ]),\n    twoTables1Nested1NestedWithAliasSameColumns: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.nested.unnamedWith2Columns12,\n        testTable.nested.unnamedWith2Columns12AndAlias,\n      ]\n    ),\n    twoTables1NestedWithAlias1NestedWithAlias2SameColumns: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.nested.unnamedWith2Columns12AndAlias,\n        testTable.nested.unnamedWith2Columns12AndAlias2,\n      ]\n    ),\n    twoTables1NestedWithAlias1NestedWithAlias2: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.nested.unnamedWith2Columns12AndAlias,\n        testTable.nested.unnamedWith2Columns34AndAlias2,\n      ]\n    ),\n    twoTables1Nested1NestedWithAlias: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.nested.unnamedWith2Columns12,\n        testTable.nested.unnamedWith2Columns34AndAlias,\n      ]\n    ),\n    twoTables1Nested1WtSameColumns: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.nested.unnamedWith2Columns12,\n        testTable.withTable.namedWith2Columns12,\n      ]\n    ),\n    twoTables1Nested1Wt: createQueryContextObject(ContextType.Column, [\n      testTable.nested.unnamedWith2Columns12,\n      testTable.withTable.namedWith2Columns34,\n    ]),\n    twoTables1Wt1WithAlias1NestedSameColumns: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.withTable.namedWith2Columns12,\n        testTable.nested.unnamedWith2Columns12AndAlias,\n      ]\n    ),\n    twoTables1Wt1NestedWithAlias: createQueryContextObject(ContextType.Column, [\n      testTable.withTable.namedWith2Columns12,\n      testTable.nested.unnamedWith2Columns34AndAlias,\n    ]),\n    threeTables1WtWith2Columns2NestedWith2Columns: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.withTable.namedWith2Columns12,\n        testTable.nested.unnamedWith2Columns34,\n        testTable.nested.unnamedWith2Columns56,\n      ]\n    ),\n    threeTables1WtWith2Columns121NestedWithColumns341NestedWithColumns34AndAlias: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.withTable.namedWith2Columns12,\n        testTable.nested.unnamedWith2Columns34,\n        testTable.nested.unnamedWith2Columns34AndAlias,\n      ]\n    ),\n    threeTables1WtWith2Columns121NestedWithColumns34Alias1NestedWithColumns34Alias2: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.withTable.namedWith2Columns12,\n        testTable.nested.unnamedWith2Columns34AndAlias,\n        testTable.nested.unnamedWith2Columns34AndAlias2,\n      ]\n    ),\n    threeTables1Ext1WtColumns121Wt2Refs: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.withTable.namedWith2TblRefs,\n        testTable.withTable.namedWith2Columns12,\n        testTable.external.ext,\n      ]\n    ),\n    threeTables2Ext1Wt1Refs2Columns: createQueryContextObject(\n      ContextType.Column,\n      [\n        testTable.withTable.named2With1TblRef1And2Columns12,\n        testTable.external.ext,\n        testTable.external.extWithAlias,\n      ]\n    ),\n  },\n  [ContextType.Table]: {},\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/get-completion-tests/test-inputs/input-table.ts",
    "content": "import { TableType } from '../../../../sql-context-evaluator/types';\nimport { createNewTableInfoObj } from '../../../../sql-context-evaluator/utils';\n\nexport const testTable = {\n  nested: {\n    emptyUnnamed: createNewTableInfoObj({\n      type: TableType.Nested,\n    }),\n    unnamedWith2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col1', 'col2'],\n    }),\n    unnamedWith2Columns34: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col3', 'col4'],\n    }),\n    unnamedWith2Columns56: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col5', 'col6'],\n    }),\n    unnamedWith2Columns12AndAlias: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col1', 'col2'],\n      alias: 'tblAlias1',\n    }),\n    unnamedWith2Columns12AndAlias2: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col1', 'col2'],\n      alias: 'tblAlias2',\n    }),\n    unnamedWith2Columns34AndAlias: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col3', 'col4'],\n      alias: 'tblAlias1',\n    }),\n    unnamedWith2Columns34AndAlias2: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['col3', 'col4'],\n      alias: 'tblAlias2',\n    }),\n    unnamedWith1TableRef1: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n    }),\n    unnamedWith1TableRef2: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n    }),\n    unnamedWith1TblRef1And2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n      columns: ['col1', 'col2'],\n    }),\n    unnamedWith1TblRef2And2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n      columns: ['col1', 'col2'],\n    }),\n    unnamedWith2TblRefs: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1', 'ctl2.schm2.tblRef2'],\n    }),\n    unnamedWith1TblRef1And2Columns12AndAlias: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n      columns: ['col1', 'col2'],\n      alias: 'tblAlias1',\n    }),\n    unnamedWith1TblRef2And2Columns12AndAlias: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n      columns: ['col1', 'col2'],\n      alias: 'tblAlias1',\n    }),\n    unnamedWith1TblRef1And2Columns12AndAlias2: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n      columns: ['col1', 'col2'],\n      alias: 'tblAlias2',\n    }),\n    unnamedWith1TblRef2And2Columns12AndAlias2: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n      columns: ['col1', 'col2'],\n      alias: 'tblAlias2',\n    }),\n  },\n\n  withTable: {\n    namedWith2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      name: 'tblName1',\n      columns: ['col1', 'col2'],\n    }),\n    namedWith2Columns34: createNewTableInfoObj({\n      type: TableType.Nested,\n      name: 'tblName1',\n      columns: ['col3', 'col4'],\n    }),\n    namedWithTblRef1: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n      name: 'tblName1',\n    }),\n    namedWithTblRef2: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n      name: 'tblName1',\n    }),\n    namedWith1TblRef1And2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n      columns: ['col1', 'col2'],\n      name: 'tblName1',\n    }),\n    namedWith1TblRef2And2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n      columns: ['col1', 'col2'],\n      name: 'tblName1',\n    }),\n    named2With1TblRef1And2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1'],\n      columns: ['col1', 'col2'],\n      name: 'tblName2',\n    }),\n    named2With1TblRef2And2Columns12: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef2'],\n      columns: ['col1', 'col2'],\n      name: 'tblName2',\n    }),\n    namedWith2TblRefs: createNewTableInfoObj({\n      type: TableType.Nested,\n      tableRefs: ['ctl1.schm1.tblRef1', 'ctl2.schm2.tblRef2'],\n      name: 'tblName1',\n    }),\n  },\n\n  external: {\n    ext: createNewTableInfoObj({\n      name: 'ctl1.schm1.extTbl1',\n    }),\n    extWithAlias: createNewTableInfoObj({\n      name: 'ctl1.schm1.extTbl1',\n      alias: 'tblAlias1',\n    }),\n    extWithAlias2: createNewTableInfoObj({\n      name: 'ctl1.schm1.extTbl1',\n      alias: 'tblAlias2',\n    }),\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/test-utils/mock-db-config.ts",
    "content": "import {\n  Catalog,\n  Column,\n  IDbInfoConfig,\n  Schema,\n  Table,\n} from '../../../db-info/types';\n\nexport class MockDbInfoService implements IDbInfoConfig {\n  \n  preFetch() {\n    return;\n  }\n\n  public async getColumnsByTable(\n    catalog: string,\n    schema: string,\n    table: string\n  ) {\n    return [\n      this.createColumn(`col1_of_${table}`),\n      this.createColumn(`col2_of_${table}`),\n    ];\n  }\n\n  public async getTablesBySchema(catalog: string, schema: string) {\n    return [\n      this.createTable(`tbl1_of_${schema}`),\n      this.createTable(`tbl2_of_${schema}`),\n    ];\n  }\n\n  public async getSchemasByCatalog(catalog: string) {\n    return [\n      this.createSchema(`schm1_of_${catalog}`),\n      this.createSchema(`schm2_of_${catalog}`),\n    ];\n  }\n\n  public async getCatalogs() {\n    return [this.createCatalog('catalog1')];\n  }\n\n  public async search(type: string, prefix: string) {\n    return [];\n  }\n\n  private createColumn = (name: string): Column => {\n    return { name: name, type: 'column', dataType: 'varchar' } as Column;\n  };\n\n  private createTable = (name: string): Table => {\n    return {\n      name: name,\n      type: 'table',\n      children: [this.createColumn('col1'), this.createColumn('col2')],\n    };\n  };\n\n  private createSchema = (name: string): Schema => {\n    return {\n      name: name,\n      type: 'schema',\n      children: [this.createTable('tbl1'), this.createTable('tbl2')],\n    };\n  };\n\n  private createCatalog = (name: string): Catalog => {\n    return {\n      name: name,\n      type: 'catalog',\n      children: [this.createSchema('schm1')],\n    };\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/test-utils/test-getCompletionItemsFromQueryContext.spec.ts",
    "content": "\nimport { DbInfoService } from \"../../../../sql-autocomplete/db-info\";\nimport { ContextType, QueryContext, TableType } from \"../../../sql-context-evaluator\";\nimport { SqlAutocompleter } from '../../sql-autocomplete-adapter';\nimport {expect} from 'chai';\nimport { MockDbInfoService } from \"./mock-db-config\";\n\ndescribe('testing autoComplete for nested objects:   ', () => {\n  const config = new MockDbInfoService();\n  const completer = new SqlAutocompleter(config);\n  const queryContext = {\n    prefix : '',\n    contextType: ContextType.Column,\n    tables : [\n      { type: TableType.External,\n        name: 'catalog0.schema0.TVAndSports',\n        alias: \"\",\n        selectAll : false,\n        tableRefs: [],\n        columns : [\n          {\n            name: 'TV',\n            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))'\n          },\n          {\n            name: 'sports',\n            dataType: 'row(team row(basketball varchar, baseball varchar, soccer varchar), individual row(tennis varchar, racketBall varchar))'\n          },\n        ]\n      },\n      { type: TableType.External,\n        name: 'catalog1.schema1.foodAndcountries',\n        alias: 'aliasName',\n        selectAll : false,\n        tableRefs: [],\n        columns : [\n          {\n            name: 'food',\n            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))'\n          },\n          {\n            name: 'countries',\n            dataType: 'row(israel row(telAviv varchar, jerusalem varchar, ramatGan varchar), USA row(NYC varchar, california varchar))'\n          },\n        ]\n      }\n    ],\n  }\n  \n\n  it('should return first level of nested object',async () => {\n    queryContext.prefix= 'catalog0.schema0.TVAndSports.TV.'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [\n      { value: 'catalog0.schema0.TVAndSports.TV.movies', meta: 'row' , caption: 'movies' },\n      { value: 'catalog0.schema0.TVAndSports.TV.tvSeries', meta: 'row' , caption: 'tvSeries' },\n    ] );\n  });\n\n  it('should return second level of nested object',async () => {\n    queryContext.prefix= 'catalog0.schema0.TVAndSports.TV.movies.'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [\n      { value: 'catalog0.schema0.TVAndSports.TV.movies.action', meta: 'row' , caption: 'action' },\n      { value: 'catalog0.schema0.TVAndSports.TV.movies.comedy', meta: 'row' , caption: 'comedy' },\n    ] );\n  });\n\n  it('should return all options that include the letter d from the second layer and above',async () => {\n    queryContext.prefix= 'catalog0.schema0.TVAndSports.TV.movies.d'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [\n      { value: 'TV.movies.action.The_Dark_Knight', meta: 'varchar' , caption: 'action.The_Dark_Knight' },\n      { value: 'TV.movies.action.Die_Hard', meta: 'varchar' , caption: 'action.Die_Hard' },\n      { value: 'TV.movies.comedy', meta: 'row' , caption: 'comedy' },\n    ] );\n  });\n\n  it('should return second level of nested object but value begins with alias',async () => {\n    queryContext.prefix= 'aliasName.foodAndcountries.food.'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [\n      { value: 'aliasName.foodAndcountries.food.fastFood', meta: 'row' , caption: 'fastFood' },\n      { value: 'aliasName.foodAndcountries.food.local', meta: 'row' , caption: 'local' },\n    ] );\n  });\n\n  it('should return options that include prefix rry in food column',async () => {\n    queryContext.prefix= 'aliasName.foodAndcountries.food.rry'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [\n      { value: 'food.fastFood.mcDonalds.mcflurry', meta: 'varchar' , caption: 'fastFood.mcDonalds.mcflurry' },\n    ] );\n  });\n\n  it('should return options that include prefix rryyyy in food column',async () => {\n    queryContext.prefix= 'aliasName.foodAndcountries.food.rryyyy'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [] );\n  });\n\n  it('should return options that include prefix Gan in from 2nd layer and higher',async () => {\n    queryContext.prefix= 'foodAndcountries.countries.Gan'\n    const completers = await getCompletions(queryContext , completer);\n    expect(completers).to.deep.equal( [\n      { value: 'countries.israel.ramatGan', meta: 'varchar' , caption: 'israel.ramatGan' },\n    ] );\n  });\n\n});\n\n\nasync function getCompletions(queryContext: QueryContext , completer: SqlAutocompleter) {\n  return completer.getCompletionItemsFromQueryContextColumn( queryContext );\n}\n\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/tests/test-utils/tests-utils.ts",
    "content": "import { expect } from 'chai';\nimport { ICompleterItem } from '../../../../code-editor/services/code-editor-completer';\nimport {\n  QueryContext,\n} from '../../../sql-context-evaluator';\nimport { SqlAutocompleter } from '../../sql-autocomplete-adapter';\nimport { MockDbInfoService } from './mock-db-config';\n\nexport const runAdapterGetCompletersTest = (\n  testnumber: number,\n  queryContext: QueryContext,\n  expected: ICompleterItem[]\n) => {\n  const config = new MockDbInfoService();\n  const autocomp = new SqlAutocompleter(config);\n  it(`test #${testnumber} should return comleters = ${expected}`, async () => {\n    const completers = await autocomp.getCompletionItemsFromQueryContext(queryContext);\n    expect(completers).to.be.deep.equal(expected);\n  });\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/trinoToJs.spec.ts",
    "content": "\nimport {expect} from 'chai';\nimport { trinoToJs } from './trinoToJs';\ndescribe.only('testing trinoToJs function usecase:   ', () => {\n\n  it('should translate a simple row to a js object', () => {\n    const path = 'row(aa varchar)';\n    expect(trinoToJs(path, 0)).to.deep.equal({ aa: 'varchar' }); //length after change of vars\n  });\n\n  it('should translate a simple nested row to a nested js object', () => {\n    const path = 'row(a varchar, b row(a varchar))';\n    expect(trinoToJs(path, 0)).to.deep.equal({ a: 'varchar', b: { a: 'varchar' } });\n  });\n\n  it('should translate the multilayered row to a js object', () => {\n    const path = 'row(a varchar, b row(c varchar), d e, f row(g row(h row(i varchar))))';\n    const expected = { a: 'varchar', b: { c: 'varchar' }, d: 'e', f: { g: { h: { i: 'varchar' } } } };\n    expect(trinoToJs(path, 0)).to.deep.equal(expected);\n  });\n\n  it('should translate a row with multiple data structures', () => {\n    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)))))';\n    expect(trinoToJs(path, 0)).to.deep.equal({ a: 'map', b: { c: 'varchar' }, d: 'array', f: {g: {h: { i: 'array'}}} });\n  });\n\n  it('should return an empty input when given an empty one', () => {\n    const path = '';\n    expect(trinoToJs(path, 0)).to.deep.equal('');\n  });\n\n  it('should parse the nested map and return \"map\"', () => {\n    const path = 'map(row(a varchar, b bigint), row(c double, d boolean))';\n    expect(trinoToJs(path, 0)).to.deep.equal('map');\n  });\n\n  it('should parse the nested array and return \"array\"', () => {\n    const path = 'array(row(a varchar, b map(c integer, d boolean)), row(e double, f map(g varchar, h array(integer))))';\n    expect(trinoToJs(path, 0)).to.deep.equal('array');\n  });\n\n  it('should fail because of invalid data structure', () => {\n    const path = 'row(a hello(a,b))';\n    try {\n      expect(trinoToJs(path, 0)).to.deep.equal({});\n    } catch (error) {\n      expect(error.message).to.equal('Error at index: hello');\n    }\n  });\n\n  it('should fail because of invalid char in key', () => {\n    const path = 'row(a@b row(a,b))';\n    try {\n      expect(trinoToJs(path, 0)).to.deep.equal({});\n    } catch (error) {\n      expect(error.message).to.equal('Error at index: 5, illegal key value');\n    }\n  });\n\n  it('should fail because of invalid comma', () => {\n    const path = 'row(a , row(a,b))';\n    try {\n      expect(trinoToJs(path, 0)).to.deep.equal({});\n    } catch (error) {\n      expect(error.message).to.equal('Error at index: ow(a , type expected before comma');\n    }\n  });\n  \n  it('should return a simple string when given one', () => {\n    const path = 'a varchar';\n    expect(trinoToJs(path, 0)).to.deep.equal('a varchar');\n  });\n  \n});"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/trinoToJs.ts",
    "content": "const enum StartingOptions {\n  Row = 'row(',\n  Map = 'map(',\n  Array = 'array(',\n  TimeStamp = 'timestamp(',\n}\nconst enum SpecialCharacters {\n  OpenParenthesis = '(',\n  ClosedParenthesis = ')',\n  Comma = ',',\n  Space = ' ',\n}\n\nexport function trinoToJs(trinoObjectAsString: string, index: number):  object|string {\n  if (trinoObjectAsString.startsWith(StartingOptions.Row , index)) {\n    return processRow(trinoObjectAsString, index + StartingOptions.Row.length);\n  }\n  if (trinoObjectAsString.startsWith(StartingOptions.Map, index )) {\n    return 'map';\n  }\n\n  if ( trinoObjectAsString.startsWith(StartingOptions.Array, index ) ) {\n    return 'array';\n  }\n    return trinoObjectAsString;\n}\n\nexport function processRow(trinoObjectAsString: string, index: number): object {\n  const finalObject: object = {};\n  let key = \"\";\n  let value = \"\";\n  let objectToInsert;\n  let isFirstWord = true;\n  const LENGTH_OF_SUBSTRING = 5;\n\n  while (index <= trinoObjectAsString.length) {\n    switch (trinoObjectAsString.charAt(index)) {\n      case SpecialCharacters.OpenParenthesis: {\n        const start = findBeginningOfWord(trinoObjectAsString, index);\n        const result = handleStartingOptions(trinoObjectAsString, start, index);\n        objectToInsert = result.objectToInsert;\n        finalObject[key] = result.type;\n        index = result.newIndex;\n        break;\n      }\n      case SpecialCharacters.ClosedParenthesis: {\n        validateKey(key, index);\n        finalObject[key] = objectToInsert || value;\n        return finalObject;\n      }\n      case SpecialCharacters.Comma: {\n        if (value === \"\") {\n          throw new Error(`Error at index: ${trinoObjectAsString.substring(index-LENGTH_OF_SUBSTRING,index)}, type expected before comma`);\n        }\n        finalObject[key] = objectToInsert || value;\n        key = \"\";\n        value = \"\";\n        objectToInsert = undefined;\n        isFirstWord = true;\n        break;\n      }\n      case SpecialCharacters.Space: {\n        isFirstWord = trinoObjectAsString[index-1] === SpecialCharacters.Comma;\n        break;\n      }\n      default: {\n        const charIndex = trinoObjectAsString.charAt(index);\n        if (isFirstWord) {\n          key += charIndex;\n          validateKey(key, index);\n        } else {\n          value += charIndex;\n        }\n      }\n    }\n    index++;\n  }\n  return {};\n}\n\nfunction findBeginningOfWord(str: string, index: number): number {\n  while (index > 0 && str[index] !== SpecialCharacters.Space) {\n    index--;\n  }\n  return index;\n}\n\nfunction handleStartingOptions(trinoObjectAsString: string, start: number, end: number) {\n  let objectToInsert;\n  let newIndex = end;\n  const rowLength = 3;\n  const lengthOfSubstring = 5;\n\n  switch (getOperator(trinoObjectAsString, start, end)) {\n    case StartingOptions.Row: {\n      objectToInsert = trinoToJs(trinoObjectAsString, end - rowLength);\n      newIndex = findClosingParentheses(trinoObjectAsString, end);\n      break;\n    }\n    case StartingOptions.Map: {\n      newIndex = findClosingParentheses(trinoObjectAsString, end);\n      return { objectToInsert, type: \"map\", newIndex };\n    }\n    case StartingOptions.Array: {\n      newIndex = findClosingParentheses(trinoObjectAsString, end);\n      return { objectToInsert, type: \"array\", newIndex };\n    }\n    case StartingOptions.TimeStamp:  {\n      newIndex = findClosingParentheses(trinoObjectAsString, end);\n      return { objectToInsert, type: \"timeStamp\", newIndex };\n    }\n    default : {\n      throw new Error(`Error at index: ${trinoObjectAsString.substring(end-lengthOfSubstring,end)}`);\n    }\n  }\n\n  return { objectToInsert, newIndex };\n}\n\nfunction validateKey(key: string, indexInOriginalString: number) {\n  const forbiddenChars = /^[^!@#$%^&*(),.:;\\s\\n]+$/;\n\n  if (!forbiddenChars.test(key)) {\n      throw new Error(`Error at index: ${indexInOriginalString}, illegal key value`);\n  }\n}\n\nfunction getOperator(trinoObjectAsString: string, start: number , end: number) {\n  return trinoObjectAsString.substring(start+1, end+1); //we are in middle of string start is ' ' \n}\n\nfunction findClosingParentheses(trinoObjectAsString: string, counter: number): number { \n  let parenthesis = 0;\n  for (let i = counter; i < trinoObjectAsString.length; i++) {\n    if (trinoObjectAsString.charAt(i) === SpecialCharacters.OpenParenthesis) {\n      parenthesis++;\n    }\n    if (trinoObjectAsString.charAt(i) === SpecialCharacters.ClosedParenthesis) {\n      parenthesis--;\n    }\n    if (parenthesis === 0) {\n      return i\n    }\n  }\n  return -1;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/adapter/types.ts",
    "content": "import { QueryContext } from '../sql-context-evaluator/types';\n\nexport type IContextEvaluator = (input: string, position: number) => any;\n\nexport interface IAutocompleter {\n  getCompletionItemsFromQueryContext(queryContext: QueryContext): any;\n}\n\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/db-info/db-info-service.ts",
    "content": "import {\n  CacheProps,\n  Catalog,\n  Column,\n  IDbInfoConfig,\n  Schema,\n  Table,\n} from './types';\nimport axios from 'axios';\n\nexport class DbInfoService implements IDbInfoConfig {\n  private readonly cache = new Map<string, CacheProps>();\n\n  constructor(\n    private readonly type: string,\n    private readonly apiBasePath: string\n  ) {}\n\n  preFetch = async (type: string = this.type) => {\n    this.addCacheTypeEntry(type);\n    if (!this.cache.get(type).catalogs) {\n      const response = await axios.get(\n        `${this.apiBasePath}/api/db/${type}/explore`\n      );\n      this.cache.set(type, response.data);\n    }\n  };\n\n  getCatalogs = async (type: string = this.type): Promise<Catalog[]> => {\n    await this.preFetch(type);\n    return this.cache[type];\n  };\n\n  getSchemasByCatalog = async (\n    catalog: string,\n    type?: string\n  ): Promise<Schema[]> => {\n    const catalogs: Catalog[] = await this.getCatalogs(type);\n    const catalogData: Catalog | undefined = catalogs.find(\n      (currCatalog) => currCatalog.name === catalog\n    );\n    return catalogData?.children || [];\n  };\n\n  getTablesBySchema = async (\n    catalog: string,\n    schema: string,\n    type?: string\n  ): Promise<Table[]> => {\n    const catalogSchemas: Schema[] = await this.getSchemasByCatalog(\n      catalog,\n      type\n    );\n    const schemaData: Schema | undefined = catalogSchemas.find(\n      (catalogSchema) => catalogSchema.name === schema\n    );\n    return schemaData?.children || [];\n  };\n\n  getColumnsByTable = async (\n    catalog: string,\n    schema: string,\n    table: string,\n    type: string = this.type\n  ): Promise<Column[]> => {\n    const query = `${encodeURIComponent(catalog)}/${encodeURIComponent(\n      schema\n    )}/${encodeURIComponent(table)}`;\n\n    this.addCacheTypeEntry(type);\n\n    if (this.cache.get(type).tables[query]) {\n      return this.cache.get(type).tables[query];\n    }\n\n    const response = await axios.get(\n      `${this.apiBasePath}/api/db/${type}/explore/${query}`\n    );\n\n    const tableData: Table = response.data;\n    this.cache.get(type).tables[query] = (tableData?.children || []).map(\n      (column) => ({\n        ...column,\n      })\n    );\n\n    return this.cache.get(type).tables[query];\n  };\n\n  search = async (\n    prefix: string,\n    type: string = this.type\n  ): Promise<Catalog[]> => {\n    return axios\n      .get(`${this.apiBasePath}/api/db/${type}/search`, {\n        params: { q: prefix },\n      })\n      .then((response) => response.data);\n  };\n\n  private readonly addCacheTypeEntry = (type: string) => {\n    if (!this.cache.has(type)) {\n      const newCacheProp: CacheProps = { catalogs: [], tables: {} };\n      this.cache.set(type, newCacheProp);\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/db-info/index.ts",
    "content": "import { DbInfoService } from './db-info-service';\nimport { IDbInfoConfig, Catalog, Schema, Table, Column } from './types';\n\nexport { DbInfoService, IDbInfoConfig, Catalog, Schema, Table, Column };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/db-info/types.ts",
    "content": "export interface BaseEntity {\n  name: string;\n  type: string;\n}\n\nexport interface Column extends BaseEntity {\n  dataType: object | string;\n}\n\nexport interface NestedColumn extends Column {\n  dataType: object;\n}\n\nexport interface Table extends BaseEntity {\n  children: Column[];\n}\n\nexport interface Schema extends BaseEntity {\n  children: Table[];\n}\n\nexport interface Catalog extends BaseEntity {\n  children: Schema[];\n}\n\nexport interface CacheProps {\n  catalogs: Catalog[];\n  tables: { [key: string]: Column[] };\n}\n\nexport interface IDbInfoConfig {\n  getColumnsByTable(\n    catalog: string,\n    schema: string,\n    table: string,\n    type?: string\n  ): Promise<Column[]>;\n  getTablesBySchema(\n    catalog: string,\n    schema: string,\n    type?: string\n  ): Promise<Table[]>;\n  getSchemasByCatalog(catalog: string, type?: string): Promise<Schema[]>;\n  getCatalogs(type?: string): Promise<Catalog[]>;\n  search(prefix: string, type?: string): Promise<Catalog[]>;\n  preFetch(type?: string): any;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/languge/reserved-words.ts",
    "content": "export const reservedPrestoWords = [\n  'ALTER',\n  'ALTER COLUMN',\n  'ALTER TABLE',\n  'AND',\n  'AS',\n  'BETWEEN',\n  'BY',\n  'CASE',\n  'CAST',\n  'CONSTRAINT',\n  'CREATE',\n  'CROSS',\n  'CROSS APPLY',\n  'CROSS JOIN',\n  'CUBE',\n  'CURRENT_DATE',\n  'CURRENT_PATH',\n  'CURRENT_ROLE',\n  'CURRENT_TIME',\n  'CURRENT_TIMESTAMP',\n  'CURRENT_USER',\n  'DEALLOCATE',\n  'DELETE',\n  'DELETE FROM',\n  'DESCRIBE',\n  'DISTINCT',\n  'DROP',\n  'ELSE',\n  'END',\n  'ESCAPE',\n  'EXCEPT',\n  'EXECUTE',\n  'EXISTS',\n  'EXTRACT',\n  'FALSE',\n  'FOR',\n  'FROM',\n  'FULL',\n  // 'GROUP',\n  'GROUP BY',\n  'GROUPING',\n  'HAVING',\n  'IN',\n  'INNER',\n  'INNER JOIN',\n  'INSERT',\n  'INSERT INTO',\n  'INTERSECT',\n  'INTO',\n  'IS',\n  'JOIN',\n  'LEFT',\n  'LEFT JOIN',\n  'LEFT OUTER JOIN',\n  'LIKE',\n  'LIMIT',\n  'LOCALTIME',\n  'LOCALTIMESTAMP',\n  'NATURAL',\n  'NORMALIZE',\n  'NOT',\n  'NULL',\n  'ON',\n  'OR',\n  // 'ORDER',\n  'ORDER BY',\n  // 'OUTER',\n  'OUTER APPLY',\n  'OUTER JOIN',\n  'PREPARE',\n  'RECURSIVE',\n  'RIGHT',\n  'RIGHT JOIN',\n  'RIGHT OUTER JOIN',\n  'ROLLUP',\n  'SELECT',\n  'SET',\n  'SET CURRENT SCHEMA',\n  'SET SCHEMA',\n  'TABLE',\n  'THEN',\n  'TRUE',\n  'UESCAPE',\n  'UNION',\n  'UNION ALL',\n  'UNNEST',\n  'UPDATE',\n  'USING',\n  'VALUES',\n  'WHEN',\n  'WHERE',\n  'WITH',\n  'XOR',\n];\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/context-evaluator.ts",
    "content": "import * as antlr4 from 'antlr4';\nimport { PrestoContextListener } from './presto-context-listener';\nimport { ContextType, QueryContext, TableInfo } from './types';\nimport { getTableInfoFromRelationNode } from './tree-analyzer';\nimport { analyzeNamedQueryNode } from './with-clause-analyzer';\nimport { createPrestoSyntaxTree } from '../../language-parsers/sql-parser/parser';\n\n/**\n * Takes query and identifier and returns the context of the given identifier in the query. \n * \n * @param   {string} input sql query\n * @param   {string} identifier to evaluate\n *\n * @returns {QueryContext} the evaluated context.\n */\nexport const evaluateContext = (\n  input: string,\n  identifier: string\n): QueryContext => {\n  const prestoSyntaxTree = createPrestoSyntaxTree(input);\n  return getContextFromSyntaxTree(prestoSyntaxTree, identifier);\n};\n\n/**\n * Takes antlr syntax tree and identifier and returns the context of the given identifier in the tree.\n *\n * @param   {any} tree antlr syntax tree\n * @param   {string} identifier to evaluate\n *\n * @returns {QueryContext} the evaluated context type and the tables info that defines the query.\n */\nconst getContextFromSyntaxTree = (\n  tree: any,\n  identifier: string\n): QueryContext => {\n  const prestoContextListener = new PrestoContextListener();\n  prestoContextListener.setIdentifier(identifier);\n  antlr4.tree.ParseTreeWalker.DEFAULT.walk(prestoContextListener, tree);\n\n  const contextType = prestoContextListener.getContextType();\n\n  const queryTables: TableInfo[] =\n    contextType === ContextType.Column\n      ? evaluateQueryTablesInfo(\n          prestoContextListener.getQuerySpecificationNode()\n        )\n      : [];\n\n  const withTablesInfo: TableInfo[] = evaluateWithTablesInfo(\n    prestoContextListener.getWithNodes()\n  );\n\n  const tables: TableInfo[] = mergeAndFilterResults(\n    contextType,\n    queryTables,\n    withTablesInfo,\n    identifier\n  );\n\n  return {\n    contextType,\n    tables,\n  };\n};\n\n/**\n * Takes querySpecificationNode and evaluate all is 'relation' childrens.\n * Creates for each relation TableInfo that defines the relation properties.\n *\n * @param   {any} querySpecificationNode antlr tree node\n *\n * @returns {TableInfo[]} TableInfo array.\n */\nconst evaluateQueryTablesInfo = (querySpecificationNode: any): TableInfo[] => {\n  return querySpecificationNode\n    ?.relation()\n    .reduce((accumulator: TableInfo[], relationNode: any) => {\n      accumulator.push(...getTableInfoFromRelationNode(relationNode));\n      return accumulator;\n    }, []);\n};\n\n/**\n * Takes array of namedQueryNodes and creates TableInfo that defines the \n * WITH table properties for each namedQueryNode.\n *\n * @param   {any[]} namedQueries array of antlr tree node\n *\n * @returns {TableInfo[]} TableInfo array.\n */\nconst evaluateWithTablesInfo = (namedQueries: any[]): TableInfo[] => {\n  return namedQueries.reduce((accumulator: TableInfo[], withNode: any) => {\n    return accumulator.concat(analyzeNamedQueryNode(withNode));\n  }, []);\n};\n\n/**\n * Takes 2 TableInfo array, one of regular query and one for the WITH tables\n * and merge them according to the context type. \n * During the merge, all the regular tables and the table references are replaced with their \n * corresponding WITH tables, if exists one.\n * \n * @param   {ContextType} contextType\n * @param   {TableInfo[]} queryTablesInfo\n * @param   {TableInfo[]} withTablesInfo\n * @param   {string} identifier\n *\n * @returns {TableInfo[]} a new TableInfo array with the results of the merge and filter.\n */\nconst mergeAndFilterResults = (\n  contextType: ContextType,\n  queryTablesInfo: TableInfo[],\n  withTablesInfo: TableInfo[],\n  identifier: string\n): TableInfo[] => {\n  const mergedTableInfoResults: TableInfo[] = [];\n  const withTablesMap = new Map<string, TableInfo>(\n    withTablesInfo.map((table) => {\n      if (table.name !== identifier && table.alias !== identifier) {\n        return [table.name, table];\n      }\n    })\n  );\n\n  queryTablesInfo.forEach((table: TableInfo) => {\n    if (table.name !== identifier && table.alias !== identifier) {\n      let currentTable: TableInfo = table;\n      if (table.name && withTablesMap.has(table.name)) {\n        currentTable = withTablesMap.get(table.name);\n        if (table.alias) {\n          currentTable.alias = table.alias;\n        }\n        withTablesMap.delete(table.name);\n      }\n      mergedTableInfoResults.push(currentTable);\n      if (currentTable.tableRefs.length > 0) {\n        replaceTableRefsAndWithTables(currentTable, withTablesMap);\n      }\n    }\n  });\n\n  if (contextType === ContextType.Table) {\n    mergedTableInfoResults.push(...withTablesMap.values());\n  }\n\n  return mergedTableInfoResults;\n};\n\n/**\n * Replace all the table references of a given TableInfo with their \n * corresponding WITH tables info, if exists one.\n * For each such table, replaces the references and adds the columns of \n * the WITH table to the given table recursively.\n * \n * @param   {TableInfo} table\n * @param   {Map<string, TableInfo>} withMap\n */\nconst replaceTableRefsAndWithTables = (\n  table: TableInfo,\n  withMap: Map<string, TableInfo>\n) => {\n  const newTableRefs: string[] = [];\n  let tableRefsChanged: boolean = false;\n\n  table.tableRefs.forEach((tableRef: string) => {\n    if (withMap.has(tableRef)) {\n      tableRefsChanged = true;\n      const withTable = withMap.get(tableRef);\n      newTableRefs.push(...withTable.tableRefs);\n      table.columns.push(...withTable.columns);\n    } else {\n      newTableRefs.push(tableRef);\n    }\n  });\n\n  if (tableRefsChanged) {\n    table.tableRefs = newTableRefs;\n    replaceTableRefsAndWithTables(table, withMap);\n  }\n  table.selectAll = table.tableRefs.length > 0;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/index.ts",
    "content": "import { evaluateContextFromPosition } from './position-evaluator';\nimport { evaluateContext } from './context-evaluator';\nimport { QueryContext, TableInfo, ContextType, TableType } from './types';\n\nexport { evaluateContextFromPosition };\nexport { evaluateContext };\nexport { QueryContext };\nexport { TableInfo };\nexport { ContextType };\nexport { TableType };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/position-evaluator.ts",
    "content": "import { evaluateContext } from './context-evaluator';\nimport { QueryContext } from './types';\n\n/**\n * Takes query and position and returns the context of the given position in the query \n * \n * @param   {string} input sql query\n * @param   {number} position to evaluate\n * \n * @returns {QueryContext} the evaluated context\n */\nexport const evaluateContextFromPosition = (\n  input: string,\n  position: number\n): QueryContext => {\n  const identifier = 'AUTOCOMPLETE_HERE';\n  const query = createQueryToEvaluate(input, position, identifier);\n  const prefix = getPrefixByPosition(input, position);\n  return { ...evaluateContext(query, identifier), prefix };\n};\n\n/**\n * Replace the nearest word to the given position in the input with the identifier\n * \n * @param   {string} input \n * @param   {number} position where to insert\n * @param   {string} identifier string to be inserted\n * \n * @returns {string} the input after replacement\n */\nconst createQueryToEvaluate = (\n  input: string,\n  position: number,\n  identifier: string\n): string => {\n  return position > 0 && position < input.length + 1\n    ? removeLastPrefix(input.slice(0, position)) +\n        ' ' +\n        identifier +\n        ' ' +\n        input.slice(position)\n    : input;\n};\n\n/**\n * Removes the last word in the string matches the format (a-z 0-9 .)\n * \n * @param   {string} input \n * \n * @returns {string} the input after removal\n */\nconst removeLastPrefix = (input: string): string => {\n  const parts = input.match(/([\\w._]+)|([\\s,()=<>'`\":;/*!@#$%^&+-]+)/g);\n  if (parts[parts.length - 1].match(/([\\w._]+)/)) {\n    parts.pop();\n  }\n  return parts.join('');\n};\n\n/**\n * @param   {string} input \n * @param   {number} position\n * \n * @returns {string} the nearest prefix that matches the format (a-z 0-9 .) before the given postion\n */\nconst getPrefixByPosition = (input: string, position: number): string => {\n  return input\n    .slice(0, position)\n    .split(/[\\s,()=<>'`\":;*!@#$%^&+-]+/)\n    .pop();\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/presto-context-listener.ts",
    "content": "import {\n  SqlBaseListener,\n  SqlBaseParser,\n} from '../../language-parsers/presto-grammar';\nimport { ContextType } from './types';\n\n/**\n * A listener to parse an Antlr4 syntax tree for presto grammar.\n * To use the listener first set an identifier and than use the DEFAULT.walk method in Antlr4.\n * The listener collects data that defines the query context based on the identifier location in the tree.\n *  \n * @extends {SqlBaseListener} Auto-generated listener by Antlr4 for presto grammar\n */\nexport class PrestoContextListener extends SqlBaseListener {\n  private identifier: string;\n  private nodeFound: any;\n  private contextType: ContextType;\n  private insidePrestoWithFlag: boolean;\n  private missingJoin: boolean = false;\n  private missingBy: boolean = false;\n  private readonly withNodes: any[] = [];\n\n  setIdentifier(value: string) {\n    this.identifier = value;\n  }\n\n  /**\n   * @returns {any[]} an array of NamedQueryNode (which defines WITH table) that collected \n   * during the 'walk' over the Antlr4 tree.\n   */\n  getWithNodes(): any[] {\n    return this.withNodes;\n  }\n\n  /**\n   * @returns {any} the tree node that matches the identifier during the 'walk' over the Antlr4 tree.\n   */\n  getNodeFound(): any {\n    return this.nodeFound;\n  }\n\n  /**\n   * The context type is evaluated based on the node found during the 'walk' over the Antlr4 tree.\n   *\n   * @returns {ContextType} context type\n   */\n  getContextType(): ContextType {\n    return (this.nodeFound && this.contextType) ?? ContextType.Undefined;\n  }\n\n  /**\n   * Using the node found (which indicates the position to evaluate the context) finds\n   * the next querySpecificationNode up the tree.\n   *\n   * @returns {any} querySpecificationNode\n   */\n  getQuerySpecificationNode(): any {\n    let currentNode = this.nodeFound;\n    let querySpecificationNode: any;\n\n    while (currentNode && !querySpecificationNode) {\n      switch (currentNode.ruleIndex) {\n        case SqlBaseParser.RULE_querySpecification:\n          querySpecificationNode = currentNode;\n          break;\n        case SqlBaseParser.RULE_queryNoWith:\n          querySpecificationNode = currentNode\n            .queryTerm()\n            .queryPrimary()\n            .querySpecification();\n          break;\n        default:\n          currentNode = currentNode.parentCtx;\n      }\n    }\n\n    return querySpecificationNode;\n  }\n\n  enterUnquotedIdentifier(ctx: any) {\n    if (ctx.getText() === this.identifier) {\n      this.nodeFound = ctx;\n\n      if (this.insidePrestoWithFlag) {\n        this.withNodes.pop();\n      }\n    }\n  }\n\n  enterColumnReference(_ctx: any) {\n    if (!this.nodeFound && !this.missingBy) {\n      this.contextType = ContextType.Column;\n    }\n  }\n\n  exitColumnReference(_ctx: any) {\n    if (!this.nodeFound) {\n      this.contextType = ContextType.Undefined;\n    }\n\n    this.missingBy = false;\n  }\n\n  enterSelectSingle(_ctx: any) {\n    if (!this.nodeFound) {\n      this.contextType = ContextType.Column;\n    }\n  }\n\n  exitSelectSingle(_ctx: any) {\n    if (!this.nodeFound) {\n      this.contextType = ContextType.Undefined;\n    }\n  }\n\n  enterJoinCriteria(_ctx: any) {\n    if (!this.nodeFound) {\n      this.contextType = ContextType.Column;\n    }\n  }\n\n  exitJoinCriteria(_ctx: any) {\n    if (!this.nodeFound) {\n      this.contextType = ContextType.Undefined;\n    }\n  }\n\n  enterJoinType(ctx: any) {\n    if (!this.nodeFound) {\n      this.missingJoin = this.missingChildrenExists(\n        ctx.parentCtx,\n        SqlBaseParser.JOIN\n      );\n    }\n  }\n\n  enterGroupBy(ctx: any) {\n    if (!this.nodeFound) {\n      this.missingBy = this.missingChildrenExists(\n        ctx.parentCtx,\n        SqlBaseParser.BY\n      );\n    }\n  }\n\n  enterSortItem(ctx: any) {\n    if (!this.nodeFound) {\n      this.missingBy = this.missingChildrenExists(\n        ctx.parentCtx,\n        SqlBaseParser.BY\n      );\n    }\n  }\n\n  enterTableName(_ctx: any) {\n    if (!this.nodeFound && !this.missingJoin) {\n      this.contextType = ContextType.Table;\n    }\n  }\n\n  exitTableName(_ctx: any) {\n    if (!this.nodeFound) {\n      this.contextType = ContextType.Undefined;\n    }\n\n    this.missingJoin = false;\n  }\n\n  enterPresto_with(_ctx: any) {\n    this.insidePrestoWithFlag = true;\n  }\n\n  exitPresto_with(_ctx: any) {\n    this.insidePrestoWithFlag = false;\n  }\n\n  enterNamedQuery(ctx: any) {\n    if (this.insidePrestoWithFlag) {\n      this.withNodes.push(ctx);\n    }\n  }\n\n  missingChildrenExists(ctx: any, symbolType: any) {\n    return (\n      ctx.children.find(\n        (child: any) =>\n          child\n            .getText()\n            .toLowerCase()\n            .indexOf('missing') !== -1 && child.symbol.type === symbolType\n      ) !== undefined\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/basic-queries.spec.ts",
    "content": "import { ContextType } from '../../types';\nimport { basicResult } from '../result-options/basic-results';\nimport { runQueryTest } from './utils';\n\ndescribe('Presto sql context evaluator: When receiving a basic query', () => {\n  runQueryTest('', basicResult[ContextType.Undefined].zeroTables);\n  runQueryTest(' ', basicResult[ContextType.Undefined].zeroTables);\n  runQueryTest('SELECT 1', basicResult[ContextType.Undefined].zeroTables);\n  runQueryTest('SE|LECT 1', basicResult[ContextType.Undefined].zeroTables);\n  runQueryTest('SELECT| 1', basicResult[ContextType.Undefined].zeroTables);\n  runQueryTest('SELECT 1|', basicResult[ContextType.Column].zeroTables);\n\n  describe('and cursor after \"SELECT\" keyword', () => {\n    runQueryTest(\n      'SELECT foo,| FROM table1 WHERE foo = \"value\"',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT |, foo FROM table1 WHERE foo = \"value\"',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT |, foo FROM table1, table2 as tbl2 WHERE foo = \"value\"',\n      basicResult[ContextType.Column].twoExternalTablesAndAlias\n    );\n    runQueryTest(\n      'SELECT |, foo FROM table1, table2, table3 WHERE foo = \"value\"',\n      basicResult[ContextType.Column].threeExternalTables\n    );\n    runQueryTest(\n      'SELECT |, foo FROM (table1), table2 as tbl2 WHERE foo = \"value\"',\n      basicResult[ContextType.Column].twoExternalTablesAndAlias\n    );\n    runQueryTest(\n      'SELECT foo,| FROM (((table1))) WHERE foo = \"value\"',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n  });\n\n  describe('and the cursor is after \"FROM\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM | WHERE foo = \"value\"',\n      basicResult[ContextType.Table].zeroTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1,| WHERE foo = \"value\"',\n      basicResult[ContextType.Table].zeroTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1,|,table2 WHERE foo = \"value\"',\n      basicResult[ContextType.Table].zeroTables\n    );\n  });\n\n  describe('with comments in it', () => {\n    runQueryTest(\n      '/* comment */ SELECT foo,| FROM table1 WHERE foo = \"value\"',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar /* comment */ FROM | WHERE foo = \"value\"',\n      basicResult[ContextType.Table].zeroTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1 GROUP BY | /* comment */',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 /* comment */ WHERE |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n\n  describe('and cursor after \"GROUP BY\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 GROUP BY |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 GROUP BY |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 as tbl2 GROUP BY |',\n      basicResult[ContextType.Column].twoExternalTablesAndAlias\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 as tbl2 GROUP |',\n      basicResult[ContextType.Undefined].zeroTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 as tbl2 GROUP B|',\n      basicResult[ContextType.Undefined].zeroTables\n    );\n  });\n\n  describe('and cursor after \"ORDER BY\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 ORDER BY |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 ORDER BY |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 as tbl2 ORDER BY |',\n      basicResult[ContextType.Column].twoExternalTablesAndAlias\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 as tbl2 ORDER |',\n      basicResult[ContextType.Undefined].zeroTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 as tbl2 ORDER B|',\n      basicResult[ContextType.Undefined].zeroTables\n    );\n  });\n\n  describe('and cursor after \"WHERE\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 WHERE |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=|',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n\n  describe('and cursor after \"WHERE NOT\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 WHERE NOT |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE NOT |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE NOT foo=|',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE NOT |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n\n  describe('and cursor after \"WHERE ... AND\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 WHERE foo=1 AND |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE | AND foo=1',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND bar=|',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE NOT foo=1 AND |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 AND NOT |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n\n  describe('and cursor after \"WHERE ... OR\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 WHERE foo=1 OR |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR |',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE | OR foo=1',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR bar=|',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE NOT foo=1 OR |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      'SELECT foo, bar FROM table1, table2 WHERE foo=1 OR NOT |=bar',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n\n  describe('and cursor after \"HAVING\" keyword', () => {\n    runQueryTest(\n      'SELECT foo, bar FROM table1 HAVING |',\n      basicResult[ContextType.Column].oneExternalTable\n    );\n  });\n\n  describe('and cursor inside function keyword', () => {\n    ['MIN', 'MAX', 'COUNT', 'AVG', 'SUM'].forEach((keyword) => {\n      describe(`=> ${keyword}`, () => {\n        runQueryTest(\n          `SELECT ${keyword}(| FROM table1`,\n          basicResult[ContextType.Column].oneExternalTable\n        );\n        runQueryTest(\n          `SELECT ${keyword}(|) FROM table1`,\n          basicResult[ContextType.Column].oneExternalTable\n        );\n        runQueryTest(\n          `SELECT ${keyword}(|, bar FROM table1`,\n          basicResult[ContextType.Column].oneExternalTable\n        );\n        runQueryTest(\n          `SELECT ${keyword}(|), bar FROM table1`,\n          basicResult[ContextType.Column].oneExternalTable\n        );\n        runQueryTest(\n          `SELECT ${keyword}(|, bar FROM table1, table2`,\n          basicResult[ContextType.Column].twoExternalTables\n        );\n        runQueryTest(\n          `SELECT ${keyword}(|), bar FROM table1, table2`,\n          basicResult[ContextType.Column].twoExternalTables\n        );\n      });\n    });\n  });\n\n  describe('and cursor inside \"CASE\" keyword after \"SELECT\" keyword', () => {\n    runQueryTest(\n      `SELECT foo,\n          CASE\n              WHEN | THEN 'something'\n              ELSE 'something else'\n          END AS goo\n          FROM table1;`,\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      `SELECT foo,\n          CASE\n              WHEN bar=1 THEN |\n              ELSE 'something else'\n          END AS goo\n          FROM table1;`,\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      `SELECT foo,\n          CASE\n              WHEN bar=1 THEN 'something'\n              ELSE |\n          END AS goo\n          FROM table1;`,\n      basicResult[ContextType.Column].oneExternalTable\n    );\n    runQueryTest(\n      `SELECT foo,\n          CASE\n              WHEN | THEN 'something'\n              ELSE 'something else'\n          END AS goo\n          FROM table1, table2, table3;`,\n      basicResult[ContextType.Column].threeExternalTables\n    );\n  });\n\n  describe('and cursor inside \"CASE\" keyword after \"ORDER BY\" keyword', () => {\n    runQueryTest(\n      `SELECT column1, column2\n          FROM table1, table2\n          ORDER BY\n          (CASE\n              WHEN | IS NULL THEN foo\n              ELSE bar\n          END);`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT column1, column2\n          FROM table1, table2\n          ORDER BY\n          (CASE\n              WHEN foo IS NULL THEN |\n              ELSE bar\n          END);`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT column1, column2\n          FROM table1, table2\n          ORDER BY\n          (CASE\n              WHEN foo IS NULL THEN bar\n              ELSE |\n          END);`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n});\n\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/join-queries.spec.ts",
    "content": "import { ContextType } from '../../types';\nimport { basicResult } from '../result-options/basic-results';\nimport { runQueryTest } from './utils';\n\ndescribe('Presto sql context evaluator: When receiving \"JOIN\" query', () => {\n  describe('and cursor after \"SELECT\"', () => {\n    runQueryTest(\n      `SELECT |\n        FROM table1\n        INNER JOIN table2 ON table1.uuid=table2.uuid;`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.OrderID, |\n        FROM (table1\n        INNER JOIN table2 ON table1.CustomerID = table2.CustomerID\n        INNER JOIN table3 ON table1.ShipperID = table3.ShipperID);`,\n      basicResult[ContextType.Column].threeExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.OrderID, |\n        FROM ((table1\n        INNER JOIN table2 ON table1.CustomerID = table2.CustomerID)\n        INNER JOIN table3 ON table1.ShipperID = table3.ShipperID);`,\n      basicResult[ContextType.Column].threeExternalTables\n    );\n  });\n\n  describe('and cursor after \"ON\"', () => {\n    runQueryTest(\n      `SELECT table1.a, table2.b\n        FROM table1\n        INNER JOIN table2 ON |;`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table2.b\n        FROM table1\n        INNER JOIN table2 ON table1.uuid=|;`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table2.b\n        FROM table1\n        INNER JOIN table2 ON |=table2.uuid;`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table2.b, table3.c\n        FROM ((table1\n        INNER JOIN table2 ON table1.CustomerID = table2.CustomerID)\n        INNER JOIN table3 ON |);`,\n      basicResult[ContextType.Column].threeExternalTables\n    );\n  });\n\n  describe('and cursor after \"USING\"', () => {\n    /*\n     * TODO : if the cursor after \"USING\" the correct result is only the columns that appear in both tables.\n     */\n\n    runQueryTest(\n      `SELECT table1.a, table2.b\n        FROM table1\n        INNER JOIN table2 USING (|;`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table2.b\n        FROM table1\n        INNER JOIN table2 USING (|);`,\n      basicResult[ContextType.Column].twoExternalTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table2.b, table3.c\n        FROM ((table1\n        INNER JOIN table2 USING (CustomerID))\n        INNER JOIN table3 USING (|));`,\n      basicResult[ContextType.Column].threeExternalTables\n    );\n  });\n\n  describe('and cursor after \"JOIN\"', () => {\n    runQueryTest(\n      `SELECT table1.a, table1.b\n        FROM table1\n        INNER JOIN |`,\n      basicResult[ContextType.Table].zeroTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table2.b\n        FROM ((table1\n        INNER JOIN table2 ON table1.CustomerID = table2.CustomerID)\n        INNER JOIN |`,\n      basicResult[ContextType.Table].zeroTables\n    );\n  });\n\n  describe('while typing \"JOIN\"', () => {\n    runQueryTest(\n      `SELECT table1.a, table1.b\n        FROM table1\n        INNER |`,\n      basicResult[ContextType.Undefined].zeroTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table1.b\n        FROM table1\n        LEFT |`,\n      basicResult[ContextType.Undefined].zeroTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table1.b\n        FROM table1\n        RIGHT |`,\n      basicResult[ContextType.Undefined].zeroTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table1.b\n        FROM table1\n        OUTER |`,\n      basicResult[ContextType.Undefined].zeroTables\n    );\n    runQueryTest(\n      `SELECT table1.a, table1.b\n        FROM table1\n        INNER JOI|`,\n      basicResult[ContextType.Undefined].zeroTables\n    );\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/nested-queries.spec.ts",
    "content": "import { ContextType } from '../../types';\nimport { nestedResult } from '../result-options/nested-results';\nimport { basicResult } from '../result-options/basic-results';\nimport { runQueryTest } from './utils';\n\ndescribe('Presto sql context evaluator: When receiving a nested query', () => {\n  describe('and the cursor is outside the nested query', () => {\n    describe('after \"SELECT\" keyword', () => {\n      runQueryTest(\n        'SELECT | FROM (SELECT a, b FROM A, B)',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT | FROM (SELECT C.a, D.b FROM A as C, B as D)',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT | FROM (SELECT a, b FROM A, B) tbl1',\n        nestedResult[ContextType.Column].oneNestedWithAlias\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT a, b FROM A, B)',\n        nestedResult[ContextType.Column].oneExtOneNested\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT a, b FROM A, B) tbl2',\n        nestedResult[ContextType.Column].oneExtOneNestedWithAlias\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT * FROM A, B) tbl2',\n        nestedResult[ContextType.Column].oneExtOneNestedWithAliasAndRefs\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT * FROM A, B)',\n        nestedResult[ContextType.Column].oneExtOneNestedAndRefs\n      );\n\n      runQueryTest(\n        'SELECT | FROM (SELECT * FROM A, B) tbl1, (SELECT a, b FROM B, C)',\n        nestedResult[ContextType.Column].twoNestedOneWithRefsAndAlias\n      );\n    });\n\n    describe('after \"FROM\" keyword', () => {\n      runQueryTest(\n        'SELECT * FROM (SELECT a, b FROM A, B), |',\n        basicResult[ContextType.Table].zeroTables\n      );\n\n      runQueryTest(\n        'SELECT * FROM (SELECT a, b FROM A, B) tbl1, |',\n        basicResult[ContextType.Table].zeroTables\n      );\n\n      runQueryTest(\n        'SELECT * FROM table1, (SELECT a, b FROM A, B), | ',\n        basicResult[ContextType.Table].zeroTables\n      );\n\n      runQueryTest(\n        'SELECT * FROM table1, (SELECT a, b FROM A, B) tbl2, |',\n        basicResult[ContextType.Table].zeroTables\n      );\n\n      runQueryTest(\n        'SELECT * FROM table1, (SELECT * FROM A, B), |',\n        basicResult[ContextType.Table].zeroTables\n      );\n    });\n  });\n\n  describe('and the cursor is inside the nested query after \"SELECT\" keyword', () => {\n    runQueryTest(\n      'SELECT FROM (SELECT | FROM table1, table2)',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n\n    runQueryTest(\n      'SELECT FROM (SELECT | FROM table1, table2) tbl1',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n\n    runQueryTest(\n      'SELECT FROM table1, (SELECT | FROM table1, table2)',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n\n    runQueryTest(\n      'SELECT FROM table1, (SELECT | FROM table1, table2) tbl2',\n      basicResult[ContextType.Column].twoExternalTables\n    );\n  });\n\n  describe('that define a column', () => {\n    runQueryTest(\n      'SELECT | FROM (SELECT *, (SELECT id FROM table2 WHERE table1.id = table2.id) as foo FROM table1)',\n      nestedResult[ContextType.Column].oneNestedWithRefAndColumn\n    );\n\n    // TODO:  Add the functionality to get 'column' autocomplete from an external table\n    //        inside a nested query that comes after SELECT keyword.\n    //        In that case we expect to get two external tables -> ['table1', 'table2']\n\n    // runQueryTest(\n    //   'SELECT *, (SELECT id FROM table2 WHERE table1.id = |) as foo FROM table1',\n    //   basicResult[ContextType.Column].twoExternalTables\n    // );\n  });\n\n  describe('(double nested)', () => {\n    describe('and the cursor is outside both nested query after \"SELECT\" keyword', () => {\n      runQueryTest(\n        'SELECT | FROM (SELECT * FROM (SELECT count(c) a, b FROM A, B))',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT | FROM (SELECT * FROM (SELECT foo.a, bar.b FROM foo, bar))',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT | FROM (SELECT * FROM (SELECT A.a, D.b FROM A, B as D))',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT | FROM (SELECT * FROM (SELECT count(c) a, b FROM A, B)) tbl1',\n        nestedResult[ContextType.Column].oneNestedWithAlias\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT * FROM (SELECT count(c) a, b FROM A, B)) tbl2',\n        nestedResult[ContextType.Column].oneExtOneNestedWithAlias\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT a, b FROM (SELECT * FROM A, B)) tbl2',\n        nestedResult[ContextType.Column].oneExtOneNestedWithAlias\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT * FROM (SELECT * FROM A, B)) tbl2',\n        nestedResult[ContextType.Column].oneExtOneNestedWithAliasAndRefs\n      );\n\n      runQueryTest(\n        'SELECT | FROM table1, (SELECT * FROM (SELECT * FROM A, B) tbl3) tbl2',\n        nestedResult[ContextType.Column].oneExtOneNestedWithAliasAndRefs\n      );\n    });\n\n    describe('and the cursor is inside the first nested query after \"SELECT\" keyword', () => {\n      runQueryTest(\n        'SELECT FROM (SELECT | FROM (SELECT count(c) a, b FROM A, B))',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT FROM (SELECT | FROM (SELECT count(c) a, b FROM A, B)) tbl1',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT FROM table1, (SELECT | FROM (SELECT count(c) a, b FROM A, B)) tbl2',\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        'SELECT FROM table1, (SELECT | FROM (SELECT count(c) a, b FROM A, B) tbl1)',\n        nestedResult[ContextType.Column].oneNestedWithAlias\n      );\n\n      runQueryTest(\n        'SELECT FROM table1, (SELECT | FROM (SELECT * FROM A, B))',\n        nestedResult[ContextType.Column].oneNestedWithRefs\n      );\n\n      runQueryTest(\n        'SELECT FROM table1, (SELECT | FROM (SELECT * FROM A, B) tbl1)',\n        nestedResult[ContextType.Column].oneNestedWithAliasAndRefs\n      );\n    });\n\n    describe('and the cursor is inside the seconed nested query after \"SELECT\" keyword', () => {\n      runQueryTest(\n        'SELECT FROM (SELECT FROM (SELECT | FROM table1, table2))',\n        basicResult[ContextType.Column].twoExternalTables\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/union-queries.spec.ts",
    "content": "import { ContextType } from '../../types';\nimport { basicResult } from '../result-options/basic-results';\nimport { nestedResult } from '../result-options/nested-results';\nimport { runQueryTest } from './utils';\n\ndescribe('Presto sql context evaluator: When receiving \"UNION\" query', () => {\n  describe('and cursor after \"SELECT\"', () => {\n    runQueryTest(\n      `SELECT a, b, | FROM table1\n        UNION\n        SELECT a, b, c FROM table2;`,\n      basicResult[ContextType.Column].oneExternalTable\n    );\n\n    runQueryTest(\n      `SELECT a, b, c FROM table2\n        UNION\n        SELECT a, b, | FROM table1;`,\n      basicResult[ContextType.Column].oneExternalTable\n    );\n\n    runQueryTest(\n      `SELECT FROM table2\n        UNION\n        SELECT a, b, | FROM table1;`,\n      basicResult[ContextType.Column].oneExternalTable\n    );\n  });\n\n  describe('with nested quary', () => {\n    describe('And cursor after \"SELECT\"', () => {\n      runQueryTest(\n        `SELECT |\n          FROM (\n          SELECT a, b FROM table1\n          UNION\n          SELECT a, b FROM table2)`,\n        nestedResult[ContextType.Column].oneNested\n      );\n\n      runQueryTest(\n        `SELECT |\n          FROM (\n          SELECT a, b FROM table1\n          UNION\n          SELECT a, b FROM table2) as tbl1`,\n        nestedResult[ContextType.Column].oneNestedWithAlias\n      );\n\n      runQueryTest(\n        `SELECT *\n          FROM (\n          SELECT a, | FROM table1\n          UNION\n          SELECT a, b FROM table2) `,\n        basicResult[ContextType.Column].oneExternalTable\n      );\n\n      runQueryTest(\n        `SELECT *\n          FROM (\n          SELECT a, b FROM table2\n          UNION\n          SELECT | FROM table1)`,\n        basicResult[ContextType.Column].oneExternalTable\n      );\n\n      runQueryTest(\n        `SELECT |\n          FROM (\n          SELECT * FROM table1\n          UNION\n          SELECT * FROM table2)`,\n        nestedResult[ContextType.Column].oneNestedWithOneRef\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/utils.ts",
    "content": "import { expect } from 'chai';\nimport { evaluateContextFromPosition } from '../../position-evaluator';\nimport { QueryContext } from '../../types';\n\nexport interface TestCase {\n  input: string;\n  expected: QueryContext;\n}\n\nconst getContext = (input: string) => {\n  return evaluateContextFromPosition(\n    input.replace('|', ''),\n    input.indexOf('|')\n  );\n};\n\nexport const runQueryTest = (\n  input: TestCase | TestCase[] | string,\n  expected?: QueryContext\n): void => {\n  const tests =\n    typeof input === 'string'\n      ? [{ input, expected }]\n      : input instanceof Array\n      ? input\n      : [input];\n\n  tests.forEach((test: TestCase) => {\n    it(`it should return contextType ${test.expected.contextType} and ${test.expected.tables.length} table info.\n    input: '${test.input}'`, () => {\n      const results: QueryContext = getContext(test.input);\n      expect(results)\n        .to.have.property('contextType')\n        .to.be.equal(test.expected.contextType);\n      expect(results)\n        .to.have.property('tables')\n        .deep.equal(test.expected.tables);\n    });\n  });\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/queries-spec/with-queries.spec.ts",
    "content": "import { ContextType, TableType } from '../../types';\nimport { runQueryTest } from './utils';\nimport { withResult } from '../result-options/with-results';\nimport { basicResult } from '../result-options/basic-results';\nimport { nestedResult } from '../result-options/nested-results';\n\ndescribe('Presto sql context evaluator: When receiving \"WITH\" query', () => {\n  describe('and cursor outside the \"WITH\"', () => {\n    describe('after \"SELECT\" keyword', () => {\n      runQueryTest(\n        'WITH table1(foo1, bar1) as (SELECT a, b FROM users) SELECT | FROM table1',\n        withResult[ContextType.Column].oneWithTable\n      );\n\n      runQueryTest(\n        'WITH table1 as (SELECT foo1, bar1 FROM users) SELECT | FROM table1',\n        withResult[ContextType.Column].oneWithTable\n      );\n\n      runQueryTest(\n        'WITH table1 as (SELECT users.foo1, users.bar1 FROM users) SELECT | FROM table1',\n        withResult[ContextType.Column].oneWithTable\n      );\n\n      runQueryTest(\n        'WITH table1 as (SELECT tblOne.foo1, tblTwo.bar1 FROM tblOne, tblTwo) SELECT | FROM table1',\n        withResult[ContextType.Column].oneWithTable\n      );\n\n      runQueryTest(\n        'WITH table1 as (SELECT foo1, bar1 FROM users) SELECT | FROM table1 as tbl1',\n        withResult[ContextType.Column].oneWithTableAliased\n      );\n\n      runQueryTest(\n        'WITH table1 as (SELECT * FROM externalTable) SELECT | FROM table1',\n        withResult[ContextType.Column].oneWithTableAndRef\n      );\n\n      runQueryTest(\n        'WITH table1 as (SELECT foo1, bar1 FROM users) SELECT | FROM table1, table2',\n        withResult[ContextType.Column].oneWithOneExternalTables\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n                  table2 as (SELECT foo2, bar2 FROM products)\n              SELECT | FROM table1, table2`,\n        withResult[ContextType.Column].twoWithTables\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, fo.bar1 FROM users as fo),\n                  table2 as (SELECT products.foo2, st.bar2 FROM products, stores as st)\n              SELECT | FROM table1, table2`,\n        withResult[ContextType.Column].twoWithTables\n      );\n\n      describe('(nested query)', () => {\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT * FROM externalTable))\n                SELECT | FROM table1`,\n          withResult[ContextType.Column].oneWithTableAndRef\n        );\n\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM externalTable))\n                SELECT | FROM table1`,\n          withResult[ContextType.Column].oneWithTable\n        );\n\n        runQueryTest(\n          `WITH table2 as (SELECT * FROM externalTable),\n              table1 as (SELECT * FROM table2)\n              SELECT | FROM table1`,\n          withResult[ContextType.Column].oneWithTableWithNameAndOneRef\n        );\n\n        runQueryTest(\n          `WITH table2 as (SELECT * FROM externalTable),\n              table3 as (SELECT * FROM table2),\n              table1 as (SELECT * FROM table3)\n              SELECT | FROM table1`,\n          withResult[ContextType.Column].oneWithTableAndRef\n        );\n      });\n    });\n\n    describe('after \"FROM\" keyword', () => {\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users)\n              SELECT foo1 FROM |`,\n        withResult[ContextType.Table].oneWithTable\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT * FROM externalTable)\n              SELECT foo FROM |`,\n        withResult[ContextType.Table].oneWithTableAndRef\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n                  table2(foo2, bar2) as (SELECT c, d FROM products)\n              SELECT foo1, b FROM |`,\n        withResult[ContextType.Table].twoWithTables\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n                  table2(foo2, bar2) as (SELECT c, d FROM products)\n              SELECT foo1, b FROM table3, |`,\n        withResult[ContextType.Table].twoWithTables\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n                  table2(foo2, bar2) as (SELECT c, d FROM products)\n              SELECT foo1, b FROM |, table3`,\n        withResult[ContextType.Table].twoWithTables\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n                  table2(foo2, bar2) as (SELECT c, d FROM products)\n              SELECT foo1, b FROM table3, |, table4`,\n        withResult[ContextType.Table].twoWithTables\n      );\n\n      describe('(nested query)', () => {\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT * FROM externalTable))\n                SELECT a FROM |`,\n          withResult[ContextType.Table].oneWithTableAndRef\n        );\n\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM externalTable))\n                SELECT a FROM |`,\n          withResult[ContextType.Table].oneWithTable\n        );\n      });\n    });\n  });\n\n  describe('and cursor inside the \"WITH\"', () => {\n    describe('after \"SELECT\" keyword', () => {\n      runQueryTest(\n        `WITH table2 as (SELECT foo1, | FROM table1)\n              SELECT foo1 FROM table2`,\n        basicResult[ContextType.Column].oneExternalTable\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n            table2(foo2, bar2) as (SELECT | FROM table1)\n              SELECT foo1 FROM table1`,\n        withResult[ContextType.Column].oneWithTable\n      );\n\n      runQueryTest(\n        `WITH table2 as (SELECT foo1, bar1 FROM users),\n            table3(foo2, bar2) as (SELECT | FROM table1)\n              SELECT foo1 FROM table2`,\n        basicResult[ContextType.Column].oneExternalTable\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n            table3(foo2, bar2) as (SELECT | FROM table1, table2)\n              SELECT foo1 FROM table3`,\n        withResult[ContextType.Column].oneWithOneExternalTables\n      );\n\n      describe('(nested query)', () => {\n        runQueryTest(\n          `WITH table2 as (SELECT * FROM (SELECT * FROM  table1)),\n            table3(foo3, bar3) as (SELECT | FROM (SELECT * FROM table2))\n              SELECT foo1 FROM table3`,\n          nestedResult[ContextType.Column].oneNestedWithOneRef\n        );\n\n        runQueryTest(\n          `WITH table2 as (SELECT * FROM (SELECT a, b FROM  table1)),\n            table3(foo3, bar3) as (SELECT | FROM (SELECT * FROM table2))\n              SELECT foo1 FROM table3`,\n          nestedResult[ContextType.Column].oneNested\n        );\n      });\n    });\n\n    describe('after \"FROM\" keyword', () => {\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM |)\n              SELECT foo1 FROM table1`,\n        basicResult[ContextType.Table].zeroTables\n      );\n\n      runQueryTest(\n        `WITH table1 as (SELECT foo1, bar1 FROM users),\n            table2(foo2, bar2) as (SELECT c, d FROM |)\n              SELECT foo1 FROM table1`,\n        withResult[ContextType.Table].oneWithTable\n      );\n\n      describe('(nested query)', () => {\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT * FROM externalTable)),\n            table2(foo2, bar2) as (SELECT c, d FROM |)\n              SELECT foo1 FROM table1`,\n          withResult[ContextType.Table].oneWithTableAndRef\n        );\n\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM users)),\n            table2(foo2, bar2) as (SELECT c, d FROM |)\n              SELECT foo1 FROM table1`,\n          withResult[ContextType.Table].oneWithTable\n        );\n\n        runQueryTest(\n          `WITH table1 as (SELECT * FROM (SELECT foo1, bar1 FROM users)),\n            table2(foo2, bar2) as (SELECT c, d FROM |)\n              SELECT foo1 FROM table1`,\n          withResult[ContextType.Table].oneWithTable\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/basic-results.ts",
    "content": "import { ContextType } from '../../types';\nimport { BasicQueryContextOption, testTable } from './utils';\n\nexport const basicResult: BasicQueryContextOption = {\n  [ContextType.Undefined]: {\n    zeroTables: {\n      contextType: ContextType.Undefined,\n      tables: [],\n    },\n  },\n  [ContextType.Column]: {\n    zeroTables: {\n      contextType: ContextType.Column,\n      tables: [],\n    },\n    oneExternalTable: {\n      contextType: ContextType.Column,\n      tables: [testTable.external.table1],\n    },\n    twoExternalTables: {\n      contextType: ContextType.Column,\n      tables: [testTable.external.table1, testTable.external.table2],\n    },\n    twoExternalTablesAndAlias: {\n      contextType: ContextType.Column,\n      tables: [\n        testTable.external.table1,\n        { ...testTable.external.table2, alias: 'tbl2' },\n      ],\n    },\n    threeExternalTables: {\n      contextType: ContextType.Column,\n      tables: [\n        testTable.external.table1,\n        testTable.external.table2,\n        testTable.external.table3,\n      ],\n    },\n  },\n  [ContextType.Table]: {\n    zeroTables: {\n      contextType: ContextType.Table,\n      tables: [],\n    },\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/nested-results.ts",
    "content": "import { ContextType } from '../../types';\nimport { BasicQueryContextOption, testTable } from './utils';\n\nexport const nestedResult: BasicQueryContextOption = {\n  [ContextType.Column]: {\n    oneNested: {\n      contextType: ContextType.Column,\n      tables: [testTable.nested.unnamedWithColumns],\n    },\n    oneNestedWithRefs: {\n      contextType: ContextType.Column,\n      tables: [\n        {\n          ...testTable.nested.unnamed,\n          columns: [],\n          tableRefs: ['A', 'B'],\n          selectAll: true,\n        },\n      ],\n    },\n    oneNestedWithOneRef: {\n      contextType: ContextType.Column,\n      tables: [\n        { ...testTable.nested.unnamed, tableRefs: ['table1'], selectAll: true },\n      ],\n    },\n    oneNestedWithRefAndColumn: {\n      contextType: ContextType.Column,\n      tables: [\n        {\n          ...testTable.nested.unnamed,\n          columns: ['foo'],\n          tableRefs: ['table1'],\n          selectAll: true,\n        },\n      ],\n    },\n    oneNestedWithAlias: {\n      contextType: ContextType.Column,\n      tables: [{ ...testTable.nested.unnamedWithColumns, alias: 'tbl1' }],\n    },\n    oneNestedWithAliasAndRefs: {\n      contextType: ContextType.Column,\n      tables: [\n        {\n          ...testTable.nested.unnamed,\n          alias: 'tbl1',\n          tableRefs: ['A', 'B'],\n          selectAll: true,\n        },\n      ],\n    },\n    oneExtOneNested: {\n      contextType: ContextType.Column,\n      tables: [testTable.external.table1, testTable.nested.unnamedWithColumns],\n    },\n    oneExtOneNestedWithAlias: {\n      contextType: ContextType.Column,\n      tables: [\n        testTable.external.table1,\n        { ...testTable.nested.unnamedWithColumns, alias: 'tbl2' },\n      ],\n    },\n    oneExtOneNestedWithAliasAndRefs: {\n      contextType: ContextType.Column,\n      tables: [\n        testTable.external.table1,\n        {\n          ...testTable.nested.unnamed,\n          alias: 'tbl2',\n          tableRefs: ['A', 'B'],\n          selectAll: true,\n        },\n      ],\n    },\n    oneExtOneNestedAndRefs: {\n      contextType: ContextType.Column,\n      tables: [\n        testTable.external.table1,\n        { ...testTable.nested.unnamed, tableRefs: ['A', 'B'], selectAll: true },\n      ],\n    },\n    twoNestedOneWithRefsAndAlias: {\n      contextType: ContextType.Column,\n      tables: [\n        {\n          ...testTable.nested.unnamed,\n          alias: 'tbl1',\n          tableRefs: ['A', 'B'],\n          selectAll: true,\n        },\n        testTable.nested.unnamedWithColumns,\n      ],\n    },\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/utils.ts",
    "content": "import { TableType, ContextType, QueryContext } from '../../types';\nimport { createNewTableInfoObj } from '../../utils';\n\nexport type BasicQueryContextOption = {\n  [key in ContextType]?: Record<string, QueryContext>;\n};\n\nexport const testTable = {\n  nested: {\n    unnamed: createNewTableInfoObj({\n      type: TableType.Nested,\n    }),\n    unnamedWithColumns: createNewTableInfoObj({\n      type: TableType.Nested,\n      columns: ['a', 'b'],\n    }),\n    table1: createNewTableInfoObj({\n      name: 'table1',\n      type: TableType.Nested,\n      columns: ['foo1', 'bar1'],\n    }),\n    table1WithRef: createNewTableInfoObj({\n      name: 'table1',\n      type: TableType.Nested,\n      tableRefs: ['externalTable'],\n      selectAll: true,\n    }),\n    table2: createNewTableInfoObj({\n      name: 'table2',\n      type: TableType.Nested,\n      columns: ['foo2', 'bar2'],\n    }),\n  },\n  external: {\n    table1: createNewTableInfoObj({\n      name: 'table1',\n      type: TableType.External,\n    }),\n    table2: createNewTableInfoObj({\n      name: 'table2',\n      type: TableType.External,\n    }),\n    table3: createNewTableInfoObj({\n      name: 'table3',\n      type: TableType.External,\n    }),\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tests/result-options/with-results.ts",
    "content": "import { ContextType } from '../../types';\nimport { BasicQueryContextOption } from '../result-options/utils';\nimport { testTable } from './utils';\n\nexport const withResult: BasicQueryContextOption = {\n  [ContextType.Column]: {\n    oneWithTable: {\n      contextType: ContextType.Column,\n      tables: [testTable.nested.table1],\n    },\n    oneWithTableWithNameAndOneRef: {\n      contextType: ContextType.Column,\n      tables: [testTable.nested.table1WithRef],\n    },\n    oneWithTableAliased: {\n      contextType: ContextType.Column,\n      tables: [{ ...testTable.nested.table1, alias: 'tbl1' }],\n    },\n    oneWithTableAndRef: {\n      contextType: ContextType.Column,\n      tables: [testTable.nested.table1WithRef],\n    },\n    twoWithTables: {\n      contextType: ContextType.Column,\n      tables: [testTable.nested.table1, testTable.nested.table2],\n    },\n    oneWithOneExternalTables: {\n      contextType: ContextType.Column,\n      tables: [testTable.nested.table1, testTable.external.table2],\n    },\n  },\n  [ContextType.Table]: {\n    oneWithTable: {\n      contextType: ContextType.Table,\n      tables: [testTable.nested.table1],\n    },\n    oneWithTableAndRef: {\n      contextType: ContextType.Table,\n      tables: [testTable.nested.table1WithRef],\n    },\n    twoWithTables: {\n      contextType: ContextType.Table,\n      tables: [testTable.nested.table1, testTable.nested.table2],\n    },\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/tree-analyzer.ts",
    "content": "import { QueryDetails, TableInfo, TableType } from './types';\nimport { createNewTableInfoObj } from './utils';\n\n/**\n * Recuresive function which takes a relationNode and returns a TableInfo array\n * that defines the relation properties considering sub-relations.\n *\n * @param   {any} relationNode\n *\n * @returns {TableInfo[]} TableInfo array\n */\nexport const getTableInfoFromRelationNode = (\n  relationNode: any\n): TableInfo[] => {\n  if (relationNode.relation) {\n    // when using 'JOIN' keyword -> split and analyze all sub-relations\n    return relationNode\n      .relation()\n      ?.reduce((accumulator: TableInfo[], subRelation: any) => {\n        return accumulator.concat(...getTableInfoFromRelationNode(subRelation));\n      }, []);\n  }\n\n  const aliasedRelationNode = relationNode.sampledRelation().aliasedRelation();\n  const relationPrimaryNode = aliasedRelationNode.relationPrimary();\n\n  if (relationPrimaryNode.relation) {\n    // dealing with nested parentheses, for example: SELECT * FROM ((some_table))\n    return getTableInfoFromRelationNode(relationPrimaryNode.relation());\n  }\n\n  const currentTableInfo: TableInfo = createNewTableInfoObj({\n    name:\n      relationPrimaryNode.qualifiedName &&\n      relationPrimaryNode.qualifiedName()?.getText(),\n    type: relationPrimaryNode.query ? TableType.Nested : TableType.External,\n    alias:\n      aliasedRelationNode.identifier &&\n      aliasedRelationNode.identifier()?.getText(),\n  });\n\n  if (currentTableInfo.type === TableType.Nested && relationPrimaryNode.query) {\n    // evaluate the nested query and merge it with the currentTableInfo\n    const nestedQueryDetails: QueryDetails = getQueryDetailsFromQuerySpecificationNode(\n      getNextQuerySpecificationNode(relationNode)\n    );\n    aggregateQueryDetailsAndTableInfo(nestedQueryDetails, currentTableInfo);\n  }\n\n  return [currentTableInfo];\n};\n\n/**\n * Recuresive function which takes a querySpecificationNode and returns a QueryDetails\n * that defines all the query properties considering tables and columns.\n *\n * @param   {any} querySpecificationNode\n *\n * @returns {QueryDetails} query properties\n */\nexport const getQueryDetailsFromQuerySpecificationNode = (\n  querySpecificationNode: any\n): QueryDetails => {\n  const tables: TableInfo[] = [];\n  const columns: string[] = [];\n  let selectAll: boolean = false;\n\n  // evaluate all relations after FROM clause\n  querySpecificationNode\n    ?.relation()\n    .forEach((relation: any) =>\n      tables.push(...getTableInfoFromRelationNode(relation))\n    );\n\n  const prefixToReplace = createRegexNameFilter(tables);\n\n  // evaluate all columns after SELECT clause\n  querySpecificationNode\n    ?.selectItem()\n    .forEach((selectItem: any) =>\n      selectItem.ASTERISK\n        ? (selectAll = true)\n        : columns.push(\n            selectItem.identifier()\n              ? selectItem.identifier().getText()\n              : selectItem.getText().replace(prefixToReplace, '')\n          )\n    );\n\n  return { tables, columns, selectAll };\n};\n\n/**\n * Takes TableInfo array and creates a RegExp to match all tables aliases/names in the given array.\n *\n * @param   {TableInfo[]} tables\n *\n * @returns {RegExp} Regular expression of all tables aliases/names\n */\nconst createRegexNameFilter = (tables: TableInfo[]): RegExp => {\n  const tablesNames = tables.reduce((names, table) => {\n    const name = table.alias || table.name;\n    if (name) {\n      names.push(name);\n    }\n    return names;\n  }, []);\n\n  return tablesNames.length > 0\n    ? new RegExp(`^(${tablesNames.join('|')})\\\\.`, 'g')\n    : undefined;\n};\n\n/**\n * Takes QueryDetails and aggregates it into a given TableInfo.\n *\n * @param   {QueryDetails} queryDetails\n * @param   {TableInfo} tableInfo\n *\n * @return {void}\n */\nexport const aggregateQueryDetailsAndTableInfo = (\n  queryDetails: QueryDetails,\n  tableInfo: TableInfo\n): void => {\n  queryDetails.tables.forEach((table: TableInfo) => {\n    if (queryDetails.selectAll) {\n      if (table.type === TableType.External) {\n        tableInfo.selectAll = true;\n        tableInfo.tableRefs.push(table.name);\n      } else if (table.type === TableType.Nested) {\n        tableInfo.selectAll = tableInfo.selectAll || table.selectAll;\n        tableInfo.tableRefs.push(...table.tableRefs);\n        tableInfo.columns.push(...table.columns);\n      }\n    }\n  });\n\n  tableInfo.columns.push(...queryDetails.columns);\n};\n\n/**\n * Takes any Antlr4 tree node and advances it to the next QuerySpecificationNode down the tree.\n *\n * @param {any} currentNode\n *\n * @return {any} querySpecificationNode\n */\nexport const getNextQuerySpecificationNode = (currentNode: any): any => {\n  if (!(currentNode?.children?.length > 0)) {\n    return null;\n  }\n\n  let nextNode: any = currentNode;\n  nextNode = nextNode?.sampledRelation ? nextNode.sampledRelation() : nextNode;\n  nextNode = nextNode?.aliasedRelation ? nextNode.aliasedRelation() : nextNode;\n  nextNode = nextNode?.relationPrimary ? nextNode.relationPrimary() : nextNode;\n  nextNode = nextNode?.query ? nextNode.query() : nextNode;\n  nextNode = nextNode?.queryNoWith ? nextNode.queryNoWith() : nextNode;\n  nextNode = nextNode?.queryTerm ? nextNode.queryTerm() : nextNode;\n  // when use 'UNION' keyword -> analyze the first table\n  nextNode = nextNode?.queryTerm ? nextNode.queryTerm()[0] : nextNode;\n  nextNode = nextNode?.queryPrimary ? nextNode.queryPrimary() : nextNode;\n\n  return nextNode?.querySpecification\n    ? nextNode.querySpecification()\n    : nextNode !== currentNode\n    ? getNextQuerySpecificationNode(nextNode)\n    : null;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/types.ts",
    "content": "import { Column } from \"../db-info\";\n\nexport enum TableType {\n  External = 'External',\n  Nested = 'Nested',\n}\n\nexport interface QueryDetails {\n  columns: string[];\n  selectAll?: boolean;\n  tables: TableInfo[];\n}\n\nexport interface TableInfo {\n  type: TableType;\n  name: string;\n  alias: string;\n  columns: (Column | string)[];\n  tableRefs: string[];\n  selectAll: boolean;\n}\n\nexport enum ContextType {\n  Table = 'Table',\n  Column = 'Column',\n  Undefined = 'Undefined',\n}\n\nexport interface QueryContext {\n  contextType: ContextType;\n  tables: TableInfo[];\n  prefix?: string;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/utils.ts",
    "content": "import { TableInfo, TableType } from './types';\n\nexport const createNewTableInfoObj = (\n  tableInfo?: Partial<TableInfo>\n): TableInfo => ({\n  type: TableType.External,\n  name: undefined,\n  alias: undefined,\n  columns: [],\n  tableRefs: [],\n  selectAll: false,\n  ...tableInfo,\n});\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-autocomplete/sql-context-evaluator/with-clause-analyzer.ts",
    "content": "import {\n  aggregateQueryDetailsAndTableInfo,\n  getQueryDetailsFromQuerySpecificationNode,\n  getNextQuerySpecificationNode,\n} from './tree-analyzer';\n\nimport { QueryDetails, TableInfo, TableType } from './types';\nimport { createNewTableInfoObj } from './utils';\n\n/**\n * Takes NamedQueryNode (which defines WITH table) and analyzes its properties using the tree-analyzer.\n *  \n * @param   {any} namedQueryNode\n *\n * @returns {TableInfo} the WITH table details as table info\n */\nexport const analyzeNamedQueryNode = (namedQueryNode: any): TableInfo => {\n  const currentTableInfo: TableInfo = createNewTableInfoObj({\n    name: getWithClauseName(namedQueryNode),\n    type: TableType.Nested,\n    columns: getColumnAliases(namedQueryNode),\n  });\n\n  if (currentTableInfo.columns.length === 0) {\n    const queryDetails: QueryDetails = getQueryDetailsFromQuerySpecificationNode(\n      getNextQuerySpecificationNode(namedQueryNode)\n    );\n\n    aggregateQueryDetailsAndTableInfo(queryDetails, currentTableInfo);\n  }\n\n  return currentTableInfo;\n};\n\n/**\n * @param   {any} namedQueryNode\n *\n * @returns {string} name\n */\nconst getWithClauseName = (namedQueryNode: any): string => {\n  return namedQueryNode.identifier().getText();\n};\n\n/**\n * In cases where the column names are defined along with the table name, an array of columns names will be returned.\n * For example: WITH foo(bar, goo) as (SELECT a, b FROM c)\n * \n * @param   {any} namedQueryNode\n *\n * @returns {string[]} columns names\n */\nconst getColumnAliases = (namedQueryNode: any): string[] => {\n  const columnsAlias: string[] = [];\n\n  if (namedQueryNode.columnAliases) {\n    namedQueryNode\n      .columnAliases()\n      ?.identifier()\n      ?.forEach((identifier: any) => {\n        columnsAlias.push(identifier.getText());\n      });\n  }\n\n  return columnsAlias;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016-present ZeroTurnaround LLC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nattributed to https://github.com/zeroturnaround/sql-formatter\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/core/Formatter.ts",
    "content": "import includes from 'lodash/includes';\nimport trimEnd from 'lodash/trimEnd';\nimport tokenTypes from './tokenTypes';\nimport Indentation from './Indentation';\nimport InlineBlock from './InlineBlock';\nimport Params from './Params';\nimport Tokenizer from './Tokenizer';\n\nexport interface Cfg {\n  indent?: string;\n  params?: Params;\n}\nexport default class Formatter {\n  private readonly cfg: Cfg;\n  private readonly indentation: Indentation;\n  private readonly inlineBlock: InlineBlock;\n  private readonly params: Params;\n  private readonly tokenizer: Tokenizer;\n  private previousReservedWord: any;\n  private index: number;\n  private tokens: any[];\n  /**\n   * @param {Object} cfg\n   *   @param {Object} cfg.indent\n   *   @param {Object} cfg.params\n   * @param {Tokenizer} tokenizer\n   */\n  constructor(cfg, tokenizer) {\n    this.cfg = cfg || {};\n    this.indentation = new Indentation(this.cfg.indent);\n    this.inlineBlock = new InlineBlock();\n    this.params = new Params(this.cfg.params);\n    this.tokenizer = tokenizer;\n    this.previousReservedWord = {};\n    this.tokens = [];\n    this.index = 0;\n  }\n\n  /**\n   * Formats whitespaces in a SQL string to make it easier to read.\n   *\n   * @param {String} query The SQL query string\n   * @return {String} formatted query\n   */\n  format(query) {\n    this.tokens = this.tokenizer.tokenize(query);\n    const formattedQuery = this.getFormattedQueryFromTokens();\n\n    return formattedQuery.trim();\n  }\n\n  getFormattedQueryFromTokens() {\n    let formattedQuery = '';\n\n    this.tokens.forEach((token, index) => {\n      this.index = index;\n\n      if (token.type === tokenTypes.WHITESPACE) {\n        // ignore (we do our own whitespace formatting)\n      } else if (token.type === tokenTypes.LINE_COMMENT) {\n        formattedQuery = this.formatLineComment(token, formattedQuery);\n      } else if (token.type === tokenTypes.BLOCK_COMMENT) {\n        formattedQuery = this.formatBlockComment(token, formattedQuery);\n      } else if (token.type === tokenTypes.RESERVED_TOPLEVEL) {\n        formattedQuery = this.formatToplevelReservedWord(token, formattedQuery);\n        this.previousReservedWord = token;\n      } else if (token.type === tokenTypes.RESERVED_NEWLINE) {\n        formattedQuery = this.formatNewlineReservedWord(token, formattedQuery);\n        this.previousReservedWord = token;\n      } else if (token.type === tokenTypes.RESERVED) {\n        formattedQuery = this.formatWithSpaces(token, formattedQuery);\n        this.previousReservedWord = token;\n      } else if (token.type === tokenTypes.OPEN_PAREN) {\n        formattedQuery = this.formatOpeningParentheses(token, formattedQuery);\n      } else if (token.type === tokenTypes.CLOSE_PAREN) {\n        formattedQuery = this.formatClosingParentheses(token, formattedQuery);\n      } else if (token.type === tokenTypes.PLACEHOLDER) {\n        formattedQuery = this.formatPlaceholder(token, formattedQuery);\n      } else if (token.value === ',') {\n        formattedQuery = this.formatComma(token, formattedQuery);\n      } else if (token.value === ':') {\n        formattedQuery = this.formatWithSpaceAfter(token, formattedQuery);\n      } else if (token.value === '.') {\n        formattedQuery = this.formatWithoutSpaces(token, formattedQuery);\n      } else if (token.value === ';') {\n        formattedQuery = this.formatQuerySeparator(token, formattedQuery);\n      } else {\n        formattedQuery = this.formatWithSpaces(token, formattedQuery);\n      }\n    });\n    return formattedQuery;\n  }\n\n  formatLineComment(token, query: string) {\n    return this.addNewline(query + token.value);\n  }\n\n  formatBlockComment(token, query: string) {\n    return this.addNewline(this.addNewline(query) + this.indentComment(token.value));\n  }\n\n  indentComment(comment) {\n    return comment.replace(/\\n/g, '\\n' + this.indentation.getIndent());\n  }\n\n  formatToplevelReservedWord(token, query) {\n    this.indentation.decreaseTopLevel();\n\n    query = this.addNewline(query);\n\n    this.indentation.increaseToplevel();\n\n    query += this.equalizeWhitespace(token.value);\n    return this.addNewline(query);\n  }\n\n  formatNewlineReservedWord(token, query) {\n    return this.addNewline(query) + this.equalizeWhitespace(token.value) + ' ';\n  }\n\n  // Replace any sequence of whitespace characters with single space\n  equalizeWhitespace(string) {\n    return string.replace(/\\s+/g, ' ');\n  }\n\n  // Opening parentheses increase the block indent level and start a new line\n  formatOpeningParentheses(token, query) {\n    // Take out the preceding space unless there was whitespace there in the original query\n    // or another opening parens or line comment\n    const preserveWhitespaceFor = [tokenTypes.WHITESPACE, tokenTypes.OPEN_PAREN, tokenTypes.LINE_COMMENT];\n    if (!includes(preserveWhitespaceFor, this.previousToken().type)) {\n      query = trimEnd(query);\n    }\n    query += token.value;\n\n    this.inlineBlock.beginIfPossible(this.tokens, this.index);\n\n    if (!this.inlineBlock.isActive()) {\n      this.indentation.increaseBlockLevel();\n      query = this.addNewline(query);\n    }\n    return query;\n  }\n\n  // Closing parentheses decrease the block indent level\n  formatClosingParentheses(token, query) {\n    if (this.inlineBlock.isActive()) {\n      this.inlineBlock.end();\n      return this.formatWithSpaceAfter(token, query);\n    }\n\n    this.indentation.decreaseBlockLevel();\n    return this.formatWithSpaces(token, this.addNewline(query));\n  }\n\n  formatPlaceholder(token, query) {\n    return query + this.params.get(token) + ' ';\n  }\n\n  // Commas start a new line (unless within inline parentheses or SQL \"LIMIT\" clause)\n  formatComma(token, query) {\n    query = this.trimTrailingWhitespace(query) + token.value + ' ';\n\n    if (this.inlineBlock.isActive()) {\n      return query;\n    }\n    if (/^LIMIT$/i.test(this.previousReservedWord.value)) {\n      return query;\n    }\n    return this.addNewline(query);\n  }\n\n  formatWithSpaceAfter(token, query) {\n    return this.trimTrailingWhitespace(query) + token.value + ' ';\n  }\n\n  formatWithoutSpaces(token, query) {\n    return this.trimTrailingWhitespace(query) + token.value;\n  }\n\n  formatWithSpaces(token, query) {\n    return query + token.value + ' ';\n  }\n\n  formatQuerySeparator(token, query) {\n    return this.trimTrailingWhitespace(query) + token.value + '\\n';\n  }\n\n  addNewline(query) {\n    return trimEnd(query) + '\\n' + this.indentation.getIndent();\n  }\n\n  trimTrailingWhitespace(query) {\n    if (this.previousNonWhitespaceToken().type === tokenTypes.LINE_COMMENT) {\n      return trimEnd(query) + '\\n';\n    }\n\n    return trimEnd(query);\n  }\n\n  previousNonWhitespaceToken() {\n    let n = 1;\n    while (this.previousToken(n).type === tokenTypes.WHITESPACE) {\n      n++;\n    }\n    return this.previousToken(n);\n  }\n\n  previousToken(offset = 1) {\n    return this.tokens[this.index - offset] || {};\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/core/Indentation.ts",
    "content": "import repeat from 'lodash/repeat';\nimport last from 'lodash/last';\n\nconst INDENT_TYPE_TOP_LEVEL = 'top-level';\nconst INDENT_TYPE_BLOCK_LEVEL = 'block-level';\n\n/**\n * Manages indentation levels.\n *\n * There are two types of indentation levels:\n *\n * - BLOCK_LEVEL : increased by open-parenthesis\n * - TOP_LEVEL : increased by RESERVED_TOPLEVEL words\n */\nexport default class Indentation {\n  private readonly indent: string;\n  private readonly indentTypes: string[];\n  /**\n   * @param {String} indent Indent value, default is \"  \" (2 spaces)\n   */\n  constructor(indent) {\n    this.indent = indent || '  ';\n    this.indentTypes = [];\n  }\n\n  /**\n   * Returns current indentation string.\n   * @return {String}\n   */\n  getIndent() {\n    return repeat(this.indent, this.indentTypes.length);\n  }\n\n  /**\n   * Increases indentation by one top-level indent.\n   */\n  increaseToplevel() {\n    this.indentTypes.push(INDENT_TYPE_TOP_LEVEL);\n  }\n\n  /**\n   * Increases indentation by one block-level indent.\n   */\n  increaseBlockLevel() {\n    this.indentTypes.push(INDENT_TYPE_BLOCK_LEVEL);\n  }\n\n  /**\n   * Decreases indentation by one top-level indent.\n   * Does nothing when the previous indent is not top-level.\n   */\n  decreaseTopLevel() {\n    if (last(this.indentTypes) === INDENT_TYPE_TOP_LEVEL) {\n      this.indentTypes.pop();\n    }\n  }\n\n  /**\n   * Decreases indentation by one block-level indent.\n   * If there are top-level indents within the block-level indent,\n   * throws away these as well.\n   */\n  decreaseBlockLevel() {\n    while (this.indentTypes.length > 0) {\n      const type = this.indentTypes.pop();\n      if (type !== INDENT_TYPE_TOP_LEVEL) {\n        break;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/core/InlineBlock.ts",
    "content": "import tokenTypes from './tokenTypes';\n\nconst INLINE_MAX_LENGTH = 50;\n\n/**\n * Bookkeeper for inline blocks.\n *\n * Inline blocks are parenthized expressions that are shorter than INLINE_MAX_LENGTH.\n * These blocks are formatted on a single line, unlike longer parenthized\n * expressions where open-parenthesis causes newline and increase of indentation.\n */\nexport default class InlineBlock {\n  private level: number;\n  constructor() {\n    this.level = 0;\n  }\n\n  /**\n   * Begins inline block when lookahead through upcoming tokens determines\n   * that the block would be smaller than INLINE_MAX_LENGTH.\n   * @param  {Object[]} tokens Array of all tokens\n   * @param  {Number} index Current token position\n   */\n  beginIfPossible(tokens, index) {\n    if (this.level === 0 && this.isInlineBlock(tokens, index)) {\n      this.level = 1;\n    } else if (this.level > 0) {\n      this.level++;\n    } else {\n      this.level = 0;\n    }\n  }\n\n  /**\n   * Finishes current inline block.\n   * There might be several nested ones.\n   */\n  end() {\n    this.level--;\n  }\n\n  /**\n   * True when inside an inline block\n   * @return {Boolean}\n   */\n  isActive() {\n    return this.level > 0;\n  }\n\n  // Check if this should be an inline parentheses block\n  // Examples are \"NOW()\", \"COUNT(*)\", \"int(10)\", key(`somecolumn`), DECIMAL(7,2)\n  isInlineBlock(tokens, index) {\n    let length = 0;\n    let level = 0;\n\n    for (let i = index; i < tokens.length; i++) {\n      const token = tokens[i];\n      length += token.value.length;\n\n      // Overran max length\n      if (length > INLINE_MAX_LENGTH) {\n        return false;\n      }\n\n      if (token.type === tokenTypes.OPEN_PAREN) {\n        level++;\n      } else if (token.type === tokenTypes.CLOSE_PAREN) {\n        level--;\n        if (level === 0) {\n          return true;\n        }\n      }\n\n      if (this.isForbiddenToken(token)) {\n        return false;\n      }\n    }\n    return false;\n  }\n\n  // Reserved words that cause newlines, comments and semicolons\n  // are not allowed inside inline parentheses block\n  isForbiddenToken({type, value}) {\n    return (\n      type === tokenTypes.RESERVED_TOPLEVEL ||\n      type === tokenTypes.RESERVED_NEWLINE ||\n      type === tokenTypes.LINE_COMMENT ||\n      type === tokenTypes.BLOCK_COMMENT ||\n      value === ';'\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/core/Params.ts",
    "content": "/**\n * Handles placeholder replacement with given params.\n */\nexport default class Params {\n  private readonly params: any;\n  private index: number;\n  /**\n   * @param {Object} params\n   */\n  constructor(params) {\n    this.params = params;\n    this.index = 0;\n  }\n\n  /**\n   * Returns param value that matches given placeholder with param key.\n   * @param {Object} token\n   *   @param {String} token.key Placeholder key\n   *   @param {String} token.value Placeholder value\n   * @return {String} param or token.value when params are missing\n   */\n  get({key, value}) {\n    if (!this.params) {\n      return value;\n    }\n    if (key) {\n      return this.params[key];\n    }\n    return this.params[this.index++];\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/core/Tokenizer.ts",
    "content": "import isEmpty from 'lodash/isEmpty';\nimport escapeRegExp from 'lodash/escapeRegExp';\nimport tokenTypes from './tokenTypes';\n\nexport default class Tokenizer {\n  private readonly WHITESPACE_REGEX: RegExp;\n  private readonly NUMBER_REGEX: RegExp;\n  private readonly OPERATOR_REGEX: RegExp;\n  private readonly BLOCK_COMMENT_REGEX: RegExp;\n  private readonly LINE_COMMENT_REGEX: RegExp;\n  private readonly RESERVED_TOPLEVEL_REGEX: RegExp;\n  private readonly RESERVED_NEWLINE_REGEX: RegExp;\n  private readonly RESERVED_PLAIN_REGEX: RegExp;\n  private readonly WORD_REGEX: RegExp;\n  private readonly STRING_REGEX: RegExp;\n  private readonly OPEN_PAREN_REGEX: RegExp;\n  private readonly CLOSE_PAREN_REGEX: RegExp;\n  private readonly INDEXED_PLACEHOLDER_REGEX: RegExp | false;\n  private readonly IDENT_NAMED_PLACEHOLDER_REGEX: RegExp | false;\n  private readonly STRING_NAMED_PLACEHOLDER_REGEX: RegExp | false;\n  // private readonly SPECIAL_TOKENS: RegExp | false = false;\n  private readonly upperCase: boolean = false;\n\n  /**\n   * @param {Object} cfg\n   *  @param {String[]} cfg.reservedWords Reserved words in SQL\n   *  @param {String[]} cfg.reservedToplevelWords Words that are set to new line separately\n   *  @param {String[]} cfg.reservedNewlineWords Words that are set to newline\n   *  @param {String[]} cfg.stringTypes String types to enable: \"\", '', ``, [], N''\n   *  @param {String[]} cfg.openParens Opening parentheses to enable, like (, [\n   *  @param {String[]} cfg.closeParens Closing parentheses to enable, like ), ]\n   *  @param {String[]} cfg.indexedPlaceholderTypes Prefixes for indexed placeholders, like ?\n   *  @param {String[]} cfg.namedPlaceholderTypes Prefixes for named placeholders, like @ and :\n   *  @param {String[]} cfg.lineCommentTypes Line comments to enable, like # and --\n   *  @param {String[]} cfg.specialWordChars Special chars that can be found inside of words, like @ and #\n   * @param {boolean} cfg.upperCase\n   */\n  constructor(cfg: any) {\n    this.WHITESPACE_REGEX = /^(\\s+)/;\n    this.NUMBER_REGEX = /^((-\\s*)?[0-9]+(\\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)\\b/;\n    this.OPERATOR_REGEX = /^(!=|<>|==|<=|>=|!<|!>|\\|\\||::|->>|->|~~\\*|~~|!~~\\*|!~~|~\\*|!~\\*|!~|.)/;\n\n    this.BLOCK_COMMENT_REGEX = /^(\\/\\*[^]*?(?:\\*\\/|$))/;\n    this.LINE_COMMENT_REGEX = this.createLineCommentRegex(cfg.lineCommentTypes);\n\n    this.RESERVED_TOPLEVEL_REGEX = this.createReservedWordRegex(cfg.reservedToplevelWords);\n    this.RESERVED_NEWLINE_REGEX = this.createReservedWordRegex(cfg.reservedNewlineWords);\n    this.RESERVED_PLAIN_REGEX = this.createReservedWordRegex(cfg.reservedWords);\n\n    this.WORD_REGEX = this.createWordRegex(cfg.specialWordChars);\n    this.STRING_REGEX = this.createStringRegex(cfg.stringTypes);\n\n    this.OPEN_PAREN_REGEX = this.createParenRegex(cfg.openParens);\n    this.CLOSE_PAREN_REGEX = this.createParenRegex(cfg.closeParens);\n\n    this.INDEXED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.indexedPlaceholderTypes, '[0-9]*');\n    this.IDENT_NAMED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.namedPlaceholderTypes, '[a-zA-Z0-9._$]+');\n    this.STRING_NAMED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(\n      cfg.namedPlaceholderTypes,\n      this.createStringPattern(cfg.stringTypes),\n    );\n    this.upperCase = !!cfg.upperCase;\n  }\n\n  createLineCommentRegex(lineCommentTypes) {\n    return new RegExp(`^((?:${lineCommentTypes.map(c => escapeRegExp(c)).join('|')}).*?(?:\\n|$))`);\n  }\n\n  createReservedWordRegex(reservedWords) {\n    const reservedWordsPattern = reservedWords.join('|').replace(/ /g, '\\\\s+');\n    return new RegExp(`^(${reservedWordsPattern})\\\\b`, 'i');\n  }\n\n  createWordRegex(specialChars = []) {\n    return new RegExp(`^([\\\\w${specialChars.join('')}]+)`);\n  }\n\n  createStringRegex(stringTypes) {\n    return new RegExp('^(' + this.createStringPattern(stringTypes) + ')');\n  }\n\n  // This enables the following string patterns:\n  // 1. backtick quoted string using `` to escape\n  // 2. square bracket quoted string (SQL Server) using ]] to escape\n  // 3. double quoted string using \"\" or \\\" to escape\n  // 4. single quoted string using '' or \\' to escape\n  // 5. national character quoted string using N'' or N\\' to escape\n  createStringPattern(stringTypes) {\n    const patterns = {\n      '``': '((`[^`]*($|`))+)',\n      '[]': '((\\\\[[^\\\\]]*($|\\\\]))(\\\\][^\\\\]]*($|\\\\]))*)',\n      '\"\"': '((\"[^\"\\\\\\\\]*(?:\\\\\\\\.[^\"\\\\\\\\]*)*(\"|$))+)',\n      \"''\": \"(('[^'\\\\\\\\]*(?:\\\\\\\\.[^'\\\\\\\\]*)*('|$))+)\",\n      \"N''\": \"((N'[^N'\\\\\\\\]*(?:\\\\\\\\.[^N'\\\\\\\\]*)*('|$))+)\",\n    };\n\n    return stringTypes.map(t => patterns[t]).join('|');\n  }\n\n  createParenRegex(parens) {\n    return new RegExp('^(' + parens.map(p => this.escapeParen(p)).join('|') + ')', 'i');\n  }\n\n  escapeParen(paren) {\n    if (paren.length === 1) {\n      // A single punctuation character\n      return escapeRegExp(paren);\n    }\n\n    // longer word\n    return '\\\\b' + paren + '\\\\b';\n  }\n\n  createPlaceholderRegex(types, pattern) {\n    if (isEmpty(types)) {\n      return false;\n    }\n    const typesRegex = types.map(escapeRegExp).join('|');\n\n    return new RegExp(`^((?:${typesRegex})(?:${pattern}))`);\n  }\n\n  /**\n   * Takes a SQL string and breaks it into tokens.\n   * Each token is an object with type and value.\n   *\n   * @param {String} input The SQL string\n   * @return {Object[]} tokens An array of tokens.\n   *  @return {String} token.type\n   *  @return {String} token.value\n   */\n  tokenize(input) {\n    const tokens = [];\n    let token;\n\n    // Keep processing the string until it is empty\n    while (input.length) {\n      // Get the next token and the token type\n      token = this.getNextToken(input, token);\n      // Advance the string\n      input = input.substring(token.value.length);\n\n      tokens.push(token);\n    }\n    return tokens;\n  }\n\n  getNextToken(input, previousToken) {\n    return (\n      this.getWhitespaceToken(input) ||\n      this.getCommentToken(input) ||\n      this.getStringToken(input) ||\n      this.getOpenParenToken(input) ||\n      this.getCloseParenToken(input) ||\n      this.getPlaceholderToken(input) ||\n      this.getNumberToken(input) ||\n      this.getReservedWordToken(input, previousToken) ||\n      this.getWordToken(input) ||\n      this.getOperatorToken(input)\n    );\n  }\n\n  getWhitespaceToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.WHITESPACE,\n      regex: this.WHITESPACE_REGEX,\n    });\n  }\n\n  getCommentToken(input) {\n    return this.getLineCommentToken(input) || this.getBlockCommentToken(input);\n  }\n\n  getLineCommentToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.LINE_COMMENT,\n      regex: this.LINE_COMMENT_REGEX,\n    });\n  }\n\n  getBlockCommentToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.BLOCK_COMMENT,\n      regex: this.BLOCK_COMMENT_REGEX,\n    });\n  }\n\n  getStringToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.STRING,\n      regex: this.STRING_REGEX,\n    });\n  }\n\n  getOpenParenToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.OPEN_PAREN,\n      regex: this.OPEN_PAREN_REGEX,\n    });\n  }\n\n  getCloseParenToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.CLOSE_PAREN,\n      regex: this.CLOSE_PAREN_REGEX,\n    });\n  }\n\n  getPlaceholderToken(input) {\n    return (\n      this.getIdentNamedPlaceholderToken(input) ||\n      this.getStringNamedPlaceholderToken(input) ||\n      this.getIndexedPlaceholderToken(input)\n    );\n  }\n\n  getIdentNamedPlaceholderToken(input) {\n    return this.getPlaceholderTokenWithKey({\n      input,\n      regex: this.IDENT_NAMED_PLACEHOLDER_REGEX,\n      parseKey: v => v.slice(1),\n    });\n  }\n\n  getStringNamedPlaceholderToken(input) {\n    return this.getPlaceholderTokenWithKey({\n      input,\n      regex: this.STRING_NAMED_PLACEHOLDER_REGEX,\n      parseKey: v => this.getEscapedPlaceholderKey({key: v.slice(2, -1), quoteChar: v.slice(-1)}),\n    });\n  }\n\n  getIndexedPlaceholderToken(input) {\n    return this.getPlaceholderTokenWithKey({\n      input,\n      regex: this.INDEXED_PLACEHOLDER_REGEX,\n      parseKey: v => v.slice(1),\n    });\n  }\n\n  getPlaceholderTokenWithKey({input, regex, parseKey}) {\n    const token = this.getTokenOnFirstMatch({input, regex, type: tokenTypes.PLACEHOLDER});\n    if (token) {\n      token.key = parseKey(token.value);\n    }\n    return token;\n  }\n\n  getEscapedPlaceholderKey({key, quoteChar}) {\n    return key.replace(new RegExp(escapeRegExp('\\\\') + quoteChar, 'g'), quoteChar);\n  }\n\n  // Decimal, binary, or hex numbers\n  getNumberToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.NUMBER,\n      regex: this.NUMBER_REGEX,\n    });\n  }\n\n  // Punctuation and symbols\n  getOperatorToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.OPERATOR,\n      regex: this.OPERATOR_REGEX,\n    });\n  }\n\n  getReservedWordToken(input, previousToken) {\n    // A reserved word cannot be preceded by a \".\"\n    // this makes it so in \"mytable.from\", \"from\" is not considered a reserved word\n    if (previousToken && previousToken.value && previousToken.value === '.') {\n      return;\n    }\n    return (\n      this.getToplevelReservedToken(input) || this.getNewlineReservedToken(input) || this.getPlainReservedToken(input)\n    );\n  }\n\n  getToplevelReservedToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.RESERVED_TOPLEVEL,\n      regex: this.RESERVED_TOPLEVEL_REGEX,\n    });\n  }\n\n  getNewlineReservedToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.RESERVED_NEWLINE,\n      regex: this.RESERVED_NEWLINE_REGEX,\n    });\n  }\n\n  getPlainReservedToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.RESERVED,\n      regex: this.RESERVED_PLAIN_REGEX,\n    });\n  }\n\n  getWordToken(input) {\n    return this.getTokenOnFirstMatch({\n      input,\n      type: tokenTypes.WORD,\n      regex: this.WORD_REGEX,\n    });\n  }\n\n  getTokenOnFirstMatch({input, type, regex}): any {\n    const matches = input.match(regex);\n\n    if (matches) {\n      let value: string = matches[1];\n      if (\n        this.upperCase &&\n        (type === tokenTypes.RESERVED || type === tokenTypes.RESERVED_TOPLEVEL || type === tokenTypes.RESERVED_NEWLINE)\n      ) {\n        value = value.toLocaleUpperCase();\n      }\n      return {type, value};\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/core/tokenTypes.ts",
    "content": "/**\n * Constants for token types\n */\nexport default {\n  WHITESPACE: 'whitespace',\n  WORD: 'word',\n  STRING: 'string',\n  RESERVED: 'reserved',\n  RESERVED_TOPLEVEL: 'reserved-toplevel',\n  RESERVED_NEWLINE: 'reserved-newline',\n  OPERATOR: 'operator',\n  OPEN_PAREN: 'open-paren',\n  CLOSE_PAREN: 'close-paren',\n  LINE_COMMENT: 'line-comment',\n  BLOCK_COMMENT: 'block-comment',\n  NUMBER: 'number',\n  PLACEHOLDER: 'placeholder',\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/index.ts",
    "content": "import QuixSqlFormatter from './languages/SqlWithQuixVarFormmater';\nexport {QuixSqlFormatter};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/languages/SqlWithQuixVarFormmater.ts",
    "content": "import Formatter from '../core/Formatter';\nimport Tokenizer from '../core/Tokenizer';\nimport {tokenizerConf} from './StandardSqlFormatter';\n\nconst reservedWords = [\n  'ALTER',\n  'AND',\n  'AS',\n  'BETWEEN',\n  'BY',\n  'CASE',\n  'CAST',\n  'CONSTRAINT',\n  'CREATE',\n  'CROSS',\n  'CUBE',\n  'CURRENT_DATE',\n  'CURRENT_PATH',\n  'CURRENT_ROLE',\n  'CURRENT_TIME',\n  'CURRENT_TIMESTAMP',\n  'CURRENT_USER',\n  'DEALLOCATE',\n  'DELETE',\n  'DESCRIBE',\n  'DISTINCT',\n  'DROP',\n  'ELSE',\n  'END',\n  'ESCAPE',\n  'EXCEPT',\n  'EXECUTE',\n  'EXISTS',\n  'EXTRACT',\n  'FALSE',\n  'FOR',\n  'FROM',\n  'FULL',\n  'GROUP',\n  'GROUPING',\n  'HAVING',\n  'IN',\n  'INNER',\n  'INSERT',\n  'INTERSECT',\n  'INTO',\n  'IS',\n  'JOIN',\n  'LEFT',\n  'LIKE',\n  'LOCALTIME',\n  'LOCALTIMESTAMP',\n  'NATURAL',\n  'NORMALIZE',\n  'NOT',\n  'NULL',\n  'ON',\n  'OR',\n  'ORDER',\n  'OUTER',\n  'PREPARE',\n  'RECURSIVE',\n  'RIGHT',\n  'ROLLUP',\n  'SELECT',\n  'TABLE',\n  'THEN',\n  'TRUE',\n  'UESCAPE',\n  'UNION',\n  'UNNEST',\n  'USING',\n  'VALUES',\n  'WHEN',\n  'WHERE',\n  'WITH',\n];\n\nconst reservedToplevelWords = [\n  'ALTER COLUMN',\n  'ALTER TABLE',\n  'DELETE FROM',\n  'EXCEPT',\n  'FROM',\n  'GROUP BY',\n  'HAVING',\n  'INSERT INTO',\n  'INSERT',\n  'INTERSECT',\n  'LIMIT',\n  'ORDER BY',\n  'SELECT',\n  'SET CURRENT SCHEMA',\n  'SET SCHEMA',\n  'SET',\n  'UNION ALL',\n  'UNION',\n  'UPDATE',\n  'VALUES',\n  'WHERE',\n];\n\nconst reservedNewlineWords = [\n  'AND',\n  'CROSS APPLY',\n  'CROSS JOIN',\n  'ELSE',\n  'INNER JOIN',\n  'JOIN',\n  'LEFT JOIN',\n  'LEFT OUTER JOIN',\n  'OR',\n  'OUTER APPLY',\n  'OUTER JOIN',\n  'RIGHT JOIN',\n  'RIGHT OUTER JOIN',\n  'WHEN',\n  'XOR',\n];\n\nconst newTokenizerConf = {\n  ...tokenizerConf,\n  namedPlaceholderTypes: tokenizerConf.namedPlaceholderTypes.concat(['$']),\n  reservedNewlineWords,\n  reservedToplevelWords,\n  reservedWords,\n};\n\nexport default class QuixSqlFormatter {\n  private readonly cfg: any;\n  private tokenizer: any;\n  /**\n   * @param {Object} cfg Different set of configurations\n   */\n  constructor(cfg = {}) {\n    this.cfg = cfg;\n  }\n\n  /**\n   * Format the whitespace in a Standard SQL string to make it easier to read\n   *\n   * @param {String} query The Standard SQL string\n   * @return {String} formatted string\n   */\n  format(query) {\n    if (!this.tokenizer) {\n      this.tokenizer = new Tokenizer({...newTokenizerConf, upperCase: this.cfg.upperCase});\n    }\n    return new Formatter(this.cfg, this.tokenizer).format(query);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/languages/StandardSqlFormatter.ts",
    "content": "import Formatter from '../core/Formatter';\nimport Tokenizer from '../core/Tokenizer';\n\nconst reservedWords = [\n  'ACCESSIBLE',\n  'ACTION',\n  'AGAINST',\n  'AGGREGATE',\n  'ALGORITHM',\n  'ALL',\n  'ALTER',\n  'ANALYSE',\n  'ANALYZE',\n  'AS',\n  'ASC',\n  'AUTOCOMMIT',\n  'AUTO_INCREMENT',\n  'BACKUP',\n  'BEGIN',\n  'BETWEEN',\n  'BINLOG',\n  'BOTH',\n  'CASCADE',\n  'CASE',\n  'CHANGE',\n  'CHANGED',\n  'CHARACTER SET',\n  'CHARSET',\n  'CHECK',\n  'CHECKSUM',\n  'COLLATE',\n  'COLLATION',\n  'COLUMN',\n  'COLUMNS',\n  'COMMENT',\n  'COMMIT',\n  'COMMITTED',\n  'COMPRESSED',\n  'CONCURRENT',\n  'CONSTRAINT',\n  'CONTAINS',\n  'CONVERT',\n  'CREATE',\n  'CROSS',\n  'CURRENT_TIMESTAMP',\n  'DATABASE',\n  'DATABASES',\n  'DAY',\n  'DAY_HOUR',\n  'DAY_MINUTE',\n  'DAY_SECOND',\n  'DEFAULT',\n  'DEFINER',\n  'DELAYED',\n  'DELETE',\n  'DESC',\n  'DESCRIBE',\n  'DETERMINISTIC',\n  'DISTINCT',\n  'DISTINCTROW',\n  'DIV',\n  'DO',\n  'DROP',\n  'DUMPFILE',\n  'DUPLICATE',\n  'DYNAMIC',\n  'ELSE',\n  'ENCLOSED',\n  'END',\n  'ENGINE',\n  'ENGINES',\n  'ENGINE_TYPE',\n  'ESCAPE',\n  'ESCAPED',\n  'EVENTS',\n  'EXEC',\n  'EXECUTE',\n  'EXISTS',\n  'EXPLAIN',\n  'EXTENDED',\n  'FAST',\n  'FETCH',\n  'FIELDS',\n  'FILE',\n  'FIRST',\n  'FIXED',\n  'FLUSH',\n  'FOR',\n  'FORCE',\n  'FOREIGN',\n  'FULL',\n  'FULLTEXT',\n  'FUNCTION',\n  'GLOBAL',\n  'GRANT',\n  'GRANTS',\n  'GROUP_CONCAT',\n  'HEAP',\n  'HIGH_PRIORITY',\n  'HOSTS',\n  'HOUR',\n  'HOUR_MINUTE',\n  'HOUR_SECOND',\n  'IDENTIFIED',\n  'IF',\n  'IFNULL',\n  'IGNORE',\n  'IN',\n  'INDEX',\n  'INDEXES',\n  'INFILE',\n  'INSERT',\n  'INSERT_ID',\n  'INSERT_METHOD',\n  'INTERVAL',\n  'INTO',\n  'INVOKER',\n  'IS',\n  'ISOLATION',\n  'KEY',\n  'KEYS',\n  'KILL',\n  'LAST_INSERT_ID',\n  'LEADING',\n  'LEVEL',\n  'LIKE',\n  'LINEAR',\n  'LINES',\n  'LOAD',\n  'LOCAL',\n  'LOCK',\n  'LOCKS',\n  'LOGS',\n  'LOW_PRIORITY',\n  'MARIA',\n  'MASTER',\n  'MASTER_CONNECT_RETRY',\n  'MASTER_HOST',\n  'MASTER_LOG_FILE',\n  'MATCH',\n  'MAX_CONNECTIONS_PER_HOUR',\n  'MAX_QUERIES_PER_HOUR',\n  'MAX_ROWS',\n  'MAX_UPDATES_PER_HOUR',\n  'MAX_USER_CONNECTIONS',\n  'MEDIUM',\n  'MERGE',\n  'MINUTE',\n  'MINUTE_SECOND',\n  'MIN_ROWS',\n  'MODE',\n  'MODIFY',\n  'MONTH',\n  'MRG_MYISAM',\n  'MYISAM',\n  'NAMES',\n  'NATURAL',\n  'NOT',\n  'NOW()',\n  'NULL',\n  'OFFSET',\n  'ON DELETE',\n  'ON UPDATE',\n  'ON',\n  'ONLY',\n  'OPEN',\n  'OPTIMIZE',\n  'OPTION',\n  'OPTIONALLY',\n  'OUTFILE',\n  'PACK_KEYS',\n  'PAGE',\n  'PARTIAL',\n  'PARTITION',\n  'PARTITIONS',\n  'PASSWORD',\n  'PRIMARY',\n  'PRIVILEGES',\n  'PROCEDURE',\n  'PROCESS',\n  'PROCESSLIST',\n  'PURGE',\n  'QUICK',\n  'RAID0',\n  'RAID_CHUNKS',\n  'RAID_CHUNKSIZE',\n  'RAID_TYPE',\n  'RANGE',\n  'READ',\n  'READ_ONLY',\n  'READ_WRITE',\n  'REFERENCES',\n  'REGEXP',\n  'RELOAD',\n  'RENAME',\n  'REPAIR',\n  'REPEATABLE',\n  'REPLACE',\n  'REPLICATION',\n  'RESET',\n  'RESTORE',\n  'RESTRICT',\n  'RETURN',\n  'RETURNS',\n  'REVOKE',\n  'RLIKE',\n  'ROLLBACK',\n  'ROW',\n  'ROWS',\n  'ROW_FORMAT',\n  'SECOND',\n  'SECURITY',\n  'SEPARATOR',\n  'SERIALIZABLE',\n  'SESSION',\n  'SHARE',\n  'SHOW',\n  'SHUTDOWN',\n  'SLAVE',\n  'SONAME',\n  'SOUNDS',\n  'SQL',\n  'SQL_AUTO_IS_NULL',\n  'SQL_BIG_RESULT',\n  'SQL_BIG_SELECTS',\n  'SQL_BIG_TABLES',\n  'SQL_BUFFER_RESULT',\n  'SQL_CACHE',\n  'SQL_CALC_FOUND_ROWS',\n  'SQL_LOG_BIN',\n  'SQL_LOG_OFF',\n  'SQL_LOG_UPDATE',\n  'SQL_LOW_PRIORITY_UPDATES',\n  'SQL_MAX_JOIN_SIZE',\n  'SQL_NO_CACHE',\n  'SQL_QUOTE_SHOW_CREATE',\n  'SQL_SAFE_UPDATES',\n  'SQL_SELECT_LIMIT',\n  'SQL_SLAVE_SKIP_COUNTER',\n  'SQL_SMALL_RESULT',\n  'SQL_WARNINGS',\n  'START',\n  'STARTING',\n  'STATUS',\n  'STOP',\n  'STORAGE',\n  'STRAIGHT_JOIN',\n  'STRING',\n  'STRIPED',\n  'SUPER',\n  'TABLE',\n  'TABLES',\n  'TEMPORARY',\n  'TERMINATED',\n  'THEN',\n  'TO',\n  'TRAILING',\n  'TRANSACTIONAL',\n  'TRUE',\n  'TRUNCATE',\n  'TYPE',\n  'TYPES',\n  'UNCOMMITTED',\n  'UNIQUE',\n  'UNLOCK',\n  'UNSIGNED',\n  'USAGE',\n  'USE',\n  'USING',\n  'VARIABLES',\n  'VIEW',\n  'WHEN',\n  'WITH',\n  'WORK',\n  'WRITE',\n  'YEAR_MONTH',\n];\n\nconst reservedToplevelWords = [\n  'ADD',\n  'AFTER',\n  'ALTER COLUMN',\n  'ALTER TABLE',\n  'DELETE FROM',\n  'EXCEPT',\n  'FETCH FIRST',\n  'FROM',\n  'GROUP BY',\n  'GO',\n  'HAVING',\n  'INSERT INTO',\n  'INSERT',\n  'INTERSECT',\n  'LIMIT',\n  'MODIFY',\n  'ORDER BY',\n  'SELECT',\n  'SET CURRENT SCHEMA',\n  'SET SCHEMA',\n  'SET',\n  'UNION ALL',\n  'UNION',\n  'UPDATE',\n  'VALUES',\n  'WHERE',\n];\n\nconst reservedNewlineWords = [\n  'AND',\n  'CROSS APPLY',\n  'CROSS JOIN',\n  'ELSE',\n  'INNER JOIN',\n  'JOIN',\n  'LEFT JOIN',\n  'LEFT OUTER JOIN',\n  'OR',\n  'OUTER APPLY',\n  'OUTER JOIN',\n  'RIGHT JOIN',\n  'RIGHT OUTER JOIN',\n  'WHEN',\n  'XOR',\n];\n\nlet tokenizer;\nexport const tokenizerConf = {\n  reservedWords,\n  reservedToplevelWords,\n  reservedNewlineWords,\n  stringTypes: [`\"\"`, \"N''\", \"''\", '``', '[]'],\n  openParens: ['(', 'CASE'],\n  closeParens: [')', 'END'],\n  indexedPlaceholderTypes: ['?'],\n  namedPlaceholderTypes: ['@', ':'],\n  lineCommentTypes: ['#', '--'],\n};\nexport default class StandardSqlFormatter {\n  private readonly cfg: any;\n  /**\n   * @param {Object} cfg Different set of configurations\n   */\n  constructor(cfg) {\n    this.cfg = cfg;\n  }\n\n  /**\n   * Format the whitespace in a Standard SQL string to make it easier to read\n   *\n   * @param {String} query The Standard SQL string\n   * @return {String} formatted string\n   */\n  format(query) {\n    if (!tokenizer) {\n      tokenizer = new Tokenizer(tokenizerConf);\n    }\n    return new Formatter(this.cfg, tokenizer).format(query);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/sql-formatter/sqlFormatter.ts",
    "content": "import StandardSqlFormatter from './languages/StandardSqlFormatter';\nimport QuixSqlFormatter from './languages/SqlWithQuixVarFormmater';\nexport interface Cfg {\n  language?: 'sql' | 'quixsql';\n  params?: Record<string, string> | string[];\n  indent?: string;\n  upperCase?: boolean;\n}\nexport default {\n  /**\n   * Format whitespaces in a query to make it easier to read.\n   *\n   * @param {String} query\n   * @param {Object} cfg\n   *  @param {String} cfg.language Query language, default is Standard SQL\n   *  @param {String} cfg.indent Characters used for indentation, default is \"  \" (2 spaces)\n   *  @param {Object} cfg.params Collection of params for placeholder replacement\n   * @return {String}\n   */\n  format: (query, cfg: Cfg = {}) => {\n    switch (cfg.language) {\n      case 'sql':\n      case undefined:\n        return new StandardSqlFormatter(cfg).format(query);\n      case 'quixsql':\n        return new QuixSqlFormatter(cfg).format(query);\n      default:\n        throw Error(`Unsupported SQL dialect: ${cfg.language}`);\n    }\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/store/index.ts",
    "content": "export {default as createStore, Store, StoreOptions, IBranch, dispatch, dispatchAndLog, logAndDispatch, ReduxStore, sessionId} from './services/store';\nexport {StoreCache, Cache, Request} from './services/store-cache';\nexport {combineReducers} from 'redux';"
  },
  {
    "path": "quix-frontend/client/src/lib/store/services/store-cache.ts",
    "content": "import {isEqual, uniqueId} from 'lodash';\nimport {inject} from '../../core';\nimport {Store} from './store';\n\nexport class Request {\n  private promise;\n  private args;\n  private id;\n\n  private shouldHandleRequest(args: any[]) {\n    return !this.promise || !isEqual(this.args, args);\n  }\n\n  private shouldHandleResponse(requestId) {\n    return requestId === this.id;\n  }\n\n  private clear() {\n    this.promise = this.args = null;\n  }\n\n  private createRequest(id: string, args, fetch: Function, onSuccess: Function, onError: Function) {\n    return fetch(...args)\n      .then(res => {\n        if (!this.shouldHandleResponse(id)) {\n          return inject('$q').reject();\n        }\n\n        delete res.$promise;\n        delete res.$resolved;\n\n        return onSuccess(res, ...args);\n      })\n      .catch(e => {\n        onError({...e.data, status: e.status}, ...args);\n        return null;\n      })\n      .finally(() => this.shouldHandleResponse(id) && this.clear());\n  }\n\n  do(args: any[], fetch: Function, onSuccess: Function, onError: Function) {\n    if (!this.shouldHandleRequest(args)) {\n      return this.promise;\n    }\n\n    this.id = uniqueId();\n    this.args = args;\n    this.promise = this.createRequest(this.id, args, fetch, onSuccess, onError);\n\n    return this.promise;\n  }\n}\n\nexport class Cache<T> {\n  protected cacher: Function;\n  protected getter: Function;\n  protected catcher: Function;\n  private fetcher: Function;\n  private readonly request = new Request();\n\n  protected getCache(...args) {\n    // abstract\n  }\n\n  protected setCache(...args) {\n    // abstract\n  }\n\n  protected setError(...args) {\n    // abstract\n  }\n\n  private fetchAndSetCache(...args): ng.IPromise<T> {\n    return this.request.do(args, this.fetcher, (...arg) => this.setCache(...arg), (...arg) => this.setError(...arg));\n  }\n\n  cacheWith(cacher: Function): Cache<T> {\n    this.cacher = cacher;\n    return this;\n  }\n\n  getWith(getter: Function): Cache<T> {\n    this.getter = getter;\n    return this;\n  }\n\n  fetchWith(fetcher: Function): Cache<T> {\n    this.fetcher = fetcher;\n    return this;\n  }\n\n  catchWith(catcher: Function): Cache<T> {\n    this.catcher = catcher;\n    return this;\n  }\n\n  /**\n   * Returns cached value if exists, otherwise fetches and sets a new value\n   */\n  get(...args): ng.IPromise<T> {\n    return inject('$q').when((this.getCache(...args) as any) || this.fetchAndSetCache(...args));\n  }\n\n  /**\n   * Fetches and sets a new value\n   */\n  fetch(...args): ng.IPromise<T> {\n    return this.fetchAndSetCache(...args);\n  }\n}\n\nexport class StoreCache<T> extends Cache<T> {\n  constructor(private readonly store: Store, private readonly branch: string) {\n    super();\n  }\n\n  protected getCache(...args): T {\n    const state = this.store.getState(this.branch);\n\n    return this.getter ? this.getter(state, ...args) : state;\n  }\n\n  protected setCache(...args): ng.IPromise<T> {\n    const action = this.cacher(...args);\n\n    if (!action) {\n      return;\n    }\n\n    return this.store.dispatch(action).then(() => this.getCache());\n  }\n\n  protected setError(...args): ng.IPromise<T> {\n    const action = this.catcher && this.catcher(...args);\n\n    if (!action) {\n      return;\n    }\n\n    return this.store.dispatch(action);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/store/services/store-logger.ts",
    "content": "import {inject, srv, utils} from '../../core';\nimport {toast} from '../../ui';\n\nconst {injector} = srv;\n\nfunction onError(error) {\n  toast.showToast({text: 'Action failed', cancel: 'close', type: 'error'}, 3000);\n  return inject('$q').reject(error);\n}\n\nconst toScalaEvent = (eventName: string, data: object) => ({name: eventName, data: utils.stripDollars(data)});\nconst toNodeAction = (eventName: string, data: object) => ({type: eventName, ...utils.stripDollars(data)});\nexport type ServerFrameworkType = 'Scala' | 'Node';\n\nexport default class StoreLogger {\n  private resource;\n  private readonly transform;\n\n  constructor(endpoint, private readonly sessionId = null, server: ServerFrameworkType = 'Scala' ) {\n    injector.on('ready', () => {\n      this.resource = inject('$resource')(endpoint, {sessionId: '@sessionId'}, {events: {method: 'POST'}});\n    });\n    this.transform = server === 'Scala' ? toScalaEvent : toNodeAction;\n  }\n\n  log(eventName, data) {\n    return this.resource.events({sessionId: this.sessionId}, [this.transform(eventName, data)]).$promise.catch(onError);\n  }\n\n  bulk() {\n    const resource = this.resource;\n    const self = this;\n    return {\n      events: [],\n      add(eventName, data) {\n        this.events.push(self.transform(eventName, data));\n        return this;\n      },\n      log() {\n        return resource.events({sessionId: this.sessionId}, this.events).$promise.catch(onError);\n      }\n    };\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/store/services/store.ts",
    "content": "import { isArray, find, pull, forEach, get, assign, chain as _ } from 'lodash';\nimport { utils, inject } from '../../core';\nimport StoreLogger, { ServerFrameworkType } from './store-logger';\nimport * as Redux from 'redux';\nimport { uuid } from '../../core/utils';\nconst { scope: scopeUtils } = utils;\n\nexport type IBranch<T = any> = (\n  fn: (reducer: Redux.Reducer<T>, ...middleware: Redux.Middleware[]) => void\n) => void;\nexport type ReduxStore<S> = Redux.Store<S>;\nexport interface IBranches {\n  [key: string]: IBranch;\n}\n\nfunction getLogParams({ type, ...action }) {\n  delete (action as any).$log;\n  delete (action as any).$defer;\n  delete (action as any).$next;\n\n  return [type, action];\n}\n\nfunction logAction(logger, action) {\n  return logger.log(...getLogParams(action));\n}\n\nfunction logBulkAction(logger, ...actions) {\n  logger = logger.bulk();\n\n  actions.forEach((action) => logger.add(...getLogParams(action)));\n\n  return logger.log();\n}\n\nconst handleReactions = (store: Store, reactions: any[]) => {\n  reactions.forEach((reaction: any) => store.dispatch(reaction));\n};\n\nfunction resolveActions(\n  action,\n  promises = [],\n  res = null,\n  deferred = null,\n  isBulk = false\n) {\n  const $q = inject('$q');\n\n  deferred = deferred || $q.defer();\n  isBulk = isBulk || isArray(action);\n  res = res || (isArray(action) ? action : [action]);\n\n  if (action.then) {\n    const promise = { promise: action, action: null };\n\n    promises.push(promise);\n\n    promise.promise.then(\n      (actn) => {\n        promise.action = actn;\n        resolveActions(actn, promises, res, deferred, isBulk);\n      },\n      () => deferred.reject()\n    );\n  } else {\n    let promise = find(promises, { action });\n\n    if (promise) {\n      pull(promises, promise);\n    } else {\n      promise = { promise: action, action };\n    }\n\n    res = _(res)\n      .map((item) => (item === promise.promise ? promise.action : item))\n      .flattenDeep()\n      .value();\n\n    if (isArray(action)) {\n      action.forEach((actn) =>\n        resolveActions(actn, promises, res, deferred, isBulk)\n      );\n    }\n\n    if (promises.length === 0) {\n      deferred.resolve({ actions: res, isBulk });\n    }\n  }\n\n  return deferred.promise;\n}\n\nfunction logMiddleware(logger) {\n  /**\n   * @param actions  array of action definitions\n   *\n   * @return Promise\n   */\n  return (store) => (next) => (actions) => {\n    const $q = inject('$q');\n\n    const { $log, $bulk, $defer } = actions;\n    const action = actions[0];\n    let res = !$bulk && !$defer ? next(action) : action;\n\n    if ($log) {\n      res = $bulk\n        ? logBulkAction(logger, ...actions)\n        : logAction(logger, action);\n\n      if ($defer && !$bulk) {\n        res.then(() => next(action));\n      }\n    }\n\n    return $q.when(res).then((data) => {\n      if (data && data.reactions) {\n        handleReactions(store, data.reactions);\n      }\n\n      return action;\n    });\n  };\n}\n\nfunction promiseMiddleware(biStore) {\n  return (store) => (next) => (action) => {\n    const { $log = false, $defer = false } = action;\n\n    const res = resolveActions(action).then(({ actions, isBulk }) => {\n      if (!actions.length) {\n        return;\n      }\n\n      actions.$log = $log;\n      actions.$defer = $defer;\n      actions.$bulk = isBulk;\n\n      if (isBulk && !$defer) {\n        actions.forEach((actn) => biStore.dispatch(actn));\n      }\n\n      return next(actions).then((result) => {\n        if (isBulk && $defer) {\n          actions.forEach((actn) => biStore.dispatch(actn));\n        }\n\n        return result;\n      });\n    });\n\n    if (!action.then) {\n      assign(res, isArray(action) ? action[0] : action);\n    }\n\n    return res;\n  };\n}\n\n// allow inversion of control\nfunction functionMiddleware(biStore) {\n  return (store) => (next) => (action) => {\n    if (typeof action === 'function') {\n      return action(biStore)((action as any).$next);\n    }\n\n    return next(action);\n  };\n}\n\nfunction initBranches(branches: IBranches) {\n  const reducers = {};\n  const branchMiddlewares = [];\n\n  forEach(branches, (branch, name) => {\n    branch((reducer, ...middleware) => {\n      reducers[name] = reducer;\n\n      if (middleware.length) {\n        branchMiddlewares.push(...middleware);\n      }\n    });\n  });\n\n  return { reducers, middlewares: branchMiddlewares };\n}\n\n/**\n * Dispatch an action\n *\n * @param action\n *    - single action\n *    - array of actions or promises (nesting supported)\n *    - promise resolved with any of the above\n */\nexport const dispatch = (storeDispatch) => (action) => {\n  if (!(action as any).$next) {\n    (action as any).$next = (actn) => dispatch(actn);\n  }\n\n  return storeDispatch(action);\n};\n\n/**\n * Same as dispatch() but also logs the action to server\n */\nexport const dispatchAndLog = (storeDispatch) => <T>(action: T): Promise<T> => {\n  (action as any).$log = true;\n\n  if (!(action as any).$next) {\n    (action as any).$next = (actn) => dispatchAndLog(storeDispatch)(actn);\n  }\n\n  return dispatch(storeDispatch)(action);\n};\n\n/**\n * Same as dispatchAndLog() but dispatching is deferred until after logging the action to server\n */\nexport const logAndDispatch = (storeDispatch) => <T>(action: T): Promise<T> => {\n  (action as any).$defer = true;\n  (action as any).$next = (actn) => logAndDispatch(storeDispatch)(actn);\n\n  return dispatchAndLog(storeDispatch)(action);\n};\n\nexport interface StoreOptions {\n  logUrl?: string;\n  server?: ServerFrameworkType;\n}\nconst defaultStoreOptions: StoreOptions = {\n  logUrl: '',\n  server: 'Scala',\n};\n\nexport const sessionId = uuid();\n\nexport class Store<S = any> {\n  private readonly store: ReduxStore<S>;\n  logger: StoreLogger;\n  private readonly options: StoreOptions;\n\n  constructor(branches: IBranches, options: StoreOptions = {}) {\n    this.options = { ...defaultStoreOptions, ...options };\n    const { reducers, middlewares } = initBranches(branches);\n    const composeEnhancers =\n      (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || Redux.compose;\n\n    this.logger = new StoreLogger(\n      this.options.logUrl,\n      sessionId,\n      this.options.server\n    );\n    this.store = Redux.createStore(\n      Redux.combineReducers(reducers),\n      composeEnhancers(\n        Redux.applyMiddleware(\n          ...[\n            functionMiddleware(this),\n            promiseMiddleware(this),\n            logMiddleware(this.logger),\n            ...middlewares,\n          ]\n        )\n      )\n    );\n\n    this.dispatch = dispatch(this.store.dispatch);\n    this.dispatchAndLog = dispatchAndLog(this.store.dispatch);\n    this.logAndDispatch = logAndDispatch(this.store.dispatch);\n  }\n\n  /**\n   * Dispatch an action\n   *\n   * @param action\n   *    - single action\n   *    - array of actions or promises (nesting supported)\n   *    - promise resolved with any of the above\n   */\n  dispatch: ReturnType<typeof dispatch>;\n\n  /**\n   * Same as dispatch() but also logs the action to server\n   */\n  dispatchAndLog: ReturnType<typeof dispatchAndLog>;\n\n  /**\n   * Same as dispatchAndLog() but dispatching is deferred until after logging the action to server\n   */\n  logAndDispatch: ReturnType<typeof logAndDispatch>;\n\n  /**\n   * Returns store's state\n   *\n   * @param branch  e.g. \"notebook.folders\"\n   */\n  getState(branch?): S {\n    const state = this.store.getState();\n\n    if (branch) {\n      return get(state, branch);\n    }\n\n    return state;\n  }\n\n  /**\n   * Subscribe to changes in a particular branch in the store\n   * The handler will be executed immediately and every time the branch state reference changes\n   *\n   * @param branch  e.g. \"notebook.folders\"\n   * @param fn      handler\n   */\n  subscribe(branch: string, fn: (state, store?) => void, scope): Function {\n    const applyScope = scope || inject('$rootScope');\n    let state = this.getState(branch);\n\n    scopeUtils.safeDigest(applyScope, () => fn(state, this.store));\n\n    const unsubscribe = this.store.subscribe(() => {\n      const newState = this.getState(branch);\n\n      if (newState !== state) {\n        scopeUtils.safeDigest(applyScope, () => fn(newState, this));\n        state = newState;\n      }\n    });\n\n    scope.$on('$destroy', unsubscribe);\n\n    return unsubscribe;\n  }\n\n  getReduxStore() {\n    return this.store;\n  }\n}\n\n/**\n * Create a new store\n *\n * @param branches  branches to init in the new store\n */\nexport default function create(\n  branches: IBranches,\n  options?: StoreOptions\n): Store {\n  return new Store(branches, options);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/app.scss",
    "content": "@import './assets/css/badge';\n@import './assets/css/fonts';\n@import './assets/css/animations';\n@import './assets/css/colors';\n@import './assets/css/flex';\n@import './assets/css/space';\n@import './assets/css/panel';\n@import './assets/css/section';\n@import './assets/css/action';\n@import './assets/css/button';\n@import './assets/css/dropdown';\n@import './assets/css/input';\n@import './assets/css/icon';\n@import './assets/css/toggle';\n@import './assets/css/align';\n@import './assets/css/border';\n@import './assets/css/table';\n@import './assets/css/label';\n@import './assets/css/app/app-header';\n@import './assets/css/app/app-menu';\n@import './assets/css/dialog';\n@import './assets/css/nav-tabs';\n@import './assets/css/caret';\n@import './assets/css/link';\n@import './assets/css/spinner';\n@import './assets/css/text';\n@import './assets/css/scroll';\n@import './assets/css/hint';\n@import './assets/css/form';\n@import './assets/css/media';\n@import './assets/css/mouse';\n@import './assets/css/tag';\n@import './assets/css/home-action';\n@import './assets/css/alert';\n@import './assets/css/empty-state';\n@import './assets/css/hover';\n@import './assets/css/theme';\n@import './assets/css/state';\n@import './assets/css/heading';\n@import './assets/css/no-select';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/action.scss",
    "content": "@import './def/colors.def';\n@import './def/action.def';\n@import './def/button.def';\n\n.bi-theme--lighter {\n  .bi-action {\n    @include action('lighter');\n  }\n\n  .bi-theme--dark {\n    .bi-action {\n      @include action('dark');\n    }\n  }\n\n  .bi-theme--darker {\n    .bi-action {\n      @include action('darker');\n    }\n  }\n}\n\n.bi-theme--light {\n  .bi-action {\n    @include action('light');\n  }\n\n  .bi-theme--lighter {\n    .bi-action {\n      @include action('lighter');\n    }\n  }\n\n  .bi-theme--dark {\n    .bi-action {\n      @include action('dark');\n    }\n  }\n\n  .bi-theme--darker {\n    .bi-action {\n      @include action('darker');\n    }\n  }\n}\n\n.bi-theme--dark {\n  .bi-action {\n    @include action('dark');\n  }\n}\n\n.bi-theme--darker {\n  .bi-action {\n    @include action('darker');\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/alert.scss",
    "content": "@import './def/alert.def';\n@import './def/colors.def';\n\n.bi-alert {\n  @include alert();\n}\n\n.bi-alert--error {\n  @include alert('error_outline', $danger, lighten($danger, 36));\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/align.scss",
    "content": "@import './def/flex.def';\n@import './def/align.def';\n\n.bi-spread {\n  @extend %spread;\n}\n\n.bi-center {\n  @include flex(row, null, center);\n}\n\n.bi-justify-right {\n  @include flex(row, null, flex-end);\n}\n\n.bi-align {\n  @include flex(row, center);\n}\n\n.bi-align--bottom {\n  @include flex(row, flex-end !important);\n}\n\n.bi-align--top {\n  @include flex(row, flex-start !important);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/animations.scss",
    "content": "@import './def/animations.def';\n\n.bi-fade-in {\n  @extend %animation-fade-in;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/app/app-header.scss",
    "content": "@import '../def/app/app-header.def';\n\n.bi-app-header {\n  @extend %app-header;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/app/app-menu.scss",
    "content": "@import '../def/app/app-menu.def';\n\n.bi-app-menu {\n  @extend %app-menu;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/badge.scss",
    "content": "@import './def/badge.def';\n@import './def/colors.def';\n\n.bi-badge {\n  @include badge();\n  color: $grey--900;\n}\n\n.bi-badge--primary {\n  @include badge($primary);\n}\n\n.bi-badge--success {\n  @include badge($success);\n}\n\n.bi-badge--warning {\n  @include badge($warning);\n}\n\n.bi-badge--danger {\n  @include badge($danger);\n}\n\n.bi-badge--sm {\n  @include badge();\n  @include badge-size(14px, 9px);\n  border-radius: 7px;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/border.scss",
    "content": "@import './def/border.def';\n\n.bi-border {\n  @include border();\n}\n\n.bi-border--top {\n  @include border(top);\n}\n\n.bi-border--right {\n  @include border(right);\n}\n\n.bi-border--bottom {\n  @include border(bottom);\n}\n\n.bi-border--left {\n  @include border(left);\n}\n\n.bi-no-border {\n  border: 0 !important;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/button.scss",
    "content": "@import './def/colors.def';\n@import './def/button.def';\n@import './def/flex.def';\n\n.bi-button--primary {\n  @include button($primary);\n}\n\n.bi-button--secondary {\n  @include button($secondary);\n}\n\n.bi-button--success {\n  @include button($success);\n}\n\n.bi-button--warning {\n  @include button($warning);\n}\n\n.bi-button--danger {\n  @include button($danger);\n}\n\n.bi-button {\n  @include button-size();\n}\n\n.bi-button--sm {\n  @include button-size(22px, 8px, 10px);\n}\n\n.bi-button-group {\n  @include flex();\n\n  border-radius: 3px;\n  overflow: hidden;\n\n  button {\n    border-radius: 0 !important;\n  }\n\n  a {\n    border-radius: 0 !important;\n  }\n}\n\n.bi-theme--lighter {\n  .bi-button {\n    @include button-theme('lighter');\n  }\n}\n\n.bi-theme--light {\n  .bi-button {\n    @include button-theme('light');\n  }\n\n  .bi-theme--lighter {\n    .bi-button {\n      @include button-theme('lighter');\n    }\n  }\n}\n\n.bi-theme--dark {\n  .bi-button {\n    @include button-theme('dark');\n  }\n}\n\n.bi-theme--darker {\n  .bi-button {\n    @include button-theme('darker');\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/caret.scss",
    "content": "@import './def/caret.def';\n\n.bi-caret {\n  @extend %caret;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/colors.scss",
    "content": "@import './def/colors.def';\n@import './def/state.def';\n\n.bi-theme--light {\n  .bi-disabled {\n    @include disabled('light');\n  }\n\n  .bi-muted {\n    @include muted('light');\n  }\n\n  .bi-theme--lighter {\n    .bi-disabled {\n      @include disabled('lighter');\n    }\n\n    .bi-muted {\n      @include muted('lighter');\n    }\n  }\n}\n\n.bi-theme--lighter {\n  .bi-disabled {\n    @include disabled('lighter');\n  }\n\n  .bi-muted {\n    @include muted('lighter');\n  }\n}\n\n.bi-theme--dark {\n  .bi-disabled {\n    @include disabled('dark');\n  }\n\n  .bi-muted {\n    @include muted('dark');\n  }\n}\n\n.bi-theme--darker {\n  .bi-disabled {\n    @include disabled('darker');\n  }\n\n  .bi-muted {\n    @include muted('darker');\n  }\n}\n\n.bi-primary {\n  color: $primary !important;\n}\n\n.bi-secondary {\n  color: $secondary !important;\n}\n\n.bi-success {\n  color: $success !important;\n}\n\n.bi-warning {\n  color: $warning !important;\n}\n\n.bi-danger {\n  color: $danger !important;\n}\n\n.bi-white {\n  color: $white !important;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/action.def.scss",
    "content": "@import 'colors.def';\n@import 'morph.def';\n@import 'state.def';\n\n%action {\n  position: relative;\n  padding: 3px;\n  border-radius: 3px;\n  font-style: normal;\n  white-space: nowrap;\n  cursor: pointer;\n  user-select: none;\n\n  &:active:not([disabled='disabled']) {\n    top: 1px;\n    left: 1px;\n  }\n}\n\n@mixin action($theme) {\n  @extend %action;\n  @include disabled($theme);\n  @include muted($theme);\n  @include hover($theme);\n  @include active($theme);\n\n  &.bi-action-loader {\n    @extend %morph-to-loader;\n\n    > span {\n      width: 30px !important;\n      height: 30px !important;\n      line-height: 30px !important;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/alert.def.scss",
    "content": "@import './colors.def';\n@import './icon.def';\n@import './flex.def';\n@import './space.def';\n@import './border.def';\n\n%alert {\n  @include space-v__inner();\n\n  padding: 11px 12px;\n  font-size: 11px;\n  border-radius: 3px;\n\n  .bi-alert-header {\n    @include flex(row, center);\n\n    font-size: 12px;\n    font-weight: 600;\n\n    &:before {\n      @extend %icon;\n      @include space-h();\n    }\n  }\n\n  .bi-alert-content {\n    @include border(top);\n\n    padding-top: 10px;\n  }\n}\n\n@mixin alert($icon: 'wb_incandescent', $iconColor: $warning, $bgColor: $grey--50) {\n  @extend %alert;\n\n  color: darken($bgColor, 50) !important;\n  background-color: $bgColor;\n  border: 1px solid darken($bgColor, 6);\n\n  .bi-alert-header {\n    &:before {\n      content: $icon;\n      color: $iconColor;\n    }\n  }\n\n  .bi-alert-content {\n    border-color: darken($bgColor, 6);\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/align.def.scss",
    "content": "@import './flex.def';\n\n%spread {\n  @include flex(row, center, space-between);\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/animations.def.scss",
    "content": "@mixin animation-scale ($duration: .11s) {\n  @keyframes scale {\n    from {\n      transform: scale(.5);\n      opacity: 0;\n    }\n\n    to {\n      transform: scale(1);\n      opacity: 1;\n    }\n  }\n\n  transform-origin: top;\n  animation: scale $duration;\n}\n\n%animation-fade-in {\n  @keyframes fade-in {\n    from {opacity: .5;}\n    to {opacity: 1;}\n  }\n\n  animation: fade-in .3s;\n}\n\n%animation-rotate {\n  @keyframes rotate {\n    from {\n      transform: rotate(0deg);\n    }\n\n    to {\n      transform: rotate(-360deg);\n    }\n  }\n\n  animation: rotate .5s linear infinite;\n}\n\n%animation-fade-in2 {\n  @keyframes fade-in2 {\n    from {\n      opacity: 0;\n    }\n\n    to {\n      opacity: 1;\n    }\n  }\n\n  animation: fade-in2 .2s linear forwards;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/app/app-header.def.scss",
    "content": "@import '../colors.def';\n@import '../header.def';\n@import '../border.def';\n\n%app-header {\n  @include header(54px, 12px);\n\n  .bi-app-user-logo {\n    width: 36px;\n    height: 36px;\n    border-radius: 100px;\n  }\n\n  .bi-app-title {\n    @include header-title(20px, 200);\n\n    font-family: bi-ui;\n\n    .bi-app-logo {\n      width: 24px;\n      margin-right: 8px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/app/app-menu.def.scss",
    "content": "@import '../colors.def';\n@import '../defaults.def';\n@import '../flex.def';\n@import '../border.def';\n@import '../action.def';\n@import '../state.def';\n\n%app-menu {\n  width: 48px;\n\n  ul {\n    li {\n      @include flex(row, center, center);\n\n      width: 100%;\n      padding: 9px;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/badge.def.scss",
    "content": "@import './colors.def';\n\n@mixin badge-size($height: 18px, $font-size: 11px) {\n  height: $height;\n  width: $height;\n  line-height: $height;\n  font-size: $font-size;\n}\n\n%badge {\n  display: inline-block;\n  text-align: center;\n  color: $white;\n  border-radius: 10px;\n  @include badge-size();\n}\n\n@mixin badge($color: $grey--400) {\n  @extend %badge;\n  background-color: $color;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/border.def.scss",
    "content": "@import 'defaults.def';\n\n@mixin border($position: null, $color: $default-border-color) {\n  @if $position {\n    border-#{$position}-width: $default-border-width;\n    border-#{$position}-style: solid;\n    border-#{$position}-color: $color;\n  } @else {\n    border: 1px solid $color;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/button.def.scss",
    "content": "@import 'colors.def';\n@import 'defaults.def';\n@import 'flex.def';\n@import 'border.def';\n@import 'icon.def';\n@import 'space.def';\n@import 'morph.def';\n@import 'state.def';\n\n%button {\n  @include flex(row, center);\n  @include space-h__inner(5px);\n\n  transition: opacity .3, background-color .3s;\n  display: inline-flex;\n  font-family: 'Open Sans';\n  text-transform: uppercase;\n  outline: 0;\n  border: none;\n  border-radius: 3px;\n  white-space: nowrap;\n  // box-shadow: 0 1px 2px rgba(0, 0, 0, .10);\n  cursor: pointer;\n\n  &[disabled='disabled'] {\n    opacity: .8;\n    cursor: default;\n  }\n\n  &.bi-button-loader {\n    @extend %morph-to-loader;\n  }\n}\n\n@mixin button-color($bgColor: $grey--200, $color: $white) {\n  background-color: $bgColor;\n  color: $color !important;\n\n  &:hover:not([disabled='disabled']) {\n    background-color: darken($bgColor, 4);\n  }\n}\n\n@mixin button-size($height: 30px, $padding: 10px, $font-size: 12px) {\n  height: $height;\n  padding: 0 $padding;\n  font-size: $font-size;\n}\n\n@mixin button($bgColor: $grey--200, $color: $white) {\n  @extend %button;\n  @include button-color($bgColor, $color);\n  @include button-size();\n\n  &:active:not([disabled='disabled']) {\n    box-shadow: inset 1px 3px 8px darken($bgColor, 15), 1px 1px 1px $white;\n  }\n}\n\n@mixin button-theme($theme) {\n  @extend %button;\n  @include disabled($theme);\n  \n  @if ($theme == 'lighter') {\n    background-color: darken($lighter-hover-bg, 2);\n    color: $lighter-color;\n  } @else if ($theme == 'light') {\n    background-color: darken($light-hover-bg, 2);\n    color: $light-color;\n  } @else if ($theme == 'dark') {\n    background-color: lighten($dark-hover-bg, 2);\n    color: $dark-color;\n  } @else {\n    background-color: lighten($darker-hover-bg, 2);\n    color: $darker-color;\n  }\n  \n  &:hover:not([disabled='disabled']) {\n    @if ($theme == 'lighter') {\n      background-color: darken($lighter-hover-bg, 5);\n    } @else if ($theme == 'light') {\n      background-color: darken($light-hover-bg, 5);\n    } @else if ($theme == 'dark') {\n      background-color: lighten($dark-hover-bg, 5);\n    } @else {\n      background-color: lighten($darker-hover-bg, 5);\n    }\n  }\n  \n  &:active:not([disabled='disabled']) {\n    @if ($theme == 'lighter') {\n      box-shadow: inset 1px 3px 8px darken($lighter-hover-bg, 10), 1px 1px 1px $lighter-bg;\n    } @else if ($theme == 'light') {\n      box-shadow: inset 1px 3px 8px darken($light-hover-bg, 10), 1px 1px 1px $light-bg;\n    } @else if ($theme == 'dark') {\n      background-color: lighten($dark-hover-bg, 3);\n      box-shadow: none;\n    } @else {\n      background-color: lighten($darker-hover-bg, 3);\n      box-shadow: none;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/caret.def.scss",
    "content": "@import './flex.def';\n@import './icon.def';\n\n%caret {\n  @include flex-inline(row, center);\n\n  &:after {\n    @extend %icon;\n\n    content: 'arrow_drop_down';\n    font-size: 18px !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/colors.def.scss",
    "content": "$grey--50: #FAFAFA;\n$grey--100: #F5F5F5;\n$grey--200: #ebebec;\n$grey--300: #d7d8da;\n$grey--400: #b8babe;\n$grey--500: #9a9da2;\n$grey--600: #686b73;\n$grey--700: #494e57;\n$grey--800: #353a44;\n$grey--900: #1d242f;\n\n$blue--300: #64B5F6;\n$blue--500: #2196F3;\n\n$orange--500: #FF9800;\n\n$red--300: #E57373;\n$red--500: #f44336;\n\n$green--300: #81C784;\n$green--500: #4CAF50;\n\n$light-green--500: #8BC34A;\n\n$white: #FFFFFF;\n$black: #000000;\n$primary: #FC4A6A;\n$secondary: #00A9F4;\n$success: $light-green--500;\n$warning: $orange--500;\n$danger: $red--500;\n$muted: $grey--600;\n\n$lighter-bg: $white;\n$lighter-hover-bg: $grey--100;\n$lighter-active-bg: $grey--100;\n$lighter-color: $grey--800;\n$lighter-muted-color: $grey--600;\n$lighter-disabled-color: $grey--400;\n$lighter-border-color: $grey--200;\n\n$light-bg: $grey--100;\n$light-hover-bg: $grey--200;\n$light-active-bg: $grey--200;\n$light-color: $grey--800;\n$light-muted-color: $grey--600;\n$light-disabled-color: $grey--500;\n$light-border-color: $grey--300;\n\n$dark-bg: $grey--800;\n$dark-hover-bg: lighten($dark-bg, 2);\n$dark-active-bg: lighten($dark-bg, 2);\n$dark-color: $grey--200;\n$dark-muted-color: $grey--500;\n$dark-disabled-color: $grey--500;\n$dark-border-color: $grey--700;\n\n$darker-bg: $grey--900;\n$darker-hover-bg: $grey--800;\n$darker-active-bg: $grey--800;\n$darker-color: $grey--200;\n$darker-muted-color: $grey--500;\n$darker-disabled-color: $grey--500;\n$darker-border-color: $grey--600;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/content.def.scss",
    "content": "@import 'defaults.def';\n\n@mixin content($padding: $default-space * 1.5) {\n  padding: $padding;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/defaults.def.scss",
    "content": "@import './colors.def';\n\n$default-font-family: 'Open Sans';\n$default-font-size: 12px;\n$default-space: 10px;\n$default-text-color: $black;\n$default-border-color: $grey--200;\n$default-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n$default-border-width: 1px;\n$default-input-height: 36px;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/dropdown.def.scss",
    "content": "@import 'colors.def';\n@import 'defaults.def';\n@import 'border.def';\n@import 'flex.def';\n@import 'icon.def';\n@import 'state.def';\n\n%dropdown-content {\n  display: block;\n  padding: 5px 10px;\n  border: 1px solid $grey--200;\n  border-radius: 3px;\n  box-shadow: $default-box-shadow;\n  overflow-y: auto;\n}\n\n%dropdown-menu {\n  @extend %dropdown-content;\n\n  padding: 5px 0;\n  max-height: 300px;\n  user-select: none;\n\n  > li {\n    @include flex(row, center);\n    @include hover('lighter');\n    @include disabled('lighter');\n\n    position: relative;\n    padding: 7px 20px;\n    white-space: nowrap;\n    cursor: pointer;\n\n    &.bi-active:not([disabled]),\n    &:hover:not([disabled]) {\n      background-color: $grey--50;\n    }\n\n    &:not([disabled='disabled']) {\n      &.selected {\n        &:before {\n          @extend %icon;\n\n          position: absolute;\n          content: 'check';\n          left: 5px;\n          color: $primary;\n          font-size: 14px !important;\n        }\n      }\n\n      .bi-icon {\n        @include muted('lighter');\n      }\n    }\n\n    .bi-icon {\n      font-size: 18px;\n    }\n  }\n\n  .bi-dropdown-separator {\n    @include border(bottom);\n\n    margin: 5px;\n    padding: 0;\n\n    &:first-child,\n    &:last-child {\n      height: 0;\n      margin: 0;\n      border: 0;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/empty-state.def.scss",
    "content": "@import './colors.def';\n\n%empty-state {\n  display: flex;\n  flex-direction: column;\n  font-family: 'bi-ui';\n  align-items: center;\n\n\n  > * {\n    display: flex;\n    justify-content: center;\n  }\n\n  .bi-empty-state-icon {\n    .bi-icon {\n      font-size: 80px;\n    }\n  }\n\n  .bi-empty-state-image {\n    width: 150px;\n    margin-bottom: 10px;\n  }\n\n  .bi-empty-state-header {\n    margin-top: 20px;\n    margin-bottom: 0;\n    font-size: 18px;\n    font-weight: 300;\n  }\n\n  .bi-empty-state-header + .bi-empty-state-content {\n    margin-top: 3px;\n  }\n\n  .bi-empty-state-content {\n    margin-top: 15px;\n    margin-bottom: 0;\n    font-size: 13px;\n    font-weight: 400;\n  }\n}\n\n%empty-state-with-image {\n  @extend %empty-state;\n\n  &:before {\n    content: '';\n    display: block;\n    height: 100px;\n    margin-bottom: 0;\n    background-size: contain;\n    background-repeat: no-repeat;\n    background-position: center;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/flex.def.scss",
    "content": "@mixin _flex($direction: row, $align: null, $justify: null) {\n flex-direction: $direction;\n\n  @if $align {\n    align-items: $align;\n  }\n\n  @if $justify {\n    justify-content: $justify;\n  }\n}\n\n@mixin flex($direction: row, $align: null, $justify: null) {\n  @include _flex($direction, $align, $justify);\n  display: flex;\n}\n\n@mixin flex-inline($direction: row, $align: null, $justify: null) {\n  @include _flex($direction, $align, $justify);\n  display: inline-flex;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/header.def.scss",
    "content": "@import 'defaults.def';\n@import 'flex.def';\n@import 'space.def';\n@import 'align.def';\n\n%header {\n  @extend %spread;\n\n  flex: 0 0 auto;\n  box-sizing: border-box;\n\n  > * {\n    @include flex(row, center);\n  }\n}\n\n@mixin header-title($font-size: 14px, $font-weight: initial) {\n  font-size: $font-size;\n\n  @if ($font-size <= 14) {\n    font-weight: 600;\n  } @else {\n    font-weight: $font-weight;\n  }\n}\n\n@mixin header-separator($color) {\n  width: 1px;\n  height: 24px;\n  border-left: 1px solid darken($color, 5);\n  border-right: 1px solid lighten($color, 5);\n  align-self: center;\n}\n\n@mixin header($height, $space: $default-space * 1.5) {\n  @extend %header;\n\n  padding: 0 $space;\n\n  > * {\n    @include space-h__inner($space);\n  }\n\n  height: $height;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/heading.def.scss",
    "content": "@import 'colors.def';\n@import 'morph.def';\n@import 'state.def';\n\n%heading {\n  position: relative;\n\n  &:after {\n    content: '';\n    position: absolute;\n    top: 50%;\n    left: 0;\n    right: 0;\n    border-bottom: 1px solid transparent;\n    z-index: 1;\n  }\n\n  .bi-heading-content {\n    padding-left: 1em;\n    padding-right: 1em;\n    z-index: 2;\n  }\n}\n\n@mixin heading($theme) {\n  @extend %heading;\n  \n  @if ($theme == 'lighter') {\n    .bi-heading-content {\n      background-color: $lighter-bg;\n    }\n\n    &:after {\n      border-color: $lighter-border-color;\n    }\n  } @else if ($theme == 'light') {\n    .bi-heading-content {\n      background-color: $light-bg;\n    }\n\n    &:after {\n      border-color: $light-border-color;\n    }\n  } @else if ($theme == 'dark') {\n    .bi-heading-content {\n      background-color: $dark-bg;\n    }\n\n    &:after {\n      border-color: $dark-border-color;\n    }\n  } @else {\n    .bi-heading-content {\n      background-color: $darker-bg;\n    }\n\n    &:after {\n      border-color: $darker-border-color;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/hint.def.scss",
    "content": "@import './colors.def';\n@import './flex.def';\n\n@mixin hint($color: $warning) {\n  @include flex(row, center);\n\n  padding-left: 6px;\n  font-size: 10px;\n  border-left: 3px solid $color;\n  color: $muted;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/icon.def.scss",
    "content": "@import 'colors.def';\n@import 'state.def';\n\n%icon {\n  display: inline-block;\n  font-family: 'Material Icons' !important;\n  font-weight: normal;\n  font-style: normal;\n  font-size: 24px;\n  line-height: 1;\n  letter-spacing: normal;\n  text-transform: none;\n  white-space: nowrap;\n  word-wrap: normal;\n  direction: ltr;\n  text-decoration: none;\n  -webkit-font-smoothing: antialiased;\n}\n\n@mixin icon($theme) {\n  @extend %icon;\n  @include disabled($theme);\n  @include muted($theme);\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/input.def.scss",
    "content": "@import 'colors.def';\n@import 'defaults.def';\n@import 'border.def';\n\n%input {\n  @include border();\n\n  transition: border-color .2s;\n  display: inline-flex;\n  height: $default-input-height;\n  min-width: 200px;\n  padding: 6px $default-space;\n  font-family: $default-font-family;\n  font-size: $default-font-size;\n  color: $black;\n  outline: none;\n  box-sizing: border-box;\n\n  &[disabled] {\n    background-color: lighten($grey--50, 1);\n    cursor: not-allowed;\n  }\n\n  &:not([disabled]) {\n    &:hover {\n      border-color: lighten($blue--300, 20);\n    }\n\n    &:focus {\n      border-color: $blue--300;\n    }\n  }\n\n  &[required] {\n    &.ng-dirty {\n      &.ng-valid {\n        border-color: $green--300;\n      }\n\n      &.ng-invalid {\n        border-color: $red--300;\n      }\n    }\n  }\n}\n\n@mixin input($theme) {\n  @extend %input;\n\n  @if ($theme == 'lighter') {\n    color: $lighter-color;\n    background-color: $white;\n\n    &::placeholder {\n      color: $lighter-muted-color;\n    }\n  } @else if ($theme == 'light') {\n    color: $light-color;\n    background-color: $white;\n\n    &::placeholder {\n      color: $light-muted-color;\n    }\n  } @else if ($theme == 'dark') {\n    border: none;\n    color: $dark-color;\n    background-color: lighten($dark-hover-bg, 3);\n\n    &::placeholder {\n      color: $dark-muted-color;\n    }\n  } @else {\n    border: none;\n    color: $darker-color;\n    background-color: lighten($darker-hover-bg, 3);\n\n    &::placeholder {\n      color: $darker-muted-color;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/label.def.scss",
    "content": "@import './colors.def';\n\n%label {\n  color: $grey--600;\n  font-weight: 600;\n  text-transform: uppercase;\n}\n\n%color-label {\n  display: inline-flex;\n  padding: 1px 6px;\n  place-content: center;\n  border-radius: 2px;\n  font-size: 9px;\n  color: $white !important;\n}\n\n@mixin label-dark() {\n  @extend %label;\n\n  color: $grey--600;\n}\n\n@mixin label-light() {\n  color: $grey--400;\n}\n\n@mixin label-color__deep($bg-intensity) {\n  .bi-label {\n    @if $bg-intensity <= 400 {\n      @include label-dark();\n    } @else {\n      @include label-light();\n    }\n  }\n}\n\n@mixin color-label($color) {\n  @extend %color-label;\n\n  background-color: $color;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/link.def.scss",
    "content": "@import './flex.def';\n@import './icon.def';\n@import './colors.def';\n\n%link {\n  @include flex-inline(row, center);\n\n  color: $primary;\n  text-decoration: none !important;\n  cursor: pointer;\n\n\n  &:hover {\n    color: darken($primary, 8);\n  }\n\n  &[target=\"_blank\"] {\n    &:after {\n      @extend %icon;\n\n      content: 'open_in_new';\n      margin-left: .3em;\n      font-size: 1em !important;\n      text-decoration: none !important;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/media.def.scss",
    "content": "$small-screen-size: 768px;"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/morph.def.scss",
    "content": "@import 'colors.def';\n@import 'animations.def';\n@import 'spinner.def';\n\n%morph-fade-out {\n  @keyframes fade-out {\n    0% {\n      max-width: 50px;\n    }\n\n    20% {\n      padding: 0;\n      background-color: transparent;\n      color: transparent;\n      border: 0;\n    }\n\n    100% {\n      max-width: 30px;\n      padding: 0;\n      border-radius: 100px;\n      background-color: transparent;\n      color: transparent;\n      border: 0;\n    }\n  }\n\n  animation: fade-out .4s linear forwards;\n}\n\n%morph-to-loader {\n  @extend %morph-fade-out;\n\n  box-shadow: none;\n  overflow: hidden;\n  cursor: default;\n\n  &:active {\n    box-shadow: none;\n  }\n\n  > * {\n    display: none;\n  }\n\n  > span {\n    @extend %spinner;\n\n    &:after {\n      @extend %animation-fade-in2;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/nav-tabs.def.scss",
    "content": "@import './colors.def';\n@import './flex.def';\n@import './border.def';\n@import './label.def';\n@import './space.def';\n\n%bi-nav-tabs {\n  @include flex(row, center, center);\n  @include border(bottom);\n  @include label-dark();\n  @include space-h__inner(20px);\n}\n\n%bi-nav-tab {\n  font-size: 15px;\n  line-height: 30px;\n  cursor: pointer;\n\n  &.bi-active {\n    color: $primary;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/panel.def.scss",
    "content": "@import 'colors.def';\n@import 'defaults.def';\n@import 'border.def';\n@import 'header.def';\n@import 'content.def';\n@import 'space.def';\n\n$panel-header-class: '.bi-panel-header';\n$panel-content-class: '.bi-panel-content';\n$panel-title-class: '.bi-panel-title';\n\n%panel {\n  border-radius: 4px;\n  box-shadow: 0 1px 3px rgba(0, 0, 0, .05);\n  overflow: hidden;\n}\n\n/// Simple panel (header + content)\n@mixin panel() {\n  @extend %panel;\n\n  > #{$panel-header-class} {\n    @include header(44px);\n\n    #{$panel-title-class} {\n      @include header-title();\n    }\n\n    & + #{$panel-content-class} {\n      padding-top: 10px;\n    }\n  }\n\n  > #{$panel-content-class} {\n    @include content();\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/section.def.scss",
    "content": "@import 'colors.def';\n@import 'defaults.def';\n@import 'header.def';\n@import 'content.def';\n@import 'flex.def';\n\n$section-header-class: '.bi-section-header';\n$section-controls-class: '.bi-section-controls';\n$section-content-class: '.bi-section-content';\n$section-title-class: '.bi-section-title';\n$section-separator-class: '.bi-section-header-spr';\n\n%section {\n  @include flex(column);\n\n  > #{$section-header-class} {\n    @include header(50px);\n\n    #{$section-title-class} {\n      @include header-title(16px);\n      letter-spacing: 1px;\n    }\n\n    #{$section-separator-class} {\n      @include header-separator($grey--200);\n    }\n  }\n\n  > #{$section-controls-class} {\n    @include header(30px);\n\n    margin-bottom: $default-space * 1.5;\n  }\n\n  > #{$section-content-class},\n  > #{$section-content-class}--center,\n  > #{$section-content-class}--list {\n    flex: 1;\n    overflow: auto;\n  }\n\n  > #{$section-content-class}--center {\n    @include flex(column, center, center);\n  }\n\n  > #{$section-content-class}--list {\n    padding-bottom: 400px !important;\n  }\n\n  &.bi-theme--dark {\n    > #{$section-header-class} {\n      color: $grey--200;\n    }\n\n    > #{$section-content-class},\n    > #{$section-content-class}--center,\n    > #{$section-content-class}--list {\n      background-color: $grey--800;\n    }\n  }\n}\n\n// Full-height, full-width section with scrollable content\n@mixin section($bg-color) {\n  @extend %section;\n\n  // background-color: $bg-color;\n\n  > #{$section-content-class},\n  > #{$section-content-class}--center,\n  > #{$section-content-class}--list {\n    @include content();\n  }\n}\n\n// Full-height, fixed-width section with scrollable content\n@mixin section-static($content-bg-color, $width) {\n  @include section($content-bg-color);\n\n  width: $width;\n  flex: 0 0 $width;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/space.def.scss",
    "content": "@import 'defaults.def';\n\n@mixin space-h($space: $default-space) {\n  margin-right: $space;\n}\n\n@mixin space-v($space: $default-space) {\n  margin-top: $space;\n}\n\n@mixin space-h__inner($space: $default-space) {\n  > *:not(:last-child) {\n    @include space-h($space);\n  }\n}\n\n@mixin space-v__inner($space: $default-space) {\n  > *:not(:first-child) {\n    @include space-v($space);\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/spinner.def.scss",
    "content": "@import 'colors.def';\n@import 'animations.def';\n\n%spinner {\n  @extend %animation-rotate;\n\n  position: relative;\n  display: inline-block;\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n\n  &:after {\n    content: '';\n    position: absolute;\n    display: block;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    border: 3px solid $blue--500;\n    border-right-color: transparent;\n    border-radius: 100px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/state.def.scss",
    "content": "@import 'colors.def';\n@import 'animations.def';\n@import 'defaults.def';\n\n@mixin disabled($theme) {\n  &.bi-disabled,\n  &[disabled='disabled'] {\n    @if ($theme == 'lighter') {\n      color: $lighter-disabled-color !important;\n    } @else if ($theme == 'light') {\n      color: $light-disabled-color !important;\n    } @else if ($theme == 'dark') {\n      color: $dark-disabled-color !important;\n    } @else {\n      color: $darker-disabled-color !important;\n    }\n\n    cursor: default;\n  }\n}\n\n@mixin fade($theme) {\n  @extend %animation-fade-in;\n\n  transition: opacity .3s;\n\n  &.bi-faded {\n    opacity: .7;\n  }\n}\n\n@mixin muted($theme) {\n  @if ($theme == 'lighter') {\n    color: $lighter-muted-color;\n  } @else if ($theme == 'light') {\n    color: $light-muted-color;\n  } @else if ($theme == 'dark') {\n    color: $dark-muted-color;\n  } @else {\n    color: $darker-muted-color;\n  }\n}\n\n@mixin active($theme, $color: null) {\n  &.bi-active {\n    @if ($theme == 'lighter') {\n      background-color: $lighter-active-bg;\n      color: $color or $lighter-color;\n    } @else if ($theme == 'light') {\n      background-color: $light-active-bg;\n      color: $color or $light-color;\n    } @else if ($theme == 'dark') {\n      background-color: $dark-active-bg;\n      color: $color or $dark-color;\n    } @else {\n      background-color: $darker-active-bg;\n      color: $color or $darker-color;\n    }\n  }\n}\n\n@mixin hover($theme, $color: null) {\n  &:hover:not([disabled='disabled']) {\n    @if ($theme == 'lighter') {\n      background-color: $lighter-hover-bg;\n      color: $color or $lighter-color;\n    } @else if ($theme == 'light') {\n      background-color: $light-hover-bg;\n      color: $color or $light-color;\n    } @else if ($theme == 'dark') {\n      background-color: $dark-hover-bg;\n      color: $color or $dark-color;\n    } @else {\n      background-color: $darker-hover-bg;\n      color: $color or $darker-color;\n    }\n  }\n}\n\n@mixin elevate() {\n  transition: box-shadow .3s;\n\n  &:hover {\n    box-shadow: 0 4px 8px lighten($grey--300, 3);\n  }\n\n  &:active {\n    transition: box-shadow .2s;\n    box-shadow: 0 2px 8px lighten($grey--300, 3);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/table.def.scss",
    "content": "@import './defaults.def';\n\n%table {\n  width: 100%;\n\n  > thead > tr > th {\n    padding: 8px;\n    border-bottom: 2px solid $default-border-color;\n    text-align: left;\n    vertical-align: bottom;\n  }\n\n  > tbody > tr > td {\n    padding: 8px;\n    border-top: 1px solid $default-border-color;\n    text-align: left;\n    vertical-align: top;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/tag.def.scss",
    "content": "@import 'colors.def';\n\n%tag {\n  display: inline-block;\n  padding: 0 8px;\n  border: 1px solid currentColor;\n  border-radius: 3px;\n  font-size: 11px;\n  line-height: 20px;\n  color: $muted;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/theme.def.scss",
    "content": "@import 'colors.def';\n\n@mixin theme($theme) {\n  @if ($theme == 'lighter') {\n    background-color: $lighter-bg;\n    color: $lighter-color;\n  } @else if ($theme == 'light') {\n    background-color: $light-bg;\n    color: $light-color;\n  } @else if ($theme == 'dark') {\n    background-color: $dark-bg;\n    color: $dark-color;\n  } @else {\n    background-color: $darker-bg;\n    color: $darker-color;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/toggle.def.scss",
    "content": "@import 'flex.def';\n@import 'icon.def';\n\n%toggle {\n  &:after {\n    @extend %icon;\n\n    content: 'arrow_drop_down';\n    display: inline-block;\n    width: 10px;\n    height: 0;\n    margin-left: -6px;\n    font-size: 20px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/def/trim.def.scss",
    "content": "%trim-hor {\n  > *:last-child {\n    margin-right: 0;\n  }\n}\n\n%trim-ver {\n  > *:last-child {\n    margin-bottom: 0;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/dialog.scss",
    "content": "@import './def/colors.def';\n\n.bi-dialog {\n  $padding : 30px;\n\n  // position: relative;\n  min-width: 400px;\n  min-height: 150px;\n  padding: $padding;\n  border: none;\n  border-radius: 4px;\n  box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n\n  dialog-title,\n  dialog-subtitle,\n  dialog-content {\n    display: flex;\n  }\n\n  dialog-title {\n    margin-bottom: 30px;\n    font-size: 22px;\n    font-weight: 300;\n    text-transform: uppercase;\n\n    .bi-dialog-icon {\n      font-size: 34px;\n    }\n  }\n\n  dialog-subtitle {\n    margin: -26px 0 40px 0;\n  }\n\n  dialog-footer {\n    position: absolute;\n    left: $padding;\n    right: $padding;\n    bottom: 20px;\n\n    button {\n      min-width: 80px;\n      justify-content: center;\n    }\n  }\n\n  .bi-dialog-close {\n    position: absolute;\n    top: 20px;\n    right: 20px;\n    z-index: 1000;\n  }\n\n  .bi-dialog-loader {\n    position: absolute;\n    bottom: 20px;\n    left: 20px;\n    z-index: 1000;\n  }\n\n  &.bi-confirm {\n    padding: $padding $padding 90px $padding;\n\n    dialog-content {\n      margin-bottom: 20px;\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/dropdown.scss",
    "content": "@import './def/dropdown.def';\n@import './def/icon.def';\n\n.bi-dropdown-menu {\n  @extend %dropdown-menu;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/empty-state.scss",
    "content": "@import './def/empty-state.def';\n@import './def/animations.def';\n@import './def/state.def';\n\n.bi-empty-state {\n  @extend %empty-state;\n}\n\n.bi-empty-state--loading {\n  @extend %empty-state;\n\n  align-items: center;\n\n  &:before {\n    @extend %animation-rotate;\n    content: '';\n    display: inline-block;\n    width: 30px;\n    height: 30px;\n    border: 3px solid $blue--500;\n    border-right-color: transparent;\n    border-radius: 100px;\n  }\n}\n\n.bi-theme--lighter {\n  .bi-empty-state,\n  .bi-empty-state--loading {\n    @include muted('lighter');\n  }\n}\n\n.bi-theme--light {\n  .bi-empty-state,\n  .bi-empty-state--loading {\n    @include muted('light');\n  }\n\n  .bi-theme--lighter {\n    .bi-empty-state,\n    .bi-empty-state--loading {\n      @include muted('lighter');\n    }\n  }\n}\n\n.bi-theme--dark {\n  .bi-empty-state,\n  .bi-empty-state--loading {\n    @include muted('dark');\n  }\n}\n\n.bi-theme--darker {\n  .bi-empty-state,\n  .bi-empty-state--loading {\n    @include muted('darker');\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/flex.scss",
    "content": "@import './def/flex.def';\n\n.bi-row,\n.bi-r {\n  @include flex(row);\n\n  min-width: 0;\n  flex: 1;\n}\n\n.bi-r-h {\n  @include flex(row);\n\n  min-width: 0;\n  flex: 1;\n  overflow: hidden;\n}\n\n.bi-row-inline,\n.bi-r-i {\n  @include flex-inline(row);\n}\n\n.bi-column,\n.bi-c {\n  @include flex(column);\n\n  min-width: 0;\n}\n\n.bi-sidebar-override {\n  .bi-c {\n    min-width: unset !important;\n  }\n}\n\n.bi-c-h {\n  @include flex(column);\n\n  min-width: 0;\n  overflow: hidden;\n}\n\n.bi-grow {\n  flex-grow: 1;\n}\n\n.bi-dont-grow {\n  flex-grow: 0;\n}\n\n.bi-dont-shrink {\n  flex-shrink: 0;\n}\n\n.bi-wrap {\n  flex-wrap: wrap;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/fonts.scss",
    "content": "@font-face {\n  font-family: 'bi-ui';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Fira Sans Light'), local('FiraSans-Light'), url(https://fonts.gstatic.com/s/firasans/v8/va9B4kDNxMZdWfMOD5VnPKreRhf6Xl7Glw.woff2) format('woff2');\n  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;\n}\n\n@font-face {\n  font-family: 'bi-ui';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Fira Sans Regular'), local('FiraSans-Regular'), url(https://fonts.gstatic.com/s/firasans/v8/va9E4kDNxMZdWfMOD5Vvl4jLazX3dA.woff2) format('woff2');\n  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;\n}\n\n@font-face {\n  font-family: 'bi-ui';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Fira Sans Bold'), local('FiraSans-Bold'), url(https://fonts.gstatic.com/s/firasans/v8/va9B4kDNxMZdWfMOD5VnLK3eRhf6Xl7Glw.woff2) format('woff2');\n  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;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/form.scss",
    "content": "@import './def/colors.def';\n@import './def/flex.def';\n@import './def/space.def';\n@import './def/defaults.def';\n\n.bi-form,\n.bi-form--vertical {\n  @include flex(column);\n  @include space-v__inner();\n\n  .bi-form-row {\n    .bi-form-label,\n    .bi-form-label--required {\n      flex-basis: 90px;\n      flex-shrink: 0;\n      font-size: 12px;\n      color: $muted;\n    }\n\n    .bi-form-label--required {\n      &:after {\n        content: ' *';\n        color: $primary;\n      }\n    }\n\n    .bi-form-input {\n      flex-grow: 1;\n    }\n  }\n\n  &.bi-form {\n    .bi-form-row {\n      @include flex(row);\n      @include space-h__inner();\n    }\n  }\n\n  &.bi-form--vertical {\n    @include space-v__inner(15px);\n\n    .bi-form-row {\n      @include flex(column);\n      @include space-v__inner(4px);\n    }\n\n    .bi-form-label,\n    .bi-form-label--required {\n      flex-basis: unset;\n    }\n\n    .bi-form-input {\n      flex-grow: unset;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/heading.scss",
    "content": "@import './def/heading.def';\n\n.bi-theme--lighter {\n  .bi-heading {\n    @include heading('lighter');\n  }\n}\n\n.bi-theme--light {\n  .bi-heading {\n    @include heading('light');\n  }\n}\n\n.bi-theme--dark {\n  .bi-heading {\n    @include heading('dark');\n  }\n}\n\n.bi-theme--darker {\n  .bi-heading {\n    @include heading('darker');\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/hint.scss",
    "content": "@import './def/colors.def';\n@import './def/hint.def';\n\n.bi-hint {\n  @include hint();\n}\n\n.bi-hint--info {\n  @include hint($primary);\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/home-action.scss",
    "content": "@import './def/defaults.def';\n@import './def/colors.def';\n@import './def/state.def';\n\n.bi-home-action {\n  display: flex;\n  height: 200px;\n  flex-direction: column;\n  flex-basis: 300px;\n  border-radius: 8px !important;\n  align-items: center;\n  justify-content: center;\n  cursor: pointer;\n\n  span {\n    font-size: 20px;\n    font-weight: 300;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/hover.scss",
    "content": "@import './def/animations.def';\n\n.bi-hover-parent {\n  .bi-hover-target {\n    transition: opacity .2s;\n    opacity: 0;\n  }\n\n  &:hover {\n    .bi-hover-target {\n      opacity: 1;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/icon.scss",
    "content": "@import './def/icon.def';\n\n.bi-icon {\n  @extend %icon;\n}\n\n.bi-icon--sm {\n  @extend %icon;\n\n  font-size: 17px !important;\n}\n\n.bi-icon--xs {\n  @extend %icon;\n\n  font-size: 14px !important;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/input.scss",
    "content": "@import './def/defaults.def';\n@import './def/flex.def';\n@import './def/input.def';\n\n.bi-theme--lighter {\n  .bi-input {\n    @include input('lighter');\n  }\n}\n\n.bi-theme--dark {\n  .bi-input {\n    @include input('dark');\n  }\n}\n\ntextarea.bi-input {\n  min-height: 50px;\n}\n\n.bi-input + .bi-input-action {\n  margin-left: -1px;\n}\n\n.bi-input-action {\n  @include flex(row, center, center);\n\n  width: $default-input-height;\n  height: $default-input-height;\n  border: 1px solid $grey--300;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/label.scss",
    "content": "@import './def/label.def';\n\n.bi-label {\n  @extend %label;\n}\n\n.bi-label--sm {\n  @extend %label;\n\n  font-size: 12px !important;\n  font-weight: normal !important;\n  color: $grey--700 !important;\n  letter-spacing: .5px;\n}\n\n.bi-label--large {\n  @extend %label;\n\n  font-size: 18px !important;\n  font-weight: 300 !important;\n}\n\n.bi-label--primary {\n  @include color-label($primary);\n}\n\n.bi-label--secondary {\n  @include color-label($secondary);\n}\n\n.bi-label--success {\n  @include color-label($success);\n}\n\n.bi-label--warning {\n  @include color-label($warning);\n}\n\n.bi-label--danger {\n  @include color-label($danger);\n}\n\n.bi-label--muted {\n  @include color-label($grey--400);\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/link.scss",
    "content": "@import './def/link.def';\n\n.bi-link {\n  @extend %link;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/media.scss",
    "content": "@import './def/media.def.scss';\n\n@media screen and (max-height: $small-screen-size) {\n  .bi-media--normal {\n    display: none;\n  }\n}\n\n@media screen and (min-height: $small-screen-size) {\n  .bi-media--small {\n    display: none;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/mouse.scss",
    "content": ".bi-pointer {\n  cursor: pointer;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/nav-tabs.scss",
    "content": "@import './def/nav-tabs.def';\n\n.bi-nav-tabs {\n  @extend %bi-nav-tabs;\n\n  .bi-nav-tab {\n    @extend %bi-nav-tab;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/no-select.scss",
    "content": ".bi-no-select {\n  user-select: none;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/panel.scss",
    "content": "@import './def/colors.def';\n@import './def/defaults.def';\n@import './def/panel.def';\n@import './def/action.def';\n\n.bi-panel {\n  @include panel();\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/reset.scss",
    "content": "/* http://meyerweb.com/eric/tools/css/reset/\n   v2.0 | 20110126\n   License: none (public domain)\n*/\n\nhtml, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nu, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed,\nfigure, figcaption, footer, header, hgroup,\nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tfont-size: 100%;\n\tfont: inherit;\n\tvertical-align: baseline;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure,\nfooter, header, hgroup, menu, nav, section {\n\tdisplay: block;\n}\nol, ul {\n\tlist-style: none;\n}\nblockquote, q {\n\tquotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n\tcontent: '';\n\tcontent: none;\n}\ntable {\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\n\n// default BI rules\nhtml,\nbody {\n\theight: 100%;\n\toverflow: hidden;\n}\n\nbody {\n\tfont-family: 'Open Sans';\n\tfont-size: 13px;\n\tline-height: 1.42857143;\n}\n\n*, :after, :before {\n\tbox-sizing: border-box;\n}\n\niframe {\n\tborder: 0;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/scroll.scss",
    "content": ".bi-scroll {\n  overflow: auto;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/section.scss",
    "content": "@import './def/colors.def';\n@import './def/border.def';\n@import './def/section.def';\n\n.bi-section {\n  @include section($grey--100);\n}\n\n.bi-section--300 {\n  @include section-static($grey--100, 300px);\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/space.scss",
    "content": "@import './def/defaults.def';\n@import './def/space.def';\n\n.bi-space-h__self {\n  @include space-h();\n}\n\n.bi-space-v__self {\n  @include space-v();\n}\n\n.bi-space-h,\n.bi-s-h {\n  @include space-h__inner();\n}\n\n.bi-space-v,\n.bi-s-v {\n  @include space-v__inner();\n}\n\n.bi-space-h--x15,\n.bi-s-h--x15 {\n  @include space-h__inner($default-space * 1.5);\n}\n\n.bi-space-h--x2,\n.bi-s-h--x2 {\n  @include space-h__inner($default-space * 2);\n}\n\n.bi-space-h--x3,\n.bi-s-h--x3 {\n  @include space-h__inner($default-space * 3);\n}\n\n.bi-space-h--x05,\n.bi-s-h--x05 {\n  @include space-h__inner($default-space / 2);\n}\n\n.bi-space-v--x15,\n.bi-s-v--x15 {\n  @include space-v__inner($default-space * 1.5);\n}\n\n.bi-space-v--x2,\n.bi-s-v--x2 {\n  @include space-v__inner($default-space * 2);\n}\n\n.bi-space-v--x3,\n.bi-s-v--x3 {\n  @include space-v__inner($default-space * 3);\n}\n\n.bi-space-v--x05,\n.bi-s-v--x05 {\n  @include space-v__inner($default-space / 2);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/spinner.scss",
    "content": "@import './def/spinner.def';\n\n.bi-spinner {\n  @extend %spinner;\n}\n\n.bi-spinner--sm {\n  @extend %spinner;\n\n  width: 20px !important;\n  height: 20px !important;\n  line-height: 20px !important;\n\n  &:after {\n    border-width: 2px !important;\n  }\n}\n\n.bi-spinner--xs {\n  @extend %spinner;\n\n  width: 14px !important;\n  height: 14px !important;\n  line-height: 14px !important;\n\n  &:after {\n    border-width: 2px !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/state.scss",
    "content": "@import 'def/state.def';\n\n// default\n.bi-muted {\n  @include muted('lighter');\n}\n\n.bi-active {\n  @include active('lighter');\n}\n\n.bi-hover {\n  @include hover('lighter');\n}\n\n.bi-fade {\n  @include fade('lighter');\n}\n\n.bi-elevate {\n  @include elevate();\n}\n\n// dark\n.bi-theme--dark {\n  .bi-muted {\n    @include muted('dark');\n  }\n  \n  .bi-active {\n    @include active('dark');\n  }\n  \n  .bi-hover {\n    @include hover('dark');\n  }\n}\n\n//  darker\n.bi-theme--darker {\n  .bi-muted {\n    @include muted('darker');\n  }\n  \n  .bi-active {\n    @include active('darker');\n  }\n  \n  .bi-hover {\n    @include hover('darker');\n  }\n}\n\n// lighter\n.bi-theme--lighter {\n  .bi-muted {\n    @include muted('lighter');\n  }\n  \n  .bi-active {\n    @include active('lighter');\n  }\n  \n  .bi-hover {\n    @include hover('lighter');\n  }\n}\n\n// light\n.bi-theme--light {\n  .bi-muted {\n    @include muted('light');\n  }\n  \n  .bi-active {\n    @include active('light');\n  }\n  \n  .bi-hover {\n    @include hover('light');\n  }\n\n  .bi-theme--lighter {\n    .bi-muted {\n      @include muted('lighter');\n    }\n    \n    .bi-active {\n      @include active('lighter');\n    }\n    \n    .bi-hover {\n      @include hover('lighter');\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/table.scss",
    "content": "@import './def/table.def';\n\n.bi-table {\n  @extend %table;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/tag.scss",
    "content": "@import './def/tag.def';\n\n.bi-tag {\n  @extend %tag;\n}\n\n.bi-tag--sm {\n  @extend %tag;\n\n  line-height: 18px;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/text.scss",
    "content": ".bi-text {\n  font-size: 13px;\n}\n\n.bi-text--ui {\n  font-family: 'bi-ui';\n}\n\n.bi-text--ellipsis {\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.bi-text--sm {\n  font-size: 10px;\n}\n\n.bi-text--md {\n  font-size: 14px;\n}\n\n.bi-text--lg,\n.bi-text--large {\n  font-size: 20px;\n}\n\n.bi-text--200 {\n  font-weight: 200;\n}\n\n.bi-text--300 {\n  font-weight: 300;\n}\n\n.bi-text--400 {\n  font-weight: 400;\n}\n\n.bi-text--600 {\n  font-weight: 600;\n}\n\n.bi-text--700 {\n  font-weight: 700;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/theme.scss",
    "content": "@import './def/colors.def';\n@import './def/theme.def';\n\n\n.bi-theme--lighter {\n  @include theme('lighter');\n}\n\n.bi-theme--light {\n  @include theme('light');\n}\n\n.bi-theme--dark {\n  @include theme('dark');\n}\n\n.bi-theme--darker {\n  @include theme('darker');\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/toggle.scss",
    "content": "@import './def/toggle.def';\n\n.bi-toggle {\n  @extend %toggle;\n}\n\n.bi-toggle-right {\n  @extend %toggle;\n\n  &:after {\n    transform: rotate(-90deg);\n  }\n}\n\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/assets/css/wrap.scss",
    "content": ""
  },
  {
    "path": "quix-frontend/client/src/lib/ui/bootstrap.ts",
    "content": "import './assets/css/reset.scss';\nimport 'jquery-ui/themes/base/resizable.css';\nimport 'jquery-ui/ui/widgets/resizable';\n\nimport './components/date-picker/DatePicker';\nimport './components/panel/Panel';"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/Highlighter.tsx",
    "content": "import React from 'react';\nimport ReactHighlighter from 'react-highlight-words';\n\nexport interface HighlighterProps {\n  term: string;\n  filter: string;\n}\n\nexport const Highlighter = ({\n  term,\n  filter,\n}: HighlighterProps) => {\n    \n  return (\n    <ReactHighlighter\n      searchWords={[filter]}\n      autoEscape={true}\n      textToHighlight={term}\n    />\n  )\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/autocomplete/Autocomplete.tsx",
    "content": "import React from 'react';\nimport { AutocompleteProps, useAutocomplete } from './autocomplete.hook';\nimport { Input } from '../input/Input';\nimport { Dropdown } from '../dropdown/Dropdown';\nimport { Highlighter } from '../Highlighter';\n\nexport const Autocomplete = (props: AutocompleteProps) => {\n  const [\n    { title, inputValue, placeholder, inputValid },\n    viewState,\n    {\n      onScroll,\n      onValueChange,\n      onValueSelect,\n      getItems,\n      onInputFocus,\n      onInputBlur,\n    },\n  ] = useAutocomplete(props);\n\n  const inputClassName = `bi-pointer ${inputValid ? '' : ' bi-border-invalid'}${\n    props.classes?.input ? ` ${props.classes?.input}` : ''\n  }`;\n\n  const renderInput = (p: any) => (\n    <Input\n      {...p}\n      readonly={props.readonly}\n      disableFreeWrite={props.disableFreeWrite}\n      data-hook={props.inputDataHook}\n      className={inputClassName}\n      placeholder={placeholder}\n      onChange={(e) => {\n        onValueChange(e.target.value);\n        p.onChange && p.onChange();\n      }}\n      onFocus={(e, ref) => onInputFocus(e, p, ref)}\n      onBlur={(e) => onInputBlur(e, p)}\n      endAdornment={<i className=\"bi-icon bi-muted\">keyboard_arrow_down</i>}\n      value={inputValue}\n    />\n  );\n\n  const optionHtml = (option: any) => {\n    if (props.primaryOption && option[title] === props.primaryOption[title]) {\n      return (\n        <li\n          key=\"autocomplete_primary\"\n          className=\"bi-muted\"\n          onMouseDown={(e) => e.preventDefault()}\n          onClick={() => onValueSelect(option)}\n        >\n          {option[title]}\n        </li>\n      );\n    }\n\n    switch (viewState.get()) {\n      case 'Error':\n        return (\n          <li key=\"autocomplete_error\" className=\"bi-text--sm\">\n            <span>Error occured</span>\n          </li>\n        );\n      case 'Loading':\n        return (\n          <li key=\"autocomplete_loading\" className=\"bi-center bi-fade-in\">\n            <span className=\"bi-spinner--sm\"></span>\n          </li>\n        );\n      case 'Content':\n        return (\n          <li\n            key={`autocomplete_${\n              props.optionKey ? props.optionKey(option) : option[title]\n            }`}\n            onClick={() => onValueSelect(option)}\n            className={props.classes?.listItem || ''}\n            data-hook={props.liDataHook}\n          >\n            {option.render ? (\n              option.render(inputValue)\n            ) : (\n              <Highlighter term={option[title]} filter={inputValue} />\n            )}\n          </li>\n        );\n      case 'Empty':\n        return (\n          <li key=\"autocomplete_empty\" className=\"bi-text--sm bi-muted\">\n            <span>No suggestions</span>\n          </li>\n        );\n      default:\n        return <> </>;\n    }\n  };\n\n  return (\n    <Dropdown\n      readonly={props.readonly}\n      toggle={renderInput}\n      options={getItems()}\n      states={{\n        toggle: {\n          onClick: true,\n        },\n      }}\n    >\n      {(options) => (\n        <ul\n          onScroll={onScroll}\n          className={`${props.classes?.list || ''} bi-dropdown-menu`}\n        >\n          {options.map(optionHtml)}\n        </ul>\n      )}\n    </Dropdown>\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/autocomplete/autocomplete.hook.ts",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\nimport { useEffect } from 'react';\nimport { isEqual } from 'lodash';\nimport {\n  useViewState,\n  ViewStateActions,\n} from '../../../../services/hooks';\n\nexport interface AutocompleteProps {\n  title: string;\n  options: any[];\n  optionKey?(option: any): string;\n  state?: string;\n  getMore?(): void;\n  defaultValue?: string;\n  onChange?(value: string): void;\n  onInputFocus?(): void;\n  onSelect(option: any): void;\n  setTitleOnValueChange?(value: string): string;\n  setTitleOnValueSelect?(option: any): string;\n  placeholder?: string;\n  inputDataHook?: string;\n  liDataHook?: string;\n  primaryOption?: any;\n  classes?: {\n    input?: string;\n    list?: string;\n    listItem?: string;\n    wrapper?: string;\n  };\n  disableFreeWrite?: boolean;\n  readonly?: boolean;\n}\n\ninterface StateData {\n  title: string;\n  currentOptions: any[];\n  inputValue: string;\n  inputValid: boolean;\n  inputValueChanged: boolean;\n  filteredOptions: any[];\n  placeholder?: string;\n  selectedOption: any;\n}\n\ninterface Actions {\n  onScroll(UIElement: any): void;\n  onValueChange(v: string): void;\n  onValueSelect(primaryOption: any): void;\n  getItems(): any[];\n  onInputFocus(\n    e: any,\n    p: any,\n    ref?: React.MutableRefObject<HTMLInputElement>,\n  ): void;\n  onInputBlur(\n    e: any,\n    p: any,\n    ref?: React.MutableRefObject<HTMLInputElement>,\n  ): void;\n}\n\nconst formatInput = (props: AutocompleteProps): StateData => {\n  return {\n    title: props.title,\n    inputValue: props.defaultValue || '',\n    inputValueChanged: false,\n    inputValid: true,\n    filteredOptions: props.options,\n    currentOptions: props.getMore ? props.options : props.options.slice(0, 50),\n    selectedOption: {},\n    placeholder: props.primaryOption\n      ? props.primaryOption[props.title]\n      : props.placeholder || 'Please select value',\n  };\n};\n\nconst States = ['Empty', 'Content', 'Loading', 'Error'];\n\nexport const useAutocomplete = (\n  props: AutocompleteProps,\n): [StateData, ViewStateActions<string, StateData>, Actions] => {\n  const [stateData, viewState] = useViewState<string, StateData>(\n    States,\n    formatInput(props),\n  );\n\n  useEffect(() => {\n    const state = props.state || 'Content';\n    const options = props.options;\n    const currentOptions = props.getMore ? options : options.slice(0, 50);\n    const inputValue = stateData.inputValueChanged\n      ? stateData.inputValue\n      : props.defaultValue;\n\n    viewState.set(state, {\n      filteredOptions: options,\n      currentOptions,\n      inputValue,\n    });\n  }, [props.state, props.options, props.defaultValue]);\n\n  const onScroll = (UIElement: any) => {\n    const element = UIElement.target;\n    if (\n      element.scrollHeight - element.scrollTop <=\n      element.clientHeight + 100\n    ) {\n      if (!props.getMore) {\n        if (\n          stateData.currentOptions.length !== stateData.filteredOptions.length\n        ) {\n          viewState.update({\n            currentOptions: stateData.filteredOptions.slice(\n              0,\n              stateData.currentOptions.length + 50,\n            ),\n          });\n        }\n      } else {\n        props.getMore();\n      }\n    }\n  };\n\n  const onValueChange = (v: string) => {\n    if (props.onChange) {\n      props.onChange(v);\n    }\n\n    const inputValue = props.setTitleOnValueChange\n      ? props.setTitleOnValueChange(v)\n      : v;\n\n    if (!props.getMore) {\n      const _filteredOptions = props.options.filter((option) =>\n        option[stateData.title].includes(v),\n      );\n      if (!_filteredOptions.length) {\n        viewState.set('Empty', {\n          filteredOptions: [],\n          currentOptions: [],\n          inputValue,\n          inputValueChanged: true,\n        });\n      } else {\n        viewState.set('Content', {\n          filteredOptions: _filteredOptions,\n          currentOptions: _filteredOptions.slice(0, 50),\n          inputValue,\n          inputValueChanged: true,\n        });\n      }\n    } else {\n      viewState.update({\n        inputValue,\n        inputValueChanged: true,\n      });\n    }\n  };\n\n  const onValueSelect = (option: any) => {\n    const isPrimaryOption =\n      props.primaryOption &&\n      option[stateData.title] === props.primaryOption[stateData.title];\n\n    viewState.update({\n      selectedOption: option,\n      inputValue: isPrimaryOption\n        ? ''\n        : props.setTitleOnValueSelect\n        ? props.setTitleOnValueSelect(option)\n        : option[stateData.title],\n      inputValueChanged: true,\n      inputValid: true,\n    });\n\n    props.onSelect(option);\n  };\n\n  const getItems = () => {\n    if (viewState.is('Empty') && props.primaryOption) {\n      return [props.primaryOption];\n    }\n\n    if (!viewState.is('Content')) {\n      return [{ [stateData.title]: '' }];\n    }\n\n    return props.readonly\n      ? []\n      : props.primaryOption &&\n        !isEqual(props.primaryOption, stateData.selectedOption)\n      ? [props.primaryOption, ...stateData.currentOptions]\n      : stateData.currentOptions;\n  };\n\n  const onInputFocus = (\n    e: any,\n    p: any,\n    ref?: React.MutableRefObject<HTMLInputElement>,\n  ) => {\n    !props.readonly && ref && ref.current.select();\n    props.onInputFocus && props.onInputFocus();\n    p.onFocus && p.onFocus();\n  };\n\n  const onInputBlur = (e: any, p: any) => {\n    let inputValue = props.defaultValue || '';\n    if (stateData.selectedOption && stateData.selectedOption[stateData.title]) {\n      inputValue = props.setTitleOnValueSelect\n        ? props.setTitleOnValueSelect(stateData.selectedOption)\n        : stateData.selectedOption[stateData.title];\n    }\n\n    viewState.update({\n      inputValid:\n        props.primaryOption?.[stateData.title] === inputValue ||\n        inputValue === stateData.inputValue,\n    });\n\n    p.onInputBlur && p.onInputBlur();\n  };\n\n  return [\n    stateData,\n    viewState,\n    {\n      onScroll,\n      onValueChange,\n      onValueSelect,\n      getItems,\n      onInputFocus,\n      onInputBlur,\n    },\n  ];\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/date-picker/DatePicker.tsx",
    "content": "import React from 'react';\nimport 'bootstrap-daterangepicker/daterangepicker.css';\nimport ReactDateRangePicker from 'react-bootstrap-daterangepicker';\nimport { DatePickerProps, useDatePicker } from './date-picker.hook';\n\nexport const DatePicker = (props: DatePickerProps) => {\n  const [\n    { customDates },\n    { handleCallback, getLabel, getInitialDates },\n    viewState,\n  ] = useDatePicker(props);\n\n  switch (viewState.get()) {\n    case 'Range':\n      return (\n        <div className={`${props.classes?.formRow || ''} bi-form-row`}>\n          {props.title ? (\n            <span className=\"bi-form-label\">{props.title}</span>\n          ) : null}\n          <ReactDateRangePicker\n            initialSettings={{\n              ranges: customDates,\n              timePicker: props.timePicker,\n              startDate: getInitialDates()[0],\n              endDate: getInitialDates()[1],\n              alwaysShowCalendars: true,\n            }}\n            onCallback={(start, end, label) =>\n              handleCallback([start, end] as any, label)\n            }\n          >\n            <div\n              className={`${\n                props.classes?.input || ''\n              }  bi-pointer bi-input bi-align`}\n            >\n              <span>{getLabel()}</span>\n            </div>\n          </ReactDateRangePicker>\n        </div>\n      );\n    case 'RangeReadOnly':\n      return (\n        <div className={`${props.classes?.formRow || ''} bi-form-row`}>\n          {props.title ? (\n            <span className=\"bi-form-label\">{props.title}</span>\n          ) : null}\n          <div className={`${props.classes?.inputDisabled || ''} bi-align`}>\n            <span>{getLabel()}</span>\n          </div>\n        </div>\n      );\n    default:\n      return <div>Type {props.type} not implemented yet.</div>;\n  }\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/date-picker/date-picker-utils.ts",
    "content": "/* tslint:disable:no-non-null-assertion */\n\nexport const getKeyByValue = (object: Record<string, any>, value: string) => {\n  return Object.keys(object).find((key) => object[key] === value);\n};\n\nconst numbersRegex = /\\d+/;\nexport const getAmountAndUnitFromString = (str: string) => {\n  const amount = str.match(numbersRegex);\n  const unit = str.split(amount![0]).pop();\n  return [amount as any, unit];\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/date-picker/date-picker.hook.ts",
    "content": "/* eslint-disable react-hooks/exhaustive-deps */\n/* tslint:disable:no-non-null-assertion */\n\nimport { useEffect } from 'react';\nimport moment, { Moment } from 'moment';\nimport _ from 'lodash';\nimport {\n  useViewState,\n  ViewStateActions,\n} from '../../../../services/hooks';\nimport { getAmountAndUnitFromString, getKeyByValue } from './date-picker-utils';\n\nexport interface Range {\n  start: null | number;\n  end?: null | number;\n  period?: null | string;\n}\n\ntype DateRanges = Record<string, any>;\ntype DatePickerTypes = 'Range';\nexport interface OnChangeDatePickerProps {\n  selectedDates: Moment[];\n  label?: string;\n  isEqualToCustomRange: boolean;\n}\n\nexport interface DatePickerProps {\n  title?: string;\n  dateFormat?: string;\n  initialDates?: Range;\n  customDates?: DateRanges;\n  timePicker?: boolean;\n  readonly?: boolean;\n  onChange(props: Range): void;\n  type: DatePickerTypes;\n  classes?: {\n    input?: string;\n    inputDisabled?: string;\n    formRow?: string;\n  };\n}\n\ninterface StateData {\n  selectedDates: Moment[];\n  isEqualToCustomRange: boolean;\n  customRangeLabel: string;\n  customDates?: DateRanges;\n}\n\ninterface DatePickerActions {\n  handleCallback(initialDates: Moment[], label?: string): void;\n  getLabel(): string;\n  getInitialDates(): Moment[];\n}\n\nconst States = ['Range', 'RangeReadOnly'];\n\nconst formatDate = (\n  dates: Moment[] = [moment(), moment()],\n  format: string = 'DD/MM/YYYY HH:mm',\n) =>\n  dates.length > 1\n    ? dates[0].format(format) + ' - ' + dates[1].format(format)\n    : dates[0].format(format);\n\nconst formatInput = (props: DatePickerProps): StateData => {\n  let formattedCustomDates: Record<string, any> | undefined;\n  if (props.customDates) {\n    Object.keys(props.customDates).forEach((key) => {\n      if (!formattedCustomDates) {\n        formattedCustomDates = {};\n      }\n\n      const [amount, unit] = getAmountAndUnitFromString(\n        props.customDates![key],\n      );\n\n      formattedCustomDates[key] = [\n        moment().subtract(amount, unit.toLowerCase()),\n        moment(),\n      ];\n    });\n  }\n\n  if (props.initialDates) {\n    const { start, end, period } = props.initialDates;\n    const selectedDates: Moment[] = [];\n    start && selectedDates.push(moment.unix(start));\n    end && selectedDates.push(moment.unix(end));\n\n    return {\n      customRangeLabel: period\n        ? getKeyByValue(props.customDates!, period)!\n        : '',\n      selectedDates,\n      isEqualToCustomRange: !!period,\n      customDates: formattedCustomDates,\n    };\n  }\n\n  return {\n    customRangeLabel: '',\n    selectedDates: [],\n    isEqualToCustomRange: false,\n    customDates: formattedCustomDates,\n  };\n};\n\nconst formatOutput = (\n  selectedDates: Moment[],\n  isEqualToCustomRange: boolean,\n  customDates?: DateRanges,\n  label?: string,\n): Range => {\n  const _selectedDates = selectedDates.map((date) => date.utc());\n  const range: Range = {\n    start: !isEqualToCustomRange ? _selectedDates[0].unix() : null,\n    end:\n      !isEqualToCustomRange && _selectedDates[1]\n        ? _selectedDates[1].unix()\n        : null,\n    period: isEqualToCustomRange ? customDates![label!] : '',\n  };\n  return range;\n};\n\nexport const useDatePicker = (\n  props: DatePickerProps,\n): [StateData, DatePickerActions, ViewStateActions<string, StateData>] => {\n  const [stateData, viewState] = useViewState<string, StateData>(\n    States,\n    formatInput(props),\n  );\n\n  useEffect(() => {\n    const newState = props.readonly ? 'RangeReadOnly' : props.type;\n    viewState.set(newState, formatInput(props));\n  }, [props]);\n\n  const handleCallback = (selectedDates: Moment[], label?: string) => {\n    const isEqualToCustomRange = !!props.customDates?.[label || ''];\n\n    viewState.update({\n      selectedDates,\n      customRangeLabel: label,\n      isEqualToCustomRange,\n    });\n\n    props.onChange(\n      formatOutput(\n        selectedDates,\n        isEqualToCustomRange,\n        props.customDates,\n        label,\n      ),\n    );\n  };\n\n  const getLabel = () => {\n    if (stateData.isEqualToCustomRange) {\n      return stateData.customRangeLabel;\n    } \n      if (stateData.selectedDates.length === 0) {\n        switch (viewState.get()) {\n          case 'Range':\n            const initialDates = getInitialDates();\n            return formatDate(initialDates);\n          default:\n            return '';\n        }\n      } \n        return formatDate(stateData.selectedDates, props.dateFormat);\n      \n    \n  };\n\n  const getInitialDates = () => {\n    const { customDates, initialDates } = props;\n    if (stateData.customDates && initialDates?.period && customDates) {\n      const key = getKeyByValue(customDates, initialDates.period);\n      return stateData.customDates[key!];\n    } \n      return [moment(), moment()];\n    \n  };\n\n  return [stateData, { handleCallback, getLabel, getInitialDates }, viewState];\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/dropdown/Dropdown.tsx",
    "content": "import React, { useRef, useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport { usePopper } from 'react-popper';\nimport { Placement } from '@popperjs/core';\nimport { isNil } from 'lodash';\nimport { withOutsideClick } from '../../../../services/hooks';\nimport './dropdown.scss';\n\ninterface DropdownProps {\n  toggle(props: any): JSX.Element;\n  options: any[];\n  isOpen?: boolean;\n  placement?: Placement;\n  children?(options: any[]): JSX.Element;\n  states?: {\n    toggle?: {\n      onClick?: boolean;\n      onKeyDown?: boolean;\n      onFocus?: boolean;\n    };\n  };\n  dynamicWidth?: boolean;\n  readonly?: boolean;\n}\n\nconst sameWidth = {\n  name: 'sameWidth',\n  enabled: true,\n  phase: 'beforeWrite' as any,\n  requires: ['computeStyles'],\n  fn: ({ state }: any) => {\n    state.styles.popper.width = `${state.rects.reference.width}px`;\n  },\n  effect: ({ state }: any) => {\n    state.elements.popper.style.width = `${state.elements.reference.offsetWidth}px`;\n  },\n};\n\nexport const Dropdown = ({\n  toggle,\n  options,\n  isOpen,\n  placement,\n  children,\n  states,\n  dynamicWidth = true,\n  readonly,\n}: DropdownProps) => {\n  const isOpenDefined = !isNil(isOpen);\n\n  const [_isOpen, setIsOpen] = useState(false);\n  const referenceToggle = useRef(null);\n  const referenceOptions = useRef(null);\n\n  const { styles, attributes, forceUpdate } = usePopper(\n    referenceToggle.current,\n    referenceOptions.current,\n    {\n      placement: placement || 'bottom-start',\n      strategy: 'fixed',\n      modifiers: dynamicWidth ? [sameWidth] : [],\n    },\n  );\n  withOutsideClick([referenceToggle], () => {\n    forceUpdate && forceUpdate();\n    setTimeout(() => setIsOpen(false), 0);\n  });\n\n  return (\n    <>\n      {toggle({\n        ref: referenceToggle,\n        onClick: () =>\n          setIsOpen(\n            isNil(states?.toggle?.onClick)\n              ? !_isOpen\n              : states?.toggle?.onClick,\n          ),\n        onKeyDown: () =>\n          setIsOpen(\n            isNil(states?.toggle?.onKeyDown)\n              ? true\n              : states?.toggle?.onKeyDown,\n          ),\n        onFocus: () =>\n          setIsOpen(\n            isNil(states?.toggle?.onFocus) ? true : states?.toggle?.onFocus,\n          ),\n      })}\n      {readonly\n        ? null\n        : ReactDOM.createPortal(\n            <div\n              style={styles.popper}\n              {...attributes.popper}\n              ref={referenceOptions}\n            >\n              {(isOpenDefined ? isOpen : _isOpen) ? (\n                <div className=\"bi-fade-in bi-theme--lighter bi-dropdown-content\">\n                  {children(options)}\n                </div>\n              ) : null}\n            </div>,\n            document.querySelector('body') as any,\n          )}\n    </>\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/dropdown/dropdown.scss",
    "content": ".bi-dropdown-content {\n  border-radius: 3px;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/hoc/makePagination.tsx",
    "content": "import React, { useEffect, useState } from 'react';\nimport { Subtract } from 'utility-types';\nimport _ from 'lodash';\n\ninterface InjectedPaginationProps {\n  data: any[];\n  columns: any[];\n  getChunk?(): void;\n  isChunking?: boolean;\n}\n\ninterface MakePaginationProps {\n  initialData: any;\n  columns: any[];\n  loadMore(offset: number, limit: number): any;\n  paginationSize: number;\n  tableSize?(size: number): void;\n  getChunk?(): void;\n}\n\nconst makePagination = <P extends InjectedPaginationProps>(\n    Component: React.ComponentType<P>,\n  ) =>  {\n    const MakePagination = (props: Subtract<P, InjectedPaginationProps> & MakePaginationProps) => {\n\n      const { initialData, columns, loadMore, paginationSize, tableSize, ...restComponentProps } = props;\n\n      const [isChunking, setIsChunking] = useState(false);\n      const [resultsLeft, setResultsLeft] = useState(initialData && initialData.length === paginationSize + 1);\n      const [data, setData] = useState(resultsLeft ? initialData.slice(0, paginationSize) : (initialData || []));\n \n      useEffect(() => {\n        if (tableSize) {\n          tableSize(data.length);\n        }\n      }, [data.length]);\n\n      const getChunk = () => {\n        if (!isChunking && resultsLeft) {\n          setIsChunking(true);\n\n          loadMore(data.length, paginationSize + 1)(response => {\n              if (response.length === paginationSize + 1) {\n                setData([...data, ...response.slice(0, paginationSize)]);\n              } else {\n                setResultsLeft(false);\n                setData([...data, ...response]);\n              }\n              setIsChunking(false);\n            });\n        }\n      }\n\n      const componentProps = {\n        columns,\n        data,\n        isChunking,\n        getChunk,\n        ...restComponentProps,\n      };\n      return <Component {...componentProps as any} />\n    }\n    return MakePagination;\n    }\n\nexport default makePagination;"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/input/Input.tsx",
    "content": "import React, { useRef } from 'react';\nimport './input.scss';\n\ninterface InputProps\n  extends Partial<\n    React.DetailedHTMLProps<\n      React.InputHTMLAttributes<HTMLInputElement>,\n      HTMLInputElement\n    >\n  > {\n  startAdornment?: JSX.Element;\n  endAdornment?: JSX.Element;\n  disableFreeWrite?: boolean;\n  readonly?: boolean;\n  onFocus?(\n    e: React.FocusEvent<HTMLInputElement>,\n    ref?: React.MutableRefObject<HTMLInputElement>,\n  ): void;\n  onBlur?(\n    e: React.FocusEvent<HTMLInputElement>,\n    ref?: React.MutableRefObject<HTMLInputElement>,\n  ): void;\n}\n\nexport const Input = React.forwardRef(\n  (\n    {\n      className,\n      startAdornment,\n      endAdornment,\n      disableFreeWrite,\n      readonly,\n      onFocus,\n      onBlur,\n      ...p\n    }: InputProps,\n    ref,\n  ) => {\n    const inputRef = useRef<HTMLInputElement>(null as any);\n\n    const _readonly = disableFreeWrite || readonly;\n    const additionalClasses = `${readonly ? ' bi-disabled' : ''}${\n      className ? ` ${className}` : ''\n    }`;\n\n    if (startAdornment || endAdornment) {\n      const _wrapperClassName =\n        'bi-input bi-input-wrapper bi-align' + additionalClasses;\n\n      return (\n        <div ref={ref as any} className={_wrapperClassName}>\n          {startAdornment}\n          <input\n            ref={inputRef}\n            readOnly={_readonly}\n            className={`bi-grow bi-input-no-border${\n              readonly ? ' bi-disabled' : ''\n            }`}\n            onFocus={(e) => onFocus && onFocus(e, inputRef)}\n            onBlur={(e) => onBlur && onBlur(e, inputRef)}\n            {...p}\n          />\n          {endAdornment}\n        </div>\n      );\n    }\n\n    const _className = 'bi-input' + additionalClasses;\n    return (\n      <input\n        ref={ref as any}\n        readOnly={_readonly}\n        className={_className}\n        onFocus={(e) => onFocus && onFocus(e, (ref as any) || inputRef)}\n        onBlur={(e) => onBlur && onBlur(e, (ref as any) || inputRef)}\n        {...p}\n      />\n    );\n  },\n);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/input/input.scss",
    "content": "@import '../../../../lib/ui/assets/css/def/colors.def.scss';\n\n.bi-input-wrapper {\n  padding: 0px 10px !important;\n\n  .bi-input-no-border {\n    border: 0;\n    outline: none;\n    cursor: inherit;\n    font: inherit;\n    color: inherit;\n    width: 100%;\n    height: 100%;\n  }\n\n}\n\n.bi-border-valid {\n  border-color: $green--300 !important;\n}\n\n.bi-border-invalid {\n  border-color: $red--300 !important;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/panel/Panel.tsx",
    "content": "import React from 'react';\n\ninterface PanelProps {\n  header?: JSX.Element;\n  children: any;\n  className?: {\n    main?: string;\n    header?: string;\n    content?: string;\n  };\n}\n\nexport const Panel = ({ header, children, className }: PanelProps) => {\n  const _main = className?.main\n    ? `bi-s-v--x15 bi-panel bi-grow ${className?.main}`\n    : 'bi-s-v--x15 bi-panel bi-grow';\n\n  const _header = className?.header\n    ? `bi-panel-header ${className?.header}`\n    : 'bi-panel-header';\n\n  const _content = className?.content\n    ? `bi-panel-content ${className?.content}`\n    : 'bi-panel-content';\n\n  return (\n    <div className={_main}>\n      {header ? <div className={_header}>{header}</div> : null}\n      <div className={_content}>{children}</div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/states/EmptyState.tsx",
    "content": "import React from 'react';\nimport noResultsImg from '../../../../assets/no_data.svg';\n\nexport const EmptyState = () => (\n  <div className=\"bi-c-h bi-align bi-center bi-grow bi-fade-in\">\n    <div className=\"bi-empty-state bi-fade-in\">\n      <img className=\"bi-empty-state-image\" src={noResultsImg}></img>\n      <div className=\"bi-empty-state-header\" data-hook=\"table-empty-result\">No results</div>\n    </div>\n  </div>\n);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/states/ErrorState.tsx",
    "content": "import React from 'react';\n\nexport const ErrorState = ({\n  errorMessage,\n}) => (\n  <div\n    className=\"bi-empty-state bi-align bi-center bi-grow bi-fade-in\"\n    data-hook=\"table-error\"\n  >\n    <div className=\"bi-empty-state-icon bi-danger\">\n      <i className=\"bi-icon bi-danger\">error_outline</i>\n    </div>\n    <div className=\"bi-empty-state-header\">{errorMessage}</div>\n  </div>\n);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/states/FilterInitialState.tsx",
    "content": "import React from 'react';\n\nexport const FilterInitialState = ({\n  entityName,\n}) => (\n  <div className=\"bi-c-h bi-align bi-center bi-grow\">\n    <div className=\"bi-empty-state--loading bi-fade-in\">\n      <div className=\"bi-empty-state-content\" data-hook=\"table-filter-initial\">Searching {entityName}...</div>\n    </div>\n  </div>\n);"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/states/InitialState.tsx",
    "content": "import React from 'react';\n\nexport const InitialState = ({\n  entityName,\n}) => (\n  <div className=\"bi-empty-state--loading bi-align bi-center bi-grow bi-fade-in\">\n    <div className=\"bi-empty-state-content\" data-hook=\"table-initial\">Loading {entityName}...</div>\n  </div>\n);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/states/index.ts",
    "content": "export {InitialState} from './InitialState';\nexport {FilterInitialState} from './FilterInitialState';\nexport {EmptyState} from './EmptyState';\nexport {ErrorState} from './ErrorState';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/table/Table.scss",
    "content": ".bi-table-cells {\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/table/Table.tsx",
    "content": "import React from 'react';\nimport { TableRow } from './TableRow';\nimport '../../directives/search/search.scss';\nimport './Table.scss';\n\nexport interface TableProps {\n  hookName?: string;\n  columns: {\n    header: string;\n    render(cell: any): React.ReactNode;\n    accessor: string;\n    className: string;\n  }[];\n  data: any[];\n  onRowClicked?(row: any): void;\n  getChunk?(): void;\n  isChunking?: boolean;\n}\n\nexport const Table = ({\n  hookName,\n  columns,\n  data,\n  onRowClicked,\n  getChunk,\n  isChunking = false,\n}: TableProps) => {\n\n  const scroll = (UIElement) => {\n    const element = UIElement.target;\n    if (element.scrollHeight - element.scrollTop <= element.clientHeight + 1000) {\n      getChunk && getChunk();\n    }\n  }\n\n  return (\n    <div\n      className=\"bi-panel bi-c-h bi-fade-in bi-theme--lighter\"\n      data-hook={hookName ? hookName + '-table' : 'table'}\n    >\n      <div className=\"bi-panel-content bi-c-h\">\n        <div className=\"bi-table-container bi-table--nav bi-c-h bi-grow bi-table-sticky-header\">\n          <div onScroll={scroll} className=\"bi-fade-in\">\n            <table className=\"bi-table\">\n              <thead className=\"bi-tbl-header\">\n                <tr>\n                    {columns.map((column, index) => (\n                      <th className={column.className} key={index}>\n                        <div className=\"bi-table-th-content bi-text--ui\">\n                          <span className=\"bi-align ng-scope\">\n                            <span className=\"bi-text--600 ng-binding\">\n                              {column.header}\n                            </span>\n                          </span>\n                        </div>\n                      </th>\n                    ))}\n                </tr>\n              </thead>\n\n              <tbody>\n                {\n                  data.map((fullRow, index) => (\n                      <TableRow\n                        key={index}\n                        onRowClicked={onRowClicked}\n                        row={fullRow}\n                        columns={columns}\n                      />\n                    )\n                  )\n                }\n              </tbody>\n            </table>\n\n            {isChunking ?\n              <div className='bi-empty-state'>\n                <div className='bi-empty-state-content'>Loading...</div>\n              </div>\n              : null\n            }\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/table/TableRow.tsx",
    "content": "import React from 'react';\n\nexport interface RowConfig<T> {\n  name: keyof T;\n  title?: string;\n  className?: string;\n  filter?(value, item: T, index?): React.ReactNode;\n}\n\nexport interface HighlightedRowConfig<T> extends RowConfig<T> {\n  filter?(\n    value,\n    item: T,\n    index,\n    highlight?: (term: string) => React.ReactNode\n  ): React.ReactNode;\n}\n\nexport interface TableRowProps {\n  columns: {\n    header: string;\n    render(cell: any): React.ReactNode;\n    accessor: string;\n    className: string;\n  }[];\n  onRowClicked(row: any): void;\n  row: any;\n}\n\nexport const TableRow = ({ row, onRowClicked, columns }: TableRowProps) => {\n  return (\n    <tr\n      onClick={() => {\n        if (typeof onRowClicked === 'function') {\n          return onRowClicked(row);\n        }\n      }}\n      data-hook='table-row'\n    >\n      {columns.map((column, index) => {\n        return (\n          <td\n            key={index}\n            className={'bi-table-cells bi-table-cell-' + column.accessor}\n          >\n            {column.render(row)}\n          </td>\n        );\n      })}\n    </tr>\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/components/table/table-testkit.ts",
    "content": "import {Testkit} from '../../../../../test/e2e/driver';\n\nconst enum Hooks {\n  Initial = 'table-initial',\n  Error = 'table-error',\n  EmptyResult = 'table-empty-result',\n  FilterInitial = 'table-filter-initial',\n  TableRow = 'table-row',\n}\n\nexport class TableTestkit extends Testkit {\n\n  tableStates = {\n    hasError: async () => {\n      return (await this.query.hook(Hooks.Error)) !== null;\n    },\n\n    hasLoading: async () => {\n      return (await this.query.hook(Hooks.Initial)) !== null;\n    },\n\n    hasFilterLoading: async () => {\n      return (await this.query.hook(Hooks.FilterInitial)) !== null;\n    },\n\n    hasEmptyResult: async () => {\n      return (await this.query.hook(Hooks.EmptyResult)) !== null;\n    },\n  }\n\n  tableTotalRows = async () => {\n    return (await this.query.hooks(Hooks.TableRow)).length;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.html",
    "content": "<div class=\"bi-align bi-s-h\">\n  <div class=\"bi-align bi-s-h\" ng-repeat=\"item in collection\">\n    <i class=\"bi-icon--sm bi-muted\" ng-if=\"$index > 0\">keyboard_arrow_right</i>\n\n    <span\n      ng-class=\"{'bi-link': $index < collection.length - 1}\"\n      bi-html=\"renderItem(item, $index)\"\n      ng-click=\"$index < collection.length - 1 && events.onItemClick(item)\"\n    ></span>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.scss",
    "content": "@import '../../assets/css/def/colors.def';\n@import '../../assets/css/def/defaults.def';\n\nbi-breadcrumbs {\n  .bi-link {\n    color: unset;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.story.ts",
    "content": "export default app => app\n  .story('UI', 'Breadcrumbs')\n    .section('Breadcrumbs', `\n      <bi-breadcrumbs ng-non-bindable bi-options=\"item as item.name for item in ::items\" on-item-click=\"onItemClick(item)\"></bi-breadcrumbs>\n      <output>Selected: {{selected}}</output>\n    `, scope => {\n      scope.items = [{name: 'Foo'}, {name: 'Goo'}];\n      scope.onItemClick = item => scope.selected = item;\n    })\n    .section('Custom breadcrumbs', `\n      <bi-breadcrumbs ng-non-bindable bi-options=\"item as item.name for item in ::items\" on-item-click=\"onItemClick(item)\">\n        <span class=\"bi-align bi-s-h--x05\">\n          <i class=\"bi-icon--sm bi-muted\">face</i>\n          <span>{{::item.name}}</span>\n        </span>\n      </bi-breadcrumbs>\n      <output>Selected: {{selected}}</output>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/breadcrumbs/breadcrumbs.ts",
    "content": "import template from './breadcrumbs.html';\nimport './breadcrumbs.scss';\n\nimport {initNgScope} from '../../../core';\n\nexport default function directive() {\n  return {\n    template,\n    require: 'biOptions',\n    restrict: 'E',\n    transclude: true,\n    scope: {\n      onItemClick: '&'\n    },\n\n    link: {\n      pre(scope, element, attrs, biOptions, transclude) {\n        initNgScope(scope)\n          .withEvents({\n            onItemClick(item) {\n              scope.onItemClick({item: biOptions.format(item)});\n            }\n          });\n\n        scope.renderItem = (item, index) => {\n          let html = transclude((_, _scope) => {\n            _scope.item = item;\n            _scope.$index = index;\n          });\n\n          html = html.text().trim().length ? html : biOptions.render(item);\n\n          return {html};\n        };\n\n        biOptions.watch(collection => {\n          scope.collection = collection;\n        });\n      }\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/common/dropdown-list.ts",
    "content": "import {IScope} from 'angular';\nimport {assign, includes, without, uniq} from 'lodash';\nimport * as JsSearch from 'js-search';\nimport {initNgScope, createNgModel, inject, utils} from '../../../core';\n\nconst isNull = value => {\n  return !value && typeof value !== 'boolean' && typeof value !== 'number';\n}\n\nconst toString = value => {\n  return isNull(value) ? '' : `${value}`;\n}\n\nexport class DropdownList {\n  private searcher: any = null;\n  private deferredId = 0;\n  private readonly $timeout: ng.ITimeoutService = inject('$timeout');\n  constructor(\n    private readonly scope: IScope,\n    private readonly element: any,\n    private readonly attrs: any,\n    private readonly controllers: Record<string, any>,\n    private readonly transclude: ng.ITranscludeFunction,\n    private readonly config: {\n      optionsAlias: string;\n      isArray?: boolean;\n      options?: Record<string, any>;\n    },\n  ) {\n    const {ngModel, biOptions} = controllers;\n\n    createNgModel(scope as any, ngModel)\n      .formatWith(model => this.format(model))\n      .parseWith(model => this.parse(model))\n      .validateWith(() => this.validate())\n      .renderWith(model => this.render(model))\n      .watchDeep(!!config.isArray)\n      .feedBack(false);\n\n    initNgScope(scope)\n      .withOptions(config.optionsAlias, {\n        freetext: false,\n        typeahead: false,\n        dropdownWidth: null,\n        dropdownMinWidth: 'toggle',\n        alignDropdown: 'left',\n        debounce: 0,\n        type: 'text',\n        filterBy: [],\n        ...config.options\n      })\n      .withVM({\n        isCustomToggle: false,\n        renderedModel: null,\n        keyNavOption: null,\n        search: {\n          text: null,\n          parsed: null,\n        },\n        options: {\n          collection: null,\n          filtered: null,\n          searched: null,\n          falsy: null,\n          deferred: {\n            loading: false\n          },\n          items() {\n            return this.searched || this.filtered;\n          }\n        }\n      })\n      .withEvents({\n        onSearchChange: () => {\n          const {vm, options} = this.scope;\n\n          vm.search.toggle(true);\n\n          if (!this.config.isArray || options.typeahead) {\n            vm.options.toggle(true);\n\n            this.search();\n\n            scope.onTypeahead({text: vm.search.text});\n          }\n        },\n        onSearchKeypress: ({key}) => {\n          const {options, vm} = scope;\n\n          if (key === 'Enter' && options.freetext && !vm.keyNavOption) {\n            this.applySearchText(vm.search.text);\n          }\n        },\n        onSearchBlur: () => {\n          const {options, vm} = scope;\n\n          if (options.freetext) {\n            this.applySearchText(vm.search.text);\n          }\n        },\n        onSearchMousedown: () => {\n          const {options, vm} = scope;\n\n          if (options.typeahead) {\n            scope.onTypeahead({text: null});\n\n            if (this.config.isArray) {\n              vm.options.toggle();\n            }\n          }\n        },\n        onDropdownShow: () => {\n          const {options} = this.scope;\n\n          if (!this.config.isArray && options.typeahead && scope.model) {\n            this.element.find('input').select();\n          }\n        },\n        onDropdownHide: () => {\n          this.reset();\n        },\n        onOptionSelect: (...options) => {\n          const {vm} = this.scope;\n\n          vm.options.toggle(false);\n\n          if (this.config.isArray) {\n            scope.model = uniq([...scope.model, ...options]);\n            vm.search.text = null;\n\n            this.element.find('input').focus();\n          } else {\n            scope.model = options[0];\n          }\n\n          if (scope.onSelect) {\n            this.$timeout(() => scope.onSelect({model: scope.model}));\n          }\n        },\n        onOptionDelete: option => {\n          if (this.config.isArray) {\n            scope.model = without(scope.model, option);\n          }\n        }\n      });\n\n    biOptions.watch(async (collection: any) => {\n      const {vm} = this.scope;\n\n      const deferredId = ++this.deferredId;\n\n      if (collection && collection.then) {\n        this.setOptions(null);\n\n        vm.options.deferred.toggle(true);\n        vm.options.deferred.loading = true;\n\n        collection = await collection;\n      }\n\n      if (deferredId === this.deferredId) {\n        utils.scope.safeApply(scope, () => {\n          this.setOptions(collection);\n          vm.options.deferred.loading = false;\n        });\n      }\n    });\n\n    scope.renderToggle = () => this.renderToggle();\n    scope.renderOption = option => this.renderOption(option);\n\n    scope.placeholder = scope.placeholder || 'Select a value';\n  }\n\n  private reset() {\n    const {vm} = this.scope;\n\n    vm.search.toggle(false);\n    vm.options.searched = null;\n\n    this.render();\n  }\n\n  private format(model: any) {\n    const {biOptions} = this.controllers;\n\n    if (this.config.isArray) {\n      return model ? model.map(item => biOptions.format(item)) : [];\n    }\n\n    return biOptions.format(model);\n  }\n\n  private parse(model: any[]) {\n    const {biOptions} = this.controllers;\n    let parsed;\n\n    if (this.config.isArray) {\n      parsed = model.map(item => biOptions.parse(item));\n    } else {\n      parsed = biOptions.parse(model);\n    }\n\n    inject('$timeout')(() => {\n      this.reset();\n      this.initOptions();\n    });\n\n    return parsed;\n  }\n\n  private validate() {\n    return {\n      required: model => {\n        if (!this.attrs.required) {\n          return true;\n        }\n\n        return this.config.isArray ? !!(model && model.length) : !isNull(model);\n      }\n    };\n  }\n\n  private render(model: any[] = this.scope.model) {\n    const {biOptions} = this.controllers;\n    const {vm} = this.scope;\n\n    if (this.config.isArray) {\n      vm.renderedModel = model.map(item => biOptions.render(item));\n      vm.search.text = '';\n    } else {\n      vm.search.text = biOptions.render(model);\n      vm.search.parsed = biOptions.parse(model);\n    }\n  }\n\n  private applySearchText(text) {\n    const {vm, events} = this.scope;\n\n    if (vm.search.enabled && !isNull(text)) {\n      if (this.config.isArray) {\n        const values: string[] | number[] = typeof text === 'string' ? text.split(',') : [text];\n        events.onOptionSelect(...values);\n      } else {\n        events.onOptionSelect(text);\n      }\n    }\n  }\n\n  private setOptions(collection: any[] = this.scope.vm.options.collection) {\n    const {vm} = this.scope;\n\n    vm.options.collection = collection;\n\n    this.initOptions();\n    this.search();\n  }\n\n  private initOptions(collection: any[] = this.scope.vm.options.collection) {\n    const {vm, options} = this.scope;\n\n    if (!collection) {\n      vm.options.filtered = null;\n      return;\n    }\n\n    const {biOptions} = this.controllers;\n\n    vm.options.falsy = null;\n    vm.options.filtered = collection.filter((option) => {\n      if (!vm.options.falsy && isNull(biOptions.parse(option))) {\n        vm.options.falsy = {option};\n        return false;\n      }\n\n      if (this.config.isArray && includes(vm.renderedModel, biOptions.render(option))) {\n        return false;\n      }\n\n      return true;\n    });\n\n    if (vm.options.filtered && options.filterBy.length && !this.scope.readonly) {\n      this.searcher = new JsSearch.Search(options.filterBy[0]);\n      this.searcher.indexStrategy = new JsSearch.AllSubstringsIndexStrategy();\n      this.searcher.tokenizer = {\n        tokenize: text =>\n          text\n            .split(/[^a-z0-9\\-'\\.]+/i)\n            .filter(t => !!t)\n      };\n\n      options.filterBy.forEach(prop => this.searcher.addIndex(prop));\n      this.searcher.addDocuments(vm.options.filtered);\n    } else {\n      this.searcher = null;\n    }\n  }\n\n  private search(collection: any[] = this.scope.vm.options.filtered) {\n    const {vm} = this.scope;\n\n    if (!collection || !vm.search.enabled || !vm.search.text) {\n      vm.options.searched = null;\n      return;\n    }\n\n    let text = vm.search.text;\n\n    if (this.searcher) {\n      vm.options.searched = this.searcher.search(text);\n      return;\n    }\n\n    const {biOptions} = this.controllers;\n    text = toString(text).toLowerCase();\n\n    vm.options.searched = collection.filter(option =>\n      includes(toString(biOptions.render(option)).toLowerCase(), text));\n  }\n\n  public renderToggle() {\n    const {scope} = this;\n    const {biOptions} = this.controllers;\n    const {vm, placeholder, options} = scope;\n    const {type} = options;\n    let html;\n\n    if (this.transclude.isSlotFilled('toggle')) {\n      html = this.transclude((_, tscope) => {\n        tscope.placeholder = placeholder;\n\n        Object.defineProperty(tscope, biOptions.getItemName(), {\n          get() {\n            return scope.model;\n          }\n        });\n\n        Object.defineProperty(tscope, 'text', {\n          get() {\n            return vm.search.text;\n          }\n        });\n      }, null, 'toggle');\n\n      vm.isCustomToggle = true;\n    } else {\n      html = inject('$compile')(`\n        <input\n          type=\"${type}\"\n          class=\"bi-input bi-grow\"\n          ng-model=\"vm.search.text\"\n          ng-model-options=\"::{debounce: options.debounce}\"\n          ng-change=\"events.onSearchChange($event)\"\n          ng-mousedown=\"events.onSearchMousedown()\"\n          ng-keydown=\"events.onSearchKeypress($event)\"\n          ng-blur=\"events.onSearchBlur()\"\n          ng-disabled=\"::readonly\"\n          ng-required=\"vm.required\"\n          ng-readonly=\"::!options.typeahead\"\n          placeholder=\"{{::placeholder}}\"\n          autocomplete=\"off\"\n        />\n        <i class=\"bi-icon bi-muted\" ng-if=\"::!readonly\">expand_more</i>\n      `)(this.scope);\n    }\n\n    return {html};\n  }\n\n  public renderOption(option: any) {\n    const {biOptions} = this.controllers;\n    const {vm} = this.scope;\n    let html;\n\n    if (this.transclude.isSlotFilled('opt')) {\n      html = this.transclude((_, tscope) => {\n        tscope[biOptions.getItemName()] = option;\n\n        Object.defineProperty(tscope, 'text', {\n          get() {\n            return vm.search.enabled ? vm.search.text : '';\n          }\n        });\n      }, null, 'opt');\n    } else {\n      const scope = assign(this.scope.$new(), {\n        option: biOptions.render(option)\n      });\n\n      html = inject('$compile')(`\n        <div ng-if=\"!vm.search.enabled\">{{::option}}</div>\n        <div ng-if=\"vm.search.enabled\" ng-bind-html=\"option | biHighlight:vm.search.text\"></div>\n      `)(scope);\n    }\n\n    return {html};\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/content-editable/content-editable.scss",
    "content": "@import '../../assets/css/def/colors.def';\n@import '../../assets/css/def/defaults.def';\n@import '../../assets/css/def/icon.def';\n\n[contenteditable] {\n  transition-duration: .15s;\n  transition-property: color, padding, border-color;\n  position: relative;\n  display: inline-block;\n  padding: 6px 0 4px;\n  border-bottom: 2px solid transparent;\n  white-space: nowrap;\n\n  &[contenteditable=true],\n  &.ce-toggler-hover {\n    margin-right: 1.5em;\n  }\n\n  &[contenteditable=true] {\n    cursor: pointer;\n\n    &:focus {\n      padding: 6px 10px 4px;\n      border-color: $primary;\n      background-color: $white;\n      color: $default-text-color;\n      outline: none;\n      cursor: text;\n    }\n\n    &.ce-toggler-hover:after {\n      display: none;\n    }\n\n    &:after {\n      @extend %icon;\n\n      transition: all .2s;\n      content: 'mode_edit';\n      position: absolute;\n      right: -1.2em;\n      top: 50%;\n      margin-top: -.4em;\n      padding-left: 8px;\n      font-size: 100%;\n      cursor: pointer;\n      opacity: .2;\n    }\n\n    &:hover:after {\n      display: inline;\n      color: $primary;\n      opacity: 1;\n    }\n\n    &:focus:after {\n      display: inline;\n      color: $primary;\n      opacity: 1;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/content-editable/content-editable.ts",
    "content": "import {initNgScope, inject} from '../../../core';\nimport './content-editable.scss';\n\nfunction selectText(element) {\n  const range = window.document.createRange();\n  range.selectNodeContents(element.get(0));\n\n  const sel = window.getSelection();\n  sel.removeAllRanges();\n  sel.addRange(range);\n}\n\nexport default () => {\n  function updateNgModel(scope, value, ngModel) {\n    if (value) {\n      ngModel.$setViewValue(value);\n    } else {\n      ngModel.$rollbackViewValue();\n    }\n\n    inject('$timeout')(() => {\n      if (!ngModel.$valid) {\n        ngModel.$setViewValue(scope.lastValidValue);\n        ngModel.$setValidity('pattern', false);\n      } else {\n        if (scope.lastValidValue !== ngModel.$viewValue) {\n          scope.onChange({prevValue: scope.lastValidValue});\n        }\n\n        scope.lastValidValue = ngModel.$viewValue;\n        ngModel.$setValidity('pattern', true);\n      }\n    });\n  }\n\nreturn {\n    restrict: 'A',\n    require: ['ngModel'],\n    scope: {\n      ceOptions: '=',\n      onChange: '&',\n      onBlur: '&'\n    },\n\n    link: {\n      pre(scope, element, attrs, [ngModel]) {\n        ngModel.$render = () => {\n          scope.lastValidValue = ngModel.$modelValue;\n          element.text(ngModel.$modelValue);\n        };\n\n        initNgScope(scope, {ngModel})\n          .withOptions('ceOptions', {\n            autoEdit: false,\n            toggler: 'always' // always | hover\n          });\n\n        if (scope.options.toggler === 'hover') {\n          element.addClass('ce-toggler-hover');\n        }\n\n        element\n          .attr('spellcheck', false)\n          .on('focusout', () => {\n            updateNgModel(scope, element.text(), ngModel);\n            scope.onBlur();\n          })\n          .on('focus', () => selectText(element))\n          .on('keypress', e => {\n            // enter\n            if (e.keyCode === 13) {\n              element.blur();\n              e.preventDefault();\n              e.stopPropagation();\n\n              return false;\n            }\n          })\n          .on('keyup', e => {\n            // escape\n            if (e.keyCode === 27) {\n              ngModel.$rollbackViewValue();\n              element.blur();\n            }\n        });\n\n        if (scope.options.autoEdit) {\n          attrs.$observe('contenteditable', enabled => {\n            if (enabled === 'true') {\n              element.focus();\n\n              setTimeout(() => {\n                selectText(element);\n              });\n            }\n          });\n        }\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.html",
    "content": "<bi-tooltip bt-text=\"Copy to clipboard\">\n  <bi-toggle>\n    <span class=\"bi-action bi-icon--sm\" ng-click=\"events.onCopy()\">content_copy</span>\n  </bi-toggle>\n</bi-tooltip>\n\n<div class=\"bctc-input\">\n  <textarea ng-model=\"textValue\"></textarea>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.scss",
    "content": "bi-copy-to-clipboard {\n  .bctc-input {\n    position: fixed;\n    left: -1000000px;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.story.ts",
    "content": "export default app => app\n  .story('UI', 'Clipboard')\n    .section('Copy to clipboard', `\n      <bi-copy-to-clipboard ng-non-bindable text=\"'Hello world!'\"></bi-copy-to-clipboard>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/copy-to-clipboard/copy-to-clipboard.ts",
    "content": "import {initNgScope, inject} from '../../../core';\nimport {showToast} from '../../services/toast';\n\nimport template from './copy-to-clipboard.html';\nimport './copy-to-clipboard.scss';\n\nexport default function directive() {\n  return {\n    template,\n    restrict: 'E',\n    transclude: true,\n    scope: {\n      text: '<',\n      lazyText:'&'\n    },\n\n    link: {\n      pre(scope, element) {\n        initNgScope(scope).withEvents({\n          onCopy() {\n            scope.textValue = scope.text || scope.lazyText();\n \n            inject('$timeout')(() => {\n              const input = element.find('textarea');\n\n              input.get(0).focus();\n              (input.get(0) as any).select();\n\n              // tslint:disable-next-line:deprecation\n              document.execCommand('Copy');\n\n              showToast({\n                text: 'Copied to clipboard',\n                hideDelay: 3000,\n                type: 'success',\n              });\n            });\n          },\n        });\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/date-picker/date-picker.scss",
    "content": "bi-date-picker {\n  position: relative;\n\n  .xdsoft_datetimepicker {\n    left: 0 !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/date-picker/date-picker.story.ts",
    "content": "export default app => app\n  .story('UI', 'Datepicker')\n    .section('Datepicker', `\n      <output>{{model}}</output>\n\n      <bi-date-picker ng-non-bindable\n        class=\"bi-grow\"\n        ng-model=\"model\"\n        bdp-options=\"::{dateFormat: 'YYYY-MM-DD HH:mm'}\"\n        placeholder=\"Enter value\"\n      ></bi-date-picker>\n    `, scope => scope.model = '2019-02-01 00:00')\n    .section('Datepicker raw', `\n      <output>{{model2}}</output>\n\n      <bi-date-picker ng-non-bindable\n        class=\"bi-grow\"\n        ng-model=\"model2\"\n        bdp-options=\"::{dateFormat: null}\"\n        placeholder=\"Enter value\"\n      ></bi-date-picker>\n    `, scope => scope.model2 = 1548979200000);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/date-picker/date-picker.ts",
    "content": "import './date-picker.scss';\n\nimport 'jquery-datetimepicker/build/jquery.datetimepicker.full.js';\nimport 'jquery-datetimepicker/jquery.datetimepicker.css';\nimport {assign} from 'lodash';\nimport {initNgScope, createNgModel} from '../../../core';\nimport BiDate from '../../services/date';\n\nfunction getRange(options) {\n  let minDate: Date, maxDate: Date;\n\n  if (options.maxRange) {\n    const range = BiDate.getRange(options.maxRange, {maxDate: options.maxDate});\n\n    maxDate = new Date(range.end);\n    minDate = new Date(range.start);\n  } else {\n    minDate = (options.minDate && new Date(options.minDate)) || undefined;\n    maxDate = (options.maxDate && new Date(options.maxDate)) || undefined;\n  }\n\n  return {minDate, maxDate};\n}\n\nfunction formatter(model, dateFormat) {\n  const date = model && new BiDate(model);\n\n  return date && (dateFormat ? date.asMoment().format(dateFormat) : date.fromUTC().format(BiDate.DATE_FORMAT));\n}\n\nfunction parser(model, dateFormat) {\n  const date = new BiDate(model).toUTC();\n\n  return dateFormat ? date.format(dateFormat) : date.valueOf();\n}\n\nfunction init(scope, element) {\n  let params = {\n    parentID: scope.options.parent === 'self' ? element : 'body',\n    lazyInit: true,\n    value: scope.model,\n    defaultTime: '00:00',\n    minDate: null,\n    maxDate: null,\n    timepicker: scope.options.timepicker,\n    format: scope.options.widgetDateFormat,\n    scrollInput: scope.options.enableScroll,\n    className: scope.options.className,\n    onShow() {\n      if (scope.options.parent === 'self') {\n        setTimeout(() => element.find('.xdsoft_datetimepicker').css({\n          left: 0,\n          top: 34\n        }, 0));\n      }\n    },\n    onChangeDateTime: date => {\n      scope.$apply(() => {\n        scope.model = date && date.valueOf();\n        scope.onChange({date: scope.model});\n      });\n    }\n  };\n\n  params = assign<typeof params, any>(params, getRange(scope.options));\n  element.find('input').datetimepicker(params);\n}\n\nfunction renderer(element, model) {\n  element.find('input').val(model);\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template: `\n      <input\n        class=\"bi-input bi-grow\"\n        ng-class=\"{'bi-input__sm': options.size === 'small'}\"\n        placeholder=\"{{::placeholder}}\"\n        ng-readonly=\"::readonly\"\n      >\n    `,\n    require: ['ngModel', '?errors'],\n    scope: {\n      onChange: '&',\n      bdpOptions: '=',\n      readonly: '='\n    },\n\n    link: {\n      pre(scope, element, attrs, [ngModel, errors]) {\n        createNgModel(scope, ngModel)\n          .formatWith(model => formatter(model, scope.options.dateFormat))\n          .parseWith(model => parser(model, scope.options.dateFormat))\n          .renderWith(model => renderer(element, model));\n\n        initNgScope(scope, {errors})\n          .readonly(scope.readonly)\n          .withOptions('bdpOptions', {\n            size: 'normal',\n            minDate: null,\n            maxDate: null,\n            maxRange: null,\n            dateFormat: BiDate.DATE_FORMAT,\n            timepicker: true,\n            widgetDateFormat: 'Y/m/d H:i',\n            enableScroll: true,\n            className: '',\n            parent: null  // null|self\n          })\n          .withErrors([{\n            name: 'required',\n            text: 'Date is required'\n          }])\n          .thenIfNotReadonly(() => init(scope, element));\n\n        scope.placeholder = attrs.placeholder;\n\n        scope.$on('$destroy', () => element.find('input').datetimepicker('destroy'));\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/draggable/draggable.story.ts",
    "content": "export default app => app\n  .story('UI', 'Draggable')\n    .section('Draggable', `\n      <div ng-non-bindable bi-draggable>\n        Drag me\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/draggable/draggable.ts",
    "content": "import {forEach} from 'lodash';\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: {\n      biDraggable: '&',\n    },\n\n    link(scope, element) {\n      let image;\n\n      element.attr('draggable', true).get(0).addEventListener('dragstart', function(e) {\n        const data = scope.biDraggable();\n\n        image = this.cloneNode(true);\n        image.style.position = 'fixed';\n        image.style.top = '-1000000px';\n        document.body.appendChild(image);\n        e.dataTransfer.setDragImage(image, 8, 10);\n\n        if (typeof data === 'object') {\n          forEach(data, (value, key) => e.dataTransfer.setData(key, value));\n        } else if (data) {\n          e.dataTransfer.setData('Text', data);\n        } else {\n          return false;\n        }\n      });\n\n      element.get(0).addEventListener('dragend', () => image && image.remove());\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.html",
    "content": "<!--  TOGGLE -->\n<div\n  class=\"bi-row bi-grow\"\n  ng-transclude=\"toggle\"\n  ng-mouseenter=\"options.toggleOn === 'hover' && actions.show()\"\n  ng-mouseleave=\"options.toggleOn === 'hover' && options.hideOn === 'hover' && actions.hide()\"\n  ng-mousedown=\"options.toggleOn === 'hover' ? actions.hide() : options.toggleOn === 'click' && actions.toggle()\"\n  ng-class=\"{\n    'bt-readonly': readonly,\n    'bt-caret': options.caret && !readonly\n  }\"\n></div>\n\n<!-- CONTENT -->\n<div\n  class=\"bd-content bi-theme--lighter\"\n  ng-if=\"vm.enabled\"\n  ng-style=\"{visibility: vm.visible ? 'visible' : 'hidden'}\"\n>\n  <div ng-transclude></div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.scss",
    "content": "@import '../../assets/css/def/icon.def';\n@import '../../assets/css/def/animations.def';\n@import '../../assets/css/def/defaults.def';\n\nbi-dropdown {\n  position: relative;\n  display: inline-flex;\n\n  [ng-transclude=\"toggle\"] {\n    display: inline-flex;\n    user-select: none;\n    cursor: pointer;\n\n    &.bt-caret {\n      &:after {\n        @extend %icon;\n\n        content: 'arrow_drop_down';\n        font-size: 18px;\n        vertical-align: text-top;\n      }\n    }\n\n    &.bt-readonly {\n      cursor: default;\n    }\n\n    bi-toggle {\n      display: inline-flex;\n    }\n  }\n\n  .bd-content {\n    position: fixed;\n    border-radius: 3px;\n    z-index: 200;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.story.ts",
    "content": "export default app => app\n  .story('UI', 'Dropdown')\n    .section('Dropdown', `\n      <bi-dropdown ng-non-bindable>\n        <bi-toggle class=\"bi-action bi-align bi-space-h--x05\">\n          <i class=\"bi-icon\">menu</i>\n          <span class=\"bi-label--sm\">Default</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n\n      <bi-dropdown bd-options=\"{align: 'right'}\" ng-non-bindable>\n        <bi-toggle class=\"bi-action bi-align bi-space-h--x05\">\n          <i class=\"bi-icon\">menu</i>\n          <span class=\"bi-label--sm\">Align right</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n\n      <bi-dropdown bd-options=\"{align: 'center'}\" ng-non-bindable>\n        <bi-toggle class=\"bi-action bi-align bi-space-h--x05\">\n          <i class=\"bi-icon\">menu</i>\n          <span class=\"bi-label--sm\">Center</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n\n      <bi-dropdown bd-options=\"{position: 'right'}\" ng-non-bindable>\n        <bi-toggle class=\"bi-action bi-align bi-space-h--x05\">\n          <i class=\"bi-icon\">menu</i>\n          <span class=\"bi-label--sm\">Position right</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n\n      <bi-dropdown bd-options=\"{hideOnClick: false}\" ng-non-bindable>\n        <bi-toggle class=\"bi-action bi-align bi-space-h--x05\">\n          <i class=\"bi-icon\">menu</i>\n          <span class=\"bi-label--sm\">Don't hide on menu click</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n\n      <bi-dropdown bd-options=\"{toggleOn: 'hover', hideOn: 'click'}\" ng-non-bindable>\n        <bi-toggle class=\"bi-align bi-space-h--x05\">\n          <i class=\"bi-icon bi-muted\">menu</i>\n          <span class=\"bi-label--sm\">Show on hover hide on click</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n\n      <bi-dropdown bd-options=\"{toggleOn: 'hover', delay: {show: 300}}\" ng-non-bindable>\n        <bi-toggle class=\"bi-align bi-space-h--x05\">\n          <i class=\"bi-icon bi-muted\">menu</i>\n          <span class=\"bi-label--sm\">With delay</span>\n        </bi-toggle>\n\n        <ul class=\"bi-dropdown-menu\">\n          <li>Option 1</li>\n          <li>Option 2</li>\n          <li>Option 3</li>\n        </ul>\n      </bi-dropdown>\n    `)\n    .section('Dropdown menu', `\n      <ul class=\"bi-dropdown-menu\">\n        <li class=\"selected\">Selected option</li>\n        <li disabled>Disabled option</li>\n        <li class=\"bi-dropdown-separator\"></li>\n        <li>Another option</li>\n      </ul>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dropdown/dropdown.ts",
    "content": "import {initNgScope, inject, utils} from '../../../core';\nimport Popper from 'popper.js';\n\nimport './dropdown.scss';\nimport template from './dropdown.html';\n\nconst {onKey, onBlur} = utils.dom;\nlet instances = [];\n\nfunction setClasses(element, popperActualPlacement) {\n  const [position_, align_] = popperActualPlacement.split('-');\n  let parsedAlign = '';\n  if (!align_) {\n    parsedAlign = 'center';\n  }\n  else if (align_ === 'start') {\n    parsedAlign = 'left';\n  } else {\n    parsedAlign = 'right'\n  }\n  element.removeClass(['top', 'bottom', 'left', 'right'].map(pos => `bd-position--${pos}`).join(' '));\n  element.addClass(`bd-position--${position_}`);\n  element.addClass(`bd-align--${parsedAlign}`);\n}\n\nfunction show(scope, element) {\n  if (scope.options.hideOthers) {\n    instances = instances.filter(instance => {\n      instance.hide();\n      return false;\n    });\n  }\n\n\n  instances.push({hide: () => scope.actions.hide(true)});\n\n  scope.vm.toggleEnabled(true);\n  const timeout = inject('$timeout')\n  return timeout(() => timeout(() => {\n    const content = element.find('.bd-content');\n    const {position, align} = scope.options;\n\n    let width = 'auto';\n    let minWidth = 'auto';\n\n    let popperPlacement = position;\n    switch (align) {\n      case 'left':\n        popperPlacement += '-start'\n        break;\n      case 'center':\n        break;\n      case 'right':\n        popperPlacement += '-end';\n        break;\n      default:\n    }\n    if (!scope.popper) {\n      scope.popper = new Popper(element.get(0), content.get(0), {\n        placement: popperPlacement,\n        positionFixed: true,\n        modifiers: {\n          preventOverflow: {\n            boundariesElement: 'viewport',\n            priority: ['bottom', 'top']\n          }\n        },\n        onCreate(data) {\n          setClasses(element, data.placement)\n        },\n        onUpdate(data) {\n          setClasses(element, data.placement)\n        }\n      });\n    }\n\n    switch (scope.options.minWidth) {\n      case 'toggle':\n        minWidth = element.width();\n        break;\n      default:\n    }\n\n    if (!scope.options.minWidth) {\n      switch (scope.options.width) {\n        case 'toggle':\n          width = element.width();\n          break;\n        default:\n      }\n    }\n\n    content.css({\n      width,\n      minWidth\n    });\n\n    scope.vm.toggle(true);\n\n    scope.onShow();\n  }))\n}\n\n\nfunction hide(scope, mute = false) {\n  scope.vm.toggle(false);\n\n  if (scope.popper) {\n    scope.popper.destroy();\n    scope.popper = null;\n  }\n\n  if (!mute) {\n    scope.onHide();\n  }\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    transclude: {\n      toggle: 'biToggle'\n    },\n    scope: {\n      bdIsOpen: '=?',\n      bdOptions: '<',\n      onShow: '&',\n      onHide: '&',\n      readonly: '='\n    },\n\n    link: {\n      pre(scope, element, attrs) {\n        let cleaners = [];\n        let timeoutPromise;\n        const timeout = inject('$timeout');\n\n        initNgScope(scope)\n          .readonly(scope.readonly)\n          .withOptions('bdOptions', {\n            align: 'left',      /* left|right|center */\n            position: 'bottom', /* bottom|top|right|left */\n            width: 'content',   /* content|toggle */\n            minWidth: null,     /* content|toggle */\n            toggleOn: 'click',  /* click|hover|manual */\n            hideOn: 'hover',    /* click|hover */\n            hideOnClick: true,\n            hideOthers: true,\n            delay: {\n              show: 0\n            },\n            caret: false\n          })\n          .withVM({\n            $init() {\n              const toggle = this.toggle.bind(this);\n              this.toggle = enabled => {\n                toggle(enabled);\n\n                inject('$timeout')(() => scope.bdIsOpen = this.enabled);\n\n                return this.enabled;\n              };\n            }\n          })\n          .withEditableActions({\n            toggle(enabled) {\n              if (typeof enabled === 'undefined') {\n                enabled = scope.vm.enabled;\n              } else {\n                enabled = !enabled;\n              }\n\n              if (enabled) {\n                scope.actions.hide();\n              } else {\n                scope.actions.show();\n              }\n            },\n            show() {\n              timeoutPromise = inject('$timeout')(() => show(scope, element).then(() => {\n                cleaners = [\n                  onKey('escape', (off) => {\n                    scope.actions.hide();\n                    off();\n                  }, scope),\n\n                  onBlur(element, (off, child) => {\n                    if (\n                      child &&\n                      (\n                        scope.options.hideOnClick === false ||\n                        child.closest('bi-toggle').length ||\n                        child.closest('[disabled]').length\n                      )\n                    ) {\n                      return false;\n                    }\n\n                    scope.actions.hide();\n                    off();\n                  }, scope)\n                ];\n              }), scope.options.delay.show);\n            },\n            hide(mute = false) {\n              timeout.cancel(timeoutPromise);\n              cleaners.forEach(cleaner => cleaner());\n              hide(scope, mute);\n            }\n          });\n\n        scope.$watch('bdIsOpen', (isOpen, prev) => {\n          if (isOpen !== prev && isOpen !== scope.vm.enabled) {\n            scope.actions.toggle(isOpen);\n          }\n        });\n        scope.$on('$destroy', () => {\n          if (scope.popper) {\n            scope.popper.destroy();\n            scope.popper = null;\n          }\n        });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/droppable/droppable.story.ts",
    "content": "export default app => app\n  .story('UI', 'Droppable')\n    .section('Droppable', `\n      <div ng-non-bindable bi-draggable=\"onDrag()\">\n        Drag me\n      </div>\n      <div ng-non-bindable bi-droppable=\"onDrop(foo)\">\n        Drop here\n      </div>\n\n      <output>{{foo}}</output>\n    `, scope => {\n      scope.onDrag = () => {\n        return {foo: 1};\n      };\n\n      scope.onDrop = foo => {\n        scope.foo = foo;\n      };\n    });\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/droppable/droppable.ts",
    "content": "import {utils} from '../../../core';\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: {\n      biDroppable: '&',\n    },\n\n    link(scope, element) {\n      element.get(0).addEventListener('dragover', e => {\n        e.preventDefault();\n        e.stopPropagation();\n      });\n\n      element.get(0).addEventListener('drop', e => {\n        e.preventDefault();\n        e.stopPropagation();\n\n        const data = e.dataTransfer.types.reduce((res, type) => {\n          res[type] = e.dataTransfer.getData(type);\n          return res;\n        }, {});\n\n        utils.scope.safeApply(scope, () => scope.biDroppable(data));\n      });\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dual-action/dual-action.html",
    "content": "<span\n  class=\"bi-action--btn\"\n  ng-click=\"events.toggle()\"\n  ng-class=\"{true: 'bi-danger', false: 'bi-success'}[bdaIsOn]\"\n>{{bdaIsOn ? bdaOnText : bdaOffText}}</span>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dual-action/dual-action.scss",
    "content": "@import '../../assets/css/def/colors.def.scss';\n\nbi-dual-action {\n\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/dual-action/dual-action.ts",
    "content": "import {initNgScope, inject} from '../../../core';\nimport template from './dual-action.html';\nimport './dual-action.scss';\n\nexport default () => {\n  return {\n    restrict: 'EA',\n    template,\n    scope: {\n      bdaIsOn: '=',\n      bdaOnText: '@',\n      bdaOffText: '@',\n      bdaOnChange: '&'\n    },\n\n    link: {\n      pre(scope) {\n        initNgScope(scope).withEvents({\n          toggle() {\n            inject('$q').when(scope.bdaOnChange({isOn: !scope.bdaIsOn})).then(() => scope.bdaIsOn = !scope.bdaIsOn);\n          }\n        });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/editable/editable.html",
    "content": "<div ng-form=\"beForm\" class=\"bi-s-v bi-c-h bi-grow\">\n  <div class=\"be-content bi-c-h bi-grow\"></div>\n\n  <span class=\"bi-danger\" ng-if=\"vm.edit.enabled && vm.error.enabled\">\n    {{::vm.error.value}}\n  </span>\n\n  <div\n    class=\"be-footer bi-justify-right bi-s-h bi-r-h bi-dont-grow bi-fade-in\"\n    ng-if=\"options.mode === 'toggle' && vm.edit.enabled\"\n  >\n    <button\n      type=\"button\"\n      class=\"bi-button\"\n      ng-if=\"!vm.loading.enabled\"\n      ng-click=\"events.onCancel()\"\n    >cancel</button>\n\n    <button\n      type=\"button\"\n      class=\"bi-button--primary\"\n      ng-disabled=\"!vm.save.isEnabled()\"\n      ng-click=\"events.onSubmit()\"\n      ng-class=\"{'bi-button-loader': vm.loading.enabled}\"\n    >\n      <span>{{options.saveText}}</span>\n    </button>\n  </div>\n</div>\n\n<span\n  class=\"bi-fade-in\"\n  be-controls\n  ng-show=\"!vm.edit.enabled && events.onToggle && options.mode === 'toggle'\"\n  ng-click=\"events.onToggle(true)\"\n>\n  <i class=\"bi-action bi-icon bi-fade-in\">edit</i>\n</span>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/editable/editable.scss",
    "content": "@import '../../assets/css/def/colors.def.scss';\n\nbi-editable {\n  position: relative;\n  display: block;\n\n  &.be--editing {\n    > [be-controls] {\n      .bi-icon {\n        font-size: 18px;\n      }\n    }\n  }\n\n  [be-controls] {\n    .bi-action {\n      font-size: 16px;\n      color: $green--300;\n\n      &:hover {\n        color: darken($green--300, 10);\n      }\n    }\n  }\n\n  > [be-controls] {\n    position: absolute;\n    top: 0;\n    right: 0;\n  }\n\n  .be-footer {\n    flex-basis: 30px;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/editable/editable.story.ts",
    "content": "export default app => app\n.story('UI', 'Editable')\n  .section('Editable', `\n    <bi-editable ng-non-bindable ng-model=\"model\">\n      <div class=\"bi-align bi-space-h\">\n        <input class=\"bi-input\" ng-disabled=\"!be.edit\" ng-model=\"be.value\">\n        <div be-controls></div>\n      </div>\n    </bi-editable>\n\n    <output>{{model}}</output>\n  `, scope => scope.model = 'edit me')\n  .section('options.mode=edit', `\n    <bi-editable ng-non-bindable ng-model=\"model\" be-options=\"::{mode: 'edit'}\">\n      <div class=\"bi-align bi-space-h\">\n        <input class=\"bi-input\" ng-disabled=\"!be.edit\" ng-model=\"be.value\">\n        <div be-controls></div>\n      </div>\n    </bi-editable>\n`)\n  .section('Custom controls', `\n    <bi-editable ng-non-bindable ng-model=\"model\">\n      <div class=\"bi-align bi-space-h\">\n        <input class=\"bi-input\" ng-disabled=\"!be.edit\" ng-model=\"be.value\">\n        <div be-controls>\n          <i class=\"bi-action--rnd bi-icon--xs\">add</i>\n        </div>\n      </div>\n    </bi-editable>\n`);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/editable/editable.ts",
    "content": "import {cloneDeep} from 'lodash';\nimport angular from 'angular';\nimport {initNgScope, inject} from '../../../core';\n\nimport template from './editable.html';\nimport './editable.scss';\n\nfunction finish(vm) {\n  vm.edit.toggle(false);\n  vm.error.toggle(false);\n  vm.error.value = '';\n}\n\nexport default () => {\n  return {\n    restrict: 'EA',\n    template,\n    require: 'ngModel',\n    transclude: true,\n    scope: {\n      beOptions: '=',\n      onToggle: '&',\n      onChange: '&',\n      readonly: '='\n    },\n\n    link(scope, element, attr, ngModel, transclude) {\n      let childScope = null;\n\n      // we're not deep-cloning ngModel.$viewValue as an optimization\n      // it'll be cloned when toggling edit mode\n      ngModel.$render = () => childScope.be.value = ngModel.$viewValue;\n\n      function submit(mute = false) {\n        // check if the model was changed\n        if (angular.equals(ngModel.$viewValue, childScope.be.value)) {\n          if (!mute) {\n            finish(scope.vm);\n          }\n\n          return;\n        }\n\n        // save reference to original value\n        const originalValue = ngModel.$viewValue;\n\n        // commit new value (can be invalid)\n        ngModel.$setViewValue(cloneDeep(childScope.be.value));\n\n        if (!mute) {\n          // wait for change to take effect\n          inject('$timeout')(() => {\n            // notify that a change has been made\n            const promise = scope.onChange();\n\n            if (!promise) {\n              finish(scope.vm);\n              return;\n            }\n\n            if (promise) {\n              scope.vm.loading.toggle(true);\n\n              promise.then(() => finish(scope.vm), error => {\n                // commit original value if promise was rejected\n                ngModel.$setViewValue(originalValue);\n\n                // show error\n                scope.vm.error.toggle(true);\n                scope.vm.error.value = error && error.data && error.data.errorDescription || 'Unknown error';\n              })\n              .finally(() => scope.vm.loading.toggle(false));\n            }\n          });\n        }\n      }\n\n      initNgScope(scope)\n        .readonly(scope.readonly)\n        .withOptions('beOptions', {\n          saveText: 'save',\n          mode: 'toggle'  // toggle(shows toggle button)|edit(in edit state by default)\n        })\n        .withVM({\n          save: {\n            isEnabled() {\n              return scope.beForm.$valid && scope.beForm.$dirty;\n            }\n          },\n          loading: {},\n          error: {\n            value: ''\n          },\n          edit: {\n            $init() {\n              this._toggle = this.toggle.bind(this);\n              this.toggle = function(value) {\n                this._toggle(value);\n\n                element.toggleClass('be--editing', this.enabled);\n                scope.beForm.$setPristine(!this.enabled);\n              };\n            }\n          }\n        })\n        .withEditableEvents({\n          onToggle(focus = false) {\n            scope.vm.edit.toggle();\n\n            if (scope.vm.edit.enabled) {\n              // make a deep copy of the model (so we can check for changes when submitting)\n              childScope.be.value = cloneDeep(ngModel.$viewValue);\n\n              if (focus) {\n                inject('$timeout')(() => {\n                  element.find('.bi-input').first().focus();\n                });\n              }\n\n              scope.onToggle();\n            }\n          },\n          onSubmit(mute = false) {\n            submit(mute);\n          },\n          onCancel() {\n            // rollback changes (will call renderer)\n            ngModel.$rollbackViewValue();\n\n            finish(scope.vm);\n          }\n        });\n\n      transclude((clone, transcludedScope) => {\n        childScope = transcludedScope;\n\n        const elementControls = element.find('[be-controls]');\n        let cloneControls = clone.find('[be-controls]');\n        cloneControls = cloneControls.length ? cloneControls : clone.filter('[be-controls]');\n\n        if (cloneControls.length) {\n          const cloneControlsChildren = cloneControls.children();\n\n          cloneControls.replaceWith(elementControls);\n\n          if (cloneControlsChildren.length) {\n            elementControls.html(cloneControlsChildren);\n          }\n        }\n\n        element.find('.be-content').html(clone);\n\n        childScope.be = {\n          get edit() {\n            return scope.vm.edit.enabled;\n          },\n          value: null,\n          save() {\n            submit();\n          }\n        };\n      });\n\n      if (scope.options.mode === 'edit' && scope.events.onToggle) {\n        scope.events.onToggle();\n\n        childScope.$watch('be.value', () => scope.events.onSubmit(true), true);\n      }\n\n      scope.$on('$destory', () => childScope.$destroy());\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/filter/filter-items.ts",
    "content": "import {set} from 'lodash';\nimport {inject} from '../../../core';\n\nexport default () => {\n  return {\n    restrict: 'A',\n    require: ['ngModel', '^biFilter'],\n    scope: false,\n\n    link(scope, element, attrs, [ngModel, biFilter]) {\n      let mute = false;\n\n      const hook = items => {\n        if (!mute) {\n          biFilter.setItems(items);\n        }\n\n        return items;\n      };\n\n      ngModel.$formatters.push(hook);\n\n      biFilter.on('filtered', (items) => {\n        mute = true;\n        set(scope, attrs.ngModel, items);\n        inject('$timeout')(() => mute = false);\n      });\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/filter/filter-term.ts",
    "content": "import {inject} from '../../../core';\n\nexport default () => {\n  return {\n    restrict: 'A',\n    require: ['ngModel', '^biFilter'],\n    scope: false,\n\n    link(scope, element, attrs, [ngModel, biFilter]) {\n      const hook = items => {\n        inject('$timeout')(() => biFilter.filter());\n        return items;\n      };\n\n      ngModel.$parsers.push(hook);\n      biFilter.addTerm(() => ngModel.$modelValue);\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/filter/filter.story.ts",
    "content": "export default app => app\n  .story('UI', 'Filter')\n    .section('Filter', `\n      <description>Allows to filter items of any directive which uses an array as input.</description>\n\n      <bi-filter on-filter=\"filter(item, terms)\" ng-non-bindable style=\"width: 400px;\">\n        <div class=\"bi-column bi-space-v\">\n          <bi-search bi-filter-term ng-model=\"text\" bi-focus placeholder=\"Lets filter some tags\"></bi-search>\n          <bi-tags bi-filter-items bi-options=\"tag for tag in tags\" bt-options=\"{freetext: true}\" ng-model=\"tags\"></bi-tags>\n        </div>\n      </bi-filter>\n    `, scope => {\n      scope.text = 'on';\n      scope.tags = ['one', 'two', 'three'];\n\n      scope.filter = (item, [term]) => {\n        return item.indexOf(term) !== -1;\n      };\n    });\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/filter/filter.ts",
    "content": "import {srv} from '../../../core';\n\nexport class Controller extends srv.eventEmitter.EventEmitter {\n  private readonly terms: Function[] = [];\n  private items: any[];\n  private filtered: any[];\n\n  constructor(private readonly $scope) {\n    super();\n  }\n\n  private getTerms() {\n    return this.terms.map(term => term());\n  }\n\n  private reset() {\n    this.filtered = this.items;\n  }\n\n  public setItems(items) {\n    this.items = items;\n    this.filter();\n  }\n\n  public addTerm(term: Function) {\n    this.terms.push(term);\n  }\n\n  public filter() {\n    const terms = this.getTerms();\n\n    this.$scope.onChange();\n\n    if (terms.every(term => !term)) {\n      this.reset();\n      this.$scope.onReset();\n    } else {\n      this.filtered = this.items && this.items.filter(item => this.$scope.onFilter({item, terms}));\n    }\n\n    this.fire('filtered', this.filtered);\n  }\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    transclude: true,\n    template: '<div ng-transclude></div>',\n    scope: {\n      onFilter: '&',\n      onReset: '&',\n      onChange: '&'\n    },\n    controller: ['$scope', Controller]\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/filter/index.ts",
    "content": "export {default as filter} from './filter';\nexport {default as filterTerm} from './filter-term';\nexport {default as filterItems} from './filter-items';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/focus/focus-if.ts",
    "content": "import {inject} from '../../../core';\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: {\n      biFocusIf: '<'\n    },\n\n    link(scope, element, attr) {\n      scope.$watch('biFocusIf', value => value && inject('$timeout')(() => {\n        element = element.is('.bi-input') ? element : element.find('.bi-input');\n        inject('$timeout')(() => element.get(0).focus());\n      }));\n   }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/focus/focus.story.ts",
    "content": "import {inject} from '../../../core';\n\nexport default app => app\n  .story('UI', 'Focus')\n    .section('Focus', `\n      <input class=\"bi-input\" bi-focus placeholder=\"I should be focused\" ng-non-bindable/>\n    `)\n    .section('Focus If', `\n      <bi-simple-select ng-model=\"data\" bi-options=\"item for item in ::[1, 2]\" ng-non-bindable/>\n      <input class=\"bi-input\" bi-focus-if=\"data\" placeholder=\"I should be focused when selectbox is populated\" ng-non-bindable/>\n    `)\n   ;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/focus/focus.ts",
    "content": "import {inject} from '../../../core';\n\nexport default () => {\n  return {\n    restrict: 'A',\n\n    link(scope, element) {\n      inject('$timeout')(() => {\n        element = element.is('.bi-input') ? element : element.find('.bi-input');\n        inject('$timeout')(() => element.get(0).focus());\n      });\n   }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/focus/index.ts",
    "content": "export {default as focus} from './focus';\nexport {default as focusIf} from './focus-if';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/foldable/foldable.html",
    "content": "<span class=\"bf-style--{{::options.style}}\" bf-controls>\n  <i\n    class=\"bi-action bi-icon bi-fade-in bf-btn bf-no-transition\"\n    ng-click=\"events.onToggle($event)\"\n    ng-class=\"{'bf-folded' : vm.fold.enabled, 'bf-unfolded': !vm.fold.enabled}\"\n  ></i>\n</span>\n\n<div class=\"bf-content\"></div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/foldable/foldable.scss",
    "content": "bi-foldable {\n  display: block\n}\n\nbi-foldable,\n[bi-foldable] {\n  [bf-toggle] {\n    cursor: pointer;\n  }\n\n  [bf-controls] {\n    display: inline-flex;\n\n    &.bf-style--folder {\n      font-size: 0;\n\n      > i {\n        font-size: 19px;\n\n        &:before {\n          content: 'arrow_drop_down';\n        }\n      }\n    }\n  }\n\n  .bf-btn {\n    transition: .3s;\n  }\n\n  .bf-folded {\n    transform: rotate(-90deg);\n\n    &:before {\n      content: 'expand_more';\n    }\n  }\n\n  .bf-unfolded {\n    &:before {\n      content: 'expand_more';\n    }\n  }\n\n  .bf-no-transition {\n    transition: none !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/foldable/foldable.story.ts",
    "content": "export default app => app\n  .story('UI', 'Foldable')\n  .section('Simple fold', `\n    <div class=\"bi-panel--grey bi-grow\" ng-non-bindable bi-foldable is-folded=\"false\">\n      <div class=\"bi-panel-header\" bf-toggle>\n        <span class=\"bi-panel-title\">bi-foldable</span>\n        <div bf-controls></div>\n      </div>\n      <div class=\"bi-panel-content bi-space-v\" ng-show=\"!bf.fold\">\n        <div class=\"bi-space-v\">\n          <div>\n            Binding from outside can go here:\n            {{outsideBinding}}\n          </div>\n          <div>\n            fold status: {{bf.fold}}\n          </div>\n        </div>\n      </div>\n    </div>\n  `, scope => {\n    scope.outsideBinding = `I'm a bidning set from outside scope`;\n  })\n  .section('Fold with saved state', `\n    <div class=\"bi-panel--grey bi-grow\" bi-foldable ng-non-bindable is-folded=\"false\" state-name=\"'someStateName'\">\n      <div class=\"bi-panel-header\" bf-toggle>\n        <span class=\"bi-panel-title\">bi-foldable</span>\n        <div bf-controls></div>\n      </div>\n      <div class=\"bi-panel-content bi-space-v\" ng-show=\"!bf.fold\">\n        <div class=\"bi-space-v\">\n          <div>\n            fold status: {{bf.fold}}\n          </div>\n        </div>\n      </div>\n    </div>\n  `)\n  .section('options.style = folder', `\n    <div bi-foldable bf-options=\"::{style: 'folder'}\" is-folded=\"true\" ng-non-bindable>\n      <div class=\"bi-align\">\n        <span bf-controls></span>\n        <span bf-toggle>folder</span>\n      </div>\n\n      <div ng-if=\"!bf.fold\">folder content</div>\n    </div>\n  `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/foldable/foldable.ts",
    "content": "import {initNgScope, inject} from '../../../core';\n\nimport template from './foldable.html';\nimport './foldable.scss';\n\nexport default () => {\n  return {\n    restrict: 'EA',\n    template,\n    transclude: true,\n    scope: {\n      isFolded: '=',\n      stateName: '<?',\n      bfOptions: '<?',\n      onToggle: '&'\n    },\n\n    link(scope: ng.IScope, element: JQuery, attr: ng.IAttributes, ctrls, transclude: ng.ITranscludeFunction) {\n      const $timeout: ng.ITimeoutService = inject('$timeout');\n\n      const scopeHelper = initNgScope(scope)\n        .withOptions('bfOptions', {\n          style: 'default'  // default|folder\n        })\n        .withVM({\n          fold: {\n            $import({fold}) {\n              this.enabled = fold;\n            },\n            $export() {\n              return {fold: this.enabled};\n            }\n          }\n        })\n        .withEvents({\n          onToggle(event: JQueryEventObject) {\n            event.preventDefault();\n            event.stopPropagation();\n\n            scope.vm.fold.toggle();\n\n            if (scope.state) {\n              scope.state.save();\n            }\n\n            inject('$timeout')(() => {\n              if (typeof scope.isFolded !== 'undefined') {\n                 scope.isFolded = scope.vm.fold.enabled;\n              }\n\n              scope.onToggle({fold: scope.vm.fold.enabled});\n            });\n          }\n        });\n\n      if (scope.stateName) {\n        scopeHelper.withState(scope.stateName, 'fold', {});\n      }\n\n      transclude((clone, transcludedScope) => {\n        let toggleElement = clone.find('[bf-toggle]');\n        toggleElement = toggleElement.length ? toggleElement : clone.filter('[bf-toggle]');\n\n        const controlsElement = element.find('[bf-controls]').remove();\n        let targetControlsElement = clone.find('[bf-controls]');\n        targetControlsElement = targetControlsElement.length ? targetControlsElement : clone.filter('[bf-controls]');\n\n        if (toggleElement.length) {\n          toggleElement.on('click', event => {\n            scope.events.onToggle(event);\n            scope.$digest();\n          });\n\n          scope.$on('$destory', () => $(toggleElement).off('click'));\n        }\n\n        if (targetControlsElement.length) {\n          targetControlsElement.replaceWith(controlsElement);\n        }\n\n        element.find('.bf-content').replaceWith(clone);\n\n        transcludedScope.bf = {\n          get fold() {\n            return scope.vm.fold.enabled;\n          }\n        };\n\n        $timeout(() => clone.find('.bf-no-transition').removeClass('bf-no-transition'));\n\n        scope.$watch('isFolded', (isFolded: boolean) => typeof isFolded === 'boolean' && scope.vm.fold.toggle(isFolded));\n      });\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/html/html.ts",
    "content": "import { inject } from '../../../core';\n\nexport default () => {\n  let timeout;\n\n  return {\n    restrict: 'A',\n    scope: {\n      biHtml: '&',\n      biHtmlDelay: '@'\n    },\n\n    async link(scope, element) {\n      const delay = parseInt(scope.biHtmlDelay, 10);\n      const html = scope.biHtml({scope: scope.$parent});\n\n      if (!html) {\n        return;\n      }\n\n      const render = () => element.html(html.html);\n\n      if (!isNaN(scope.biHtmlDelay)) {\n        (timeout = timeout || inject('$timeout'))(render, delay);\n      } else {\n        render();\n      }\n   }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/icon-badge/icon-badge.html",
    "content": "<div class=\"bi-icon-with-badge\">\n  <div\n    class=\"bi-badge bi-badge--sm\"\n    ng-class=\"{'bi-icon-badge-wide': count > 99}\"\n    ng-if=\"!hide\"\n  >\n    {{countValue()}}\n  </div>\n  <ng-transclude></ng-transclude>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/icon-badge/icon-badge.scss",
    "content": "@import '../../assets/css/def/defaults.def';\n@import '../../assets/css/def/colors.def';\n\n.bi-icon-with-badge {\n  position: relative;\n\n  .bi-icon-badge-wide {\n    font-size: 0.45rem;\n    right: -3px;\n  }\n\n  .bi-badge {\n    position: absolute;\n    z-index: 1;\n    right: 0;\n    padding: 0 3px;\n  }\n\n  ng-transclude {\n    display: block;\n    line-height: 0;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/icon-badge/icon-badge.ts",
    "content": "import './icon-badge.scss';\nimport template from './icon-badge.html';\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    transclude: true,\n    scope: { count: '<', hide: '<' },\n    link(scope) {\n      scope.countValue = () => (scope.count < 100 ? scope.count : '99+');\n    },\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/index.ts",
    "content": "export { default as stateLoader } from './state-loader/state-loader';\nexport { default as dropdown } from './dropdown/dropdown';\nexport { default as tbl } from './table/table';\nexport { default as tblHeader } from './table/header/table-header';\nexport { default as tblRow } from './table/row/table-row';\nexport { default as contenteditable } from './content-editable/content-editable';\nexport { default as editable } from './editable/editable';\nexport { default as foldable } from './foldable/foldable';\nexport { default as datePicker } from './date-picker/date-picker';\nexport { focus, focusIf } from './focus';\nexport { default as progressLine } from './progress-line/progress-line';\nexport { default as simpleSelect } from './simple-select/simple-select';\nexport { default as info } from './info/info';\nexport { default as iconWithBadge } from './icon-badge/icon-badge';\nexport { default as tooltip } from './tooltip/tooltip';\nexport { default as tags } from './tags/tags';\nexport { default as tabs } from './tabs/tabs';\nexport { default as tabsRouter } from './tabs/tabs-router';\nexport { default as onImageLoad } from './on-image-load/on-image-load';\nexport { default as dualAction } from './dual-action/dual-action';\nexport { default as search } from './search/search';\nexport { default as maximizable } from './maximizable/maximizable';\nexport { default as copyToClipboard } from './copy-to-clipboard/copy-to-clipboard';\nexport { default as progressGauge } from './progress-gauge/progress-gauge';\nexport { default as draggable } from './draggable/draggable';\nexport { default as droppable } from './droppable/droppable';\nexport { filter, filterTerm, filterItems } from './filter';\nexport { default as html } from './html/html';\nexport { default as breadcrumbs } from './breadcrumbs/breadcrumbs';\nexport { scrollTo } from './scroll';\nexport { default as resizable } from './resizable/resizable';\nexport { default as infiniteScroll } from './infinite-scroll/infinite-scroll';\nexport { default as keyNav } from './key-nav/key-nav';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/infinite-scroll/infinite-scroll.ts",
    "content": "import {throttle} from 'lodash';\nimport {initNgScope, inject} from '../../../core';\nimport {BufferedCollection} from '../../../core/srv/collections';\n\nconst shouldFetchMore = element => {\n  const viewportHeight = element.height();\n  const contentHeight = element.get(0).scrollHeight;\n  const topOffset = element.scrollTop();\n\n  return contentHeight - topOffset - viewportHeight < 40;\n}\n\nconst sync = (scope, collection: BufferedCollection) => {\n  inject('$timeout')(() => scope.bisBuffer = collection.models.map(({data}) => data));\n}\n\nconst getScrollhandler = (scope, element) => throttle(() => {\n  const {collection} = scope.vm;\n\n  if (collection && collection.hasMore() && shouldFetchMore(element)) {\n    collection.more();\n    sync(scope, collection);\n  }\n\n  return true;\n}, 500);\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: {\n      biInfiniteScroll: '<',\n      bisOptions: '<',\n      bisBuffer: '=',\n    },\n\n    link(scope, element) {\n      initNgScope(scope)\n        .withOptions('bisOptions', {\n          chunkSize: 20\n        })\n        .withVM({\n          collection: null\n        });\n\n      element.on('scroll', getScrollhandler(scope, element));\n\n      scope.$watch('biInfiniteScroll', items => {\n        if (!items || typeof items.length === 'undefined') {\n          return;\n        }\n\n        const collection = new BufferedCollection().setChunkSize(scope.options.chunkSize);\n        collection.fetch();\n        collection.feed(items);\n\n        if (items.length < scope.options.chunkSize) {\n          collection.seal();\n        }\n\n        scope.vm.collection = collection;\n\n        sync(scope, collection);\n      });\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/info/info.html",
    "content": "<bi-dropdown bd-options=\"{toggleOn: 'hover', hideOnClick: false, align: 'center'}\">\n  <bi-toggle class=\"bi-icon\">info_outline</bi-toggle>\n  <div class=\"bi-info-content\">\n    <div class=\"bi-info-backdrop\"></div>\n    <div ng-transclude></div>\n  </div>\n</bi-dropdown>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/info/info.scss",
    "content": "@import '../../assets/css/def/defaults.def';\n@import '../../assets/css/def/colors.def';\n\nbi-info {\n  width: 17px;\n  height: 18px;\n\n  bi-dropdown {\n    bi-toggle {\n      display: inline-block;\n      height: 18px;\n      font-size: 18px !important;\n      color: $primary;\n    }\n  }\n\n  .bi-info-content {\n    position: relative;\n    margin-top: 4px;\n    padding: 8px 10px;\n    color: $white;\n    font-size: 12px;\n    white-space: nowrap;\n    box-shadow: $default-box-shadow;\n\n    &:before {\n      position: absolute;\n      content: '';\n      top: -6px;\n      left: 50%;\n      width: 0;\n      height: 0;\n      margin-left: -6px;\n      border-style: solid;\n      border-width: 0 6px 6px 6px;\n      border-color: transparent transparent #000000 transparent;\n      opacity: .75;\n    }\n\n    > .bi-info-backdrop {\n      position: absolute;\n      top: 0;\n      left: 0;\n      right: 0;\n      bottom: 0;\n      border-radius: 3px;\n      background-color: $black;\n      opacity: .75;\n    }\n\n    > [ng-transclude] {\n      position: relative;\n      z-index: 1;\n\n      > * {\n        text-transform: initial;\n        font-weight: normal;\n        white-space: nowrap;\n      }\n    }\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/info/info.ts",
    "content": "import './info.scss';\nimport template from './info.html';\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    transclude: true,\n    scope: false\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/key-nav/key-nav.ts",
    "content": "import {values, isUndefined } from 'lodash';\nimport angular from 'angular';\nimport {initNgScope, inject, utils} from '../../../core';\n\nconst NAVIGATION_KEYS = {\n  UP: 38,\n  DOWN: 40,\n  SELECT: 13,\n  PAGEDOWN: 34,\n  PAGEUP: 33,\n  END: 35,\n  HOME: 36\n};\n\nfunction canScroll(element) {\n  return element.css('overflow-y') === 'scroll' || element.css('overflow-y') === 'auto';\n}\n\nfunction adjustScroll(scope, element) {\n  const {scrollableElement} = scope.vm;\n  const item = angular.element(getElements(scope, element)[scope.vm.currentItemIndex]);\n\n  if (item.length) {\n    const topPeekHeight = 50;\n    const {top} = item.position();\n\n    if (top <= 0 || top + item.outerHeight() >= scrollableElement.innerHeight()) {\n      scrollableElement.stop().animate({scrollTop: scrollableElement.scrollTop() + top - topPeekHeight}, 100);\n    }\n  }\n}\n\nfunction setCurrentItemByIndex(scope, element, index) {\n  scope.vm.currentItemIndex = index;\n\n  if (index >= 0) {\n    // TODO: review; timeout to give ng-repeat time to do it's magic\n    inject('$timeout')(() => {\n      const elements = getElements(scope, element);\n      if (elements.length !== scope.vm.collection.length) {\n        throw new Error('KeyNav: number of elements doesn\\'t match collection!');\n      }\n\n      scope.keyNavCurrentItem = scope.vm.collection[index];\n    });\n  } else {\n    scope.keyNavCurrentItem = null;\n  }\n}\n\nfunction dispatchNavigationEvent(scope: any, key: any) {\n  switch (key) {\n    case NAVIGATION_KEYS.SELECT:\n      scope.actions.selectCurrentItem();\n      break;\n    default:\n      scope.actions.navigate(key);\n  }\n}\n\nfunction isItemDisabled(scope, element,index) {\n  const elements = getElements(scope, element);\n  return !isUndefined(elements.eq(index).attr('disabled'));\n}\n\nfunction setupCollection(scope, element, collection) {\n  scope.vm.elements = null;\n  scope.vm.collection = collection;\n\n  if (scope.vm.collection.length && scope.options.markFirst) {\n    setCurrentItemByIndex(scope, element, 0);\n  } else {\n    setCurrentItemByIndex(scope, element, -1);\n  }\n}\n\nfunction getElements(scope, element) {\n  let elements;\n  if (scope.vm.elements) {\n    elements = scope.vm.elements;\n  } else {\n    scope.vm.elements = elements = element.find('[key-nav-item]');\n  }\n  return elements;\n}\n\nexport default function () {\n  return {\n    restrict: 'EA',\n    scope: {\n      biKeyNav: '=',\n      keyNavCurrentItem: '=?',\n      keyNavOnSelect: '&',\n      keyNavOptions: '='\n    },\n    link: {\n      post(scope: ng.IScope, element) {\n        initNgScope(scope)\n          .withOptions(scope.keyNavOptions, {\n            markFirst: false\n          }, false)\n          .withVM({\n            currentItemIndex: null,\n            collection: null,\n            elements: null,\n            $init() {\n              this.scrollableElement = canScroll(element) ? element : element.scrollParent();\n            }\n          })\n          .withActions({\n            selectItem(index) {\n              const item = scope.vm.collection[index];\n\n              if (isUndefined(item) || isItemDisabled(scope, element, index)) {\n                return;\n              }\n\n              setCurrentItemByIndex(scope, element, index);\n\n              inject('$timeout')(() => scope.keyNavOnSelect({item}));\n            },\n\n            selectCurrentItem() {\n              scope.actions.selectItem(scope.vm.currentItemIndex);\n            },\n\n            navigate(key: any) {\n              let index = scope.vm.currentItemIndex;\n\n              switch (key) {\n                case NAVIGATION_KEYS.DOWN:\n                  // tslint:disable-next-line: restrict-plus-operands\n                  index = Math.min(scope.vm.collection.length - 1, index + 1);\n                  break;\n                case NAVIGATION_KEYS.UP:\n                  index = Math.max(0, index - 1);\n                  break;\n                case NAVIGATION_KEYS.PAGEDOWN:\n                  // tslint:disable-next-line: restrict-plus-operands\n                  index = Math.min(scope.vm.collection.length - 1, index + 7);\n                  break;\n                case NAVIGATION_KEYS.PAGEUP:\n                  index = Math.max(0, index - 7);\n                  break;\n                case NAVIGATION_KEYS.HOME:\n                  index = 0;\n                  break;\n                case NAVIGATION_KEYS.END:\n                  index = scope.vm.collection.length - 1;\n                  break;\n                default:\n                  return;\n              }\n\n              setCurrentItemByIndex(scope, element, index);\n              adjustScroll(scope, element);\n            }\n          });\n\n        utils.dom.onKey(values(NAVIGATION_KEYS), (_, key) => {\n          dispatchNavigationEvent(scope, key);\n        }, scope);\n\n        scope.$watch('biKeyNav', collection => collection && setupCollection(scope, element, collection));\n      }\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/maximizable/maximizable.scss",
    "content": "@import '../../assets/css/def/colors.def';\n\n[bi-maximizable] {\n  position: relative;\n\n  .bm-toggle {\n    position: absolute;\n    top: 0;\n    right: 0;\n\n    &.bm-toggle-custom {\n      position: unset;\n    }\n  }\n\n  &.bm--maximized {\n    position: fixed;\n    right: 5%;\n    left: 5%;\n    top: 5%;\n    bottom: 5%;\n    margin: 0 !important;\n    padding: 15px;\n    background: $white;\n    border-radius: 3px;\n    z-index: 201;\n\n    + .bm-backdrop {\n      display: block;\n    }\n\n    .bm-toggle {\n      position: absolute;\n      top: 15px;\n      right: 15px;\n      z-index: 1000;\n\n      &.bm-toggle-custom {\n        position: unset;\n      }\n    }\n  }\n\n  & + .bm-backdrop {\n    content: '';\n    position: fixed;\n    display: none;\n    right: 0;\n    left: 0;\n    top: 0;\n    bottom: 0;\n    background-color: $black;\n    opacity: .5;\n    z-index: 200;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/maximizable/maximizable.story.ts",
    "content": "export default app => app\n  .story('UI', 'Maximizable')\n    .section('Maximizable', `\n      <div ng-non-bindable bi-maximizable>\n        Maximize me\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/maximizable/maximizable.ts",
    "content": "import {initNgScope, inject, utils} from '../../../core';\n\nimport './maximizable.scss';\n\nconst renderToggle = (scope, element) => {\n  let parent = element.find('[bm-toggle]');\n  let isCustom = false;\n\n  if (parent.length) {\n    isCustom = true;\n  } else {\n    parent = element;\n  }\n\n  parent.append(inject('$compile')(`\n    <span class=\"bm-toggle ${isCustom ? 'bm-toggle-custom' : ''}\" ng-if=\"biMaximizable !== false\" ng-click=\"actions.toggle()\">\n      <i class=\"bi-action bi-icon\" ng-if=\"!vm.enabled\">{{::options.onIcon}}</i>\n      <i class=\"bi-action bi-icon\" ng-if=\"vm.enabled\">{{::options.offIcon}}</i>\n    </span>\n  `)(scope));\n}\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: {\n      biMaximizable: '=',\n      isMaximized: '=',\n      bmOptions: '=',\n      onLoad: '&',\n      onToggle: '&',\n    },\n\n    link(scope, element) {\n      let cleaner: Function = () => {};\n\n      initNgScope(scope)\n        .withVM({})\n        .withOptions('bmOptions', {\n          onIcon: 'fullscreen',\n          offIcon: 'fullscreen_exit'\n        })\n        .withActions({\n          toggle() {\n            scope.vm.toggle();\n\n            element.toggleClass('bm--maximized', scope.vm.enabled);\n\n            if (scope.vm.enabled) {\n              element.after('<div class=\"bm-backdrop\"></div>');\n              cleaner = utils.dom.onKey('escape', () => scope.actions.toggle(), scope);\n            } else {\n              element.parent().find('.bm-backdrop').remove();\n              cleaner();\n            }\n\n            inject('$timeout')(() => {\n              if (typeof scope.isMaximized !== 'undefined') {\n                scope.isMaximized = scope.vm.enabled;\n              }\n\n              scope.onToggle({maximized: scope.vm.enabled});\n            });\n          }\n        });\n\n      renderToggle(scope, element);\n\n      scope.onLoad({\n        instance: {\n          toggle() {\n            scope.actions.toggle();\n          }\n        }\n      });\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/on-image-load/on-image-load.ts",
    "content": "import {utils} from '../../../core';\n\nexport default function() {\n  return {\n    restrict: 'A',\n    scope: {\n      biOnImageLoad: '<'\n    },\n\n    link(scope, element) {\n      element.\n        on('load', () => {\n          utils.scope.safeApply(scope, () => scope.biOnImageLoad.onLoad && scope.biOnImageLoad.onLoad());\n        }).\n        on('error', () => {\n          utils.scope.safeApply(scope, () => scope.biOnImageLoad.onError && scope.biOnImageLoad.onError());\n        });\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.html",
    "content": "<round-progress radius=\"{{options.radius}}\" stroke=\"{{options.stroke}}\" max=\"100\" current=\"value\" color=\"#5ca2db\"></round-progress>\n\n<span>\n  <span>{{value}}<i class=\"percent\">%</i></span>\n</span>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.scss",
    "content": "@import '../../assets/css/def/colors.def';\n\nbi-progress-gauge {\n  position: relative;\n  font-size: 0;\n\n  > span {\n    position: absolute;\n    display: flex;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    align-items: center;\n    font-size: 9px;\n    font-weight: 200;\n    color: $muted;\n    text-align: center;\n\n    > * {\n      margin: auto;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.story.ts",
    "content": "export default app => app\n  .story('UI', 'Progress')\n    .section('Progress gauge', `\n      <bi-progress-gauge value=\"75\" ng-non-bindable></bi-progress-gauge>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-gauge/progress-gauge.ts",
    "content": "import {initNgScope} from '../../../core';\n\nimport template from './progress-gauge.html';\nimport './progress-gauge.scss';\n\nexport default function () {\n  return {\n    template,\n    restrict: 'E',\n    scope: {\n      value: '=',\n      bpgOptions: '='\n    },\n\n    link (scope, element) {\n      initNgScope(scope).withOptions(scope.bpgOptions, {\n        radius: 15,\n        stroke: 3\n      });\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-line/progress-line.html",
    "content": "<div ng-if=\"!off\" class=\"bpl-container\">\n  <div class=\"bpl-main\" ng-style=\"progressBarStyle()\"></div>\n</div>\n<div ng-if=\"off\" class=\"bpl-container-off\"></div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-line/progress-line.scss",
    "content": "bi-progress-line {\n  position: relative;\n  display: block;\n  height: 0;\n\n  $progress-line-fg: #4c9ef0;\n\n  div {\n    height: 3px;\n    margin: 0;\n\n    &.bpl-main {\n      transition: width .5s;\n      background-color: $progress-line-fg;\n    }\n\n    &.bpl-container {\n      position: absolute;\n      left: 0;\n      right: 0;\n      top: 0;\n      bottom: 0;\n    }\n\n    &.bpl-container-off {\n      transition: opacity 3.5s;\n      position: absolute;\n      left: 0;\n      right: 0;\n      top: 0;\n      bottom: 0;\n      background-color: $progress-line-fg;\n      opacity: 1;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/progress-line/progress-line.ts",
    "content": "import {inject} from '../../../core';\n\nimport template from './progress-line.html';\nimport './progress-line.scss';\n\nexport default function () {\n  return {\n    template,\n    restrict: 'E',\n    scope: {\n      value: '=',\n      running: '='\n    },\n\n    link (scope, element) {\n      scope.off = false;\n      scope.progressBarStyle = function() {\n        if (scope.running) {\n          return {\n            // tslint:disable-next-line: restrict-plus-operands\n            width: scope.running ? scope.value + '%' : '100%'\n          };\n        }\n\n        return {\n          width: '0'\n        };\n      };\n\n      scope.$watch('running', running => {\n        if (running === false) {\n          scope.off = true;\n          inject('$timeout')(() => {\n            element.find('.bpl-container-off').css('opacity', 0);\n          });\n        }\n      });\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/resizable/resizable.ts",
    "content": "import {initNgScope, inject} from '../../../core';\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: {\n      onResize: '&',\n      brOptions: '=',\n    },\n\n    link(scope, element) {\n      const conf = initNgScope(scope)\n        .withVM({\n          $export() {\n            return {width: element.width()};\n          },\n          $import({width}) {\n            element.width(width);\n          }\n        })\n        .withOptions('brOptions', {\n          minWidth: null,\n          handles: null\n        })\n        .withEvents({\n          onResize() {\n            inject('$timeout')(() => scope.onToggle({maximized: scope.vm.enabled}));\n          }\n        });\n\n      if (scope.options.stateName) {\n        conf.withState(scope.options.stateName, 'resizable', {});\n      }\n\n      inject('$timeout')(() => element.resizable({\n        minWidth: scope.options.minWidth,\n        handles: scope.options.handles,\n        resize(event, ui) {\n          ui.size.height = ui.originalSize.height;\n          scope.state.save();\n        }\n      }));\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/scroll/index.ts",
    "content": "export {default as scrollTo} from './scroll-to';"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/scroll/scroll-to.ts",
    "content": "import {inject, utils} from '../../../core';\n\nconst OFFSET = -10;\n\nexport default () => {\n  return {\n    restrict: 'A',\n    scope: false,\n    link(scope, element, attr) {\n      attr.$observe('biScrollTo', scroll => {\n        if (scroll === 'true') {\n          inject('$timeout')(() => {\n            utils.dom.scrollIntoView(element, true, OFFSET);\n          });\n        }\n      });\n   }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/search/search.html",
    "content": "<i\n  class=\"bs-context bi-icon bi-muted\"\n  ng-class=\"{'bi-primary': !!model.text}\"\n  ng-if=\"::options.contextIcon\"\n\n>{{::options.contextIcon}}</i>\n\n<input\n  class=\"bi-input bi-grow\"\n  ng-class=\"{\n    'bs-has-context-icon': !!options.contextIcon,\n    'bs-has-text': !!model.text\n  }\"\n  ng-model=\"model.text\"\n  ng-minlength=\"minLength\"\n  ng-keypress=\"events.onKeypress($event)\"\n  placeholder=\"{{placeholder || 'Search'}}\"\n/>\n\n<i class=\"bs-search bi-icon bi-muted\" ng-if=\"!model.text\">{{::options.searchIcon}}</i>\n\n<span class=\"bs-close\">\n  <i class=\"bi-action bi-icon bi-fade-in\" ng-if=\"model.text\" ng-click=\"events.onClear()\">close</i>\n</span>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/search/search.scss",
    "content": "@import '../../assets/css/def/colors.def';\n@import '../../assets/css/def/defaults.def';\n\nbi-search {\n  display: inline-flex;\n  position: relative;\n\n  .bi-input {\n    padding-right: 32px;\n\n    &.bs-has-context-icon {\n      padding-left: 34px;\n    }\n  }\n\n  .bi-icon {\n    font-size: 22px;\n  }\n\n  .bs-search,\n  .bs-close,\n  .bs-context {\n    transition: color .3s;\n    position: absolute;\n    top: 50%;\n    margin-top: -11px;\n  }\n\n  .bs-search {\n    right: 6px;\n  }\n\n  .bs-close {\n    right: 5px;\n    margin-top: -14px;\n\n    .bi-icon {\n      color: $primary !important;\n    }\n  }\n\n  .bs-context {\n    left: 6px;\n  }\n\n  &.bs-focused,\n  &.bs-hovered\n  &.bs-has-text {\n    .bs-search {\n      color: $primary !important;\n    }\n  }\n\n  &.bs-has-text {\n    .bi-input {\n      border-color: $blue--300 !important;\n    }\n  }\n\n  &.bi-search--rnd,\n  &.bi-search--borderless {\n    .bi-input {\n      height: 42px !important;\n      font-weight: 600;\n\n      &.bs-has-context-icon {\n        padding-left: 40px;\n      }\n    }\n\n    .bs-context {\n      left: 12px;\n    }\n\n    .bs-search {\n      right: 14px;\n    }\n\n    .bs-close {\n      right: 12px;\n    }\n  }\n\n  &.bi-search--rnd {\n    border-radius: 100px;\n\n    .bi-input {\n      padding: 0 40px 0 20px;\n      border-radius: 100px;\n    }\n  }\n\n  &.bi-search--borderless {\n    .bi-input {\n      padding-left: 0;\n      border: 0;\n\n      &.bs-has-context-icon {\n        padding-left: 29px;\n      }\n    }\n\n    .bs-context {\n      left: 0;\n    }\n\n    .bs-search,\n    .bs-close {\n      right: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/search/search.story.ts",
    "content": "export default app => app\n  .story('UI', 'Input')\n    .section('Search input', `\n      <bi-search ng-non-bindable ng-model=\"searchText\" bi-focus placeholder=\"Search for something\"></bi-search>\n      <output>searchText: {{searchText}}</output>\n    `)\n    .section('Round search input', `\n      <bi-search ng-non-bindable class=\"bi-search--rnd\" ng-model=\"searchText\" placeholder=\"Search for something\"></bi-search>\n      <output>searchText: {{searchText}}</output>\n    `)\n    .section('Borderless search input', `\n      <bi-search ng-non-bindable class=\"bi-search--borderless\" ng-model=\"searchText\" placeholder=\"Search for something\"></bi-search>\n      <output>searchText: {{searchText}}</output>\n    `)\n    .section('Custom icons', `\n      <bi-search\n        ng-non-bindable\n        ng-model=\"searchText\"\n        bs-options=\"::{searchIcon: 'filter_list', contextIcon: 'account_circle'}\"\n        placeholder=\"Search for something\"\n      ></bi-search>\n\n      <bi-search\n        ng-non-bindable\n        class=\"bi-search--rnd\"\n        ng-model=\"searchText\"\n        bs-options=\"::{searchIcon: 'filter_list', contextIcon: 'account_circle'}\"\n        placeholder=\"Search for something\"\n      ></bi-search>\n\n      <bi-search\n        ng-non-bindable\n        class=\"bi-search--borderless\"\n        ng-model=\"searchText\"\n        bs-options=\"::{searchIcon: 'filter_list', contextIcon: 'account_circle'}\"\n        placeholder=\"Search for something\"\n      ></bi-search>\n\n      <output>searchText: {{searchText}}</output>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/search/search.ts",
    "content": "import {initNgScope, createNgModel} from '../../../core';\n\nimport template from './search.html';\nimport './search.scss';\n\nexport default function directive() {\n  return {\n    template,\n    require: 'ngModel',\n    restrict: 'E',\n    transclude: true,\n    scope: {\n      minLength: '<',\n      bsOptions: '<',\n      onEnter: '&',\n      placeholder: '@'\n    },\n\n    link: {\n      pre(scope, element, attrs, ngModel) {\n        createNgModel(scope, ngModel)\n          .formatWith(text => ({text}))\n          .parseWith(({text}) => text)\n          .feedBack(false)\n          .watchWith(({text}) => element.toggleClass('bs-has-text', !!text))\n          .watchDeep(true);\n\n        initNgScope(scope)\n          .withOptions('bsOptions', {\n            searchIcon: 'search',\n            contextIcon: null\n          })\n          .withEvents({\n            onClear() {\n              scope.model.text = '';\n              element.find('.bi-input').focus();\n            },\n            onKeypress(e) {\n              if (e.keyCode === 13) {\n                scope.onEnter();\n              }\n            }\n          });\n\n        element.on('mouseenter', '.bi-input', () => element.addClass('bs-hovered'));\n        element.on('mouseleave', '.bi-input', () => element.removeClass('bs-hovered'));\n        element.on('focus', '.bi-input', () => element.addClass('bs-focused'));\n        element.on('blur', '.bi-input', () => element.removeClass('bs-focused'));\n      }\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.html",
    "content": "<bi-dropdown\n  class=\"bi-grow\"\n  ng-class=\"{'bs-custom-toggle': vm.isCustomToggle}\"\n  bd-options=\"::{\n    width: options.dropdownWidth,\n    minWidth: options.dropdownMinWidth,\n    align: options.alignDropdown\n  }\"\n  bd-is-open=\"vm.options.enabled\"\n  on-show=\"events.onDropdownShow()\"\n  on-hide=\"events.onDropdownHide()\"\n  readonly=\"::readonly\"\n>\n  <bi-toggle class=\"bi-grow bi-align\" bi-html=\"renderToggle()\"></bi-toggle>\n\n  <div\n    bi-key-nav=\"buffer\"\n    key-nav-options=\"::{markFirst: options.typeahead && !options.freetext}\"\n    key-nav-current-item=\"vm.keyNavOption\"\n    key-nav-on-select=\"events.onOptionSelect(item)\"\n  >\n    <ul\n      class=\"bi-dropdown-menu\"\n      bi-infinite-scroll=\"vm.options.items()\"\n      bis-buffer=\"buffer\"\n    >\n      <li\n        class=\"bi-muted\"\n        ng-if=\"vm.options.falsy && vm.search.parsed\"\n        ng-show=\"!vm.search.enabled\"\n        ng-mousedown=\"$event.preventDefault()\"\n        ng-click=\"events.onOptionSelect(vm.options.falsy.option)\"\n        bi-html=\"renderOption(vm.options.falsy.option || placeholder)\"\n      ></li>\n\n      <li\n        class=\"bi-text--sm bi-muted bi-fade-in\"\n        ng-class=\"{'bi-active': vm.search.enabled && options.freetext}\"\n        ng-if=\"options.typeahead && !vm.options.items().length && !vm.options.deferred.loading\"\n      >\n        <span ng-if=\"vm.search.enabled\">\n          <span class=\"bi-text--600\" ng-if=\"options.freetext\">{{vm.search.text}}</span>\n          <span ng-if=\"!options.freetext\">No matches</span>\n        </span>\n\n        <span ng-if=\"!vm.search.enabled\">Start typing to see matches</span>\n      </li>\n\n      <li class=\"bi-center bi-fade-in\" ng-if=\"vm.options.deferred.loading\">\n        <span class=\"bi-spinner--sm\"></span>\n      </li>\n\n      <li\n        ng-class=\"{\n          selected: option === model,\n          'bi-active': option === vm.keyNavOption\n        }\"\n        ng-repeat=\"option in buffer\"\n        ng-mousedown=\"$event.preventDefault()\"\n        ng-click=\"events.onOptionSelect(option)\"\n        bi-html=\"renderOption(option)\"\n        key-nav-item\n      ></li>\n    </ul>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.scss",
    "content": "@import '../../assets/css/def/colors.def';\n\nbi-select,\nbi-simple-select {\n  display: inline-flex;\n\n  input[type=\"number\"]::-webkit-outer-spin-button,\n  input[type=\"number\"]::-webkit-inner-spin-button {\n    -webkit-appearance: none;\n    margin: 0;\n  }\n\n  bi-dropdown {\n    &.bs-custom-toggle {\n      bi-toggle {\n        i {\n          position: unset;\n        }\n      }\n    }\n\n    bi-toggle {\n      position: relative;\n\n      i {\n        position: absolute;\n        right: 5px;\n        top: 6px;\n        cursor: pointer;\n      }\n\n      .bi-input {\n        padding-right: 30px;\n        cursor: pointer;\n      }\n    }\n\n    .bd-content {\n      [ng-transclude=''] {\n        .bi-dropdown-menu {\n          width: 100%;\n          line-height: initial !important;\n          font-size: 13px !important;\n          border-top: 0;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.story.ts",
    "content": "import {inject} from '../../../core';\n\nexport default app => app\n  .story('UI', 'Select')\n    .section('Select', `\n      <bi-simple-select ng-non-bindable bi-options=\"option for option in ::['option 2', 'option 1', 'option 3']\" ng-model=\"selected1\">\n      </bi-simple-select>\n      <output>selected1: {{selected1 || 'Nothing selected'}}</output>\n\n      <bi-simple-select ng-non-bindable bi-options=\"option.title for option in ::[{title: 'option 1'}, {title: 'option 2'}, {title: 'option 3'}]\" ng-model=\"selected2\"></bi-simple-select>\n      <output>selected2: {{selected2 || 'Nothing selected'}}</output>\n\n      <bi-simple-select ng-non-bindable bi-options=\"option.value as option.title for option in ::[{title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]\" ng-model=\"selected3\"></bi-simple-select>\n      <output>selected3: {{selected3 || 'Nothing selected'}}</output>\n\n      <bi-simple-select ng-non-bindable bi-options=\"option.value as option.title for option in ::[{title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]\" ng-model=\"selected3\" readonly=\"true\"></bi-simple-select>\n    `)\n    .section('Typeahead', `\n       <bi-simple-select\n       bi-focus\n        ng-non-bindable\n        ng-model=\"typeahead\"\n        bi-options=\"option.value as option.title for option in ::[{title: 'Empty', value: ''}, {title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]\"\n        bs-options=\"::{typeahead: true}\"\n      ></bi-simple-select>\n\n      <bi-simple-select\n        ng-non-bindable\n        ng-model=\"typeaheadPromise\"\n        bi-options=\"option.value as option.title for option in promise\"\n        bs-options=\"::{typeahead: true}\"\n        on-search-change=\"onSearchChange(text)\"\n        placeholder=\"Promise based\"\n      ></bi-simple-select>\n    `, scope => {\n      scope.onSearchChange = () => scope.promise = inject('$timeout')(() => {\n        return [{title: 'Empty', value: ''}, {title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}];\n      }, 2000);\n    })\n    .section('Null item', `\n      <bi-simple-select ng-non-bindable bi-options=\"option for option in ::[null, 'option 1', 'option 2', 'option 3']\" ng-model=\"nullItem1\"></bi-simple-select>\n      <bi-simple-select ng-non-bindable bi-options=\"option.value as option.title for option in ::[{title: 'Empty', value: ''}, {title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]\" ng-model=\"nullItem2\"></bi-simple-select>\n  `)\n    .section('Custom toggle', `\n      <bi-simple-select ng-non-bindable bi-options=\"option.value as option.title for option in ::[{title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]\" ng-model=\"selected4\">\n        <toggle>\n          {{item.formatted}}\n        </toggle>\n      </bi-simple-select>\n      <output>selected: {{selected4 || 'Nothing selected'}}</output>\n  `)\n    .section('Custom items', `\n      <bi-simple-select ng-non-bindable bi-options=\"option.value as option.title for option in ::[{title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}]\" ng-model=\"selected4\">\n        <div>{{::item.value}}. {{::item.title}}</div>\n      </bi-simple-select>\n      <output>selected: {{selected4 || 'Nothing selected'}}</output>\n  `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/simple-select/simple-select.ts",
    "content": "import template from './simple-select.html';\nimport './simple-select.scss';\n\nimport {DropdownList} from '../common/dropdown-list';\n\nexport interface IScope extends ng.IScope {\n  model: any[];\n}\n\nexport default function directive() {\n  return {\n    template,\n    require: ['ngModel', 'biOptions'],\n    restrict: 'E',\n    transclude: {\n      toggle: '?toggle',\n      opt: '?opt'\n    },\n    scope: {\n      bsOptions: '=',\n      onTypeahead: '&',\n      readonly: '=',\n      placeholder: '@'\n    },\n\n    link: {\n      pre(scope: IScope, element, attrs, [ngModel, biOptions], transclude) {\n        return new DropdownList(scope, element, attrs, {ngModel, biOptions}, transclude, {\n          optionsAlias: 'bsOptions',\n        });\n      }\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/state-loader/state-loader.scss",
    "content": "@import '../../assets/css/def/animations.def';\n\n[bi-state-loader] {\n  @extend %animation-fade-in;\n  transition: opacity .3s !important;\n\n  &.loading-state {\n    opacity: .5;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/state-loader/state-loader.ts",
    "content": "import './state-loader.scss';\n\nlet prefix = '';\n\nfunction getTargetDepth(state1: string, state2: string) {\n  let res = 0;\n  const prefixLength = prefix ? prefix.split('.').length - 1 : 0;\n\n  if (state1 === state2) {\n    return prefixLength || res;\n  }\n\n  const s1 = state1.split('.');\n  const s2 = state2.split('.');\n  const len = Math.min(s1.length, s2.length);\n\n  for (let i = 0; i < len; i++) {\n    if (s1[i] === s2[i]) {\n      res++;\n    } else {\n      break;\n    }\n  }\n\n  return res;\n}\n\nexport function setPrefix(p: string) {\n  prefix = p;\n}\n\nexport default function() {\n  return {\n    restrict: 'A',\n    scope: {},\n\n    link(scope, element, attrs) {\n      scope.$on('$stateChangeStart', function (_, to, __, from) {\n        const myDepth = element.parents('[ui-view]').length;\n        const targetDepth = getTargetDepth(to.name, from.name);\n\n        if (myDepth === targetDepth) {\n          element.addClass('loading-state spinner');\n        }\n      });\n\n      scope.$on('$stateChangeSuccess', function () {\n        element.removeClass('loading-state spinner');\n      });\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/header/table-header.html",
    "content": "<thead class=\"bi-tbl-header\">\n  <tr>\n    <th ng-repeat=\"field in fields\">\n      <div class=\"bi-table-th-placeholder\">\n        <span class=\"bi-align\" ng-if=\"::!!order && field.sort !== false\" href ng-click=\"setOrder(field)\">\n          <span class=\"bi-tbl-sort-icon bi-icon--sm\">unfold_more</span>\n          <span class=\"bi-text--600\">{{::formatField(field)}}</span>\n        </span>\n\n        <span ng-if=\"::!order || field.sort !== false\" class=\"bi-text--600\">{{::formatField(field)}}</span>\n      </div>\n\n      <div class=\"bi-table-th-content bi-text--ui\">\n        <span class=\"bi-align bi-pointer\" ng-if=\"!!order && field.sort !== false\" href ng-click=\"setOrder(field)\">\n          <span class=\"bi-tbl-sort-icon bi-icon--sm\" ng-class=\"{'bi-primary': order.field === field}\">\n            {{order.field !== field ? 'unfold_more' : order.field === field && !order.reverse ? 'arrow_drop_up' : 'arrow_drop_down'}}\n          </span>\n          <span class=\"bi-text--600\">{{::formatField(field)}}</span>\n        </span>\n\n        <span ng-if=\"!order || field.sort === false\" class=\"bi-text--600\">{{::formatField(field)}}</span>\n      </div>\n    </th>\n  </tr>\n</thead>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/header/table-header.scss",
    "content": "@import '../../../assets/css/def/defaults.def';\n\n// sortable-table-header\n.bi-tbl-header {\n  .bi-table-th-content span {\n    white-space: nowrap;\n  }\n\n  .bi-tbl-sort-icon {\n    margin-left: -8px;\n  }\n\n  a {\n    color: $default-text-color !important;\n    text-decoration: none !important;\n    white-space: nowrap;\n\n    .fa {\n      position: relative;\n      margin-right: 3px;\n      color: $default-text-color;\n\n      &.fa-sort-desc {\n        top: -2px;\n      }\n\n      &.fa-sort-asc {\n        top: 3px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/header/table-header.ts",
    "content": "import {inject} from '../../../../core';\n\nimport template from './table-header.html';\nimport './table-header.scss';\n\nexport default () => {\n  return {\n    template,\n    restrict: 'A',\n    replace: true,\n    scope: {\n      fields: '=',\n      order: '=',\n      biTableHeaderOptions: '=',\n      onOrderChange: '&'\n    },\n\n    link: {\n      pre(scope) {\n        const options = scope.biTableHeaderOptions || {};\n        const toHumanCase = inject('$filter')('biToHumanCase');\n\n        scope.setOrder = function (field) {\n          if (field === scope.order.field) {\n            scope.order.reverse = !scope.order.reverse;\n          } else {\n            scope.order.field = field;\n            scope.order.reverse = false;\n          }\n\n          scope.onOrderChange({order: scope.order});\n        };\n\n        scope.formatField = function (field) {\n          field = field.title || field.name || field;\n\n          return options.dontTransformColumnNames ? field : toHumanCase(field);\n        };\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/row/table-row.ts",
    "content": "import {assign} from 'lodash';\nimport angular from 'angular';\nimport {inject} from '../../../../core';\n\nexport default () => {\n    const entityMap = {\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      '\\'': '&#39;',\n      '/': '&#x2F;'\n    };\n\n    const htmlEscape = function (string) {\n      if (typeof string === 'undefined') {\n        return '';\n      }\n\n      // tslint:disable-next-line: restrict-plus-operands\n      return ('' + string).replace(/[&<>\"'\\/]/g, function (s) {\n        return entityMap[s];\n      });\n    };\n\n    const getColumnsHtml = function (row, fields, index, formatter) {\n      const res = [];\n\n      fields.forEach(function (field) {\n        const data = typeof row.data === 'object' ? row.data : row;\n        const name = field.name || field;\n        let content;\n\n        const contentElement = angular.element('<td class=\"' + htmlEscape(name) + '-column\"><div class=\"bi-table-row-value\"></div></td>');\n        const $compile: angular.ICompileService = inject('$compile');\n\n        if (field.filter) {\n          content = field.filter(data[name], row, index, (html, locals, scope) => $compile(html)(assign(scope.$new(), locals))\n            .on('$destroy', e => {\n              const elementScope = angular.element(e.target).scope();\n\n              if (elementScope) {\n                elementScope.$destroy();\n              }\n            }));\n        } else if (formatter) {\n          content = formatter(name, data[name], row, index, (html, locals, scope) => $compile(html)(assign(scope.$new(), locals)));\n        } else {\n          content = htmlEscape(data[name]);\n        }\n\n        if (typeof content === 'object') {\n          contentElement.html(content);\n        } else {\n          contentElement.html(content === '' ? '&nbsp;' : content);\n        }\n\n        res.push(contentElement);\n      });\n\n      return res;\n    };\n\n    return {\n      restrict: 'A',\n      scope: {\n        fields: '=',\n        row: '=',\n        index: '<',\n        formatter: '&',\n        biTableRowOptions: '='\n      },\n\n      link: {\n        pre(scope, element) {\n          if (scope.biTableRowOptions.dynamicFields) {\n            scope.$watch('fields', fields => {\n              element.html(getColumnsHtml(scope.row, scope.fields, scope.index, scope.formatter()));\n            });\n          } else {\n            element.html(getColumnsHtml(scope.row, scope.fields, scope.index, scope.formatter()));\n          }\n        }\n      }\n    };\n  };\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/table.html",
    "content": "<div class=\"bi-fade-in\" ng-show=\"vm.visible\">\n  <table ng-if=\"vm.enabled\" class=\"bi-table\">\n    <thead\n      ng-if=\"::options.dynamicFields\"\n      bi-tbl-header\n      fields=\"fields\"\n      order=\"::order\"\n      bi-table-header-options=\"::options\"\n      on-order-change=\"events.onOrderChange()\"\n    ></thead>\n\n    <thead\n      ng-if=\"::!options.dynamicFields\"\n      bi-tbl-header\n      fields=\"::fields\"\n      order=\"::order\"\n      bi-table-header-options=\"::options\"\n      on-order-change=\"events.onOrderChange()\"\n    ></thead>\n\n    <tbody ng-class=\"{'bi-tbl-fade-out': vm.loading}\"></tbody>\n  </table>\n\n  <div class=\"bi-tbl-spinner-container bi-center\" ng-if=\"::options.infiniteScroll\" ng-show=\"items.hasMore()\">\n    <span class=\"bi-spinner\"></span>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/table.scss",
    "content": "@import '../../assets/css/def/defaults.def';\n@import '../../assets/css/def/colors.def';\n\n.bi-table-container,\nbi-tbl {\n  display: block;\n\n  table > tbody {\n    transition: opacity 0.3s;\n\n    &.bi-tbl-fade-out {\n      opacity: 0.2;\n    }\n  }\n\n  .bi-table-th-placeholder {\n    height: 0;\n    overflow: hidden;\n  }\n\n  &.bi-table-sticky-header {\n    position: relative;\n    display: flex;\n    flex-direction: column;\n    padding-top: 36px;\n\n    > div {\n      border-top: 2px solid $default-border-color;\n      overflow: auto;\n    }\n\n    table {\n      th {\n        padding: 0 8px !important;\n        border-bottom: 0 !important;\n\n        .bi-table-th-content {\n          position: absolute;\n          top: 10px;\n        }\n      }\n\n      tr:first-child td {\n        border-top: 1px solid transparent;\n      }\n    }\n  }\n\n  .bi-tbl-spinner-container {\n    height: 30px;\n    overflow: hidden;\n  }\n\n  &.bi-table--nav {\n    tbody {\n      tr {\n        cursor: pointer;\n\n        &.bi-active {\n          background-color: $grey--100 !important;\n        }\n\n        &:hover {\n          background-color: $grey--50;\n        }\n\n        td {\n          a,\n          .bi-hint {\n            line-height: normal;\n          }\n        }\n      }\n    }\n  }\n\n  &.bi-table--data {\n    $header-height: 32px;\n\n    padding-top: $header-height !important;\n    background-color: $grey--200;\n    border: 1px solid $grey--300;\n    overflow: hidden;\n\n    > div {\n      display: flex;\n      flex-direction: column;\n      flex-grow: 1;\n      border-top: 2px solid $grey--300;\n      background-color: $white;\n    }\n\n    table > thead,\n    table > tbody {\n      td,\n      th {\n        max-width: 300px;\n        white-space: nowrap;\n        word-break: break-all;\n        overflow: hidden;\n      }\n    }\n\n    table > thead {\n      th {\n        &:not(:first-child) > .bi-table-th-content > span {\n          margin-left: -8px;\n          padding-left: 8px;\n          border-left: 1px solid $grey--300 !important;\n        }\n\n        border-bottom: none;\n      }\n\n      .bi-table-th-content {\n        top: 0 !important;\n\n        span {\n          display: flex;\n          height: $header-height;\n          font-weight: bold;\n          align-items: center;\n        }\n      }\n    }\n\n    table > tbody {\n      > tr {\n        &:nth-child(even) {\n          background-color: $grey--100;\n        }\n\n        &:nth-child(odd) {\n          background-color: $white;\n        }\n\n        &:last-child {\n          border-bottom: 1px solid $grey--300;\n        }\n\n        > td {\n          padding: 5px 8px !important;\n          border-top: 1px solid $grey--300;\n          font-size: 12px;\n\n          &:not(:first-child) {\n            border-left: 1px solid $grey--300;\n          }\n\n          a:visited {\n            color: $muted !important;\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/table.story.ts",
    "content": "import { BufferedCollection } from \"../../../core/dist/src/srv/collections\";\n\nexport default app => app\n  .story('UI', 'Table')\n  .section('Simple table', `\n    <bi-tbl\n      ng-non-bindable\n      fields=\"::fields\"\n      rows=\"rows\"\n      bt-options=\"{trackBy: 'colA'}\"\n      order-by=\"colB\"\n      filter=\"filter\"\n      reverse=\"true\"\n    >\n    </bi-tbl>\n  `, scope => {\n    scope.fields = ['colA', 'colB', 'colC'];\n    scope.rows = [{\n      colA: 1,\n      colB: 2,\n      colC: 3\n    },\n    {\n      colA: 4,\n      colB: 5,\n      colC: 6\n    }];\n\n    scope.filter = (row) => {\n      return true;\n    };\n\n    scope.emptyFilter = (row) => {\n      return false;\n    };\n  })\n  .section('Nav table', `\n    <bi-tbl\n      ng-non-bindable\n      class=\"bi-table--nav\"\n      fields=\"::fields\"\n      rows=\"rows\"\n    ></bi-tbl>\n  `)\n  .section('Data table', `\n    <bi-tbl\n      ng-non-bindable\n      class=\"bi-table--data\"\n      fields=\"::fields\"\n      rows=\"rows\"\n      bt-options=\"::{stickyHeader: true, trackBy: 'colA'}\"\n      order-by=\"colA\"\n    ></bi-tbl>\n  `)\n  .section('Data table with infinite scroll', `\n    <bi-tbl\n      ng-non-bindable\n      class=\"bi-table--data\"\n      style=\"width: 100px; height: 110px;\"\n      fields=\"::fields\"\n      rows=\"::items\"\n      bt-options=\"::{stickyHeader: true, infiniteScroll: true, trackBy: 'colA', chunkSize: 3}\"\n      order-by=\"colA\"\n    ></bi-tbl>\n  `, scope => {\n    scope.items = '123456'.split('').map((num, index) => ({colA: num + index, colB: num + index + 1, colC: num + index + 2}));\n  })\n  .section('Empty table', `\n    <bi-tbl\n      ng-non-bindable\n      fields=\"::fields\"\n      rows=\"::rows\"\n      filter=\"emptyFilter\"\n      empty-state-msg=\"No rows\"\n    ></bi-tbl>\n  `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/table/table.ts",
    "content": "import {throttle, debounce, without, find} from 'lodash';\nimport {inject, initNgScope} from '../../../core';\n\nimport template from './table.html';\nimport './table.scss';\nimport { BufferedCollection, PartitionedCollection } from '../../../core/srv/collections';\n\nconst isCollection = (collection: BufferedCollection | PartitionedCollection) => {\n  return collection && collection.models instanceof Array;\n}\n\nexport default () => {\n    const ACTIONS = {\n      getSortValue(scope, row) {\n        const fieldName = scope.order.field.name || scope.order.field;\n\n        return scope.order.field.sort ? scope.order.field.sort(row[fieldName], row) : row[fieldName];\n      }\n    };\n\n    function shouldFetchMore(container) {\n      const viewportHeight = container.height();\n      const contentHeight = container.get(0).scrollHeight;\n      const topOffset = container.scrollTop();\n\n      return contentHeight - topOffset - viewportHeight < 40;\n    }\n\n    function adjustHeaderPosition(container, columns) {\n      // tslint:disable-next-line: restrict-plus-operands\n      columns.css('margin-left', (-1 * container.get(0).scrollLeft) + 'px');\n    }\n\n    function initInfiniteScroll(scope, element, container, options) {\n      if (options.infiniteScroll) {\n        let columns = element.find('table thead .bi-table-th-content');\n        scope.infiniteScrollEnabled = true;\n\n        const redrawColumnsFunc = debounce(() => {\n          if (!columns.length) {\n            columns = element.find('table thead .bi-table-th-content');\n          }\n\n          columns.hide().show(0);\n          adjustHeaderPosition(container, columns);\n        }, 200);\n        const applyFunc = () => scope.vm.getItems().more();\n        const thenFunc = options.stickyHeader ? () => redrawColumnsFunc() : () => null;\n\n        return throttle(axis => {\n          if (axis === 'y' && scope.vm.getItems().hasMore() && shouldFetchMore(container)) {\n            scope.$apply(applyFunc).then(thenFunc);\n          }\n\n          return true;\n        }, 500);\n      }\n    }\n\n    function initStickyHeader(element, container, options) {\n      if (options.stickyHeader) {\n        let columns = element.find('table thead .bi-table-th-content');\n        element.addClass('bi-table-sticky-header');\n\n        // scroll the sticky header horizontally\n        return axis => {\n          if (axis === 'x') {\n            if (!columns.length) {\n              columns = element.find('table thead .bi-table-th-content');\n            }\n\n            adjustHeaderPosition(container, columns);\n          }\n\n          return true;\n        };\n      }\n    }\n\n    function initEvents(scope, element, container, options) {\n      const scrollHandlers = without([\n        initInfiniteScroll(scope, element, container, options),\n        initStickyHeader(element, container, options)\n      ], undefined);\n\n      if (scrollHandlers.length) {\n        const domContainer = container.get(0);\n        let lastXScroll = 0;\n\n        const scrollHandler = () => {\n          const axis = lastXScroll - domContainer.scrollLeft !== 0 ? 'x' : 'y';\n          scrollHandlers.every(handler => handler(axis));\n          lastXScroll = domContainer.scrollLeft;\n        };\n\n        container.on('scroll', scrollHandler);\n      }\n    }\n\n    function initOrderBy(scope) {\n      if (scope.orderBy) {\n        const orderByField = find(scope.fields, field => field === scope.orderBy || (field as any).name === scope.orderBy);\n\n        scope.order = {\n          field: orderByField,\n          reverse: !!scope.reverse\n        };\n\n        if (!(scope.vm.getItems() instanceof BufferedCollection)) {\n          scope.getSortValue = row => ACTIONS.getSortValue(scope, row);\n        }\n      }\n    }\n\n    function orderCollection(scope, element) {\n      if (isCollection(scope.vm.getItems())) {\n        scope.vm.loading = true;\n\n        inject('$timeout')(() => {\n          const copy = Object.assign( Object.create( Object.getPrototypeOf(scope.vm.getItems())), scope.vm.getItems());\n          const buffer = copy._buffer;\n\n          copy.fetch();\n          copy.feed(inject('$filter')('orderBy')(buffer, row => ACTIONS.getSortValue(scope, row), scope.order.reverse));\n\n          if (buffer.length < scope.options.chunkSize) {\n            copy.seal();\n          }\n\n          renderItems(scope, element, copy);\n        });\n      }\n    }\n\n    const initRows = (scope, element, rows: any[]) => {\n      let items: any = rows;\n\n      if (scope.options.infiniteScroll) {\n        const collection = new BufferedCollection().setChunkSize(scope.options.chunkSize);\n        collection.fetch();\n        collection.feed(scope.rows);\n\n        if (scope.rows.length < scope.options.chunkSize) {\n          collection.seal();\n        }\n\n        items = collection;\n      }\n\n      renderItems(scope, element, items);\n    }\n\n    const initCollection = (scope, element, collection) => {\n      renderItems(scope, element, collection);\n    }\n\n    const renderItems = (scope, element, items = scope.vm.getItems()) => {\n      scope.vm.loading = true;\n      scope.vm.toggleEnabled(true);\n\n      inject('$timeout')(() => {\n        scope.vm.setItems(items);\n\n        const itemsRef = isCollection(scope.vm.getItems()) ? `items.models` : `items`;\n        const itemRef = isCollection(scope.vm.getItems()) ? `model.data` : `model`;\n\n        const html = inject('$compile')(`\n          <tr\n            bi-tbl-row\n            ng-repeat=\"model in ${[\n              scope.filter ? `(filteredItems = (${itemsRef} | filter:filter))` : `${itemsRef}`,\n              scope.orderBy && !isCollection(items) ? 'orderBy:getSortValue:order.reverse' : '',\n            ].filter(x => !!x).join(' | ')} track by ${scope.options.trackBy ? `${itemRef}[options.trackBy]`: '$index'}\"\n            ng-click=\"events.onRowClick(${itemRef})\"\n            ng-class=\"{selected: ${itemRef} === vm.selected}\"\n            fields=\"fields\"\n            row=\"::model\"\n            index=\"::$index\"\n            formatter=\"formatter()\"\n            bi-table-row-options=\"::options\"\n          ></tr>\n          <tr ng-if=\"filteredItems.length === 0\">\n            <td class=\"bi-muted\" colspan=\"{{fields.length}}\">{{::emptyStateMsg}}</td>\n          </tr>\n        `)(scope.vm.getScope());\n\n        element.find('tbody').html(html);\n\n        inject('$timeout')(() => {\n          scope.vm.destroyOldScope();\n          scope.vm.toggleVisible(true);\n          scope.vm.loading = false;\n\n          scope.onRendered();\n        });\n      });\n    }\n\n    return {\n      template,\n      restrict: 'E',\n      scope: {\n        fields: '=',\n        rows: '=',\n        collection: '=',\n        selected: '=',\n        orderBy: '@',\n        reverse: '@',\n        filter: '&',\n        formatter: '&',\n        btOptions: '=',\n        onRowClick: '&',\n        onRowSelect: '&',\n        onRowDeselect: '&',\n        onRendered: '&',\n        onDestroyed: '&',\n        emptyStateMsg: '@'\n      },\n\n      link: {\n        pre(scope, element, attrs) {\n          const container = element.find('> div');\n\n          initNgScope(scope)\n            .withOptions('btOptions', {\n              dynamicFields: false,\n              infiniteScroll: false,\n              stickyHeader: false,\n              dontTransformColumnNames: false,\n              trackBy: null,\n              chunkSize: 50\n            })\n            .withVM({\n              enabled: false,\n              id: '',\n              scope: null,\n              oldScope: null,\n              $init() {\n                this.selected = scope.selected;\n              },\n              setItems(items) {\n                this.oldScope = this.scope;\n                this.scope = scope.$new();\n                this.scope.items = items;\n\n                scope.items = items;\n              },\n              getItems() {\n                return this.scope && this.scope.items;\n              },\n              getScope() {\n                return this.scope;\n              },\n              destroyOldScope() {\n                if (this.oldScope) {\n                  this.oldScope.$destroy();\n                  scope.onDestroyed();\n                }\n              }\n            })\n            .withEvents({\n              onOrderChange() {\n                orderCollection(scope, element);\n              },\n              onRowClick(row) {\n                if (scope.vm.selected === row) {\n                  scope.vm.selected = null;\n                  scope.onRowDeselect({row});\n                } else {\n                  scope.vm.selected = row;\n                  scope.onRowSelect({row});\n                }\n\n                scope.onRowClick({row});\n              }\n            });\n\n          initEvents(scope, element, container, scope.options);\n          initOrderBy(scope);\n\n          scope.filter = scope.filter();\n          scope.emptyStateMsg = scope.emptyStateMsg || `Can't find any items`;\n\n          scope.$watch('selected', selected => scope.vm.selected = selected);\n\n          scope.$watch('rows', (rows, prev) => {\n            if (rows && (rows !== prev || !scope.vm.getItems())) {\n              initRows(scope, element, rows);\n            }\n          });\n\n          scope.$watch('collection', (collection, prev) => {\n            if (collection && (collection !== prev || !scope.vm.getItems())) {\n              initCollection(scope, element, collection);\n            }\n          });\n        }\n      }\n    };\n  };"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tabs/tabs-router.html",
    "content": "<div class=\"bi-tabs-header bi-row bi-dont-grow bi-dont-shrink\">\n  <div\n    class=\"bi-tab bi-align bi-center\"\n    ng-repeat=\"tab in ::vm.tabs.all\"\n    ng-class=\"{'bi-active': tab.name === vm.tabs.current}\"\n    ng-click=\"events.onTabClick(tab.name)\"\n    data-hook=\"h-bt-button2\"\n  >\n    <span class=\"bi-action bi-label bi-align bi-space-h--x05\">\n      <i class=\"bi-icon--sm\">{{::tab.icon}}</i>\n      <span data-hook=\"h-bt-button\">{{::tab.title || tab.name}}</span>\n    </span>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tabs/tabs-router.ts",
    "content": "import {initNgScope, inject} from '../../../core';\nimport {last} from 'lodash';\nimport {IScope} from 'angular';\n\nimport template from './tabs-router.html';\nimport './tabs.scss';\n\nexport interface IBiTab {\n  name: string;\n  title: string;\n  icon: string;\n  id: string;\n}\n\nexport interface TabsRouterScope extends IScope {\n  tabs: IBiTab[];\n}\n\nexport default () => {\n  const $state = inject('$state');\n\n  return {\n    restrict: 'E',\n    template,\n    transclude: true,\n    scope: {\n      tabs: '<',\n      btOptions: '='\n    },\n\n    link(scope: TabsRouterScope, element: JQuery, attr: ng.IAttributes, ctrls) {\n      initNgScope(scope)\n        .withOptions('btOptions', {\n          mode: 'default', // default | flat\n        })\n        .withVM({\n          tabs: {\n            $init() {\n              this.current = last($state.current.name.split('.'));\n              this.all = scope.tabs;\n            },\n          }\n        })\n        .withEvents({\n          onTabClick(tabName: string) {\n            scope.vm.tabs.current = tabName;\n            $state.go(`^.${tabName}`);\n          }\n        });\n\n      element.addClass(`bi-tabs--${scope.options.mode}`);\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tabs/tabs.html",
    "content": "<div class=\"bi-tabs-header bi-row bi-dont-grow bi-dont-shrink\" ng-class=\"::options.headerClass\">\n  <div\n    class=\"bi-tab bi-align bi-center\"\n    ng-repeat=\"tab in ::vm.tabs.all\"\n    ng-class=\"{\n      'bi-active': tab.name === vm.tabs.current,\n      'bi-muted': tab.name !== vm.tabs.current,\n    }\"\n    ng-click=\"events.onTabClick(tab.name)\"\n    data-hook=\"h-bt-button2\"\n  >\n    <span class=\"bi-action bi-align bi-space-h--x05\">\n      <i class=\"bi-icon--sm\">{{::tab.icon}}</i>\n      <span class=\"bi-text--ui\" data-hook=\"h-bt-button\">\n        <span ng-if=\"::tab.title\">{{::tab.title}}</span>\n        <span ng-if=\"::!tab.title\">{{::tab.name | biToHumanCase}}</span>\n      </span>\n    </span>\n  </div>\n</div>\n\n<div class=\"bi-tabs-content bi-c-h\" ng-class=\"::options.contentClass\"></div>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tabs/tabs.scss",
    "content": "@import '../../assets/css/def/colors.def';\n@import '../../assets/css/def/defaults.def';\n\nbi-tabs,\nbi-tabs-router {\n  .bi-tabs-header {\n    position: relative;\n    flex-basis: 42px;\n    border-bottom: 1px solid $default-border-color;\n\n    .bi-tab {\n      min-width: 80px;\n      margin-bottom: -1px;\n      padding: 0 15px;\n      cursor: pointer;\n\n      &.bi-active {\n        > * {\n          color: $grey--800 !important;\n        }\n      }\n    }\n  }\n\n  &.bi-tabs--default {\n    .bi-tab {\n      height: 36px;\n      border: 1px solid transparent;\n\n      &.bi-active {\n        border-color: $grey--300;\n        border-top: 2px solid $warning;\n        border-bottom-color: $grey--50;\n        border-radius: 3px 3px 0 0;\n        background-color: $grey--50;\n\n        > * {\n          margin-top: -1px;\n          color: $grey--800 !important;\n        }\n      }\n    }\n\n    .bi-tabs-content {\n      margin-top: -1px;\n    }\n  }\n\n  &.bi-tabs--flat {\n    .bi-tabs-header {\n      border-bottom: 1px solid $default-border-color;\n    }\n\n    .bi-tab {\n      transition: border-color .3s;\n      height: 42px;\n      border-bottom: 2px solid transparent;\n\n      &:hover,\n      &.bi-active {\n        border-bottom: 2px solid $warning;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tabs/tabs.story.ts",
    "content": "export default app => app\n  .story('UI', 'Tabs')\n    .section('Tabs', `\n      <bi-tabs ng-non-bindable class=\"bi-grow\" tabs=\"::[{name: 'one', icon: 'settings'}, {name: 'two'}, {name: 'three'}]\">\n        <div class=\"bi-panel--grey\">\n          <div class=\"bi-panel-content\">\n            <div ng-if=\"tabs.current === 'one'\">Content of {{::tabs.current}}</div>\n            <div ng-if=\"tabs.current === 'two'\">Content of {{::tabs.current}}</div>\n            <div ng-if=\"tabs.current === 'three'\">Content of {{::tabs.current}}</div>\n          </div>\n        </div>\n      </bi-tabs>\n\n      <bi-tabs\n        ng-non-bindable\n        class=\"bi-grow\"\n        tabs=\"::[{name: 'one', icon: 'settings'}, {name: 'two'}, {name: 'three'}]\"\n        bt-current=\"current\"\n      >\n        <div class=\"bi-panel--grey\">\n          <div class=\"bi-panel-content\">\n            <div ng-if=\"tabs.current === 'one'\">Content of {{::tabs.current}}</div>\n            <div ng-if=\"tabs.current === 'two'\">Content of {{::tabs.current}}</div>\n            <div ng-if=\"tabs.current === 'three'\">Content of {{::tabs.current}}</div>\n          </div>\n        </div>\n      </bi-tabs>\n\n      <output>current: {{current}}</output>\n    `, $scope => $scope.current = 'two')\n\n    .section('Flat tabs', `\n      <bi-tabs\n        ng-non-bindable\n        class=\"bi-grow\"\n        tabs=\"::[{name: 'one'}, {name: 'two'}, {name: 'three'}]\"\n        bt-options=\"::{mode: 'flat'}\"\n      >\n        <div class=\"bi-panel\">\n          <div class=\"bi-panel-content\">\n            <div ng-if=\"tabs.current === 'one'\">Content of {{::tabs.current}}</div>\n            <div ng-if=\"tabs.current === 'two'\">Content of {{::tabs.current}}</div>\n            <div ng-if=\"tabs.current === 'three'\">Content of {{::tabs.current}}</div>\n          </div>\n        </div>\n      </bi-tabs>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tabs/tabs.ts",
    "content": "import {initNgScope, inject} from '../../../core';\nimport {IScope as ngScope} from 'angular';\n\nimport template from './tabs.html';\nimport './tabs.scss';\n\nexport interface IBiTab {\n  name: string;\n  title: string;\n  icon: string;\n}\n\nexport interface IScope extends ngScope {\n  tabs: IBiTab[];\n}\n\nexport default () => {\n  const $timeout: ng.ITimeoutService = inject('$timeout');\n  return {\n    restrict: 'E',\n    template,\n    transclude: true,\n    scope: {\n      tabs: '<',\n      btCurrent: '=',\n      btOptions: '=',\n      onChange: '&'\n    },\n\n    link(scope: IScope, element: JQuery, attr: ng.IAttributes, ctrls, transclude: ng.ITranscludeFunction) {\n      initNgScope(scope)\n        .withOptions('btOptions', {\n          mode: 'default', // default | flat\n          headerClass: [],\n          contentClass: []\n        })\n        .withVM({\n          tabs: {\n            $init() {\n              this.current = scope.btCurrent || scope.tabs[0].name;\n              this.all = scope.tabs;\n            },\n          }\n        })\n        .withEvents({\n          onTabClick(tabName: string) {\n            scope.vm.tabs.current = tabName;\n            $timeout(() => scope.onChange({tab: tabName}));\n          }\n        });\n\n      transclude((clone, transcludedScope) => {\n        element.find('.bi-tabs-content').append(clone);\n\n        transcludedScope.tabs = {\n          get current() {\n            return scope.vm.tabs.current;\n          }\n        };\n      });\n\n      element.addClass(`bi-tabs--${scope.options.mode}`);\n      scope.$watch('btCurrent', current => current && (scope.vm.tabs.current = current));\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tags/tags.html",
    "content": "<bi-dropdown\n  class=\"bi-row-inline bi-grow\"\n  bd-is-open=\"vm.options.enabled\"\n  bd-options=\"::{\n    width: options.dropdownWidth,\n    minWidth: options.dropdownMinWidth,\n    toggleOn: 'manual'\n  }\"\n  on-show=\"events.onDropdownShow()\"\n  on-hide=\"events.onDropdownHide()\"\n  readonly=\"::readonly\"\n  >\n  <bi-toggle class=\"bi-grow\">\n    <div class=\"bi-tags-container bi-input bi-wrap bi-grow\">\n      <div\n        class=\"bi-tags-tag bi-r-i bi-dont-grow bi-align bi-border bi-space-h--x05\"\n        ng-repeat=\"tag in model\"\n      >\n        <span class=\"bi-tags-content\" bi-html=\"renderTag(tag)\"></span>\n        <i\n          ng-if=\"::!readonly\"\n          class=\"bi-tags-remove bi-action bi-icon bi-fade-in\"\n          ng-click=\"events.onOptionDelete(tag);\"\n        >close</i>\n      </div>\n\n      <input\n        class=\"bi-tags-input bi-input bi-grow\"\n        ng-if=\"::!readonly\"\n        ng-model=\"vm.search.text\"\n        ng-model-options=\"::{debounce: options.debounce}\"\n        ng-change=\"events.onSearchChange()\"\n        ng-keydown=\"events.onSearchKeypress($event)\"\n        ng-blur=\"events.onSearchBlur()\"\n        ng-mousedown=\"events.onSearchMousedown()\"\n        placeholder=\"{{::placeholder || 'Enter a tag'}}\"\n        type=\"{{options.type}}\"\n      >\n      </input>\n    </div>\n  </bi-toggle>\n\n  <div\n    bi-key-nav=\"buffer\"\n    key-nav-options=\"::{markFirst: !options.freetext}\"\n    key-nav-current-item=\"vm.keyNavOption\"\n    key-nav-on-select=\"events.onOptionSelect(item)\"\n  >\n    <ul\n      class=\"bi-dropdown-menu\"\n      bi-infinite-scroll=\"vm.options.items()\"\n      bis-buffer=\"buffer\"\n    >\n      <li\n        class=\"bi-text--sm bi-muted bi-fade-in\"\n        ng-class=\"{'bi-active': vm.search.enabled && options.freetext}\"\n        ng-if=\"options.typeahead && !vm.options.items().length && !vm.options.deferred.loading\"\n      >\n        <span ng-if=\"vm.search.enabled\">\n          <span class=\"bi-text--600\" ng-if=\"options.freetext\">{{vm.search.text}}</span>\n          <span ng-if=\"!options.freetext\">No matches</span>\n        </span>\n\n        <span ng-if=\"!vm.search.enabled\">Start typing to see matches</span>\n      </li>\n\n      <li class=\"bi-center bi-fade-in\" ng-if=\"vm.options.deferred.loading\">\n        <span class=\"bi-spinner--sm\"></span>\n      </li>\n\n      <li\n        ng-class=\"{\n          selected: option === model,\n          'bi-active': option === vm.keyNavOption\n        }\"\n        ng-repeat=\"option in buffer\"\n        ng-mousedown=\"$event.preventDefault()\"\n        ng-click=\"events.onOptionSelect(option)\"\n        bi-html=\"renderOption(option)\"\n        key-nav-item\n      ></li>\n    </ul>\n  </div>\n</bi-dropdown>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tags/tags.scss",
    "content": "@import '../../assets/css/def/defaults.def.scss';\n@import '../../assets/css/def/colors.def.scss';\n@import '../../assets/css/def/flex.def.scss';\n\n$tags-input-height: $default-input-height - 2*$default-border-width;\n\nbi-tags {\n  @include flex(column);\n\n  .bi-tags-container {\n    display: flex !important;\n    min-height: 36px !important;\n    padding: 5px 5px 0 5px !important;\n    background: $white !important;\n    height: auto !important;\n  }\n\n  .bi-tags-input {\n    min-width: 50px !important;\n    height: 25px !important;\n    margin: 0 5px 5px 0 !important;\n    padding: 0 10px !important;\n    border: 0 !important;\n    background-color: transparent !important;\n  }\n\n  .bi-tags-tag {\n    max-width: 100%;\n    margin: 0 5px 5px 0;\n    padding: 0 10px;\n    background-color: $grey--200;\n    border-radius: 3px;\n    height: $default-input-height - 2 * 6px;\n    line-height: 24px;\n\n    &:last-of-type {\n      margin-right: 0;\n    }\n\n    .bi-tags-content {\n      white-space: nowrap;\n      overflow: hidden;\n      text-overflow: ellipsis;\n    }\n\n    .bi-tags-remove {\n      margin-right: -4px;\n      font-size: 10px;\n      font-weight: bold;\n\n      &:hover {\n        background-color: darken($grey--200, 5) !important;\n      }\n    }\n  }\n\n  bi-dropdown {\n    .bi-dropdown-menu {\n      display: block;\n      margin-top: -1px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tags/tags.story.ts",
    "content": "import {inject} from '../../../core';\n\nexport default app => app\n  .story('UI', 'Tags')\n    .section('Tags', `\n      <bi-tags\n        ng-non-bindable\n        style=\"width: 500px;\"\n        bi-options=\"tag for tag in ::['one', 'two', 'three']\"\n        ng-model=\"tags\"\n        placeholder=\"Add a tag\"\n      ></bi-tags>\n\n      <output>tags: {{tags}}</output>\n\n      <bi-tags\n        ng-non-bindable\n        bi-options=\"tag for tag in ::['one', 'two', 'three']\"\n        bt-options=\"::{freetext: true}\"\n        ng-model=\"tagsfreetext\"\n        placeholder=\"Add a tag (freetext)\"\n      ></bi-tags>\n\n      <output>tagsfreetext: {{tagsfreetext}}</output>\n\n      <bi-tags\n        ng-non-bindable\n        bi-options=\"tag for tag in ::['one', 'two', 'three']\"\n        bt-options=\"::{freetext: true, autocomplete: false}\"\n        ng-model=\"tagsfreetextnoac\"\n        placeholder=\"Add a tag (freetext + noautocomplete)\"\n      ></bi-tags>\n\n      <output>tagsfreetext: {{tagsfreetextnoac}}</output>\n\n      <bi-tags\n        ng-non-bindable\n        bi-options=\"tag for tag in ::['one', 'two', 'three']\"\n        ng-model=\"tagsdisabled\"\n        placeholder=\"I'm disabled\"\n        readonly=\"true\"\n      ></bi-tags>\n\n      <output>tagsrequired: {{tagsrequired}}</output>\n\n      <bi-tags\n        ng-non-bindable\n        bi-options=\"tag for tag in ::['one', 'two', 'three']\"\n        ng-model=\"tagsrequired\"\n        placeholder=\"I'm required\"\n        required=\"true\"\n      ></bi-tags>\n    `).section('Tags deferred', `\n      <bi-tags\n        ng-non-bindable\n        style=\"width: 500px;\"\n        bi-options=\"tag as tag.title for tag in promise\"\n        ng-model=\"deferredTags\"\n        on-input-change=\"onInputChange()\"\n        placeholder=\"Add a tag\"\n      ></bi-tags>\n    `, scope => {\n      scope.onInputChange = () => scope.promise = inject('$timeout')(() => {\n        return [{title: 'option 1', value: 1}, {title: 'option 2', value: 2}, {title: 'option 3', value: 3}];\n      }, 2000);\n    });\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tags/tags.ts",
    "content": "import template from './tags.html';\nimport './tags.scss';\n\nimport {DropdownList} from '../common/dropdown-list';\n\nexport interface IScope extends ng.IScope {\n  model: any[];\n}\n\nfunction renderTag(transclude, biOptions, tag) {\n  let html;\n\n  if (transclude.isSlotFilled('tag')) {\n    html = transclude((_, tscope) => {\n      tscope.tag = tag;\n    }, null, 'tag');\n  } else {\n    html = biOptions.render(tag);\n  }\n\n  return {html};\n}\n\nexport default function directive(): ng.IDirective {\n  return {\n    template,\n    require: ['ngModel', 'biOptions'],\n    restrict: 'E',\n    transclude: {\n      tag: '?tag',\n      opt: '?opt',\n    },\n    scope: {\n      btOptions: '=',\n      onTypeahead: '&',\n      readonly: '=',\n      placeholder: '@'\n    },\n\n    link: {\n      pre(scope: IScope, element, attrs, [ngModel, biOptions]: [ng.INgModelController, any], transclude) {\n        scope.renderTag = tag => renderTag(transclude, biOptions, tag);\n\n        return new DropdownList(scope, element, attrs, {ngModel, biOptions}, transclude, {\n          optionsAlias: 'btOptions',\n          isArray: true,\n          options: {\n            freetext: false,\n            typeahead: true,\n          }\n        });\n      }\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.html",
    "content": "<bi-dropdown bd-options=\"::{\n  toggleOn: 'hover',\n  hideOnClick: false,\n  align: 'center',\n  delay: {show: 150},\n  position: options.position\n}\">\n  <bi-toggle ng-transclude=\"toggle\"></bi-toggle>\n\n  <div class=\"bi-tooltip-content\">\n    <div class=\"bi-tooltip-backdrop\"></div>\n    <div ng-if=\"!!btText\">{{::btText}}</div>\n    <div ng-transclude></div>\n  </div>\n</bi-dropdown>"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.scss",
    "content": "@import '../../assets/css/def/defaults.def';\n@import '../../assets/css/def/colors.def';\n\nbi-tooltip {\n  display: inline-flex;\n\n  .bd-content {\n    background-color: transparent !important;\n  }\n\n  .bd-position--top {\n    .bi-tooltip-content {\n      margin-top: 0;\n      margin-bottom: 8px;\n\n      &:before {\n        top: initial;\n        bottom: -6px;\n        border-width: 6px 6px 0 6px;\n        border-color: #000000 transparent transparent transparent;\n      }\n    }\n  }\n\n  .bi-tooltip-content {\n    position: relative;\n    margin-top: 16px;\n    padding: 8px 14px;\n    color: $white;\n    font-size: 11px;\n    white-space: nowrap;\n    box-shadow: $default-box-shadow;\n\n    &:before {\n      position: absolute;\n      content: '';\n      top: -6px;\n      left: 50%;\n      width: 0;\n      height: 0;\n      margin-left: -5px;\n      border-style: solid;\n      border-width: 0 6px 6px 6px;\n      border-color: transparent transparent #000000 transparent;\n      opacity: .8;\n    }\n\n    > .bi-tooltip-backdrop {\n      position: absolute;\n      top: 0;\n      left: 0;\n      right: 0;\n      bottom: 0;\n      background-color: $black;\n      border-radius: 3px;\n      opacity: .8;\n    }\n\n    > * {\n      position: relative;\n      z-index: 1;\n\n      > * {\n        text-transform: initial;\n        font-weight: normal;\n        white-space: nowrap;\n      }\n    }\n  }\n\n  [ng-transclude=\"toggle\"] {\n    cursor: default !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.story.ts",
    "content": "export default app => app\n  .story('UI', 'Tooltip')\n    .section('Tooltip', `\n      <bi-tooltip bt-text=\"This does something\" ng-non-bindable>\n        <bi-toggle>\n          <button type=\"button\" class=\"bi-button--primary\">default tooltip</button>\n        </bi-toggle>\n      </bi-tooltip>\n\n      <bi-tooltip bt-text=\"I'm on top\" bt-options=\"{position: 'top'}\" ng-non-bindable>\n        <bi-toggle>\n          <button type=\"button\" class=\"bi-button--primary\">tooltip on top</button>\n        </bi-toggle>\n      </bi-tooltip>\n\n      <bi-tooltip ng-non-bindable>\n        <bi-toggle>\n          <button type=\"button\" class=\"bi-button--primary\">HTML tooltip</button>\n        </bi-toggle>\n\n        <div class=\"bi-text--lg\">I'm big!</div>\n        <div>Linebreak!</div>\n      </bi-tooltip>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/directives/tooltip/tooltip.ts",
    "content": "import {initNgScope} from '../../../core';\n\nimport './tooltip.scss';\nimport template from './tooltip.html';\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    transclude: {\n      toggle: 'biToggle'\n    },\n    scope: {\n      btText: '@',\n      btOptions: '<'\n    },\n\n    link: {\n      pre(scope) {\n        initNgScope(scope).withOptions('btOptions', {\n          position: 'bottom'\n        });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/absolute-date.ts",
    "content": "import DateService from '../services/date';\n\nexport default function() {\n  return function (date: string) {\n    return DateService.moment(date).format(DateService.DATE_FORMAT);\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/date-utc.ts",
    "content": "import {inject} from '../../core';\nimport DateService from '../services/date';\n\nexport default function() {\n  return function (date: string | number, resolutionOrFormat: 'seconds' | 'milliseconds') {\n    date = DateService.fromUTC(date).valueOf();\n\n    let format = 'yyyy-MM-dd HH:mm';\n\n    if (resolutionOrFormat === 'seconds') {\n      format += ':ss';\n    } else if (resolutionOrFormat === 'milliseconds') {\n      format += ':ss.sss';\n    } else {\n      format = resolutionOrFormat;\n    }\n\n    return inject('$filter')('date')(date, format);\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/date.ts",
    "content": "import {inject} from '../../core';\n\nexport default function() {\n  return function (date: string, resolutionOrFormat?: 'seconds' | 'milliseconds') {\n    let format = 'yyyy-MM-dd HH:mm';\n\n    if (resolutionOrFormat === 'seconds') {\n      format += ':ss';\n    } else if (resolutionOrFormat === 'milliseconds') {\n      format += ':ss.sss';\n    } else {\n      format = resolutionOrFormat;\n    }\n\n    return inject('$filter')('date')(date, format);\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/highlight.story.ts",
    "content": "export default app => app\n  .story('UI', 'Highlight')\n    .section('Highlight', `\n      <div ng-non-bindable ng-bind-html=\"'Hello World!' | biHighlight:'World'\"></div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/highlight.ts",
    "content": "export default [\n  '$sce',\n  ($sce) => {\n    return (haystack, needle: string | string[]) => {\n      if (!haystack || !needle) {\n        return haystack;\n      }\n      const needles: string[] = typeof needle === 'string' ? [needle] : needle;\n\n      // tslint:disable-next-line: restrict-plus-operands\n      return $sce.trustAsHtml(('' + haystack).replace(new RegExp(needles.map(n => `(${n})`).join('|'), 'gi'), match => `<mark>${match}</mark>`));\n    };\n  },\n];\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/index.ts",
    "content": "export {default as biToHumanCase} from './to-human-case';\nexport {default as biDate} from './date';\nexport {default as biDateUTC} from './date-utc';\nexport {default as biRelativeDate} from './relative-date';\nexport {default as biHighlight} from './highlight';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/relative-date.ts",
    "content": "import DateService from '../services/date';\n\nexport default function() {\n  return function (date: string) {\n    return DateService.moment(date).fromNow();\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/filters/to-human-case.ts",
    "content": "import {last} from 'lodash';\n\nexport default function() {\n  const regexp = /(^.)|(_.)|(.[A-Z])/g;\n\n  function capitalize(input: string) {\n    return input.replace(regexp, function (match) {\n      const res = last(match).toUpperCase();\n\n      if (match.length === 1) {\n        return res;\n      }  if (match.charAt(0) === '_') {\n        return ' ' + res;\n      }\n\n      return match.charAt(0) + ' ' + res;\n    });\n  }\n\n  return function (input: string) {\n    return capitalize(input || '');\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/index.ts",
    "content": "import angular from 'angular';\nimport 'angular-sanitize';\nimport 'angular-svg-round-progressbar';\n\nimport init from './init';\nimport './app.scss';\n\ninit(angular.module('bi.ui', [\n  'ngSanitize',\n  'bi.core',\n  'angular-svg-round-progressbar'\n]));\n\nexport * from './services';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/init.ts",
    "content": "import {forEach} from 'lodash';\nimport * as directives from './directives';\nimport * as filters from './filters';\n\nconst excluded = ['contenteditable'];\n\nfunction toDirectiveName(name: string) {\n  if (excluded.indexOf(name) !== -1) {\n    return name;\n  }\n\n  return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`;\n}\n\nexport default function init(ngApp: angular.IModule) {\n  forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any));\n  forEach(filters, (fn, name) => ngApp.filter(name, fn as any));\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/confirm.story.ts",
    "content": "import {inject} from '../../../core';\nimport {default as confirm} from './confirm';\n\nexport default app => app\n  .story('UI', 'Dialog')\n    .section('Confirm dialog', `\n      <button class=\"bi-button--primary\" ng-click=\"showConfirm()\">show confirm dialog</button>\n\n      <code>import {confirm} from '@wix/bi-ui';</code>\n      <output>{{output}}</output>\n\n      <dialog class=\"confirm\" yes=\"continue\" no=\"nope\" ng-non-bindable>\n        <dialog-title>my custom confirm dialog</dialog-title>\n        <dialog-content>Are you sure you want to continue?</dialog-content>\n      </dialog>\n    `, (scope, element) => {\n      scope.showConfirm = () => confirm(element.find('dialog.confirm'), scope)\n        .then(() => scope.output = 'resolved', () => scope.output = 'rejected');\n    })\n    .section('Deferred confirm', `\n      <button class=\"bi-button--primary\" ng-click=\"showDeferred()\">show deferred</button>\n      <button class=\"bi-button--primary\" ng-click=\"showDeferredWithError()\">show deferred with error</button>\n\n      <dialog class=\"deferred-confirm\" on-confirm=\"onConfirm()\" ng-non-bindable>\n        <dialog-title>deferred confirm</dialog-title>\n        <dialog-content>Are you sure you want to continue?</dialog-content>\n      </dialog>\n\n      <dialog class=\"deferred-confirm-error\" on-confirm=\"onConfirmWithError()\" ng-non-bindable>\n        <dialog-title>deferred confirm</dialog-title>\n        <dialog-content>Are you sure you want to continue?</dialog-content>\n      </dialog>\n    `, (scope, element) => {\n      scope.showDeferred = () => confirm(element.find('dialog.deferred-confirm'), scope);\n      scope.showDeferredWithError = () => confirm(element.find('dialog.deferred-confirm-error'), scope);\n      scope.onConfirm = () => inject('$timeout')(() => true, 3000);\n      scope.onConfirmWithError = () => inject('$timeout')(() => {\n        return inject('$q').reject({errorDescription: 'Deferred error!'});\n      }, 3000);\n    });\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/confirm.ts",
    "content": "import { defaults, assign } from 'lodash';\nimport { inject } from '../../core';\nimport { default as dialog, IDialogOptions } from './dialog';\n\nexport interface IConfirmOptions extends IDialogOptions {\n  actionType: 'create' | 'destroy' | 'trash' | 'neutral';\n  icon?: string;\n  yes?: string;\n  no?: string;\n  resolveOnEnter?: boolean;\n}\n\nfunction init(htmlOrOptions: string | IConfirmOptions, promise: any) {\n  let { scope, element } = promise;\n  let options: Partial<IConfirmOptions>;\n\n  scope = scope();\n  element = element();\n\n  if (typeof htmlOrOptions === 'string') {\n    options = {\n      actionType: 'neutral',\n      yes: element.attr('yes'),\n      no: element.attr('no'),\n    };\n  } else {\n    options = htmlOrOptions;\n  }\n\n  options = defaults({}, options, {\n    actionType: 'neutral',\n    yes: 'yes',\n    no: 'cancel',\n  });\n\n  scope.dialogOptions.showCloseAction = false;\n  scope.dialogOptions.iconClass =\n    options.actionType === 'destroy' || options.actionType === 'trash'\n      ? 'bi-danger'\n      : 'bi-primary';\n\n  if (options.resolveOnEnter) {\n    element = element.bind('keyup', (event) => {\n      if (event.which === 13) {\n        scope.dialogEvents.resolve();\n      }\n    });\n  }\n\n  element.addClass('bi-confirm').append(\n    inject('$compile')(`\n      <dialog-footer class=\"bi-justify-right bi-space-h\">\n        <button \n          class=\"bi-button\"\n          ng-click=\"dialogEvents.reject()\"\n        >{{::confirmOptions.no}}</button>\n\n        <button\n          ng-class=\"::{\n            destroy: 'bi-button--danger',\n            trash: 'bi-button--danger',\n            create: 'bi-button--success',\n            neutral: 'bi-button--primary'\n          }[confirmOptions.actionType]\"\n          ng-click=\"dialogEvents.resolve()\"\n          ng-disabled=\"form && !form.$valid\"\n        >{{::confirmOptions.yes}}</button>\n      </dialog-footer>\n    `)(assign(scope, { confirmOptions: options }))\n  );\n\n  return promise;\n}\n\nexport default function(\n  htmlOrOptions: string | IConfirmOptions,\n  scope?,\n  locals?\n) {\n  return init(htmlOrOptions, dialog(htmlOrOptions, scope, locals));\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/date.ts",
    "content": "import moment from 'moment';\n\nif (moment) {\n  moment.locale('en', {\n    relativeTime : {\n      future: 'in %s',\n      past: '%s ago',\n      s: '%d second',\n      ss: '%d seconds',\n      m: '%d minute',\n      mm: '%d minutes',\n      h: '%d hour',\n      hh: '%d hours',\n      d: '%d day',\n      dd: '%d days',\n      M: '%d month',\n      MM: '%d months',\n      y: '%d year',\n      yy: '%d years'\n    }\n  });\n}\n\nfunction getTimezoneOffset(date) {\n  return new Date(date).getTimezoneOffset();\n}\n\nexport default class DateService {\n  public static DATE_FORMAT = 'YYYY-MM-DD HH:mm';\n  private readonly date: number | string;\n\n  constructor(date?: number | string) {\n    this.date = date || Date.now();\n  }\n\n  static moment = moment;\n\n  static getRange(duration, {maxDate = null, format = false} = {}) {\n    let start, end;\n    const now = moment(maxDate || undefined).utc().startOf('day');\n\n    start = now.clone().subtract(moment.duration(duration));\n    end = now;\n\n    if (format) {\n      start = start.format();\n      end = end.format();\n    } else {\n      start = start.valueOf();\n      end = end.valueOf();\n    }\n\n    return {start, end};\n  }\n\n  static fromUTC(date) {\n    return moment(date).add(getTimezoneOffset(date), 'minutes');\n  }\n\n  fromUTC() {\n    return moment(this.date).add(getTimezoneOffset(this.date), 'minutes');\n  }\n\n  toUTC() {\n    return moment.utc(this.date).subtract(getTimezoneOffset(this.date), 'minutes');\n  }\n\n  asMoment() {\n    return moment(this.date);\n  }\n\n  asDate() {\n    return new Date(this.date as string);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/dialog-testkit.ts",
    "content": "import { Testkit } from '../../../../test/e2e/driver';\n\nexport class DialogTestkit extends Testkit {\n  async isShown() {\n    return (await this.query.$('dialog')) !== null;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/dialog.story.ts",
    "content": "import {default as dialog} from './dialog';\n\nexport default app => app\n  .story('UI', 'Dialog')\n    .section('Dialog', `\n      <button class=\"bi-button--primary\" ng-click=\"showDialog()\">show dialog</button>\n\n      <code>import {dialog} from '@wix/bi-ui';</code>\n      <output>{{output}}</output>\n\n      <dialog class=\"dialog\" ng-non-bindable>\n        <dialog-title>my custom dialog</dialog-title>\n        <dialog-content>Dialog content</dialog-content>\n      </dialog>\n    `, (scope, element) => {\n      scope.showDialog = () => {\n        dialog(element.find('dialog.dialog'), scope).then(() => scope.output = 'resolved', () => scope.output = 'rejected');\n      };\n    });\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/dialog.ts",
    "content": "import {assign, defaults} from 'lodash';\nimport angular from 'angular';\nimport {registerDialog} from 'dialog-polyfill';\nimport {inject} from '../../core';\n\nlet instance = {scope: null, dialog: null};\n\nexport interface IDialog extends ng.IPromise<any> {\n  element(): Object;\n  scope(): Object;\n}\n\nexport interface IDialogOptions {\n  html: string;\n  title?: string;\n  subTitle?: string;\n  icon?: string;\n  showCloseAction?: boolean;\n  onConfirm?(scope): any;\n}\n\nfunction createScope(deferred, scope?, locals?) {\n  scope = scope ? scope.$new() : inject('$rootScope').$new(true);\n\n  if (locals) {\n    assign(scope, locals);\n  }\n\n  scope.dialogEvents = {\n    reject() {\n      deferred.reject();\n    },\n    resolve() {\n      const res = this.onConfirm(scope);\n\n      if (res && res.then) {\n        scope.dialogError = null;\n        scope.dialogResolving = true;\n\n        res\n          .then(r => deferred.resolve(r, scope), e => scope.dialogError = e)\n          .finally(() => scope.dialogResolving = false);\n      } else {\n        deferred.resolve(scope);\n      }\n    }\n  };\n\n  return scope;\n}\n\nfunction showDialog(scope, htmlOrOptions: string | IDialogOptions) {\n  let options: IDialogOptions;\n\n  if (typeof htmlOrOptions === 'string') {\n    options = {\n      html: htmlOrOptions\n    }\n  } else {\n    options = {\n      ...htmlOrOptions,\n      html:  `\n        <dialog class=\"bi-theme--lighter\">\n          <dialog-title class=\"bi-align bi-s-h\">\n            ${htmlOrOptions.icon ? `\n            <i\n              class=\"bi-dialog-icon bi-icon\"\n              ng-class=\"dialogOptions.iconClass\"\n            >${htmlOrOptions.icon}</i>\n          ` : ''}\n            <span>${htmlOrOptions.title}</span>\n          </dialog-title>\n\n          ${htmlOrOptions.subTitle ? `<dialog-subtitle class=\"bi-muted\">${htmlOrOptions.subTitle}</dialog-subtitle>` : ''}\n\n          <dialog-content class=\"bi-c-h\">\n            ${htmlOrOptions.html}\n          </dialog-content>\n        </dialog>\n      `\n    };\n  }\n\n  options = defaults({}, options, {\n    showCloseAction: true\n  });\n\n  const element = angular.element(options.html)\n    .removeAttr('ng-non-bindable')\n    .addClass('bi-dialog')\n    .prepend(`\n      <span class=\"bi-dialog-close\" ng-if=\"dialogOptions.showCloseAction\">\n        <i class=\"bi-action bi-icon\" ng-click=\"dialogEvents.reject()\">close</i>\n      </span>\n      <span class=\"bi-dialog-loader bi-spinner\" ng-if=\"dialogResolving\"><span>\n    `)\n    .append(`\n      <dialog-error \n        class=\"bi-danger\"\n        ng-if=\"error\"\n      >{{dialogError.data && dialogError.data.errorDescription || 'Unknown error'}}</dialog-error>\n    `);\n\n  scope.dialogEvents.onConfirm = options.onConfirm || (() => inject('$parse')(element.attr('on-confirm'))(scope));\n\n  const dialog = inject('$compile')(element)(assign(scope, {dialogOptions: options}))\n    .on('close', () => scope.dialogEvents.reject())\n    .appendTo(window.document.body)\n    .get(0);\n\n  registerDialog(dialog);\n\n  inject('$timeout')(() => dialog.showModal());\n\n  return (instance = {scope, dialog});\n}\n\nfunction destroy({scope, dialog}) {\n  if (scope) {\n    scope.$destroy();\n  }\n\n  if (dialog) {\n    if (dialog.getAttribute('open') !== null) {\n      dialog.close();\n    }\n    dialog.remove();\n  }\n\n  instance = {scope: null, dialog: null};\n}\n\nexport default function(htmlOrOptions: string | IDialogOptions, parentScope?, locals?): IDialog {\n  destroy(instance);\n\n  const deferred = ((inject('$q') as ng.IQService)).defer();\n  const {scope, dialog} = showDialog(createScope(deferred, parentScope, locals), htmlOrOptions);\n\n  const promise = deferred.promise.finally(() => destroy({scope, dialog})) as IDialog;\n  promise.element = () => angular.element(dialog);\n  promise.scope = () => scope;\n\n  return promise;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/index.ts",
    "content": "export {default as dialog} from './dialog';\nexport {default as confirm} from './confirm';\nexport {default as BiDate} from './date';\n\nimport * as toastExport from './toast';\nexport const toast = toastExport;\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/toast.scss",
    "content": "@import '../assets/css/def/colors.def';\n@import '../assets/css/def/defaults.def';\n@import '../assets/css/def/action.def';\n\n.bi-toast {\n  position: fixed;\n  left: 15px;\n  bottom: 15px;\n  padding: 0 20px;\n  line-height: 48px;\n  color: $white;\n  background-color: darken($grey--800, 7);\n  border-radius: 3px;\n  box-shadow: $default-box-shadow;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/toast.story.ts",
    "content": "import * as toast from './toast';\n\nexport default app => app\n  .story('UI', 'Toast')\n    .section('Toast', `\n      <code>import {toast} from '@wix/bi-ui';</code>\n\n      <button\n        type=\"button\"\n        class=\"bi-button--primary\"\n        ng-click=\"status !== 'visible' ? showToast({\n          text: 'I am a toast'\n        }) : hideToast()\"\n      >\n        {{status !== 'visible' ? 'show toast' : 'hide toast'}}\n      </button>\n\n      <button\n        type=\"button\"\n        class=\"bi-button--primary\"\n        ng-click=\"showToast({\n          text: 'You can hide me',\n          ok: 'do something',\n          cancel: 'hide'\n        })\"\n      >\n        show toast with actions\n      </button>\n\n      <button\n        type=\"button\"class=\"bi-button--primary\"\n        ng-click=\"showToast({\n          text: 'I will be hidden in 3 seconds',\n          hideDelay: 3000\n        })\"\n      >\n        show toast with hide delay\n      </button>\n\n      <output>Status: {{status}}</output>\n    `, $scope => {\n      $scope.status = 'hidden';\n\n      $scope.showToast = (({text, cancel, ok, hideDelay}) => {\n        $scope.status = 'visible';\n\n        toast.showToast({text, cancel, ok, hideDelay})\n          .then(() => $scope.status = 'hidden and resolved')\n          .catch(() => $scope.status = 'hidden and rejected');\n      });\n\n      $scope.hideToast = () => {\n        $scope.status = 'hidden';\n        toast.hideToast();\n      };\n    });\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/services/toast.ts",
    "content": "import {last} from 'lodash';\nimport {inject, utils} from '../../core';\n\nimport './toast.scss';\n\nenum Icons {\n  success = 'check',\n  error = 'error_outline',\n}\n\nenum IconClass {\n  success = 'bi-success',\n  error = 'bi-danger',\n}\n\nlet instances = [];\nlet hideTimeout = null;\n\nfunction createScope(deferred) {\n  const scope = inject('$rootScope').$new(true);\n\n  scope.ok = function() {\n    deferred.resolve();\n  };\n\n  scope.cancel = function() {\n    deferred.reject();\n  };\n\n  return scope;\n}\n\nfunction show(scope, text, type, okText, cancelText) {\n  scope.text = text;\n  scope.type = Icons[type];\n  scope.okText = okText;\n  scope.cancelText = cancelText;\n  scope.iconClass = IconClass[type];\n\n  const element = inject('$compile')(`\n    <div class=\"bi-toast bi-align bi-s-h--x3 bi-fade-in\">\n      <span class=\"bi-align bi-s-h\">\n        <span class=\"bi-icon {{::iconClass}}\" ng-if=\"type\">{{::type}}</span>\n        <span class=\"bi-toast-text\">{{text}}</span>\n      </span>\n\n      <span class=\"bi-s-h\">\n        <span class=\"bi-action bi-label\" ng-if=\"okText\" ng-click=\"ok()\">{{::okText}}</span>\n        <span class=\"bi-action bi-label\" ng-if=\"cancelText\" ng-click=\"cancel()\">{{::cancelText}}</span>\n      </span>\n    </div>\n  `)(scope);\n\n  instances.push({scope, element});\n\n  inject('$timeout')(() => element.appendTo(window.document.body));\n}\n\nfunction destroy() {\n  while (instances.length) {\n    const {scope, element} = instances.pop();\n\n    element.remove();\n    scope.$destroy();\n  }\n\n  inject('$timeout').cancel(hideTimeout);\n\n  hideTimeout = null;\n  instances = [];\n}\n\nexport function showToast({\n  text,\n  type = null,\n  ok = '',\n  cancel = '',\n  hideDelay = 0\n}: {\n  text: string;\n  type?: 'success' | 'error' | null;\n  ok?: string;\n  cancel?: string;\n  hideDelay?: number;\n}, hideDelayArg = hideDelay) {\n  const deferred = ((inject('$q') as ng.IQService)).defer();\n  const scope = createScope(deferred);\n\n  destroy();\n  show(scope, text, type, ok, cancel);\n\n  if (hideDelayArg) {\n    hideTimeout = inject('$timeout')(destroy, hideDelayArg);\n  }\n\n  return deferred.promise.finally(destroy);\n}\n\nexport function hideToast() {\n  destroy();\n}\n\nexport function updateText(text: string) {\n  if (!instances.length) {\n    return;\n  }\n\n  const {scope} = last(instances);\n  utils.scope.safeApply(scope, () => scope.text = text);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/action.story.ts",
    "content": "export default app => {\n  app.story('UI', 'Action')\n    .section('Icon actions', /*html*/`\n      <div class=\"bi-column bi-space-v\">\n        <div class=\"bi-space-h--x2\">\n          <span class=\"bi-action bi-icon\">save</span>\n          <span class=\"bi-action bi-icon\">cached</span>\n          <span class=\"bi-action bi-icon\">delete</span>\n          <span class=\"bi-action bi-icon--sm\">save</span>\n          <span class=\"bi-action bi-icon--sm\">cached</span>\n          <span class=\"bi-action bi-icon--sm\">delete</span>\n          <span class=\"bi-action bi-icon--xs\">save</span>\n          <span class=\"bi-action bi-icon--xs\">cached</span>\n          <span class=\"bi-action bi-icon--xs\">delete</span>\n        </div>\n        <div class=\"bi-space-h--x2\">\n          <span class=\"bi-action bi-icon\" disabled=\"disabled\">save</span>\n          <span class=\"bi-action bi-icon\" disabled=\"disabled\">cached</span>\n          <span class=\"bi-action bi-icon\" disabled=\"disabled\">delete</span>\n          <span class=\"bi-action bi-icon--sm\" disabled=\"disabled\">save</span>\n          <span class=\"bi-action bi-icon--sm\" disabled=\"disabled\">cached</span>\n          <span class=\"bi-action bi-icon--sm\" disabled=\"disabled\">delete</span>\n          <span class=\"bi-action bi-icon--xs\" disabled=\"disabled\">save</span>\n          <span class=\"bi-action bi-icon--xs\" disabled=\"disabled\">cached</span>\n          <span class=\"bi-action bi-icon--xs\" disabled=\"disabled\">delete</span>\n        </div>\n      </div>\n      <footer>See all available icons <a class=\"bi-link\" href=\"https://material.io/icons/\" target=\"_blank\">here</a></footer>\n    `)\n    .section('Buttons actions', /*html*/`\n      <div class=\"bi-column bi-space-v\">\n        <div class=\"bi-space-h--x2\">\n          <span class=\"bi-action--btn\">default</span>\n          <span class=\"bi-action--btn bi-primary bi-text--sm\">primary</span>\n          <span class=\"bi-action--btn bi-success\">success</span>\n          <span class=\"bi-action--btn bi-warning\">warning</span>\n          <span class=\"bi-action--btn bi-danger\">danger</span>\n        </div>\n        <div class=\"bi-space-h--x2\">\n          <span class=\"bi-action--btn\" disabled=\"disabled\">default</span>\n          <span class=\"bi-action--btn bi-primary\" disabled=\"disabled\">primary</span>\n          <span class=\"bi-action--btn bi-success\" disabled=\"disabled\">success</span>\n          <span class=\"bi-action--btn bi-warning\" disabled=\"disabled\">warning</span>\n          <span class=\"bi-action--btn bi-danger\" disabled=\"disabled\">danger</span>\n        </div>\n      </div>\n    `)\n    .section('Round actions', /*html*/`\n      <div class=\"bi-column bi-space-v\">\n        <div class=\"bi-space-h--x2\">\n          <span class=\"bi-action--rnd bi-icon\">edit</span>\n          <span class=\"bi-action--rnd bi-icon--sm\">edit</span>\n          <span class=\"bi-action--rnd bi-icon--xs\">edit</span>\n        </div>\n        <div class=\"bi-space-h--x2\">\n          <span class=\"bi-action--rnd bi-icon\" disabled=\"disabled\">edit</span>\n          <span class=\"bi-action--rnd bi-icon--sm\" disabled=\"disabled\">edit</span>\n          <span class=\"bi-action--rnd bi-icon--xs\" disabled=\"disabled\">edit</span>\n        </div>\n      </div>\n    `);\n\n  app.story('UI', 'Loader')\n    .section('Action loader', /*html*/`\n    <span class=\"bi-action bi-icon\" ng-class=\"{'bi-action-loader': actionClicked}\" ng-click=\"actionClicked = !actionClicked\">\n      <span>cached</span>\n    </span>\n  `);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/alert.story.ts",
    "content": "export default app => app\n  .story('UI', 'Alert')\n    .section('Alert', /*html*/`\n      <div class=\"bi-s-v\">\n        <div class=\"bi-alert\" style=\"width: 300px;\">\n          <div class=\"bi-alert-header\">\n            My alert\n          </div>\n\n          <div class=\"bi-alert-content\">\n            My alert content\n          </div>\n        </div>\n        <div class=\"bi-alert--error\" style=\"width: 300px;\">\n          <div class=\"bi-alert-header\">\n            My error\n          </div>\n\n          <div class=\"bi-alert-content\">\n            01010110100100010101\n          </div>\n        </div>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/align.story.ts",
    "content": "export default app => app\n  .story('UI', 'Layout')\n    .section('Align', `\n      <div class=\"bi-row-inline bi-space-h--x05\">\n        <button class=\"bi-button\" type=\"button\">1</button>\n        <i class=\"bi-label--sm\">top</i>\n      </div>\n\n      <div class=\"bi-row-inline bi-space-h--x05 bi-align\">\n        <button class=\"bi-button\" type=\"button\">2</button>\n        <i class=\"bi-label--sm\">middle</i>\n      </div>\n\n      <div class=\"bi-row-inline bi-space-h--x05 bi-align--bottom\">\n        <button class=\"bi-button\" type=\"button\">3</button>\n        <i class=\"bi-label--sm\">bottom</i>\n      </div>\n    `)\n    .section('Spread', `\n      <div class=\"bi-spread\" style=\"width: 100%;\">\n        <button class=\"bi-button\" type=\"button\">look right</button>\n        <button class=\"bi-button\" type=\"button\">look left</button>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/badge.story.ts",
    "content": "export default app => app\n  .story('UI', 'Badge')\n    .section('Badge', `\n      <span class=\"bi-badge\">1</span>\n      <span class=\"bi-badge--primary\">2</span>\n      <span class=\"bi-badge--success\">3</span>\n      <span class=\"bi-badge--warning\">4</span>\n      <span class=\"bi-badge--danger\">5</span>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/border.story.ts",
    "content": "export default app => app\n  .story('UI', 'Misc')\n    .section('Border', `\n      <div class=\"bi-border\">I have a border</div>\n      <div class=\"bi-border--top\">I have a top border</div>\n      <div class=\"bi-border--right\">I have a right border</div>\n      <div class=\"bi-border--bottom\">I have a bottom border</div>\n      <div class=\"bi-border--left\">I have a left border</div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/button.story.ts",
    "content": "export default app => {\n  app.story('UI', 'Button')\n    .section('Main Buttons', `\n      <div class=\"bi-column bi-space-v\">\n        <div class=\"bi-space-h--x2\">\n          <button class=\"bi-button\" type=\"button\">Default</button>\n          <button class=\"bi-button--primary\" type=\"button\">primary</button>\n          <button class=\"bi-button--success\" type=\"button\">success</button>\n          <button class=\"bi-button--warning\" type=\"button\">warning</button>\n          <button class=\"bi-button--danger\" type=\"button\">danger</button>\n        </div>\n        <div class=\"bi-space-h--x2\">\n          <button class=\"bi-button\" type=\"button\" disabled=\"disabled\">Default</button>\n          <button class=\"bi-button--primary\" type=\"button\" disabled=\"disabled\">primary</button>\n          <button class=\"bi-button--success\" type=\"button\" disabled=\"disabled\">success</button>\n          <button class=\"bi-button--warning\" type=\"button\" disabled=\"disabled\">warning</button>\n          <button class=\"bi-button--danger\" type=\"button\" disabled=\"disabled\">danger</button>\n        </div>\n      </div>\n    `);\n\n  app.story('UI', 'Loader')\n    .section('Button loader', `\n      <button type=\"button\" class=\"bi-button--primary\" ng-class=\"{'bi-button-loader': buttonClicked}\" ng-click=\"buttonClicked = !buttonClicked\">\n        <span>click me</span>\n      </button>\n    `);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/colors.story.ts",
    "content": "export default app => app\n  .story('UI', 'Colors')\n    .section('Main colors', `\n      <span class=\"bi-icon\">color_lens</span>\n      <span class=\"bi-icon bi-muted\">color_lens</span>\n      <span class=\"bi-icon bi-primary\">color_lens</span>\n      <span class=\"bi-icon bi-success\">color_lens</span>\n      <span class=\"bi-icon bi-warning\">color_lens</span>\n      <span class=\"bi-icon bi-danger\">color_lens</span>\n\n      <code>@import '../lib/ui/assets/css/def/colors.def';</code>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/empty-state.story.ts",
    "content": "export default app => app\n  .story('UI', 'Empty state')\n    .section('Empty state', `\n      <div class=\"bi-empty-state\">\n        <div class=\"bi-empty-state-header\">Default state</div>\n        <div class=\"bi-empty-state-content\">State content</div>\n      </div>\n      <div class=\"bi-empty-state--info\">\n        <div class=\"bi-empty-state-header\">Info state</div>\n        <div class=\"bi-empty-state-content\">Empty state content</div>\n      </div>\n      <div class=\"bi-empty-state--info\">\n        <div class=\"bi-empty-state-content\">Empty state without header</div>\n      </div>\n      <div class=\"bi-empty-state--nothing\">\n        <div class=\"bi-empty-state-header\">Nothing state</div>\n        <div class=\"bi-empty-state-content\">Empty state content</div>\n      </div>\n      <div class=\"bi-empty-state--pending\">\n        <div class=\"bi-empty-state-header\">Pending state</div>\n        <div class=\"bi-empty-state-content\">Empty state content</div>\n      </div>\n      <div class=\"bi-empty-state--error\">\n        <div class=\"bi-empty-state-header\">Error state</div>\n        <div class=\"bi-empty-state-content\">Empty state content</div>\n      </div>\n      <div class=\"bi-empty-state--loading\">\n        <div class=\"bi-empty-state-content\">Empty state content</div>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/flex.story.ts",
    "content": "export default app => app\n  .story('UI', 'Layout')\n    .section('Column / Row', `\n      <div class=\"bi-row-inline bi-space-h--x3\">\n        <div class=\"bi-space-v\">\n          <span class=\"bi-label--sm\">column</span>\n          <div class=\"bi-column\">\n            <div><button class=\"bi-button\" type=\"button\">1</button></div>\n            <div><button class=\"bi-button\" type=\"button\">2</button></div>\n            <div><button class=\"bi-button\" type=\"button\">3</button></div>\n          </div>\n        </div>\n\n        <div class=\"bi-space-v\">\n          <span class=\"bi-label--sm\">row</span>\n          <div class=\"bi-row\">\n            <button class=\"bi-button\" type=\"button\">1</button>\n            <button class=\"bi-button\" type=\"button\">2</button>\n            <button class=\"bi-button\" type=\"button\">3</button>\n          </div>\n        </div>\n      </div>\n    `)\n    .section('Grow', `\n      <div class=\"bi-row bi-space-h\">\n        <button class=\"bi-button\" type=\"button\">1</button>\n        <button class=\"bi-button\" type=\"button\">2</button>\n        <button class=\"bi-button bi-grow\" type=\"button\">I should grow</button>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/form.story.ts",
    "content": "export default app => app\n  .story('UI', 'Form')\n    .section('Horizontal labels (Default)', `\n      <div class=\"bi-form\" style=\"width: 500px;\" ng-non-bindable>\n        <div class=\"bi-form-row\">\n          <div class=\"bi-form-label\">label1</div>\n          <input class=\"bi-form-input bi-input\" ng-model=\"model1\" placeholder=\"Enter value\">\n        </div>\n        <div class=\"bi-form-row\">\n          <div class=\"bi-form-label--required\">label1</div>\n          <input class=\"bi-form-input bi-input\" ng-model=\"model2\" placeholder=\"Enter value\" required=\"true\">\n        </div>\n      </div>\n    `)\n    .section('Vertical labels', `\n      <div class=\"bi-form--vertical\" style=\"width: 500px;\" ng-non-bindable>\n        <div class=\"bi-form-row\">\n          <div class=\"bi-form-label\">label1</div>\n          <input class=\"bi-form-input bi-input\" ng-model=\"model1\" placeholder=\"Enter value\">\n        </div>\n        <div class=\"bi-form-row\">\n          <div class=\"bi-form-label--required\">label1</div>\n          <input class=\"bi-form-input bi-input\" ng-model=\"model2\" placeholder=\"Enter value\" required=\"true\">\n        </div>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/hint.story.ts",
    "content": "export default app => app\n  .story('UI', 'Hint')\n    .section('Hint', `\n      <div class=\"bi-c bi-s-v\">\n        <span class=\"bi-hint\">I'm a hint</span>\n        <span class=\"bi-hint--info\">I'm an info</span>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/home-action.story.ts",
    "content": "export default app => {\n  app.story('UI', 'Home action')\n    .section('Home action', `\n      <div class=\"bi-home-action\">\n        <i class=\"bi-icon\">assignment_ind</i>\n        <span>View profile by user</span>\n      </div>\n    `);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/input.story.ts",
    "content": "export default app => app\n  .story('UI', 'Input')\n    .section('Text input', `\n      <input class=\"bi-input\" placeholder=\"Default\"/>\n      <input class=\"bi-input\" bi-focus placeholder=\"Auto focused\"/>\n      <input class=\"bi-input\" placeholder=\"I'm disabled\" disabled=\"true\"/>\n      <input class=\"bi-input\" placeholder=\"I'm required\" ng-required=\"true\" ng-model=\"someVar\"/>\n    `)\n    .section('Textarea', `\n      <textarea class=\"bi-input\" placeholder=\"Enter some text\"></textarea>\n      <textarea class=\"bi-input\" placeholder=\"I'm disabled\" disabled=\"true\"></textarea>\n    `)\n    .section('Input with action', `\n      <div class=\"bi-r-i\" ng-non-bindable>\n        <input class=\"bi-input\" placeholder=\"Default\"/>\n        <span class=\"bi-input-action\">\n          <bi-copy-to-clipboard text=\"'hi!'\"></bi-copy-to-clipboard>\n        </span>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/label.story.ts",
    "content": "export default app => app\n  .story('UI', 'Label')\n    .section('Labels', `\n      <span class=\"bi-label--big\">big</span>\n      <span class=\"bi-label\">default</span>\n      <span class=\"bi-label--sm\">small</span>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/media.story.ts",
    "content": "export default app => app\n  .story('UI', 'Media')\n    .section('Media', `\n      <span class=\"bi-media--normal\">I should be visible on <b>normal</b> screens only</span>\n      <span class=\"bi-media--small\">I should be visible on <b>small</b> screens only</span>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/scroll.story.ts",
    "content": "export default app => app\n  .story('UI', 'Scroll')\n    .section('Scroll', `\n      <div class=\"bi-scroll\" style=\"width: 100%; height: 300px;\">\n        <div class=\"bi-center bi-muted\" style=\"height:1000px;\">I'm scrollable</div>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/space.story.ts",
    "content": "export default app => app\n  .story('UI', 'Layout')\n    .section('Space', `\n      <div class=\"bi-c bi-s-v\">\n        <span class=\"bi-label--sm\">horizontal</span>\n\n        <div class=\"bi-r bi-s-h--x05\">\n          <button class=\"bi-button\" type=\"button\">1</button>\n          <button class=\"bi-button\" type=\"button\">2</button>\n          <button class=\"bi-button\" type=\"button\">3</button>\n        </div>\n\n        <div class=\"bi-r bi-s-h\">\n          <button class=\"bi-button\" type=\"button\">1</button>\n          <button class=\"bi-button\" type=\"button\">2</button>\n          <button class=\"bi-button\" type=\"button\">3</button>\n        </div>\n\n        <div class=\"bi-r bi-s-h--x2\">\n          <button class=\"bi-button\" type=\"button\">1</button>\n          <button class=\"bi-button\" type=\"button\">2</button>\n          <button class=\"bi-button\" type=\"button\">3</button>\n        </div>\n\n        <div class=\"bi-r bi-s-h--x3\">\n          <button class=\"bi-button\" type=\"button\">1</button>\n          <button class=\"bi-button\" type=\"button\">2</button>\n          <button class=\"bi-button\" type=\"button\">3</button>\n        </div>\n      </div>\n\n      <div class=\"bi-c bi-s-v\">\n        <span class=\"bi-label--sm\">vertical</span>\n\n        <div class=\"bi-r bi-s-h\">\n          <div class=\"bi-c bi-s-v--x05\">\n            <button class=\"bi-button\" type=\"button\">1</button>\n            <button class=\"bi-button\" type=\"button\">2</button>\n            <button class=\"bi-button\" type=\"button\">3</button>\n          </div>\n\n          <div class=\"bi-c bi-s-v\">\n            <button class=\"bi-button\" type=\"button\">1</button>\n            <button class=\"bi-button\" type=\"button\">2</button>\n            <button class=\"bi-button\" type=\"button\">3</button>\n          </div>\n\n          <div class=\"bi-c bi-s-v--x2\">\n            <button class=\"bi-button\" type=\"button\">1</button>\n            <button class=\"bi-button\" type=\"button\">2</button>\n            <button class=\"bi-button\" type=\"button\">3</button>\n          </div>\n\n          <div class=\"bi-c bi-s-v--x3\">\n            <button class=\"bi-button\" type=\"button\">1</button>\n            <button class=\"bi-button\" type=\"button\">2</button>\n            <button class=\"bi-button\" type=\"button\">3</button>\n          </div>\n        </div>\n      </div>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/spinner.story.ts",
    "content": "export default app => app\n  .story('UI', 'Loader')\n    .section('Spinner', `\n      <span class=\"bi-spinner\"></span>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/tag.story.ts",
    "content": "export default app => {\n  app.story('UI', 'Tag')\n    .section('Tags', `\n      <span class=\"bi-tag\">Default</span>\n      <span class=\"bi-tag bi-primary\">Primary</span>\n      <span class=\"bi-tag bi-success\">Success</span>\n      <span class=\"bi-tag bi-warning\">Warning</span>\n      <span class=\"bi-tag bi-danger\">Danger</span>\n    `);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/stories/text.story.ts",
    "content": "export default app => app\n  .story('UI', 'Text')\n    .section('Small text', `\n      <span class=\"bi-text--sm\">I'm a small text</span>\n    `);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/typings/globals.d.ts",
    "content": "import {LoDashStatic} from \"lodash\";\n\ndeclare global {\n  module NodeJS {\n    interface Global {\n      window: Window;\n      angular: ng.IAngularStatic;\n      localStorage: any;\n      inject: ng.IInjectStatic;\n      _: LoDashStatic\n\n    }\n  }\n\n  interface Window {\n    beforeEach: any;\n    afterEach: any;\n    angular: ng.IAngularStatic;\n    localStorage: any;\n    inject: ng.IInjectStatic;\n    _: LoDashStatic\n    jQuery: JQueryStatic\n  }\n}\n\n"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/typings/turnerjs.d.ts",
    "content": "/// <reference path=\"../../node_modules/turnerjs/module/generated/turnerjs-driver.d.ts\" />\ndeclare class __TurnerComponentDriver__ extends TurnerComponentDriver {}\ndeclare module 'turnerjs' {\n  export class TurnerComponentDriver extends __TurnerComponentDriver__ {}\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/ui/typings/types.d.ts",
    "content": "declare module '*.scss';\ndeclare module '*.html';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/bootstrap.ts",
    "content": "import angular from 'angular';\nimport '../../lib/core';\nimport '../ui';\nimport '../code-editor';\n\nexport default angular.module('bi.viz', ['bi.core', 'bi.ui', 'bi.codeEditor']);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/chart-renderer.ts",
    "content": "import {IMeta, IFilterData} from '../../services/chart/chart-conf';\nimport {isDimension, isDate} from '../../services/chart/chart-utils';\n\ndeclare const Plotly;\n\nfunction getXAxisType(filter: IFilterData, meta: IMeta) {\n  if (isDate(filter.x, meta)) {\n    return 'date';\n  } if (isDimension(filter.x, meta)) {\n    return 'bar';\n  }\n}\n\nexport class ChartRenderer {\n  private chart = null;\n\n  constructor(private readonly container) {\n\n  }\n\n  public error(e) {\n    this.container.html(`<div class=\"bi-center bi-danger\">${e}</div>`);\n  }\n\n  public draw(data: any[], filteredMeta: IMeta, meta: IMeta, filter: IFilterData) {\n    const xAxisType = getXAxisType(filter, meta);\n\n    data = data.map(serie => ({\n      ...serie,\n      type: xAxisType,\n    }));\n\n    const layout = {\n      barmode: 'group',\n      margin: {\n        l: 30,\n        r: 30,\n        b: 30,\n        t: 30,\n        pad: 4,\n      },\n      legend: {\n        'orientation': 'v',\n      },\n      yaxis: {\n        automargin: true,\n      },\n      xaxis: {\n        automargin: true,\n        autorange: true,\n        type: xAxisType,\n      }\n    };\n\n    if (this.chart) {\n      this.destroy();\n    }\n\n    this.chart = Plotly.newPlot(this.container.get(0), data, layout, {\n      displaylogo: false,\n    });\n  }\n\n  public destroy() {\n    Plotly.purge(this.container.get(0));\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/chart.html",
    "content": "<div\n  class=\"bi-c\"\n  bi-maximizable\n  on-toggle=\"events.onMaximizeToggle()\"\n  on-load=\"events.onMaximizableLoad(instance)\"\n>\n  <div class=\"bi-r bi-s-h--x2\">\n    <bi-viz-chart-filter\n      class=\"bi-scroll\"\n      ng-if=\"::options.filter\"\n      ng-model=\"viz.getFilter().data\"\n      meta=\"viz.getFilter().meta\"\n      on-change=\"events.onFilterChange()\"\n    ></bi-viz-chart-filter>\n\n    <div class=\"bvc-content bi-c bi-grow\">\n      <div class=\"bvc-container bi-c bi-grow\" data-hook=\"bvc-container\"></div>\n    </div>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/chart.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n\nbi-viz-chart {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n\n  [bi-maximizable] {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n  }\n\n  .bm--maximized {\n    .bvc-container {\n      max-height: 70%;\n    }\n  }\n\n  .modebar-container {\n    margin: 2px 30px 0 0 !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/chart.ts",
    "content": "import {initNgScope, inject} from '../../../core';\nimport {ChartRenderer} from './chart-renderer';\nimport {IInputItem} from '../../services/viz-conf';\nimport {ChartViz} from '../../services/chart/chart-viz-service';\n\nimport template from './chart.html';\nimport './chart.scss';\n\nexport interface IScope extends angular.IScope {\n  vm: any;\n  state: any;\n  statePrefix: string;\n  $state: any;\n  data: IInputItem[];\n  fields: string[];\n  maximizable: any;\n  viz: ChartViz;\n  events: any;\n}\n\nfunction createRenderer(scope: IScope, element) {\n  return new ChartRenderer(element.find('.bvc-container'));\n}\n\nfunction load(scope: IScope, element) {\n  scope.viz = scope.viz || new ChartViz(scope.data, createRenderer(scope, element), {\n    fields: scope.fields,\n    xMeta: 'all',\n  });\n\n  scope.viz.filter().draw();\n}\n\nfunction loadAsync(scope, element) {\n  inject('$timeout')(() => load(scope, element));\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      data: '<',\n      fields: '<',\n      bvOptions: '<',\n      statePrefix: '@',\n      $state: '<'\n    },\n\n    link: {\n      pre(scope: IScope, element) {\n        const timeout = inject('$timeout');\n\n        initNgScope(scope)\n          .withOptions('bvOptions', {\n            filter: true\n          })\n          .withVM({\n            maximize: {\n              $export() {\n                return {isMaximized: this.enabled};\n              },\n              $import({isMaximized}) {\n                this.toggle(isMaximized === 'true');\n              }\n            }\n          })\n          .withEvents({\n            onMaximizableLoad(instance) {\n              if (scope.vm.maximize.enabled) {\n                timeout(() => instance.toggle(true), 100);\n                scope.vm.maximize.toggle(false);\n              }\n            },\n            onMaximizeToggle() {\n              loadAsync(scope, element);\n            },\n            onFilterChange() {\n              loadAsync(scope, element);\n            }\n          })\n          .withState(scope.$state || 'chart', `${scope.statePrefix}chart`, {});\n\n        if (!scope.vm.maximize.enabled) {\n          loadAsync(scope, element);\n        }\n\n        scope.$on('$destroy', () => scope.viz.destroy());\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/filter/chart-filter.html",
    "content": "<div class=\"bi-s-v--x2\" ng-if=\"::model\">\n  <div class=\"bi-c\">\n    <span class=\"bi-label--sm\">X Axis</span>\n    <bi-simple-select\n      ng-model=\"model.x\"\n      bi-options=\"value for value in meta.x\"\n      bs-options=\"::{dropdownMinWidth: 'toggle', typeahead: true}\"\n      ng-change=\"events.onDataFilterSelect()\"\n    ></bi-simple-select>\n  </div>\n\n  <div class=\"bi-c\">\n    <div class=\"bi-spread\">\n      <span class=\"bi-label--sm\">Y Axis</span>\n\n      <div class=\"bi-s-h--x05\">\n        <label>\n          <input type=\"radio\" name=\"chartAggType\" value=\"sum\" ng-model=\"model.aggType\" ng-change=\"events.onDataFilterSelect()\">\n          <span>sum</span>\n        </label>\n        <label>\n          <input type=\"radio\" name=\"chartAggType\" value=\"avg\" ng-model=\"model.aggType\" ng-change=\"events.onDataFilterSelect()\">\n          <span>avg</span>\n        </label>\n      </div>\n    </div>\n    <bi-tags\n      ng-model=\"model.y\"\n      bi-options=\"value for value in meta.y\"\n      bt-options=\"::{dropdownMinWidth: 'toggle'}\"\n      ng-change=\"events.onDataFilterSelect()\"\n      placeholder=\"Add field\"\n    ></bi-tags>\n  </div>\n\n  <div class=\"bi-c\" ng-if=\"meta.group.length\">\n    <span class=\"bi-label--sm\">Group by</span>\n    <bi-tags\n      ng-model=\"model.group\"\n      bi-options=\"value for value in meta.group\"\n      bt-options=\"::{dropdownMinWidth: 'toggle'}\"\n      ng-change=\"events.onDataFilterSelect()\"\n      placeholder=\"Add field\"\n    ></bi-tags>\n  </div>\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/filter/chart-filter.scss",
    "content": "@import '../../../../ui/assets/css/def/colors.def';\n\nbi-viz-chart-filter {\n  display: block;\n  flex-basis: 300px;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/chart/filter/chart-filter.ts",
    "content": "import {initNgScope, createNgModel} from '../../../../core';\nimport {IFilterData, IFilterMeta} from '../../../services/chart/chart-conf';\n\nimport template from './chart-filter.html';\nimport './chart-filter.scss';\n\nexport interface IScope {\n  model: IFilterData;\n  meta: IFilterMeta;\n  onChange: Function;\n  onReset: Function;\n  onDataFilterChange: Function;\n  onViewFilterChange: Function;\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    require: 'ngModel',\n    scope: {\n      meta: '=',\n      onChange: '&',\n      onViewFilterChange: '&',\n      onDataFilterChange: '&',\n      onReset: '&'\n    },\n\n    link: {\n      pre(scope: IScope, element, attr, ngModel) {\n        createNgModel(scope as any, ngModel).watchDeep(true);\n\n        initNgScope(scope).withEvents({\n          onReset() {\n            scope.onChange();\n            scope.onReset();\n          },\n          onDataFilterSelect() {\n            scope.onChange();\n            scope.onDataFilterChange();\n          }\n        });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/index.ts",
    "content": "export {default as viz} from './viz';\nexport {default as vizChart} from './chart/chart';\nexport {default as vizChartFilter} from './chart/filter/chart-filter';\nexport {default as vizTable} from './table/table';\nexport {default as vizPicker} from './picker/picker';\nexport {default as vizPie} from './pie/pie';\nexport {default as vizPieFilter} from './pie/filter/pie-filter';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/picker/picker.html",
    "content": "<div class=\"bi-c bi-s-v\">\n  <i\n    class=\"bi-action bi-icon\"\n    ng-class=\"{'bi-active': type === vm.selected}\"\n    ng-repeat=\"type in ::vm.types\"\n    ng-click=\"events.onSelect(type)\"\n    title=\"{{::type}}\"\n  >\n    {{::{\n      table: 'table_chart',\n      pie: 'pie_chart',\n      chart: 'show_chart',\n      har: 'network_check',\n      path: 'bubble_chart',\n      sankey: 'sort',\n      funnel: 'view_column',\n      plan: 'info'\n    }[type]}}\n  </i>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/picker/picker.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n\nbi-viz-picker {\n  display: block;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/picker/picker.ts",
    "content": "import {difference, intersection} from 'lodash';\nimport {initNgScope, inject} from '../../../core';\nimport {IFieldCategories} from '../../services/chart/chart-conf';\nimport {categorizeFields} from '../../services/chart/chart-utils';\n\nimport template from './picker.html';\nimport './picker.scss';\n\nfunction getVizTypes({dimensions, values, all}: IFieldCategories, types: string[] = []): string[] {\n  const res = ['table'];\n\n  if (values.length > 0 && all.length > 1) {\n    res.push('chart');\n  }\n\n  if (values.length > 0 && dimensions.length > 0) {\n    res.push('pie');\n  }\n\n  if (!difference(['pathString', 'count'], all).length) {\n    res.push('sankey', 'funnel');\n  }\n\n  return types.length ? intersection(types, res) : res;\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      data: '<',\n      selected: '=',\n      types: '=',\n      onSelect: '&'\n    },\n\n    link: {\n      pre(scope, element) {\n        initNgScope(scope)\n          .withVM({\n            init() {\n              this.types = getVizTypes(categorizeFields(scope.data && scope.data[0]), scope.types);\n              this.selected = this.types.indexOf(scope.selected) !== -1 ? scope.selected : this.types[0];\n            }\n          })\n          .withEvents({\n            onSelect(type) {\n              scope.vm.selected = type;\n              inject('$timeout')(() => scope.onSelect({type}));\n            }\n          });\n\n        scope.types = scope.vm.types.length > 1 ? scope.vm.types : null;\n        scope.onSelect({type: scope.vm.selected});\n\n        scope.$watch('data', (d, pd) => d !== pd && scope.vm.init());\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/filter/pie-filter.html",
    "content": "<div class=\"bi-s-v--x2\" ng-if=\"::model\">\n  <div class=\"bi-c\">\n    <span class=\"bi-label--sm\">Label</span>\n    <bi-simple-select\n      ng-model=\"model.x\"\n      bi-options=\"value for value in meta.dimensions\"\n      bs-options=\"::{dropdownMinWidth: 'toggle', typeahead: true}\"\n      ng-change=\"events.onDataFilterSelect()\"\n    ></bi-simple-select>\n  </div>\n\n  <div class=\"bi-c\">\n    <div class=\"bi-spread\">\n      <span class=\"bi-label--sm\">Value</span>\n\n      <div class=\"bi-s-h--x05\">\n        <label>\n          <input type=\"radio\" name=\"pieAggType\" value=\"sum\" ng-model=\"model.aggType\" ng-change=\"events.onDataFilterSelect()\">\n          <span>sum</span>\n        </label>\n        <label>\n          <input type=\"radio\" name=\"pieAggType\" value=\"avg\" ng-model=\"model.aggType\" ng-change=\"events.onDataFilterSelect()\">\n          <span>avg</span>\n        </label>\n      </div>\n    </div>\n\n    <bi-tags\n      ng-model=\"model.y\"\n      bi-options=\"value for value in meta.y\"\n      bt-options=\"::{dropdownMinWidth: 'toggle'}\"\n      ng-change=\"events.onDataFilterSelect()\"\n      placeholder=\"Add field\"\n    ></bi-tags>\n  </div>\n\n  <!-- <div class=\"bi-c\" ng-if=\"meta.group.length\">\n    <span class=\"bi-label--sm\">Group by</span>\n\n    <bi-tags\n      ng-model=\"model.group\"\n      bi-options=\"value for value in meta.group\"\n      bt-options=\"::{dropdownMinWidth: 'toggle'}\"\n      ng-change=\"events.onDataFilterSelect()\"\n      placeholder=\"Add field\"\n    ></bi-tags>\n  </div> -->\n</div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/filter/pie-filter.scss",
    "content": "@import '../../../../ui/assets/css/def/colors.def';\n\nbi-viz-pie-filter {\n  display: block;\n  flex-basis: 300px;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/filter/pie-filter.ts",
    "content": "import {initNgScope, createNgModel} from '../../../../core';\nimport {IFilterData, IFilterMeta} from '../../../services/chart/chart-conf';\n\nimport template from './pie-filter.html';\nimport './pie-filter.scss';\n\nexport interface IScope {\n  model: IFilterData;\n  meta: IFilterMeta;\n  onChange: Function;\n  onReset: Function;\n  onDataFilterChange: Function;\n  onViewFilterChange: Function;\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    require: 'ngModel',\n    scope: {\n      meta: '=',\n      onChange: '&',\n      onViewFilterChange: '&',\n      onDataFilterChange: '&',\n      onReset: '&'\n    },\n\n    link: {\n      pre(scope: IScope, element, attr, ngModel) {\n        createNgModel(scope as any, ngModel)\n          .watchDeep(true);\n\n        initNgScope(scope).withEvents({\n          onReset() {\n            scope.onChange();\n            scope.onReset();\n          },\n          onDataFilterSelect() {\n            scope.onChange();\n            scope.onDataFilterChange();\n          }\n        });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/pie-renderer.ts",
    "content": "import {IMeta, IFilterData} from '../../services/chart/chart-conf';\n\ndeclare const Plotly;\n\nexport class PieRenderer {\n  private chart = null;\n\n  constructor(private readonly container) {\n\n  }\n\n  public error(e) {\n    this.container.html(`<div class=\"bi-center bi-danger\">${e}</div>`);\n  }\n\n  public draw(data: any[], filteredMeta: IMeta, meta: IMeta, filter: IFilterData) {\n    const xAxisType = 'pie';\n\n    data = data.map(serie => ({\n      ...serie,\n      type: xAxisType,\n      labels: serie.x,\n      values: serie.y,\n    }));\n\n    const layout = {\n      margin: {\n        l: 30,\n        r: 30,\n        b: 30,\n        t: 30,\n        pad: 4,\n      },\n      legend: {\n        'orientation': 'v',\n      },\n    };\n\n    if (this.chart) {\n      this.destroy();\n    }\n\n    this.chart = Plotly.newPlot(this.container.get(0), data, layout, {\n      displaylogo: false,\n    });\n  }\n\n  public destroy() {\n    Plotly.purge(this.container.get(0));\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/pie.html",
    "content": "<div\n  class=\"bi-c\"\n  bi-maximizable\n  on-toggle=\"events.onMaximizeToggle()\"\n  on-load=\"events.onMaximizableLoad(instance)\"\n>\n  <div class=\"bi-r bi-s-h--x2\">\n    <bi-viz-pie-filter\n      class=\"bi-scroll\"\n      ng-if=\"::options.filter\"\n      ng-model=\"viz.getFilter().data\"\n      meta=\"viz.getFilter().meta\"\n      on-change=\"events.onFilterChange()\"\n    ></bi-viz-pie-filter>\n\n    <div class=\"bvp-content bi-c bi-grow\">\n      <div class=\"bvp-container bi-c bi-grow\" data-hook=\"bvp-container\"></div>\n    </div>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/pie.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n\nbi-viz-pie {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n\n  .bvp-container {\n    margin-left: -16px;\n    width: 100%\n  }\n\n  [bi-maximizable] {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n  }\n\n  .bm--maximized {\n    .bvp-container {\n      max-height: 70%;\n    }\n  }\n  .modebar-container {\n    margin: 2px 30px 0 0 !important;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/pie/pie.ts",
    "content": "import { initNgScope, inject } from '../../../core';\nimport {PieRenderer} from './pie-renderer';\nimport {IInputItem} from '../../services/viz-conf';\nimport {ChartViz} from '../../services/chart/chart-viz-service';\n\nimport template from './pie.html';\nimport './pie.scss';\n\nexport interface IScope extends angular.IScope {\n  vm: any;\n  state: any;\n  statePrefix: string;\n  $state: any;\n  data: IInputItem[];\n  fields: string[];\n  maximizable: any;\n  viz: ChartViz;\n  events: any;\n}\n\nfunction createRenderer(scope: IScope, element) {\n  return new PieRenderer(element.find('.bvp-container'));\n}\n\nfunction load(scope: IScope, element) {\n  scope.viz = scope.viz || new ChartViz(scope.data, createRenderer(scope, element), {\n    fields: scope.fields,\n    xMeta: 'dimensions',\n  });\n\n  scope.viz.filter().draw();\n}\n\nfunction loadAsync(scope, element) {\n  inject('$timeout')(() => load(scope, element));\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      data: '<',\n      fields: '<',\n      bvOptions: '<',\n      statePrefix: '@',\n      $state: '<'\n    },\n\n    link: {\n      pre(scope: IScope, element) {\n        const timeout = inject('$timeout');\n\n        initNgScope(scope)\n          .withOptions('bvOptions', {\n            filter: true\n          })\n          .withVM({\n            maximize: {\n              $export() {\n                return {isMaximized: this.enabled};\n              },\n              $import({isMaximized}) {\n                this.toggle(isMaximized === 'true');\n              }\n            }\n          })\n          .withEvents({\n            onMaximizableLoad(instance) {\n              if (scope.vm.maximize.enabled) {\n                timeout(() => instance.toggle(true), 100);\n                scope.vm.maximize.toggle(false);\n              }\n            },\n            onMaximizeToggle() {\n              loadAsync(scope, element);\n            },\n            onFilterChange() {\n              loadAsync(scope, element);\n            }\n          })\n          .withState(scope.$state || 'pie', `${scope.statePrefix}pie`, {});\n\n        if (!scope.vm.maximize.enabled) {\n          loadAsync(scope, element);\n        }\n\n        scope.$on('$destroy', () => scope.viz.destroy());\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/table/table-renderer.ts",
    "content": "import {inject} from '../../../core';\nimport {BufferedCollection} from '../../../core/srv/collections';\n\nexport class TableRenderer {\n  constructor(private readonly container) {\n\n  }\n\n  public draw(scope, data: BufferedCollection, fields: string[], formatter) {\n    const childScope = scope.$new();\n\n    childScope.data = data;\n    childScope.fields = fields;\n    childScope.formatter = formatter;\n\n    this.container.html(inject('$compile')(`\n      <bi-tbl\n        class=\"bi-table--data bi-c bi-grow\"\n        ng-if=\"data.bufferSize()\"\n        fields=\"::fields\"\n        collection=\"::data\"\n        formatter=\"formatter()\"\n        bt-options=\"::{dontTransformColumnNames: true, stickyHeader: true, infiniteScroll: true}\"\n      ></bi-tbl>\n\n      <div class=\"bi-muted bi-center\" ng-if=\"!data.bufferSize() && isPartial\">\n        <span class=\"bi-spinner\"></span>\n      </div>\n      <div class=\"bi-muted\" ng-if=\"!data.bufferSize() && !isPartial\">No results</div>\n    `)(childScope));\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/table/table.html",
    "content": "<div class=\"bvt-container bi-c-h bi-grow\" data-hook=\"bvt-container\"></div>\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/table/table.scss",
    "content": "@import '../../../ui/assets/css/def/colors.def';\n\nbi-viz-table {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n  overflow: hidden;\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/table/table.ts",
    "content": "import jquery from 'jquery';\nimport {initNgScope, inject} from '../../../core';\nimport {BufferedCollection} from '../../../core/srv/collections';\nimport {TableRenderer} from './table-renderer';\n\nimport template from './table.html';\nimport './table.scss';\n\nexport interface IScope extends angular.IScope {\n  vm: any;\n  state: any;\n  statePrefix: string;\n  $state: any;\n  data: BufferedCollection;\n  fields: string[];\n  maximizable: any;\n  events: any;\n}\n\nfunction load(scope: IScope, element) {\n  new TableRenderer(element.find('.bvt-container')).draw(scope, scope.data, scope.fields, scope.formatter);\n}\n\nfunction loadAsync(scope, element) {\n  inject('$timeout')(() => load(scope, element));\n}\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      data: '<',\n      fields: '<',\n      isPartial: '<',\n      formatter: '&',\n      statePrefix: '@',\n      $state: '<'\n    },\n\n    link: {\n      pre(scope: IScope, element) {\n        const timeout = inject('$timeout');\n\n        initNgScope(scope)\n          .withVM({\n            maximize: {\n              $export() {\n                return {isMaximized: this.enabled};\n              },\n              $import({isMaximized}) {\n                this.toggle(isMaximized === 'true');\n              }\n            }\n          })\n          .withEvents({\n            onMaximizableLoad(instance) {\n              if (scope.vm.maximize.enabled) {\n                timeout(() => instance.toggle(true), 100);\n                scope.vm.maximize.toggle(false);\n              }\n            },\n            onMaximizeToggle() {\n              loadAsync(scope, element);\n            },\n            onFilterChange() {\n              loadAsync(scope, element);\n            }\n          })\n          .withState(scope.$state || 'table', `${scope.statePrefix}table`, {});\n\n        if (!scope.vm.maximize.enabled) {\n          loadAsync(scope, element);\n        }\n\n        element.on('dblclick', 'bi-tbl td', e => {\n          jquery(e.currentTarget).css('white-space', 'normal');\n        });\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/viz.html",
    "content": "<div class=\"bi-r-h\" ng-if=\"vm.enabled\">\n  <bi-viz-picker\n    ng-if=\"::options.picker\"\n    data=\"data\"\n    selected=\"vm.type\"\n    types=\"options.types\"\n    on-select=\"events.onSelect(type)\"\n  ></bi-viz-picker>\n\n  <bi-viz-path\n    ng-if=\"vm.isVisible('path')\"\n    ng-show=\"vm.type === 'path'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    bv-options=\"::{filter: options.filter}\"\n    state-prefix=\"{{::statePrefix}}\"\n    $state=\"state\"\n  ></bi-viz-path>\n\n  <bi-viz-sankey\n    ng-if=\"vm.isVisible('sankey')\"\n    ng-show=\"vm.type === 'sankey'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    bv-options=\"::{filter: options.filter}\"\n    state-prefix=\"{{::statePrefix}}\"\n    $state=\"state\"\n  ></bi-viz-sankey>\n\n  <bi-viz-chart\n    ng-if=\"vm.isVisible('chart')\"\n    ng-show=\"vm.type === 'chart'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    state-prefix=\"{{::statePrefix}}\"\n    bv-options=\"::{filter: options.filter}\"\n    $state=\"state\"\n  ></bi-viz-chart>\n\n  <bi-viz-pie\n    ng-if=\"vm.isVisible('pie')\"\n    ng-show=\"vm.type === 'pie'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    state-prefix=\"{{::statePrefix}}\"\n    bv-options=\"::{filter: options.filter}\"\n    $state=\"state\"\n  ></bi-viz-pie>\n  \n  <bi-viz-har\n    ng-if=\"vm.isVisible('har')\"\n    ng-show=\"vm.type === 'har'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    bv-options=\"::{filter: options.filter}\"\n    state-prefix=\"{{::statePrefix}}\"\n    $state=\"state\"\n  ></bi-viz-har>\n\n  <bi-viz-table\n    ng-if=\"vm.isVisible('table')\"\n    ng-show=\"vm.type === 'table'\"\n    data=\"::tableData\"\n    fields=\"::tableFields\"\n    bv-options=\"::{filter: options.filter}\"\n    is-partial=\"isPartial\"\n    formatter=\"tableFormatter()\"\n    state-prefix=\"{{::statePrefix}}\"\n    $state=\"state\"\n  ></bi-viz-table>\n\n  <bi-viz-funnel\n    ng-if=\"vm.isVisible('funnel')\"\n    ng-show=\"vm.type === 'funnel'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    bv-options=\"::{filter: options.filter}\"\n    state-prefix=\"{{::statePrefix}}\"\n    $state=\"state\"\n  ></bi-viz-funnel>\n\n  <bi-viz-plan\n    ng-if=\"vm.isVisible('plan')\"\n    ng-show=\"vm.type === 'plan'\"\n    data=\"::data\"\n    fields=\"::fields\"\n    bv-options=\"::{filter: options.filter}\"\n    state-prefix=\"{{::statePrefix}}\"\n    $state=\"state\"\n  ></bi-viz-plan>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/viz.scss",
    "content": "bi-viz {\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n\n  bi-viz-picker {\n    margin-right: 20px;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/directives/viz.ts",
    "content": "import {initNgScope} from '../../core';\n\nimport template from './viz.html';\nimport './viz.scss';\n\nexport default () => {\n  return {\n    restrict: 'E',\n    template,\n    scope: {\n      type: '@',\n      data: '<',\n      fields: '<',\n      tableData: '<',\n      tableFields: '<',\n      isPartial: '<',\n      bvOptions: '<',\n      tableFormatter: '&',\n      statePrefix: '@',\n      $state: '<'\n    },\n\n    link: scope => {\n      initNgScope(scope)\n        .withOptions('bvOptions', {\n          picker: false,\n          filter: true,\n          types: []\n        })\n        .withVM({\n          selected: {},\n          $init() {\n            this.toggle(true);\n\n            if (!scope.options.picker) {\n              this.select(scope.type || 'table');\n            }\n          },\n          isVisible(type) {\n            return this.selected[type];\n          },\n          select(type) {\n            this.type = type;\n            this.selected[type] = true;\n\n            scope.type = type;\n          }\n        })\n        .withEvents({\n          onSelect(type) {\n            scope.vm.select(type);\n          }\n        })\n        .withState(scope.$state || 'viz', 'viz', {});\n\n      scope.$watch('type', type => type && scope.events.onSelect(type));\n      scope.$watch('data', (d, pd) => d !== pd && scope.vm.init());\n    }\n  };\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/index.ts",
    "content": "import ngApp from './bootstrap';\nimport init from './init';\n\ninit(ngApp);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/init.ts",
    "content": "import {forEach} from 'lodash';\nimport * as directives from './directives';\n\nfunction toDirectiveName(name: string) {\n  return `bi${name.charAt(0).toUpperCase() + name.slice(1)}`;\n}\n\nexport default function init(ngApp: angular.IModule) {\n  forEach(directives, (fn, name) => ngApp.directive(toDirectiveName(name), fn as any));\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/chart/chart-conf.ts",
    "content": "import {IInputItem} from '../viz-conf';\n\nexport type IData = IInputItem[];\nexport interface IMeta extends IFieldCategories {}\n\nexport interface IFilterMeta extends IMeta {\n  x: string[];\n  y: string[];\n  group: string[];\n}\n\nexport interface IFilterData {\n  x: string;\n  y: string[];\n  group: string[];\n  aggType: 'sum' | 'avg';\n}\n\nexport interface IFieldCategories {\n  all: string[];\n  dimensions: string[];\n  values: string[];\n  dates: string[];\n}\n\nexport interface IRendererData {\n\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/chart/chart-data-service.ts",
    "content": "import {VizData} from '../viz-data-service';\nimport {IInputItem} from '../viz-conf';\nimport {IMeta, IData, IFilterData} from './chart-conf';\nimport {metaTransducer, inputFilterTransducer} from '../../transducers/chart';\n\n/**\n * Class responsible for input transformation and filtering\n */\nexport class ChartData extends VizData<IInputItem, IMeta, IData, IFilterData> {\n  constructor(input: IInputItem[], customTransducers?) {\n    super(input, {\n      metaTransducer,\n      inputFilterTransducer\n    }, customTransducers);\n  }\n\n  filterData(filter: IFilterData) {\n    const serieIndexes = {};\n\n    this.filteredData = this.data.reduce<any>((res, item) => {\n      filter.y.forEach((yField) => {\n        const key = `${filter.group.map(field => item[field]).join(' + ')}${\n          filter.group.length ? (filter.y.length > 1 ? `[${yField}]` : '') : yField\n        }`;\n\n        serieIndexes[key] = typeof serieIndexes[key] === 'undefined' ? res.length : serieIndexes[key];\n\n        res[serieIndexes[key]] = res[serieIndexes[key]] || {\n          name: key,\n          x: [],\n          y: [],\n        };\n\n        const {x, y} = res[serieIndexes[key]];\n\n        x.push(item[filter.x]);\n        y.push(item[yField]);\n      });\n\n      return res;\n    }, []);\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/chart/chart-filter-service.ts",
    "content": "import {defaults, assign} from 'lodash';\nimport {IMeta, IFilterData, IFilterMeta} from './chart-conf';\nimport {VizFilter} from '../viz-filter-service';\n\nfunction getDefaults(filterMeta: IFilterMeta, fields: string[]): IFilterData {\n  const {x, y} = filterMeta;\n  const res: IFilterData =  {x: null, y: [], group: [], aggType: 'sum'};\n\n  if (!fields) {\n    return assign(res, {x: x[0], y: [y[1]]});\n  }\n\n  return fields.reduce((result, field) => {\n    if (result.x && result.y.length) {\n      return result;\n    }\n\n    if (x.indexOf(field) !== -1 && !result.x) {\n      result.x = field;\n    } else if (y.indexOf(field) !== -1 && !result.y.length) {\n      result.y.push(field);\n    }\n\n    return result;\n  }, res);\n}\n\nexport class ChartFilter extends VizFilter<IMeta, IFilterMeta, IFilterData> {\n  constructor(private readonly fields: string[], private readonly xMeta: 'all' | 'dimensions') {\n    super();\n  }\n\n  protected createMeta(meta: IMeta, filteredMeta: IMeta): IFilterMeta {\n    return {\n      all: meta.all,\n      dimensions: meta.dimensions,\n      values: meta.values,\n      dates: meta.dates,\n      x: meta[this.xMeta],\n      y: meta.values,\n      group: [...meta.dimensions, ...meta.values]\n    };\n  }\n\n  protected createData(filterMeta: IFilterMeta): IFilterData {\n    return defaults(this.data, getDefaults(filterMeta, this.fields));\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/chart/chart-utils.ts",
    "content": "import {IInputItem} from '../viz-conf';\nimport {IFieldCategories, IMeta} from './chart-conf';\n\nconst getValueType = (value: string): string => {\n  if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}/.test(value)) {\n      return 'date';\n  }  if (!isNaN(value as any) && (!!value || value as any === 0)) {\n    return 'value';\n  }\n\n  return 'dimension';\n};\n\nexport const categorizeFields = (input: IInputItem = {}): IFieldCategories => {\n  return Object.keys(input || {}).reduce((res, field) => {\n    const type = getValueType(input[field]);\n\n    if (type === 'dimension') {\n      res.dimensions.push(field);\n    } else if (type === 'value') {\n      res.values.push(field);\n    } else if (type === 'date') {\n      res.dates.push(field);\n    }\n\n    res.all.push(field);\n\n    return res;\n  }, {all: [], dimensions: [], values: [], dates: []});\n};\n\nexport const isDate = (field: string, meta: IMeta): boolean => {\n  return meta.dates.indexOf(field) !== -1;\n};\n\nexport const isDimension = (field: string, meta: IMeta): boolean => {\n  return meta.dimensions.indexOf(field) !== -1;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/chart/chart-viz-service.ts",
    "content": "import {Viz} from '../viz-service';\nimport {ChartData} from './chart-data-service';\nimport {IData, IMeta, IFilterData} from './chart-conf';\nimport {ChartFilter} from './chart-filter-service';\nimport {IInputItem, IRenderer} from '../viz-conf';\n\nexport class ChartViz extends Viz<IInputItem, IMeta, IData, IMeta, IFilterData> {\n  constructor (data: IInputItem[], renderer: IRenderer<IMeta, IData, IFilterData>, {\n    fields,\n    xMeta,\n  }: {\n    fields: string[];\n    xMeta: 'all' | 'dimensions';\n  }) {\n    super(new ChartData(data), new ChartFilter(fields, xMeta), renderer);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/viz-conf.ts",
    "content": "export interface IInputItem {\n  [key: string]: any;\n}\n\nexport interface IRenderer<Meta, Data, FilterData> {\n  error(e): any;\n  draw(data: Data, meta: Meta, filteredMeta: Meta, filter: FilterData): void;\n  destroy(): void;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/viz-data-service.ts",
    "content": "import {clone} from 'lodash';\nimport {seq, compose, map} from 'transducers.js';\n\nexport interface ITransducers<Input, Data, Meta, FilterData> {\n  inputTransducer?(input: Input): Function;\n  inputFilterTransducer?(filterData: FilterData, meta: Meta): Function;\n  metaTransducer?(): Function;\n  dataTransducer?(meta: Meta): Function;\n}\n\nexport interface ICustomTransducers<Meta> {\n  meta?(): Function;\n  data?(meta: Meta): Function;\n}\n\nfunction transduce<Input, Data, Meta, FilterData>(\n  rawInput: Input,\n  transducers: ITransducers<Input, Data, Meta, FilterData>,\n  customTransducers: ICustomTransducers<Meta> = {}\n) {\n  const {input, meta} = seq(rawInput, compose(\n    transducers.inputTransducer(rawInput),\n    transducers.metaTransducer(),\n    customTransducers.meta()\n  ));\n\n  const data = seq(input, compose(\n    transducers.dataTransducer(meta),\n    customTransducers.data(meta)\n  ));\n\n  return {input, meta, data};\n}\n\n/**\n * Class responsible for input transformation and filtering\n */\nexport class VizData<Input, Meta, Data, FilterData> {\n  private readonly input: Input;\n  private readonly meta: Meta;\n  protected data: Data;\n  private filteredMeta: Meta;\n  protected filteredData: Data;\n\n  constructor(\n    rawInput: Input,\n    private readonly transducers: ITransducers<Input, Data, Meta, FilterData> = {},\n    private readonly customTransducers: ICustomTransducers<Meta> = {}\n  ) {\n    [\n      'inputTransducer',\n      'inputFilterTransducer',\n      'metaTransducer',\n      'dataTransducer'\n    ].forEach(transducer => transducers[transducer] = transducers[transducer] || (() => map(x => x)));\n\n    [\n      'meta',\n      'data'\n    ].forEach(transducer => customTransducers[transducer] = customTransducers[transducer] || (() => map(x => x)));\n\n    let input, meta, data;\n\n    if (rawInput && typeof rawInput[Symbol.iterator] === 'function') {\n      const res = transduce(rawInput, transducers, this.customTransducers);\n      input = res.input;\n      meta = res.meta;\n      data = res.data;\n    } else {\n      input = rawInput;\n      meta = null;\n      data = rawInput;\n    }\n\n    this.input = input;\n    this.meta = this.filteredMeta = meta;\n    this.data = this.filteredData = data;\n  }\n\n  public getMeta(): Meta {\n    return this.meta;\n  }\n\n  public getFilteredMeta(): Meta {\n    return this.filteredMeta;\n  }\n\n  public getFilteredData(): Data {\n    return this.filteredData;\n  }\n\n  public filterInput(filter: FilterData, customInputFilterTransducer: (filter: FilterData, meta: Meta) => any = () => map(x => x)): VizData<Input, Meta, Data, FilterData> {\n    const input = seq(this.input, compose(customInputFilterTransducer(filter, this.meta), this.transducers.inputFilterTransducer(filter, this.meta)));\n    const {meta, data} = transduce(input, this.transducers, this.customTransducers);\n\n    this.filteredMeta = meta;\n    this.data = this.filteredData = data;\n\n    return this;\n  }\n\n  public filterData(filter: FilterData, dataFilter?: (data: Data, filter: FilterData, meta: Meta) => Data): VizData<Input, Meta, Data, FilterData> {\n    if (dataFilter) {\n      this.filteredData = dataFilter(clone(this.data), filter, this.filteredMeta);\n      return this;\n    }\n\n    this.filteredData = clone(this.data);\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/viz-filter-service.ts",
    "content": "import {assign} from 'lodash';\n\nexport abstract class VizFilter<Meta, FilterMeta, FilterData> {\n  private meta: FilterMeta = {} as any;\n  protected data: FilterData = {} as any;\n\n  protected abstract createMeta(meta: Meta, filteredMeta: Meta): FilterMeta;\n  protected abstract createData(filterMeta: FilterMeta): FilterData;\n\n  init(meta: Meta, filteredMeta: Meta): VizFilter<Meta, FilterMeta, FilterData> {\n    this.meta = assign(this.meta, this.createMeta(meta, filteredMeta));\n    this.data = assign(this.data, this.createData(this.meta));\n\n    return this;\n  }\n\n  getMeta(): FilterMeta {\n    return this.meta;\n  }\n\n  getData(): FilterData {\n    return this.data;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/services/viz-service.ts",
    "content": "import {VizData} from './viz-data-service';\nimport {VizFilter} from './viz-filter-service';\nimport {IRenderer} from './viz-conf';\n\nexport class Viz<InputItem, Meta, Data, FilterMeta, FilterData> {\n  constructor (\n    private readonly data: VizData<InputItem, Meta, Data, FilterData>,\n    private readonly fltr: VizFilter<Meta, FilterMeta, FilterData>,\n    private readonly renderer: IRenderer<Meta, Data, FilterData>,\n  ) {}\n\n  private initFilter() {\n    return this.fltr.init(this.data.getMeta(), this.data.getFilteredMeta()).getData();\n  }\n\n  getFilter() {\n    return this.fltr;\n  }\n\n  filterInput(filterTransducer?: (filter: FilterData, meta: Meta) => any): Viz<InputItem, Meta, Data, FilterMeta, FilterData> {\n    this.data.filterInput(this.initFilter(), filterTransducer);\n\n    return this;\n  }\n\n  filterData(dataFilter?: (data: Data, filter: FilterData, meta: Meta) => Data): Viz<InputItem, Meta, Data, FilterMeta, FilterData> {\n    this.data.filterData(this.initFilter(), dataFilter);\n\n    return this;\n  }\n\n  filter(): Viz<InputItem, Meta, Data, FilterMeta, FilterData> {\n    try {\n      return this.filterInput().filterData();\n    } catch (e) {\n      console.error(e);\n      this.renderer.error(e);\n      throw e;\n    }\n  }\n\n  draw(): Viz<InputItem, Meta, Data, FilterMeta, FilterData> {\n    this.renderer.draw(this.data.getFilteredData(), this.data.getFilteredMeta(), this.data.getMeta(), this.getFilter().getData());\n\n    return this;\n  }\n\n  destroy() {\n    this.renderer.destroy();\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/chart/chart-input-filter-transducer.ts",
    "content": "import {pick} from 'lodash';\nimport {compose, map} from 'transducers.js';\nimport {IFilterData, IMeta} from '../../services/chart/chart-conf';\nimport {ungroup, parseFloats, sort} from '../';\nimport {IInputItem} from '../../services/viz-conf';\nimport {isDimension} from '../../services/chart/chart-utils';\nimport {parseDates} from '../parse-dates-transducer';\n\nfunction sortByContext(filter: IFilterData, meta: IMeta) {\n  return sort((a: IInputItem, b: IInputItem) => {\n    if (isDimension(filter.x, meta)) {\n      return b[filter.y[0]] - a[filter.y[0]];\n    }\n\n    return a[filter.x] - b[filter.x];\n  });\n}\n\nexport const inputFilterTransducer = (filter: IFilterData, meta: IMeta) => {\n  const fields = [filter.x, ...filter.group];\n  const values = filter.y;\n  const all = [...fields, ...values];\n\n  return compose(\n    map(input => pick(input, all)),\n    parseDates(meta.dates),\n    parseFloats(meta.values),\n    ungroup({fields, values, aggType: filter.aggType}),\n    sortByContext(filter, meta)\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/chart/chart-meta-transducer.ts",
    "content": "import {IInputItem} from '../../services/viz-conf';\nimport {IMeta} from '../../services/chart/chart-conf';\nimport {categorizeFields} from '../../services/chart/chart-utils';\n\nexport class Meta {\n  private index = 0;\n  private readonly input = [];\n  private meta: IMeta = {\n    all: [],\n    dimensions: [],\n    values: [],\n    dates: []\n  };\n\n  constructor(private readonly xform) {\n\n  }\n\n  '@@transducer/result'() {\n    return {input: this.input, meta: this.meta};\n  }\n\n  '@@transducer/step'(res, input: IInputItem, index) {\n    this.input.push(input);\n\n    if (this.index === 0) {\n      this.meta = categorizeFields(input);\n    }\n\n    this.xform['@@transducer/step'](res, [input, this.meta]);\n    this.index++;\n\n    return res;\n  }\n}\n\nexport const metaTransducer = () => xform => new Meta(xform);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/chart/index.ts",
    "content": "export {metaTransducer} from './chart-meta-transducer';\nexport {inputFilterTransducer} from './chart-input-filter-transducer';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/index.ts",
    "content": "export {sort} from './sort-transducer';\nexport {ungroup} from './ungroup-transducer';\nexport {parseFloats} from './parse-floats-transducer';\nexport {parseDates} from './parse-dates-transducer';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/parse-dates-transducer.ts",
    "content": "import {IInputItem} from '../services/viz-conf';\nimport {BiDate} from '../../ui';\n\nexport class ParseDates {\n  constructor(private readonly fields: string[], private readonly xform) {\n\n  }\n\n  '@@transducer/result'(v) {\n    return this.xform['@@transducer/result'](v);\n  }\n\n  '@@transducer/step'(res, input: IInputItem) {\n    this.fields.forEach(field => input[field] = BiDate.moment(input[field]).valueOf());\n\n    this.xform['@@transducer/step'](res, input);\n\n    return res;\n  }\n}\n\nexport const parseDates = (fields: string[]) => xform => new ParseDates(fields, xform);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/parse-floats-transducer.ts",
    "content": "import {IInputItem} from '../services/viz-conf';\n\nexport class ParseFloats {\n  constructor(private readonly fields: string[], private readonly xform) {\n\n  }\n\n  '@@transducer/result'(v) {\n    return this.xform['@@transducer/result'](v);\n  }\n\n  '@@transducer/step'(res, input: IInputItem) {\n    this.fields.forEach(field => input[field] = parseFloat(input[field]));\n\n    this.xform['@@transducer/step'](res, input);\n\n    return res;\n  }\n}\n\nexport const parseFloats = (fields: string[]) => xform => new ParseFloats(fields, xform);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/sort-transducer.ts",
    "content": "import {seq} from 'transducers.js';\nimport {IInputItem} from '../services/viz-conf';\n\nexport class Sort {\n  constructor(private readonly fn, private readonly xform) {\n\n  }\n\n  '@@transducer/result'(v) {\n    return seq(v.sort(this.fn), xform => this.xform);\n  }\n\n  '@@transducer/step'(res, input: IInputItem) {\n    res.push(input);\n\n    return res;\n  }\n}\n\nexport const sort = fn => xform => new Sort(fn, xform);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/transducers/ungroup-transducer.ts",
    "content": "import {clone} from 'lodash';\nimport {IInputItem} from '../services/viz-conf';\n\nexport interface IUngroupConf {\n  fields: string[];\n  values: string[];\n  aggType: 'sum' | 'avg';\n}\n\nexport class Ungroup {\n  private readonly inputCache = {};\n  private readonly indexCache = {};\n\n  constructor(private readonly conf: IUngroupConf, private readonly xform) {\n\n  }\n\n  '@@transducer/result'(v) {\n    return this.xform['@@transducer/result'](v);\n  }\n\n  '@@transducer/step'(res, input: IInputItem) {\n    const key = this.conf.fields.map(field => input[field]).join('|');\n\n    if (!this.inputCache[key]) {\n      this.inputCache[key] = clone(input);\n      this.indexCache[key] = 1;\n      this.xform['@@transducer/step'](res, this.inputCache[key]);\n    } else {\n      this.conf.values.forEach(value => {\n        if (this.conf.aggType === 'sum') {\n          this.inputCache[key][value] += input[value];\n        } else if (this.conf.aggType === 'avg') {\n          this.inputCache[key][value] = ((this.inputCache[key][value] * this.indexCache[key]) + input[value]) / (this.indexCache[key] + 1);\n        }\n      });\n\n      this.indexCache[key]++;\n    }\n\n    return res;\n  }\n}\n\nexport const ungroup = (conf: IUngroupConf) => xform => new Ungroup(conf, xform);\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/utils/index.ts",
    "content": "export * from './utils';\n"
  },
  {
    "path": "quix-frontend/client/src/lib/viz/utils/utils.ts",
    "content": "export function percentage(what: number, of: number): number {\n  return Math.round((what / of * 100) * 100) / 100;\n}\n\nexport function normalize(value, maxValue, min, max): number {\n  return Math.max(Math.round(value / maxValue * max), min);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/web-worker-infra/types.ts",
    "content": "/* Constraints */\nexport interface RQRSConstraint {\n  [key: string]: any;\n}\nexport type RqtoRSConstraint<RQ, RS> = {[K in keyof RQ]: keyof RS};\n\n/* Basic Types */\nexport type RequestMsgTypes<RQ> = keyof RQ; //all possible request types\nexport type ResponseMsgTypes<RS> = keyof RS; //all possible response types\nexport type AllMsgTypes<RQ, RS> = keyof RQ | keyof RS; //guess\nexport type RequestTypeToResponseTypeMap<RQ, RS, RQtoRs extends RqtoRSConstraint<RQ, RS>> = {\n  [K in RequestMsgTypes<RQ>]: RQtoRs[K];\n};\n\nexport type WorkerFunctionsMap<RQ, RS, RQtoRs extends RqtoRSConstraint<RQ, RS>> = {\n  [K in RequestMsgTypes<RQ>]: (data: RQ[K]) => RS[RQtoRs[K]];\n};\n\n/**\n * Helper type for next types\n */\nexport interface WorkerMsgT<RQ, RS, T extends RequestMsgTypes<RQ> | ResponseMsgTypes<RS>> {\n  id: number;\n  type: T;\n  data: (RS & RQ)[T];\n}\n\n/*\n * Bit of explanation for this ugliness:\n * We need both generic types, and union types.\n * We need union types because Map() an onMessage() must have a concrete type.\n */\n\n//Union types\nexport type WorkerResponse<RQ, RS> = {\n  [T in ResponseMsgTypes<RS>]: WorkerMsgT<RQ, RS, T>;\n}[ResponseMsgTypes<RS>];\n\nexport type WorkerResponseData<RQ, RS> = RS[keyof RS];\n\nexport type WorkerRequest<RQ, RS> = {\n  [T in RequestMsgTypes<RQ>]: WorkerMsgT<RQ, RS, T>;\n}[RequestMsgTypes<RQ>];\n\n//Generic types\nexport type WorkerResponseDataT<\n  RQ,\n  RS,\n  T extends RequestMsgTypes<RQ>,\n  RQtoRs extends RqtoRSConstraint<RQ, RS>\n> = RS[RQtoRs[T]];\n\nexport type WorkerRequestT<RQ, RS, T extends RequestMsgTypes<RQ>> = WorkerMsgT<RQ, RS, T>;\nexport type WorkerResponseT<RQ, RS, T extends ResponseMsgTypes<RS>> = WorkerMsgT<RQ, RS, T>;\n\n/* Worker types */\nexport interface WorkerClientMessageEvent<RQ, RS> extends MessageEvent {\n  data: WorkerResponse<RQ, RS>;\n}\nexport interface WorkerClient<RQ, RS> extends Worker {\n  onmessage(e: WorkerClientMessageEvent<RQ, RS>): void;\n  postMessage<T extends RequestMsgTypes<RQ>>(message: WorkerRequestT<RQ, RS, T>, transfer?: any[]): void;\n  postMessage<T extends RequestMsgTypes<RQ>>(message: WorkerRequestT<RQ, RS, T>, options: {transfer: any[]}): void;\n}\n\nexport interface WorkerMessageEvent<RQ, RS> extends MessageEvent {\n  data: WorkerRequest<RQ, RS>;\n}\n\nexport interface TypedWorker<RQ, RS> extends DedicatedWorkerGlobalScope {\n  onmessage(e: WorkerMessageEvent<RQ, RS>): void;\n  postMessage<T extends ResponseMsgTypes<RS>>(message: WorkerResponseT<RQ, RS, T>, transfer?: any[]): void;\n  postMessage<T extends ResponseMsgTypes<RS>>(message: WorkerResponseT<RQ, RS, T>, options: {transfer: any[]}): void;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/web-worker-infra/web-worker/index.ts",
    "content": "import {\n  TypedWorker,\n  RQRSConstraint,\n  RqtoRSConstraint,\n  WorkerFunctionsMap,\n  RequestMsgTypes,\n  WorkerRequestT,\n  RequestTypeToResponseTypeMap,\n} from '../types';\nexport {TypedWorker, RequestTypeToResponseTypeMap, WorkerFunctionsMap} from '../types';\n\nexport function TypedWorkerFactory<\n  RQ extends RQRSConstraint,\n  RS extends RQRSConstraint,\n  RQtoRs extends RqtoRSConstraint<RQ, RS>\n>(msgTypeMapping: RequestTypeToResponseTypeMap<RQ, RS, RQtoRs>, functionsMap: WorkerFunctionsMap<RQ, RS, RQtoRs>) {\n  return (self: TypedWorker<RQ, RS>) => {\n    self.onmessage = e => {\n      try {\n        handleMsg(e.data);\n      } catch (e) {\n        console.error('something bad happened', e);\n      }\n    };\n\n    function handleMsg<T extends RequestMsgTypes<RQ>>(req: WorkerRequestT<RQ, RS, T>) {\n      const {data} = req;\n      const responseType = msgTypeMapping[req.type];\n      const responseData = functionsMap[req.type](data);\n      const response = {\n        id: req.id,\n        type: responseType,\n        data: responseData,\n      } as any;\n\n      self.postMessage(response);\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/lib/web-worker-infra/web-worker-manager/index.ts",
    "content": "import {\n  RequestMsgTypes,\n  RQRSConstraint,\n  RqtoRSConstraint,\n  WorkerClient,\n  WorkerRequestT,\n  WorkerResponseData,\n  WorkerResponseDataT,\n} from '../types';\n\nexport {RequestTypeToResponseTypeMap, WorkerFunctionsMap} from '../types';\n\nfunction XHRWorker(url, maxAge?): Promise<Worker> {\n  return new Promise((resolve, reject) => {\n    const oReq = new XMLHttpRequest();\n    oReq.addEventListener('load', () => {\n      const worker = new Worker(URL.createObjectURL(new Blob([oReq.responseText])));\n      resolve(worker);\n    });\n    oReq.addEventListener('error', e => {\n      reject(new Error(oReq.responseText || 'Unknown error, failed fetching web worker'));\n    });\n    oReq.open('get', url, true);\n    if (maxAge) {\n      oReq.setRequestHeader('Cache-Control', `max-age=${maxAge}`);\n    }\n    oReq.send();\n  });\n}\nexport type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;\n\nexport class TypedWorkerManager<\n  RQ extends RQRSConstraint,\n  RS extends RQRSConstraint,\n  RQtoRS extends RqtoRSConstraint<RQ, RS>\n> {\n  private requestId = 1;\n  private readonly requestIdToPromise = new Map<number, (value: WorkerResponseData<RQ, RS>) => void>();\n\n  constructor(private readonly worker: WorkerClient<RQ, RS>) {\n    this.worker.onmessage = e => {\n      const response = e.data;\n      const resolve = this.requestIdToPromise.get(response.id);\n      this.requestIdToPromise.delete(response.id);\n\n      if (!resolve) {\n        throw new Error(`WorkerMngr:: Can't find promise, something horrible happend. id: ${response.id}`);\n      }\n      resolve(response.data);\n    };\n  }\n\n  protected sendMsg<T extends RequestMsgTypes<RQ>>(\n    msg: Omit<WorkerRequestT<RQ, RS, T>, 'id'>,\n  ): Promise<WorkerResponseDataT<RQ, RS, T, RQtoRS>> {\n    const sentMsg: WorkerRequestT<RQ, RS, T> = {...msg, id: this.requestId++};\n    return new Promise(resolve => {\n      this.requestIdToPromise.set(sentMsg.id, resolve);\n      this.worker.postMessage(sentMsg);\n    });\n  }\n\n  static async createFromUrl<\n    RQ extends RQRSConstraint,\n    RS extends RQRSConstraint,\n    RQtoRS extends RqtoRSConstraint<RQ, RS>,\n    T extends TypedWorkerManager<RQ, RS, RQtoRS>\n  >(this: new (w: WorkerClient<RQ, RS>) => T, url: string, maxAge = null) {\n    const worker = await XHRWorker(url, maxAge);\n    // tslint:disable-next-line: no-static-this\n    return new this(worker);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/plugins/db/athena-db-plugin.ts",
    "content": "import { App } from '../../lib/app';\nimport {DbPlugin} from '../../services/plugins';\nimport {DB} from '../../config';\nimport {IFile, ModuleEngineType} from '@wix/quix-shared';\nimport {sanitizeTableToken} from '../../services';\n\n\nexport class AthenaDbPlugin extends DbPlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Athena, hooks);\n  }\n\n  getSampleQuery(table: IFile) {\n    return `SELECT *\nFROM ${[...table.path, table].map(({name}) => sanitizeTableToken(name, '\"')).join('.')}\nLIMIT ${DB.SampleLimit}\n`    \n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/db/bigquery-db-plugin.ts",
    "content": "import {DbPlugin} from '../../services/plugins';\nimport {IFile, ModuleEngineType} from '@wix/quix-shared';\nimport {DB} from '../../config';\nimport { App } from '../../lib/app';\n\nexport class BigQueryDbPlugin extends DbPlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.BigQuery, hooks);\n  }\n\n  getSampleQuery(table: IFile) {\n    return `SELECT *\nFROM \\`${[...table.path, table].map(({name}) => name).join('.')}\\`\nLIMIT ${DB.SampleLimit}\n`    \n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/db/index.ts",
    "content": "export * from './athena-db-plugin';\nexport * from './presto-db-plugin';\nexport * from './jdbc-db-plugin';\nexport * from './bigquery-db-plugin';"
  },
  {
    "path": "quix-frontend/client/src/plugins/db/jdbc-db-plugin.ts",
    "content": "import { App } from '../../lib/app';\nimport {DbPlugin} from '../../services/plugins';\nimport {IFile, ModuleEngineType} from '@wix/quix-shared';\nimport {DB} from '../../config';\nimport {sanitizeTableToken} from '../../services';\n\nexport class JdbcDbPlugin extends DbPlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Jdbc, hooks);\n  }\n\n  getSampleQuery(table: IFile) {\n    return `SELECT *\nFROM ${[...table.path, table].map(({name}) => sanitizeTableToken(name, '\"')).join('.')}\nLIMIT ${DB.SampleLimit}\n`    \n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/db/presto-db-plugin.ts",
    "content": "import { App } from '../../lib/app';\nimport {DbPlugin} from '../../services/plugins';\nimport {IFile, ModuleEngineType} from '@wix/quix-shared';\nimport {DB} from '../../config';\nimport {sanitizeTableToken} from '../../services';\n\nexport class PrestoDbPlugin extends DbPlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Presto, hooks);\n  }\n\n  getSampleQuery(table: IFile) {\n    return `SELECT *\nFROM ${[...table.path, table].map(({name}) => sanitizeTableToken(name, '\"')).join('.')}\nLIMIT ${DB.SampleLimit}\n`    \n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/index.ts",
    "content": "import {pluginFactory} from './plugin-factory';\nimport {PluginManager} from '../services/plugins';\nimport {hooks} from '../hooks';\n\nexport const pluginManager = new PluginManager(pluginFactory, hooks.note);\n"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/athena-note-plugin.ts",
    "content": "import { ModuleEngineType } from '@wix/quix-shared';\nimport { App } from '../../lib/app';\nimport { NotePlugin } from '../../services/plugins';\n\nexport class AthenaNotePlugin extends NotePlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Athena, hooks, {\n      syntaxValidation: true,\n      canCreate: true,\n      enableQueryFormatter: true,\n    });\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/bigquery-note-plugin.ts",
    "content": "import bytes from 'bytes';\nimport { ModuleEngineType } from '@wix/quix-shared';\nimport { App } from '../../lib/app';\nimport { NotePlugin } from '../../services/plugins';\n\nexport class BigQueryNotePlugin extends NotePlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.BigQuery, hooks, {\n      syntaxValidation: true,\n      canCreate: true,\n      dateFormat: 'YYYY/MM/DD HH:mm:ss',\n    });\n  }\n\n  formatStats(stats: {[key: string]: any}) {\n    const bytesConfig = {thousandsSeparator: ',', unitSeparator: ' ', decimalPlaces: 0};\n\n    return [{\n      title: 'Cache',\n      value: stats.cacheHit ? 'Hit' : 'Miss',\n    }, {\n      title: 'Bytes processed',\n      value: bytes(stats.bytesProcessed, bytesConfig),\n    }, {\n      title: 'Bytes billed',\n      value: bytes(stats.bytesBilled, bytesConfig),\n    }];\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/default-note-plugin.ts",
    "content": "import {ModuleEngineType} from '@wix/quix-shared';\nimport {NotePlugin} from '../../services/plugins';\n\nexport class DefaultNotePlugin extends NotePlugin {\n  constructor(app) {\n    super(\n      app,\n      'default',\n      ModuleEngineType.Presto,\n      {},\n      {\n        syntaxValidation: false,\n        canCreate: false,\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/index.ts",
    "content": "export * from './default-note-plugin';\nexport * from './athena-note-plugin';\nexport * from './presto-note-plugin';\nexport * from './jdbc-note-plugin';\nexport * from './bigquery-note-plugin';\nexport * from './python-note-plugin';\n"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/jdbc-note-plugin.ts",
    "content": "import { ModuleEngineType } from '@wix/quix-shared';\nimport { App } from '../../lib/app';\nimport { NotePlugin } from '../../services/plugins';\n\nexport class JdbcNotePlugin extends NotePlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Jdbc, hooks, {\n      syntaxValidation: false,\n      canCreate: true,\n    });\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/presto-note-plugin.ts",
    "content": "import { ModuleEngineType } from '@wix/quix-shared';\nimport { App } from '../../lib/app';\nimport { NotePlugin } from '../../services/plugins';\n\nexport class PrestoNotePlugin extends NotePlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Presto, hooks, {\n      syntaxValidation: true,\n      canCreate: true,\n      enableQueryFormatter: true,\n    });\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/plugins/note/python-note-plugin.ts",
    "content": "import { ModuleEngineType } from '@wix/quix-shared';\nimport { App } from '../../lib/app';\nimport { NotePlugin } from '../../services/plugins';\n\nexport class PythonNotePlugin extends NotePlugin {\n  constructor(app: App, name: string, hooks: any) {\n    super(app, name, ModuleEngineType.Python, hooks, {\n      syntaxValidation: true,\n      canCreate: true,\n    });\n  }\n\n  renderRunner() {\n    return `\n      <bi-python-runner\n        class=\"bi-c-h bi-grow bi-fade-in\"\n        ng-model=\"textContent\"\n        ng-change=\"events.onContentChange(textContent)\"\n        bpr-options=\"::{\n          fitContent: true,\n          params: true,\n          focus: options.focusEditor,\n          showEditor: options.showEditor,\n          showSyntaxErrors: vm.showSyntaxErrors,\n          shareParams: options.shareParams,\n          autoRun: options.autoRun,\n          dateFormat: vm.dateFormat\n        }\"\n        type=\"vm.type\"\n        runner=\"runner\"\n        download-file-name=\"actions.getDownloadFileName(query)\"\n        table-formatter=\"tableFormatter()\"\n        on-save=\"events.onSave()\"\n        on-run=\"events.onRun()\"\n        on-editor-load=\"events.onEditorInstanceLoad(instance)\"\n        on-runner-load=\"events.onRunnerInstanceLoad(instance)\"\n        on-runner-created=\"events.onRunnerCreated(runner)\"\n        on-runner-destroyed=\"events.onRunnerDestroyed(runner)\"\n        on-params-share=\"events.onParamsShare(params)\"\n        readonly=\"readonly\"\n      >\n        <controls>\n          <quix-npc></quix-npc>\n        </controls>\n      </bi-python-runner>\n    `;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/plugins/plugin-factory.ts",
    "content": "import {App} from '../lib/app';\nimport { Store } from '../lib/store';\nimport * as DbPlugins from './db';\nimport * as NotePlugins from './note';\n\nexport const pluginFactory = {\n  db(app: App, store: Store, id: string, engine: string, noteHooks: any) {\n    switch (engine) {\n      case 'presto':\n        return new DbPlugins.PrestoDbPlugin(app, id, noteHooks);\n      case 'athena':\n        return new DbPlugins.AthenaDbPlugin(app, id, noteHooks);\n      case 'jdbc':\n        return new DbPlugins.JdbcDbPlugin(app, id, noteHooks);\n      case 'bigquery':\n        return new DbPlugins.BigQueryDbPlugin(app, id, noteHooks);\n      default:\n        throw new Error(`No definition for \"${engine}\" engine db plugin`);\n    }\n  },\n\n  note(app: App, store: Store, id: string, engine: string, noteHooks: any) {\n    switch (engine) {\n      case 'presto':\n        return new NotePlugins.PrestoNotePlugin(app, id, noteHooks);\n      case 'athena':\n        return new NotePlugins.AthenaNotePlugin(app, id, noteHooks);\n      case 'jdbc':\n        return new NotePlugins.JdbcNotePlugin(app, id, noteHooks);\n      case 'bigquery':\n        return new NotePlugins.BigQueryNotePlugin(app, id, noteHooks);\n      case 'python':\n        return new NotePlugins.PythonNotePlugin(app, id, noteHooks);\n      default:\n        return noteHooks.plugin.call(app, store, engine, id) || new NotePlugins.DefaultNotePlugin(app);\n    }\n  },\n};\n"
  },
  {
    "path": "quix-frontend/client/src/react-components/file-explorer/FileExplorerComponent.scss",
    "content": "@import '../../lib/ui/assets/css/def/state.def';\n@import '../../lib/ui/assets/css/def/colors.def';\n@import '../../lib/ui/assets/css/text.scss';\n@import '../../lib/file-explorer/directives/file-explorer.scss';\n\nquix-file-explorer {\n  .bi-spinner--xs {\n    &:after {\n      border-color: $dark-muted-color;\n      border-right-color: transparent;\n    }\n    margin-right: 3px;\n  }\n\n  @for $i from 0 through 3 {\n    .fe-item-depth-#{$i} {\n      padding-left: $i * 12px + 6px;\n      padding-right: 3px;\n    }\n  }\n\n  .fe-item {\n    border-left: 2px solid transparent;\n    transition: border-color .2s;\n    &:hover {\n      border-color: $primary;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/react-components/file-explorer/FileExplorerComponent.tsx",
    "content": "import './FileExplorerComponent.scss';\nimport * as _ from 'lodash';\nimport React, { useEffect, useState } from 'react';\nimport { v4 as uuid } from 'uuid';\nimport {TreeItem, Node} from './TreeItem';\n\nconst EXPAND_ALL_NODES_LIMIT = 3000;\n\ninterface MenuOptionProps {\n  title: string;\n  action(sub: Tree, path: string[]): void;\n}\n\nexport interface FileExplorerProps {\n  tree: Tree[] | Tree;\n  onTransformNode(node: Tree, path: string[]): Tree;\n  onFetchChildren?(node: Tree, path: string[]): Promise<Tree[]>;\n  menuOptions: {\n    [key:string]: MenuOptionProps[];\n  };\n  expandedNodes: boolean;\n  highlight: string;\n}\n\nexport interface Tree {\n  id: string;\n  name: string;\n  type: string;\n  transformed: boolean;\n  lazy?: boolean;\n  icon?: string;\n  textIcon?: string;\n  children?: Tree[];\n}\n\nconst countAllSubChildren = (node: Tree, withLazy: boolean = false, count = 0) => {\n  if (!node.children || (!withLazy && node.lazy)) {\n    return count;\n  }\n\n  const sum = node.children.length;\n  const sumChildren = node.children.map(child => countAllSubChildren(child, withLazy, count)).reduce((a, b) => a + b, 0);\n\n  return sum + sumChildren;\n}\n\n\nexport const FileExplorer = (props: FileExplorerProps) => {\n\n  const [innerTree, setInnerTree] = useState<Tree[]>([]);\n\n  useEffect(() => {\n    const transformedNode = transformChildNodes(\n      {\n        children: Array.isArray(props.tree) ? props.tree : [props.tree]\n      } as Node,\n      [],\n    );\n    setInnerTree(transformedNode.children);\n  }, [props.tree]);\n\n  const updateNode = (subNode: Node, transformedNode: Node, iteratorNode: Tree, path: string[]) => {\n    const fullPath = [...path, transformedNode.id || subNode.id];\n  \n    for (let i = 1; i < fullPath.length; i++) {\n      iteratorNode = iteratorNode?.children.find(nodeProps => nodeProps.id === fullPath[i]);\n    }\n\n    iteratorNode.children = transformedNode.children;\n    return iteratorNode;\n  }\n\n  const transformLazy = async (index: number, subNode: Node, path: string[]) => {\n    const iteratorNode = innerTree[index];\n    const transformedNode = await transformChildNodesLazy(iteratorNode, subNode, path);\n    return updateNode(subNode, transformedNode, iteratorNode, path);\n  }\n\n  const transform = (index: number, subNode: Node, path: string[]) => {\n    const iteratorNode = innerTree[index];\n    const transformedNode = transformChildNodes(subNode, path);\n    return updateNode(subNode, transformedNode, iteratorNode, path);\n  }\n\n  const transformChildNodesLazy = async (mainNode: Node, node: Node, path: string[]): Promise<Node> => {\n    let transformedNode = node;\n\n    if (node.lazy) {\n      if (!_.isEqual(node.children, [{}])) {\n        return node;\n      }\n      const fetchedChildren = await props.onFetchChildren(mainNode, [...path, node.id]);\n      transformedNode = {children: fetchedChildren} as Node;\n    }\n\n    return transformChildNodes(transformedNode, path);\n  }\n\n  const transformChildNodes = (node: Node, path: string[]): Node => {\n    const currentNode = _.cloneDeep(node);\n    for (const [index, child] of currentNode.children.entries()) {\n      if (!child.transformed) {\n        const shouldBeLazy = !!child.children && !child.children.length;\n        const transformedChild = props.onTransformNode(child, path);\n        transformedChild.children = transformedChild.lazy && shouldBeLazy ? [{} as any] : transformedChild.children;\n        transformedChild.id = transformedChild.id || uuid();\n\n        currentNode.children[index] = transformedChild;\n      }\n    }\n    return currentNode;\n  }\n\n  const onMenuClick = (subNode: Node, option: { title: string }, path: string[], node: Node) => {\n    (option as MenuOptionProps).action(node, [...path, subNode.id])\n  };\n\n  return (\n    <ul className=\"fe-folders\">\n      {\n        innerTree.length !== 0 ?\n        innerTree.map((sub, index) => (\n          <TreeItem\n            key={sub.id}\n            node={sub}\n            menuOptions={props.menuOptions}\n            onMenuClick={(subNode, option, path) => onMenuClick(subNode, option, path, sub)}\n            onTransformChildNodesLazy={(subNode, path) => transformLazy(index, subNode, path)}\n            onTransformChildNodes={(subNode, path) => transform(index, subNode, path)}\n            expandAllNodes={\n              props.expandedNodes && countAllSubChildren({children: innerTree} as Node) < EXPAND_ALL_NODES_LIMIT\n            }\n            path={[]}\n            highlight={props.highlight || null}\n          />\n        )) : null\n      }\n    </ul>\n  )\n}\n"
  },
  {
    "path": "quix-frontend/client/src/react-components/file-explorer/TreeItem.tsx",
    "content": "import React, {useEffect, useState} from 'react';\nimport _ from 'lodash';\nimport {TreeItemMenu} from './TreeItemMenu';\nimport {Highlighter} from '../../lib/ui/components/Highlighter';\n\nexport interface Node {\n  id: string;\n  name: string;\n  type: string;\n  transformed: boolean;\n  lazy?: boolean;\n  icon?: string;\n  textIcon?: string;\n  children?: Node[];\n  more?: boolean;\n}\n\ninterface TreeItemProps {\n  node: Node;\n  menuOptions: {\n    [key:string]: {\n      title: string;\n    }[];\n  };\n  path: string[];\n  highlight: string;\n  expandAllNodes: boolean;\n  onMenuClick(node: Node, option: { title: string }, path: string[]): void;\n  onTransformChildNodes(node: Node, path: string[]): Node;\n  onTransformChildNodesLazy(node: Node, path: string[]): Promise<Node>;\n}\n\n\nconst InnerTreeItem = ({\n    node: initialNode,\n    menuOptions,\n    path,\n    highlight,\n    expandAllNodes,\n    onMenuClick,\n    onTransformChildNodes,\n    onTransformChildNodesLazy,\n  }: TreeItemProps) => {\n  const [node] = useState<Node>(initialNode);\n  const [isLoading, setIsLoading] = useState(false);\n  const [expanded, setExpanded] = useState(false);\n  const [clickedFirstTime, setClickedFirstTime] = useState(false);\n\n  useEffect(() => {\n    if (!node.lazy && expandAllNodes) {\n      toggleNode();\n    }\n  }, []);\n\n  const onClick = async () => {\n    if (!expanded) {\n      toggleNode();\n    } else {\n      setExpanded(false);\n    }\n    if (!clickedFirstTime) {\n      setClickedFirstTime(true);\n    }\n  }\n\n  const toggleNode = async () => {\n    setExpanded(true);\n    if (!node.children || !node.children.find(child => !child.transformed)) {\n      return;\n    }\n\n    if (node.lazy) {\n      setIsLoading(true);\n      const transformedNode = await onTransformChildNodesLazy(node, path);\n      node.children = transformedNode.children;\n      setIsLoading(false);\n    } else {\n      const transformedNode = onTransformChildNodes(node, path);\n      node.children = transformedNode.children;\n    }\n  }\n\n  const preIcon = (_onClick: () => void) => (\n    isLoading ? \n      <span className=\"bi-align\">\n        <span data-hook=\"tree-item-loading-icon\" className=\"bi-align bi-spinner--xs\">\n        </span>\n      </span>\n    : Array.isArray(node.children) ?\n        expanded ?\n        <i onClick={_onClick} className=\"bi-action bi-icon--sm\" data-hook=\"tree-item-opened-icon\">arrow_drop_down</i>\n        : <i onClick={_onClick} className=\"bi-action bi-icon--sm\" data-hook=\"tree-item-closed-icon\">arrow_right</i>\n      : null\n  )\n\n  const describeIcon = (\n    node.textIcon ?\n    <div className=\"bi-text--sm\">{node.textIcon}</div>\n    : <i className=\"bi-icon--xs\">{node.icon || 'hourglass_empty'}</i>\n  )\n\n  const menu = (\n    menuOptions[node.type] ?\n      <TreeItemMenu\n        menuOptions={menuOptions[node.type]}\n        onMenuClick={(option) => onMenuClick(node, option, path)}\n      />\n      : null\n  )\n\n  const getText = () => {\n    if (highlight && node.children) {\n        return (\n        <Highlighter\n          term={node.name}\n          filter={highlight}\n        />\n      );\n    }\n    return node.name;\n  }\n\n  return (\n    <li>\n      <div className={`fe-item bi-spread bi-fade-in bi-hover bi-muted fe-item-depth-${path.length} ui-droppable-disabled`}>\n        <div\n        className=\"bi-align bi-grow\">\n          {preIcon(onClick)}\n          <span className=\"bi-r-h bi-spread bi-pointer\">\n            <span\n              onClick={onClick}\n              className=\"fe-item-name bi-s-h--x05 bi-align bi-grow bi-text--ellipsis\"\n            >\n              <span className=\"fe-icon-container\">\n                {describeIcon}\n              </span>\n              <span data-hook=\"tree-item-content\" className=\"bi-text--ellipsis\">\n              {getText()}\n              </span>\n            </span>\n\n            {menu}\n\n          </span>\n        </div>\n      </div>\n      <ul>\n        {\n          expanded && !isLoading ? \n            node.children?.map(childNode =>\n              childNode.id &&\n              <InnerTreeItem\n                key={childNode.id}\n                menuOptions={menuOptions}\n                node={childNode}\n                onTransformChildNodes={onTransformChildNodes}\n                onTransformChildNodesLazy={onTransformChildNodesLazy}\n                onMenuClick={onMenuClick}\n                path={[...path, node.id]}\n                expandAllNodes={!clickedFirstTime ? expandAllNodes : false}\n                highlight={highlight}\n              />\n            )\n          : null\n        }\n      </ul>\n    </li>\n  )\n}\n\nfunction TreeItemPropsAreEqual(prevProps, nextProps) {\n  const prevNode: Node = prevProps.node;\n  const nextNode: Node = nextProps.node;\n  \n  return prevNode.id === nextNode.id;\n}\n\nexport const TreeItem = React.memo(InnerTreeItem, TreeItemPropsAreEqual);"
  },
  {
    "path": "quix-frontend/client/src/react-components/file-explorer/TreeItemMenu.tsx",
    "content": "import React from 'react';\nimport {Dropdown} from '../../lib/ui/components/dropdown/Dropdown';\n\ninterface TreeItemMenuProps {\n  menuOptions: {\n    title: string;\n  }[];\n  onMenuClick(option: {\n    title: string;\n  }): void;\n}\n\n\nexport const TreeItemMenu = ({\n  menuOptions,\n  onMenuClick,\n}: TreeItemMenuProps) => {\n\n  return (\n    <Dropdown\n      toggle={(p) => \n        <i {...p} className=\"bi-action bi-icon\">\n          more_vert\n        </i>}\n      placement=\"bottom-end\"\n      options={menuOptions}\n      dynamicWidth={false}\n    >\n      {(options) => \n        <ul className=\"bi-dropdown-menu\">\n          {options.map((option) => \n            <li\n              key={option.title}\n              onClick={() => {\n                onMenuClick(option);\n              }}\n            >\n              {option.title}\n            </li>\n          )}\n        </ul>\n      }</Dropdown>\n  )\n}"
  },
  {
    "path": "quix-frontend/client/src/react-components/file-explorer/file-explorer-testkit.ts",
    "content": "import { Testkit } from '../../../test/e2e/driver';\n\nconst enum Hooks {\n  FileExplorerTab = 'app-menu-DB Explorer',\n  TreeItemContent = 'tree-item-content',\n  TreeItemLoadingIcon = 'tree-item-loading-icon',\n  TreeItemOpenedIcon = 'tree-item-opened-icon',\n  TreeItemClosedIcon = 'tree-item-closed-icon',\n  FileExplorerSearch = 'file-explorer-search',\n}\n\nexport class FileExplorerTestkit extends Testkit {\n  async toggleFileExplorerTab() {\n    await this.click.hook(Hooks.FileExplorerTab);\n  }\n  \n  async numOfTreeItems() {\n    return (await this.query.hooks(Hooks.TreeItemContent)).length;\n  }\n\n  async numOfLoadingTreeItems() {\n    return (await this.query.hooks(Hooks.TreeItemLoadingIcon)).length;\n  }\n\n  async numOfOpenedTreeItems() {\n    return (await this.query.hooks(Hooks.TreeItemOpenedIcon)).length;\n  }\n\n  async numOfClosedTreeItems() {\n    return (await this.query.hooks(Hooks.TreeItemClosedIcon)).length;\n  }\n\n  async clickOnTreeItemByPosition(position: number) {\n    return (await this.query.hooks(Hooks.TreeItemContent))[position].click();\n  }\n\n  async getTreeItemIndexByName(name: string) {\n    const position = await this.evaluate.hooks(\n      Hooks.TreeItemContent,\n      (elements, args) =>\n        elements.findIndex(element => element.innerHTML === args.name),\n      {name});\n    return position;\n  }\n\n  async isTreeItemExistsByName(name: string) {\n    const res = await this.getTreeItemIndexByName(name);\n    return res !== -1;\n  }\n  \n  async clickOnItemByName(name: string) {\n    const position = await this.getTreeItemIndexByName(name);\n    return this.clickOnTreeItemByPosition(position);\n  }\n\n  async search(query: string) {\n    return this.keyboard.type(Hooks.FileExplorerSearch, query);\n  }\n\n}\n"
  },
  {
    "path": "quix-frontend/client/src/react-components/file-explorer/file-explorer.ts",
    "content": "import { IReactComponentConfig } from '../../lib/app/services/plugin-builder';\nimport {FileExplorer} from './FileExplorerComponent';\n\nexport default (): IReactComponentConfig => ({\n  name: 'File Explorer',\n  template: FileExplorer,\n  scope: ['tree', 'onTransformNode', 'onFetchChildren', 'menuOptions', 'expandedNodes', 'highlight'],\n});\n"
  },
  {
    "path": "quix-frontend/client/src/react-components/index.ts",
    "content": "export {default as quixFileExplorer} from './file-explorer/file-explorer';\n"
  },
  {
    "path": "quix-frontend/client/src/services/db.ts",
    "content": "export const sanitizeTableToken = (token: string, quoteChar: string) => {\n  if (token.includes('.') || token.includes('-')) {\n    return `${quoteChar}${token}${quoteChar}`;\n  }\n\n  return token;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/services/dialog.ts",
    "content": "import { isArray } from 'lodash';\nimport { confirm } from '../lib/ui';\nimport { utils } from '../lib/core';\n\nfunction contextText(context: any, type: string) {\n  return isArray(context)\n    ? `the <b>(${context.length})</b> selected ${utils.dom.escape(type)}s`\n    : `the ${utils.dom.escape(type)} <b>\"${utils.dom.escape(\n        context.name\n      )}</b>\"`;\n}\n\nfunction confirmActionTitle(action: string, type: string): string {\n  switch (action) {\n    case 'delete':\n      return `${action} ${type}`;\n    case 'trash':\n      return `Move ${type} to Trash Bin`;\n    default:\n      return `Operation failed`;\n  }\n}\n\nfunction actionText(action: string) {\n  switch (action) {\n    case 'trash':\n      return 'move';\n    case 'delete':\n      return 'delete';\n    default:\n      return '';\n  }\n}\n\nfunction confirmHtml(\n  action: string,\n  context: any,\n  type: string,\n  customText: string\n): string {\n  const custom = customText ? `(${utils.dom.escape(customText)})` : '';\n  const areYouSure =\n    'Are you sure you want to ' +\n    `${actionText(action)} ${contextText(context, type)}`;\n\n  switch (action) {\n    case 'delete':\n      return `\n      <div>\n        ${areYouSure}\n        ${custom} ?\n      </div>`;\n    case 'trash':\n      return `\n      <div>\n        ${areYouSure} to Trash Bin\n        ${custom} ?\n      </div>`;\n    default:\n      return `${customText}`;\n  }\n}\n\nexport const confirmAction = (\n  action: 'delete' | 'trash' | 'retry',\n  type: 'notebook' | 'note' | 'folder' | 'item',\n  context: any,\n  customText = '',\n  onConfirm: (scope: any) => any = () => {}\n) => {\n  return confirm({\n    title: confirmActionTitle(action, type),\n    actionType: { delete: 'destroy' }[action] || 'neutral',\n    icon: { delete: 'delete_forever', retry: 'report' }[action] || null,\n    yes: action === 'trash' ? 'move to trash bin' : action,\n\n    onConfirm,\n    html: confirmHtml(action, context, type, customText),\n  });\n};\n\nexport const prompt = (\n  {\n    title,\n    subTitle,\n    yes,\n    content,\n    onConfirm,\n  }: {\n    title: string;\n    subTitle?: string;\n    yes: string;\n    content: string;\n    onConfirm?(scope: any): any;\n  },\n  scope?,\n  locals?\n) => {\n  return confirm(\n    {\n      title,\n      subTitle,\n      actionType: 'neutral',\n      yes,\n      html: `<form name=\"form\">${content}</form>`,\n      onConfirm,\n    },\n    scope,\n    locals\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/services/files.ts",
    "content": "import { isArray, last, takeWhile } from 'lodash';\nimport { Store } from '../lib/store';\nimport { App } from '../lib/app';\nimport {\n  IFile,\n  FileActions,\n  createFolder,\n  IFilePathItem,\n  FileType,\n  TrashBinActions,\n} from '@wix/quix-shared';\nimport { isOwner } from './permissions';\nimport { cache } from '../store';\n\nexport const addFolder = async (\n  store: Store,\n  app: App,\n  parentOrPath: IFile | IFilePathItem[],\n  props: Partial<IFile> = {}\n): Promise<IFile> => {\n  let path = isArray(parentOrPath)\n    ? parentOrPath\n    : [\n        ...parentOrPath.path,\n        {\n          id: parentOrPath.id,\n          name: parentOrPath.name,\n        },\n      ];\n\n  path = path.length ? path : await fetchRootPath();\n\n  const folder = createFolder(path, {\n    ...props,\n    owner: app.getUser().getEmail(),\n  });\n\n  return store\n    .logAndDispatch(FileActions.createFile(folder.id, folder))\n    .then(() => folder);\n};\n\nexport const deleteFolder = (store: Store, app: App, folder: IFile) => {\n  const { id } = folder;\n\n  return store\n    .logAndDispatch(TrashBinActions.moveFolderToTrashBin(id))\n    .then(() => {\n      if (store.getState('folder.folder')) {\n        goUp(app, folder);\n      }\n    });\n};\n\nexport const isRoot = (file: Pick<IFile, 'type' | 'path'>) => {\n  return !file.path.length && file.type === FileType.folder;\n};\n\nexport const fetchRoot = (): Promise<IFile> => {\n  return cache.files.get().then((files) => files.find(isRoot));\n};\n\nexport const fetchFile = (id: string): Promise<IFile> => {\n  return cache.files\n    .get()\n    .then((files) => files.find((file) => file.id === id));\n};\n\nexport const fetchFileByName = (\n  name: string,\n  parent?: IFile\n): Promise<IFile> => {\n  return cache.files\n    .get()\n    .then((files) =>\n      files.find(\n        (file) =>\n          file.name === name &&\n          (!parent ||\n            (file.path.length && last<IFile>(file.path).id === parent.id))\n      )\n    );\n};\n\nexport const createFileByNamePath = <T>(\n  store: Store,\n  app: App,\n  namePath: string[],\n  fileCreator: (name: string, parent: IFile) => Promise<T>\n): Promise<T> => {\n  return (namePath.reduce<Promise<IFile>>(async (res, name, index) => {\n    const parent = await res;\n    let file = await fetchFileByName(name, parent);\n\n    if (!file) {\n      const isFolder = index < namePath.length - 1;\n\n      if (isFolder) {\n        file = file || (await addFolder(store, app, parent, { name }));\n      } else {\n        file = fileCreator(name, parent) as any;\n      }\n    }\n\n    return file;\n  }, fetchRoot()) as unknown) as Promise<T>;\n};\n\nexport const fetchFileParent = (id: string): Promise<IFile> => {\n  return fetchFile(id).then((file) => fetchFile(last<any>(file.path).id));\n};\n\nexport const fetchRootPath = (): Promise<IFilePathItem[]> => {\n  return fetchRoot().then(\n    (file) => (file && [{ id: file.id, name: file.name }]) || []\n  );\n};\n\nexport const goToFile = (\n  app: App,\n  file: Pick<IFile, 'id' | 'type' | 'owner' | 'path'>,\n  params: {\n    isNew?: boolean;\n    note?: string;\n  } = {\n    isNew: false,\n    note: null,\n  },\n  options?: any\n) => {\n  const id = isRoot(file) && isOwner(app, file) ? null : file.id;\n\n  return app.go(\n    file && file.type === FileType.notebook ? 'notebook' : 'files',\n    {\n      id,\n      isNew: params.isNew,\n      note: params.note,\n    },\n    options\n  );\n};\n\nexport const goToRoot = (app: App) => {\n  app.go('files', {\n    id: null,\n    isNew: false,\n  });\n};\n\nexport const goUp = (app: App, file: Pick<IFile, 'id' | 'path' | 'owner'>) => {\n  const pathItem = last(file.path);\n\n  const folder = {\n    ...pathItem,\n    type: FileType.folder,\n    path: takeWhile(file.path, (item) => item.id !== pathItem.id),\n    owner: file.owner,\n  };\n\n  goToFile(app, folder);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/services/hooks/index.ts",
    "content": "export * from './with-outside-click';\nexport * from './use-view-state';"
  },
  {
    "path": "quix-frontend/client/src/services/hooks/use-view-state.ts",
    "content": "import { useState } from 'react';\n\nexport interface ViewStateActions<S, D> {\n  get(): S;\n  set(s: S, d?: Partial<D>): void;\n  update(d: Partial<D>): void;\n  is(s: S): boolean;\n  min(s: S): boolean;\n  after(s: S): boolean;\n}\n\nexport const useViewState = <S extends string, D>(\n  states: S[],\n  defaultData: D,\n) => {\n  const [{ state, data }, setState] = useState({\n    state: states[0],\n    data: defaultData,\n  });\n\n  return [\n    data,\n    {\n      get: () => state,\n      set: (s: S, d?: Partial<D>) =>\n        setState((prevState) => ({ state: s, data: { ...prevState.data, ...d } })),\n      update: (d: Partial<D>) => setState((prevState) => ({ state, data: { ...prevState.data, ...d } })),\n      is: (s: S) => s === state,\n      min: (s: S) => states.indexOf(s) <= states.indexOf(state),\n      after: (s: S) => states.indexOf(s) < states.indexOf(state),\n    },\n  ] as const;\n};"
  },
  {
    "path": "quix-frontend/client/src/services/hooks/with-outside-click.ts",
    "content": "import { useEffect } from 'react';\n\nexport const withOutsideClick = (\n  refs: React.MutableRefObject<any>[],\n  onClickOutside: () => void,\n) => {\n  useEffect(() => {\n    const handler = (event: any) => {\n      const inside: boolean[] = [];\n      refs\n        .filter((ref) => ref?.current)\n        .forEach((ref) => {\n          const parent = $(ref.current.parentElement);\n          const target = $(event.target);\n\n          if (!target.closest(parent).length || target.closest(event).length) {\n            inside.push(false);\n          } else {\n            inside.push(true);\n          }\n        });\n\n      if (inside.length && inside.every((i) => !i)) {\n        onClickOutside();\n      }\n    };\n\n    $('body').on('click', handler);\n    return () => {\n      $('body').off('click', handler);\n    };\n  }, [refs]);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/services/index.ts",
    "content": "export {addNotebook, deleteNotebook, saveQueuedNotes, hasQueuedNotes, goToExamples, copyNotebook, copyNote} from './notebook';\nexport {addFolder, deleteFolder, isRoot, goToFile, goToRoot, goUp, fetchRoot, fetchFile, fetchFileParent, fetchRootPath} from './files';\nexport {confirmAction, prompt} from './dialog';\nexport {StateManager} from './state';\nexport {getRunners} from './runners';\nexport {closePopup, openTempQuery, openSearchResults} from './popup';\nexport {extractTextAroundMatch as extractLinesAroundMatch} from './search';\nexport {browserNotificationsManager} from './notifications';\nexport {sanitizeTableToken} from './db';\nexport {subscribeToStateChanges} from './subscription';\n\nexport {\n  IPermissions,\n  isOwner,\n  getDefaultPermissions,\n  getFolderPermissions,\n  getNotebookPermissions\n} from './permissions';"
  },
  {
    "path": "quix-frontend/client/src/services/notebook.ts",
    "content": "import { isArray } from 'lodash';\nimport { Store } from '../lib/store';\nimport { App } from '../lib/app';\nimport {\n  FileType,\n  IFile,\n  INotebook,\n  INote,\n  NotebookActions,\n  createNotebook,\n  NoteActions,\n  IFilePathItem,\n  createNote,\n  TrashBinActions,\n} from '@wix/quix-shared';\nimport { fetchRootPath, goUp, goToFile, confirmAction } from './';\nimport { createFileByNamePath as addFileByNamePath } from './files';\nimport { pluginManager } from '../plugins';\nimport { setSaving } from '../store/notebook/notebook-actions';\n\nconst resolvePath = async (parentOrPath: IFile | IFilePathItem[]) => {\n  const path = isArray(parentOrPath)\n    ? parentOrPath\n    : [\n        ...parentOrPath.path,\n        {\n          id: parentOrPath.id,\n          name: parentOrPath.name,\n        },\n      ];\n\n  return path.length ? path : fetchRootPath();\n};\n\nexport const addNotebook = async (\n  store: Store,\n  app: App,\n  parentOrPath: IFile | IFilePathItem[],\n  options: { addNote: boolean },\n  props: Partial<INotebook> = {}\n): Promise<INotebook> => {\n  const path = await resolvePath(parentOrPath);\n  const notebook = createNotebook(path, {\n    ...props,\n    owner: app.getUser().getEmail(),\n  });\n\n  const actions: any[] = [\n    NotebookActions.createNotebook(notebook.id, notebook),\n  ];\n\n  if (options.addNote) {\n    const types = pluginManager\n      .module('note')\n      .plugins()\n      .filter((plugin) => plugin.getConfig().canCreate)\n      .map((plugin) => plugin.getId());\n\n    const note = createNote(notebook.id, { type: types[0] });\n\n    actions.push(NoteActions.addNote(note.id, note));\n  }\n\n  return store.logAndDispatch(actions).then(() => notebook);\n};\n\nexport const addNote = async (\n  store: Store,\n  notebookId: string,\n  type: string,\n  props: Partial<INote> = {},\n  onCreate?: (note: INote) => void\n): Promise<INote> => {\n  const note = createNote(notebookId, { ...props, type });\n\n  return store\n    .logAndDispatch(NoteActions.addNote(note.id, note))\n    .then(() => {\n      if (onCreate) {\n        onCreate(note);\n      }\n\n      return note;\n    })\n    .catch(() =>\n      confirmAction(\n        'retry',\n        'note',\n        note,\n        'Failed to create a new note. Please try again in a few moments.',\n        () => addNote(store, notebookId, type, props, onCreate)\n      )\n    );\n};\n\nexport const addNotebookByNamePath = async (\n  store: Store,\n  app: App,\n  namePath: string[]\n): Promise<INotebook> => {\n  return addFileByNamePath<INotebook>(store, app, namePath, (name, parent) =>\n    addNotebook(store, app, parent, { addNote: false }, { name })\n  );\n};\n\nexport const copyNotebook = async (\n  store: Store,\n  app: App,\n  parentOrPath: IFile | IFilePathItem[],\n  sourceNotebook: INotebook\n) => {\n  const { name, notes } = sourceNotebook;\n  const path = await resolvePath(parentOrPath);\n\n  const newNotebook = createNotebook(path, {\n    name: `Copy of ${name}`,\n    owner: app.getUser().getEmail(),\n  });\n\n  return store\n    .logAndDispatch([\n      NotebookActions.createNotebook(newNotebook.id, newNotebook),\n      ...notes.map(({ name: noteName, type, content, richContent, owner }) => {\n        const note = createNote(newNotebook.id, {\n          name: noteName,\n          type,\n          content,\n          richContent,\n          owner,\n        } as any);\n        return NoteActions.addNote(note.id, note);\n      }),\n    ])\n    .then(() =>\n      goToFile(\n        app,\n        { ...newNotebook, type: FileType.notebook },\n        { isNew: false }\n      )\n    )\n    .then(() => newNotebook);\n};\n\nexport const copyNote = async (\n  store: Store,\n  app: App,\n  targetNotebook: INotebook,\n  sourceNote: INote\n) => {\n  const { name, content, richContent, type } = sourceNote;\n\n  const newNote = createNote(targetNotebook.id, {\n    name: `Copy of ${name}`,\n    type,\n    content,\n    richContent,\n    owner: app.getUser().getEmail(),\n  });\n\n  return store\n    .logAndDispatch([NoteActions.addNote(newNote.id, newNote)])\n    .then(() =>\n      goToFile(\n        app,\n        { ...targetNotebook, type: FileType.notebook },\n        { isNew: false, note: newNote.id }\n      )\n    )\n    .then(() => newNote);\n};\n\nexport const deleteNotebook = async (\n  store: Store,\n  app: App,\n  notebook: INotebook\n) => {\n  const { id } = notebook;\n\n  store\n    .dispatchAndLog(TrashBinActions.moveNotebookToTrashBin(id))\n    .then(() => goUp(app, notebook));\n};\n\nexport const saveQueuedNotes = (store: Store) => {\n  const { notes } = store.getState('notebook.queue') as {\n    notes: Record<string, INote>;\n  };\n\n  store.dispatch(setSaving(true));\n\n  return (store.logAndDispatch(\n    Object.keys(notes).map((id) =>\n      NoteActions.updateContent(id, notes[id].content, notes[id].richContent)\n    )\n  ) as any).finally(() => store.dispatch(setSaving(false)));\n};\n\nexport const hasQueuedNotes = (store: Store) => {\n  return store.getState('notebook.queue.size') > 0;\n};\n\nexport const goToNotebook = (\n  app: App,\n  notebook: INotebook,\n  params?: { isNew?: boolean; note?: string },\n  options?: any\n) => {\n  return goToFile(\n    app,\n    { ...notebook, type: FileType.notebook },\n    params,\n    options\n  );\n};\n\nexport const goToExamples = (app: App) => {\n  app.go('notebook', {\n    id: 'examples',\n    note: 'simple',\n    isNew: false,\n  });\n};\n"
  },
  {
    "path": "quix-frontend/client/src/services/notifications.ts",
    "content": "import {isFunction} from 'lodash';\n\ninterface INotificationTemplate {\n  name: string;\n  icon: string;\n  title: string;\n  body: ((...args: any[]) => string) | string;\n  onlyWhenHidden: boolean;\n  onClick?(window: Window): void;\n}\n\n\nclass BrowserNotificationsManager {\n  private staticsBaseUrl: string;\n  private readonly Notification = typeof Notification === 'undefined' ? null : Notification;\n  private readonly templates: Record<string, INotificationTemplate> = {};\n\n  constructor() {\n    if (this.Notification && this.Notification.permission === 'default') {\n      this.Notification.requestPermission();\n    }\n  }\n\n  private fixUrl(url: string) {\n    return `${this.staticsBaseUrl}${url}`;\n  }\n\n  setStaticsBaseUrl(staticsBaseUrl: string) {\n    this.staticsBaseUrl = staticsBaseUrl;\n  }\n\n  register(template: INotificationTemplate) {\n    this.templates[template.name] = template;\n  }\n\n  notify(templateName: string, ...args: any[]) {\n    const template = this.templates[templateName];\n    if (!this.Notification || !template) {\n      return;\n    }\n\n    let body: string;\n    if (!template.onlyWhenHidden || window.document.hidden) {\n      if (isFunction(template.body)) {\n        body = template.body(...args);\n      } else {\n        body = template.body;\n      }\n      const notification = new this.Notification(template.title, {body, icon: this.fixUrl(template.icon)});\n      if (template.onClick) {\n        notification.onclick = template.onClick.bind(notification, window);\n      }\n    }\n  }\n\n}\n\nexport const browserNotificationsManager = new BrowserNotificationsManager();\n"
  },
  {
    "path": "quix-frontend/client/src/services/permissions.ts",
    "content": "import {App} from '../lib/app';\nimport {IEntity, IFile} from '@wix/quix-shared';\nimport {isRoot} from './files';\n\nexport interface IPermissions {\n  edit?: boolean;\n  delete?: boolean;\n  rename?: boolean;\n  clone?: boolean;\n  like?: boolean;\n  share?: boolean;\n  bulk?: IPermissions;\n}\n\nexport interface IFolderPermissions extends IPermissions{\n  addFolder?: boolean;\n  addNotebook?: boolean;\n}\n\nexport interface INotebookPermissions extends IPermissions{\n  addNote?: boolean;\n  note?: IPermissions & {\n    reorder?: boolean;\n  };\n  bulk?: INotebookPermissions & {\n    reorder?: boolean;\n  };\n}\n\nexport const isOwner = (app: App, entity: Pick<IEntity, 'owner'>) => {\n  return entity.owner === app.getUser().getEmail();\n}\n\nexport const getDefaultPermissions = (): IPermissions => {\n  return {\n    edit: false,\n    delete: false,\n    rename: false,\n    clone: false,\n    like: false,\n    bulk: null\n  };\n}\n\nexport const getFolderPermissions = (app: App, folder: IFile): IFolderPermissions => {\n  const isFolderOwner = isOwner(app, folder);\n  const isRootFolder = isRoot(folder);\n\n  return {\n    edit: isFolderOwner,\n    delete: isFolderOwner && !isRootFolder,\n    rename: isFolderOwner && !isRootFolder,\n    clone: false,\n    like: false,\n    share: true,\n    addFolder: isFolderOwner && folder.path.length < 2,\n    addNotebook: isFolderOwner,\n    bulk: {\n      delete: isFolderOwner,\n      rename: false,\n      clone: false,\n      like: false,\n    }\n  };\n}\n\nexport const getNotebookPermissions = (app: App, folder: IFile): INotebookPermissions => {\n  const isFolderOwner = isOwner(app, folder);\n\n  return {\n    edit: isFolderOwner,\n    delete: isFolderOwner,\n    rename: isFolderOwner,\n    addNote: isFolderOwner,\n    clone: true,\n    like: true,\n    share: true,\n    note: {\n      edit: isFolderOwner,\n      delete: isFolderOwner,\n      rename: isFolderOwner,\n      reorder: isFolderOwner,\n      clone: true,\n      like: false,\n      share: true,\n    },\n    bulk: {\n      delete: isFolderOwner,\n      reorder: isFolderOwner,\n      clone: false,\n      like: false,\n    },\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/services/plugins/index.ts",
    "content": "export * from './plugin-manager';\nexport * from './plugin-types';"
  },
  {
    "path": "quix-frontend/client/src/services/plugins/plugin-manager.ts",
    "content": "import {App} from '../../lib/app';\nimport {TModuleComponentType, ModuleEngineType} from '@wix/quix-shared';\nimport {Plugin, TPluginMap, resolvePluginType} from './plugin-types';\nimport { Store } from '../../lib/store';\n\nexport class PluginManager<H> {\n  private readonly pool: Plugin[] = [];\n\n  constructor(private readonly pluginFactory: any, public readonly hooks: H) {}\n\n  private getPluginById<T extends TModuleComponentType>(\n    id: string,\n    type: T,\n  ): TPluginMap[T] {\n    const PluginClass = resolvePluginType(type);\n\n    return this.pool.find(\n      p => p.getId() === id && p instanceof PluginClass,\n    ) as any;\n  }\n\n  private getPluginsByType<T extends TModuleComponentType>(\n    type: T,\n  ): TPluginMap[T][] {\n    const PluginClass = resolvePluginType(type);\n\n    return this.pool.filter(p => p instanceof PluginClass) as any;\n  }\n\n  module<T extends TModuleComponentType>(type: T) {\n    return {\n      plugin: (id: string, engine?: ModuleEngineType, app?: App, store?: Store) => {\n        if (engine) {\n          const plugin = this.pluginFactory[type](app, store, id, engine, this.hooks);\n\n          if (plugin) {\n            this.pool.push(plugin);\n          }\n        }\n\n        return (\n          this.getPluginById(id, type) || this.getPluginById('default', type)\n        );\n      },\n\n      plugins: () => {\n        return this.getPluginsByType(type);\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/services/plugins/plugin-types.ts",
    "content": "import {IFile, TModuleComponentType, ModuleEngineType, INote} from '@wix/quix-shared';\nimport { Time } from '../../config';\nimport {App} from '../../lib/app';\nimport formatter from '../../lib/sql-formatter/sqlFormatter';\n\ninterface CustomAction {\n  icon: string;\n  title: string;\n  permissions: string;\n  handler(note: INote): INote;\n}\n\nexport const resolvePluginType = (type: TModuleComponentType) => {\n  if (PluginMap[type]) {\n    return PluginMap[type];\n  }\n\n  throw new Error(`\"${type}\" doesn't mach any known plugin type`);\n};\n\nexport class Plugin {\n  constructor(\n    app: App,\n    protected readonly id: string,\n    protected readonly engine: ModuleEngineType,\n    hooks: any,\n  ) {}\n\n  public getId() {\n    return this.id;\n  }\n\n  public getEngine() {\n    return this.engine;\n  }\n}\n\nexport class NotePlugin extends Plugin {\n  constructor(\n    app: App,\n    id: string,\n    engine: ModuleEngineType,\n    hooks: any,\n    private readonly config: {\n      syntaxValidation: boolean;\n      canCreate: boolean;\n      dateFormat?: string;\n      enableQueryFormatter?: boolean;\n    },\n  ) {\n    super(app, id, engine, hooks);\n\n    this.config.dateFormat = this.config.dateFormat || Time.Format;\n  }\n\n  getConfig() {\n    return this.config;\n  }\n\n  formatStats(stats: {[key: string]: any}) {\n    return [];\n  }\n\n  renderRunner() {\n    return `\n      <bi-sql-runner\n        class=\"bi-c-h bi-grow bi-fade-in\"\n        ng-model=\"textContent\"\n        ng-change=\"events.onContentChange(textContent)\"\n        bsr-options=\"::{\n          fitContent: true,\n          params: true,\n          focus: options.focusEditor,\n          showEditor: options.showEditor,\n          showSyntaxErrors: vm.showSyntaxErrors,\n          shareParams: options.shareParams,\n          autoRun: options.autoRun,\n          dateFormat: vm.dateFormat\n        }\"\n        type=\"vm.type\"\n        runner=\"runner\"\n        download-file-name=\"actions.getDownloadFileName(query)\"\n        table-formatter=\"tableFormatter()\"\n        on-save=\"events.onSave()\"\n        on-run=\"events.onRun()\"\n        on-editor-load=\"events.onEditorInstanceLoad(instance)\"\n        on-runner-load=\"events.onRunnerInstanceLoad(instance)\"\n        on-runner-created=\"events.onRunnerCreated(runner)\"\n        on-runner-destroyed=\"events.onRunnerDestroyed(runner)\"\n        on-params-share=\"events.onParamsShare(params)\"\n        readonly=\"readonly\"\n        autocomplete-db-fetchers=\"autocompleteDbFetchers\"\n      >\n        <controls>\n          <quix-npc></quix-npc>\n        </controls>\n\n        <stats class=\"bi-align bi-s-h--x15\" bi-html=\"actions.renderStats()\"></stats>\n      </bi-sql-runner>\n    `;\n  }\n\n  getCustomActions(): CustomAction[] {\n    const res: CustomAction[] = [];\n\n    if (this.config.enableQueryFormatter) {\n      res.push({\n        icon: 'format_paint',\n        title: 'Format query',\n        permissions: 'edit',\n        handler: (note: INote) => {\n          note.content = formatter.format(note.content, {upperCase: true, language: 'quixsql'});\n  \n          return note;\n        }\n      })\n    }\n\n    return res;\n  }\n}\n\nexport class DbPlugin extends Plugin {\n  constructor(app: App, id: string, engine: ModuleEngineType, hooks: any) {\n    super(app, id, engine, hooks);\n  }\n\n  getSampleQuery(table: IFile): string {\n    throw new Error(`No default implementation`);\n  }\n}\n\nexport const PluginMap = {\n  note: NotePlugin,\n  db: DbPlugin,\n};\n\nexport type TPluginMap = {\n  [K in keyof typeof PluginMap]: InstanceType<typeof PluginMap[K]>;\n};\n"
  },
  {
    "path": "quix-frontend/client/src/services/popup.ts",
    "content": "import {assign} from 'lodash';\nimport {inject} from '../lib/core';\nimport {singletone} from '../utils';\n\nconst popup = singletone();\n\nexport const closePopup = () => popup((scope, element) => {\n  element.remove();\n  scope.$destroy();\n\n  return null;\n});\n\nconst openPopup = (html: string, scope, locals: Record<any, any> = {}) => {\n  if (popup()) {\n    return () => {};\n  }\n\n  const popupScope: any = assign(scope.$new(true), locals, {\n    events: {\n      onLoad(instance) {\n        inject('$timeout')(() => instance.toggle());\n      },\n      onToggle(maximized: boolean) {\n        if (!maximized) {\n          closePopup();\n        }\n      }\n    }\n  });\n\n  const element = inject('$compile')(`\n    <div \n      class=\"quix-popup bi-c-h bi-theme--lighter\"\n      bi-maximizable=\"true\"\n      bm-options=\"::{offIcon: 'close'}\"\n      on-load=\"events.onLoad(instance)\"\n      on-toggle=\"events.onToggle(maximized)\"\n    >${html}</div>\n  `)(popupScope).appendTo(document.body);\n\n  closePopup()(popupScope, element);\n\n  return closePopup;\n}\n\nexport const openSearchResults = (scope) => {\n  const closeFn = openPopup(`\n    <quix-search-results class=\"bi-c-h bi-grow\"></quix-search-results>\n  `, scope);\n\n  popup((_, element) => element.addClass('quix-search-popup'));\n\n  return closeFn;\n}\n\nexport const openTempQuery = (scope, type?: string, code: string = '', autorun = false) => {\n  return openPopup(`\n    <quix-temp-query\n      class=\"bi-c-h bi-grow\"\n      type=\"type\"\n      text-content=\"code\"\n      autorun=\"autorun\"\n    ></quix-temp-query>`, \n    scope, {\n      type,\n      code,\n      autorun\n    }\n  );\n}"
  },
  {
    "path": "quix-frontend/client/src/services/resources.ts",
    "content": "import { mapValues } from 'lodash';\nimport { inject, Config } from '../lib/core';\nimport {\n  IFile,\n  IFolder,\n  INotebook,\n  SearchResult,\n  IUser,\n  IHistory,\n  IDeletedNotebook,\n} from '@wix/quix-shared';\n\nexport const config = new Config<{\n  apiBasePath: string;\n}>();\n\nconst api = (endpoint: TemplateStringsArray) =>\n  `${config.get().apiBasePath}/api/` + endpoint[0];\n\nconst resource = (\n  action: 'get' | 'query',\n  endpoint: string,\n  params: Record<string, any>\n) =>\n  inject('$resource')(\n    endpoint,\n    mapValues(params, (v, k) => `@${k}`)\n  )[action](params).$promise;\n\nconst one = <T>(\n  endpoint: string,\n  params: Record<string, any> = {}\n): Promise<T> => resource('get', endpoint, params);\nconst many = <T>(\n  endpoint: string,\n  params: Record<string, any> = {}\n): Promise<T[]> => resource('query', endpoint, params);\n\nexport const users = () => many<IUser>(api`users`);\nexport const history = (options) =>\n  many<IHistory>(api`history`, {\n    offset: options.offset,\n    limit: options.limit,\n    user: options.user,\n    query: options.query,\n  });\nexport const files = () => many<IFile>(api`files`);\nexport const folder = (id: string) => one<IFolder>(api`files/:id`, { id });\nexport const notebook = (id: string) =>\n  one<INotebook>(api`notebook/:id`, { id });\nexport const favorites = () => many<IFile>(api`favorites`);\nexport const search = (text: string, offset: number, total: number) =>\n  one<SearchResult>(api`search/:text`, {\n    text,\n    offset,\n    total,\n  });\n\nexport const deletedNotebooks = () =>\n  many<IDeletedNotebook>(api`deletedNotebooks`);\n\n\nexport const db = (type: string) => many(api`db/:type/explore`, { type });\nexport const dbColumns = (\n  type: string,\n  catalog: string,\n  schema: string,\n  table: string\n) =>\n  one(api`db/:type/explore/:catalog/:schema/:table`, {\n    type,\n    catalog,\n    schema,\n    table,\n  });\n\nexport const dbSearch = (type: string, q: string) =>\n  many(api`db/:type/search`, { type, q });\n"
  },
  {
    "path": "quix-frontend/client/src/services/runners.ts",
    "content": "import {fromPairs} from 'lodash';\nimport {App} from '../lib/app';\nimport {Store} from '../lib/store';\nimport {Runner} from '../lib/runner';\nimport {browserNotificationsManager} from '../services/notifications';\nimport {INotebook, INote} from '@wix/quix-shared';\nimport {hooks} from '../hooks';\n\nconst runners = new Map();\n\nconst computeFinishState = (runner: Runner) => {\n  const status = runner.getState().getStatus();\n\n  if (status.error) {\n    return 'error';\n  } if (status.killed) {\n    return 'killed';\n  }\n\n  return 'finished';\n}\n\nexport const addRunner = (app: App, store: Store, id: string, runner: Runner, note: INote, notebook: INotebook) => {\n  hooks.note.runStart.call(app, store, note, runner);\n  runner.on('finish', (r: Runner) => {\n    const status = computeFinishState(r);\n\n    if (status === 'finished') {\n      browserNotificationsManager.notify('runnerFinished', note, notebook);\n    } else {\n      browserNotificationsManager.notify('runnerError', note, notebook);\n    }\n\n    hooks.note.runFinish.call(app, store, note, runner);\n  });\n\n  runners.set(id, runner);\n}\n\nexport const removeRunner = (id: string) => {\n  runners.delete(id);\n}\n\nexport const getRunner = (id: string) => {\n  return runners.get(id);\n}\n\nexport const getRunners = () => fromPairs([...runners.entries()]);\n"
  },
  {
    "path": "quix-frontend/client/src/services/scope.ts",
    "content": "import {mapValues} from 'lodash';\nimport {Store} from '../lib/store';\n\nexport function initEvents(scope, conf, app, store: Store, events) {\n  conf.withEvents(mapValues(events, event => (event as any)(scope, store, app)));\n\n  scope.$on('$destroy', () => scope.events.$onDestroy && scope.events.$onDestroy())\n}\n"
  },
  {
    "path": "quix-frontend/client/src/services/search.ts",
    "content": "import {findIndex} from 'lodash';\n\nexport const extractTextAroundMatch = (text: string, match: string, numOfWrappingLines = 2) => {\n  match = match.toLowerCase();\n\n  const lines = text.split('\\n');\n  const index = findIndex(lines, line => line.toLowerCase().indexOf(match) !== -1);\n\n  return lines\n    .slice(Math.max(0, index - numOfWrappingLines), Math.min(lines.length, index + 1 + numOfWrappingLines))\n    .join('\\n');\n}\n"
  },
  {
    "path": "quix-frontend/client/src/services/state.ts",
    "content": "import {assign} from 'lodash';\n\nconst keys = e => Object.keys(e).filter(k => typeof e[k as any] === 'number');\nconst values = e => keys(e).map(k => e[k as any]);\n\nclass State {\n  constructor(public index: number = -1) {}\n}\n\nexport class StateManager<E> {\n  private current: State;\n  private readonly val = {};\n\n  constructor(private readonly states: E) {\n    this.current = new State(values(states)[0]);\n  }\n\n  is(state: keyof E) {\n    return this.states[state] === this.current.index as any;\n  }\n\n  before(state: keyof E) {\n    return this.current.index as any < this.states[state] as any;\n  }\n\n  after(state: keyof E) {\n    return this.current.index as any > this.states[state] as any;\n  }\n\n  get() {\n    return this.states[this.current.index];\n  }\n\n  set(state: keyof E, condition: boolean | Function = true, value: Record<string, any> | Function = null) {\n    if (this.after(state) || (typeof condition === 'function' ? !condition(this.val) : !condition)) {\n      return new NullStateManager();\n    }\n\n    this.current = new State(this.states[state] as any);\n    this.value(value);\n\n    return this;\n  }\n  \n  force(state: keyof E, condition: boolean | Function = true, value: Record<string, any> | Function = null) {\n    if ((typeof condition === 'function' ? !condition(this.val) : !condition)) {\n      return new NullStateManager();\n    }\n\n    this.current = new State(this.states[state] as any);\n    this.value(value);\n\n    return this;\n  }\n\n  value(val?: Record<string, any> | Function) {\n    if (typeof val === 'undefined') {\n      return this.val;\n    }\n\n    assign(this.val, typeof val === 'function' ? val(this.val) : val);\n\n    return this;\n  }\n\n  then(fn: Function) {\n    fn(this);\n    return this;\n  }\n\n  else(fn: Function) {\n    return this;\n  }\n}\n\nclass NullStateManager {\n  is() {\n    return this;\n  }\n  before() {\n    return this;\n  }\n  after() {\n    return this;\n  }\n  set() {\n    return this;\n  }\n  value() {\n    return null;\n  }\n  then() {\n    return this;\n  }\n  else(fn: Function) {\n    fn();\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/services/subscription.ts",
    "content": "import {ClientConfigHelper} from '@wix/quix-shared';\nimport {Store, sessionId} from '../lib/store';\nimport {App} from '../lib/app';\n\nexport const subscribeToStateChanges = (app: App<ClientConfigHelper>, store: Store) => {\n  const ws = new WebSocket(`${location.protocol.replace('http', 'ws')}//${location.host}${app.getConfig().getClientTopology().apiBasePath}/subscription`);\n\n  ws.onopen = () => {\n    ws.onmessage = (message: MessageEvent) => {\n      store.dispatch(JSON.parse(message.data).data);\n    };\n\n    ws.send(JSON.stringify({ event: 'subscribe', data: {sessionId} }));\n  };\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/base/base.html",
    "content": "<div ui-view class=\"quix-content bi-c-h bi-grow bi-theme--light\" bi-state-loader></div>\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/base/base.ts",
    "content": "import template from './base.html';\n\nimport {ClientConfigHelper} from '@wix/quix-shared';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IStateComponentConfig} from '../../lib/app/services/plugin-builder';\nimport {setUrlSearchText, setSearchPage} from '../../store/app/app-actions';\nimport {openSearchResults, closePopup, hasQueuedNotes, subscribeToStateChanges} from '../../services';\n\nexport default (app: App<ClientConfigHelper>, store: Store) => ({\n  name: '',\n  abstract: true,\n  template,\n  url: {\n    urlSearchText: setUrlSearchText,\n    searchPage: page => setSearchPage(page && parseInt(page, 10))\n  },\n  scope: {},\n  controller: (scope, params, {syncUrl}) => {\n    syncUrl();\n    subscribeToStateChanges(app, store);\n\n    store.subscribe('app.inputSearchText', text => text ? openSearchResults(scope) : closePopup(), scope);\n\n    window.onbeforeunload = () => hasQueuedNotes(store) || undefined;\n  },\n  link: (scope) => {\n\n  }\n}) as IStateComponentConfig;\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/embed.ts",
    "content": "import {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IStateComponentConfig} from '../../lib/app/services/plugin-builder';\n\nexport default (app: App, store: Store) => ({\n  name: 'embed',\n  abstract: true,\n  template: '<div ui-view class=\"bi-c-h bi-grow\"></div>',\n  url: {},\n  scope: {},\n  controller: (scope, params, {syncUrl}) => {\n  },\n  link: (scope) => {\n\n  },\n  onEnter() {\n    app.toggleHeader(false);\n    app.toggleMenu(false);\n  }\n}) as IStateComponentConfig;\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note-events.ts",
    "content": "import { takeWhile } from 'lodash';\nimport { utils } from '../../../lib/core';\nimport { Store } from '../../../lib/store';\nimport { toast } from '../../../lib/ui';\nimport { App } from '../../../lib/app';\nimport {\n  INote,\n  NotebookActions,\n  IFile,\n  NoteActions,\n  INotebook,\n  IFilePathItem,\n} from '@wix/quix-shared';\nimport { FileType } from '@wix/quix-shared/dist/entities/file';\nimport { IScope } from './embed-note-types';\nimport {\n  setNotebook,\n  setNote,\n  queueNote,\n  toggleMark,\n  unmarkAll,\n} from '../../../store/notebook/notebook-actions';\nimport {\n  saveQueuedNotes,\n  deleteNotebook,\n  copyNotebook,\n  goToFile,\n  goToRoot,\n  prompt,\n  copyNote,\n} from '../../../services';\nimport { removeRunner, addRunner } from '../../../store/app/app-actions';\nimport { addNote } from '../../../services/notebook';\n\nexport const onBreadcrumbClick = (scope: IScope, store: Store, app: App) => (\n  file: IFilePathItem\n) => {\n  const {\n    notebook: { owner, path },\n  } = scope.vm.state.value();\n\n  goToFile(app, {\n    ...file,\n    owner,\n    type: FileType.folder,\n    path: takeWhile(path, (item) => item.id !== file.id),\n  });\n};\n\nexport const onGoToRootClick = (\n  scope: IScope,\n  store: Store,\n  app: App\n) => () => {\n  goToRoot(app);\n};\n\nexport const onNameChange = (scope: IScope, store: Store, app: App) => (\n  file: IFile\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  const { id, name } = file;\n\n  store.dispatchAndLog(NotebookActions.updateName(id, name));\n};\n\nexport const onDelete = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  deleteNotebook(store, app, notebook).then(() =>\n    toast.showToast(\n      {\n        text: `Deleted notebook \"${notebook.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onClone = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  prompt(\n    {\n      title: 'Clone notebook',\n      subTitle: 'Choose destination folder',\n      yes: 'clone',\n      content: `<quix-destination-picker ng-model=\"model.folder\" context=\"folder\" required></quix-destination-picker>`,\n      onConfirm: ({ model: { folder } }) =>\n        copyNotebook(store, app, folder, {\n          ...notebook,\n          notes: scope.vm.state.value().notes,\n        }),\n    },\n    scope,\n    { model: { folder: null } }\n  ).then((res) =>\n    toast.showToast(\n      {\n        text: `Cloned notebook as \"${res.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onShare = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  utils.copyToClipboard(app.getNavigator().getUrl(null, { id: notebook.id }));\n\n  toast.showToast(\n    {\n      text: 'Copied notebook url to clipboard',\n      type: 'success',\n    },\n    3000\n  );\n};\n\nexport const onLikeToggle = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  const { id, isLiked } = notebook;\n\n  store\n    .dispatchAndLog(NotebookActions.toggleIsLiked(id, !isLiked))\n    .then((action) =>\n      toast.showToast(\n        {\n          text: action.isLiked\n            ? 'Added notebook to favorites'\n            : 'Removed notebook from favorites',\n          type: 'success',\n        },\n        3000\n      )\n    );\n};\n\nexport const onSave = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onRun = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onNoteSave = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onNoteRun = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onNoteAdd = (scope: IScope, store: Store, app: App) => (\n  type: any = scope.vm.noteTypes[0]\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  const { notebook } = scope.vm.state.value();\n\n  addNote(store, notebook.id, type, {}, (note) => {\n    scope.vm.notes.get(note).focusName = true;\n    store.dispatch(setNote(note));\n  });\n};\n\nexport const onNoteClone = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  prompt(\n    {\n      title: 'Clone note',\n      subTitle: 'Choose destination notebook',\n      yes: 'clone',\n      content: `<quix-destination-picker ng-model=\"model.notebook\" context=\"notebook\" required></quix-destination-picker>`,\n      onConfirm: ({ model: { notebook } }) =>\n        copyNote(store, app, notebook, note),\n    },\n    scope,\n    { model: { notebook: null } }\n  ).then((res) =>\n    toast.showToast(\n      {\n        text: `Cloned note as \"${res.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onNoteShare = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  const { notebook } = scope.vm.state.value();\n\n  utils.copyToClipboard(\n    app.getNavigator().getUrl(null, { id: notebook.id, note: note.id })\n  );\n\n  toast.showToast(\n    {\n      text: 'Copied note url to clipboard',\n      type: 'success',\n    },\n    3000\n  );\n};\n\nexport const onNoteDelete = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatchAndLog(NoteActions.deleteNote(note.id)).then(() =>\n    toast.showToast(\n      {\n        text: `Deleted note \"${note.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onNoteContentChange = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatch(queueNote(note));\n};\n\nexport const onNoteNameChange = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatchAndLog(NoteActions.updateName(note.id, note.name));\n};\n\nexport const onNoteReorder = (scope: IScope, store: Store, app: App) => (\n  e: any,\n  { item }: any\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  const { model: note, dropindex: index } = item.sortable;\n\n  if (typeof index !== 'undefined') {\n    store.dispatchAndLog(NoteActions.reorderNote(note.id, index));\n  }\n};\n\nexport const onMarkToggle = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatch(toggleMark(note));\n};\n\nexport const onMarkedNotesDelete = (scope: IScope, store: Store, app: App) => (\n  notes: INote[]\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store\n    .dispatchAndLog(notes.map((note) => NoteActions.deleteNote(note.id)))\n    .then(() =>\n      toast.showToast(\n        {\n          text: `Deleted ${notes.length} notes`,\n          type: 'success',\n        },\n        3000\n      )\n    );\n};\n\nexport const onUnmarkAll = (scope: IScope, store: Store, app: App) => () => {\n  store.dispatch(unmarkAll());\n};\n\nexport const onRunnerCreated = (scope: IScope, store: Store) => (\n  note,\n  runner\n) => {\n  store.dispatch(\n    addRunner(note.id, runner, note, scope.vm.state.value().notebook)\n  );\n};\n\nexport const onRunnerDestroyed = (scope: IScope, store: Store) => (note) => {\n  store.dispatch(removeRunner(note.id));\n};\n\nexport const $onDestroy = (scope: IScope, store: Store, app: App) => () => {\n  if (scope.permissions.edit) {\n    saveQueuedNotes(store);\n  }\n\n  store.dispatch(setNotebook(null));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note-reactions.ts",
    "content": "import {INote} from '@wix/quix-shared';\n\nexport function setError(scope: ng.IScope, error: any) {\n  scope.vm.state.force('Error', !!error, {error});\n}\n\nexport function setNote(scope: ng.IScope, note: INote) {\n  scope.vm.state.set('Content', !!note, {note});\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note-scope.ts",
    "content": "import * as Reactions from './embed-note-reactions';\n\nexport const error = (scope, value) => Reactions.setError(scope, value);\nexport const permissions = x => x;\n\nexport const view = {\n  note: (scope, value) => Reactions.setNote(scope, value),\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note-url.ts",
    "content": "import {find} from 'lodash';\nimport {INote} from '@wix/quix-shared';\nimport {setNote} from '../../../store/notebook/notebook-actions';\n\nexport const note = (id: string, notes: INote[]) => setNote(id && find(notes, {id}));"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note-vm.ts",
    "content": "import {StateManager} from '../../../services/state';\nimport {App} from '../../../lib/app';\n\nenum States {\n  Initial,\n  Error,\n  Content\n}\n\nexport default (app: App) => ({\n  $init() {\n    this.state = new StateManager(States);\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note.html",
    "content": "<div class=\"bi-c-h bi-center bi-grow\" ng-if=\"vm.state.before('Content')\">\n  <div class=\"bi-center bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Initial')\">\n    <div class=\"bi-empty-state-content\">Loading note...</div>\n  </div>\n\n  <div class=\"bi-center bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Error')\" data-hook=\"note-error\">\n    <quix-image class=\"bi-empty-state-image\" name=\"error_{{::vm.state.value().error.status}}.svg\"></quix-image>\n    <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n  </div>\n</div>\n\n<quix-note\n  class=\"bi-fade-in\"\n  ng-if=\"vm.state.is('Content')\"\n  note=\"::vm.state.value().note\"\n  quix-note-options=\"{\n    fold: false,\n    autoRun: true,\n    maximizable: false,\n    shareParams: false,\n    showEditor: false,\n    showDates: false,\n  }\"\n></quix-note>"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note.scss",
    "content": "@import '../../../lib/ui/assets/css/def/colors.def';\n\nquix-notebook {\n  .quix-note-container {\n    position: relative;\n\n    &.quix-note-container--editable {\n      padding-left: 8px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/embed/note/embed-note.ts",
    "content": "import template from './embed-note.html';\nimport './embed-note.scss';\n\nimport {initNgScope} from '../../../lib/core';\nimport {Store} from '../../../lib/store';\nimport {App} from '../../../lib/app';\nimport {IStateComponentConfig} from '../../../lib/app/services/plugin-builder';\nimport {cache} from '../../../store';\nimport VM from './embed-note-vm';\nimport * as Url from './embed-note-url';\nimport * as Scope from './embed-note-scope';\n\nexport default (app: App, store: Store) => ({\n  name: 'embed.notebook:id',\n  template,\n  url: Url,\n  scope: Scope,\n  controller: async (scope: ng.IScope, params, {syncUrl}) => {\n    await cache.notebook.fetch(params.id);\n    \n    syncUrl(() => [store.getState('notebook.notes') || []]);\n\n    store.subscribe('notebook', ({error, permissions, view}) => {\n      scope.error = error;\n      scope.permissions = permissions;\n      scope.view = view;\n    }, scope);\n  },\n  link: scope => {\n    initNgScope(scope).withVM(VM(app));\n  }\n}) as IStateComponentConfig;\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/favorites/FavoritesComponent.tsx",
    "content": "import React, {useEffect} from 'react';\nimport {IFile} from '@wix/quix-shared';\nimport {cloneDeep} from 'lodash';\nimport {favoritesTableFields} from './favorites-table-fields';\nimport {useViewState} from '../../services/hooks';\nimport {Table} from '../../lib/ui/components/table/Table';\nimport {EmptyState, ErrorState, InitialState} from '../../lib/ui/components/states';\n\nexport interface FavoritesProps {\n  favorites: IFile[];\n  error: {message: string};\n  onFavoriteClick(favorite: IFile): void;\n  onLikeToggle(favorite: IFile): void;\n  emptyStateImgSrc: string;\n}\n\nconst States = [\n  'Initial',\n  'Error',\n  'Empty',\n  'Content',\n];\n\nexport function Favorites(props: FavoritesProps) {\n  const {favorites: serverFavorites, error, onFavoriteClick, onLikeToggle: onLikeToggleServer} = props;\n\n  const [stateData, viewState] = useViewState(States, {\n    favorites: [],\n    emailFilter: '',\n    errorMessage: '',\n  });\n\n  useEffect(() => {\n    if (!error && serverFavorites?.length >= 0) {\n      viewState.set(serverFavorites?.length ? 'Content' : 'Empty', {favorites: serverFavorites || []});\n    }\n  },[serverFavorites]);\n\n  useEffect(() => {\n    if (error) {\n      viewState.set('Error', {errorMessage: error.message});\n    }\n  }, [error]);\n\n  const onLikeToggle = (file: IFile) => {\n    const tempFavorites = cloneDeep(stateData.favorites);\n    const currentFile = tempFavorites.find(favorite => favorite.id === file.id);\n    currentFile.isLiked = !currentFile.isLiked;\n    onLikeToggleServer(file);\n    viewState.set('Content', {favorites: tempFavorites});\n  }\n\n  const renderContentState = () => (\n    <Table\n      hookName=\"favorites\"\n      columns={favoritesTableFields(onLikeToggle).map(field => ({\n        header: field.title || field.name,\n        render: row => field.filter(undefined, row),\n        accessor: field.name,\n        className: field.className,\n      }))}\n      data={stateData.favorites}\n      onRowClicked={row => onFavoriteClick(row)}\n    />\n  );\n\n  return (\n    <div className=\"bi-section bi-c-h bi-grow\">\n      <div className=\"bi-section-header\">\n        <div className=\"bi-section-title\">\n          <span>Favorites {viewState.min('Empty') && <span className='bi-fade-in'>({stateData.favorites.length})</span>}</span>\n        </div>\n      </div>\n\n      <div className=\"bi-section-content bi-c-h bi-s-v--x15\">\n        {\n          (() => {\n            switch(viewState.get()) {\n              case 'Initial':\n                return <InitialState entityName=\"favorites\" />;\n              case 'Error':\n                return <ErrorState errorMessage={error.message} />;\n              case 'Empty':\n                return <EmptyState />;\n              case 'Content':\n                return renderContentState();\n              default:\n            }\n          })()\n        }\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/favorites/favorites-events.ts",
    "content": "import {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IFile, NotebookActions} from '@wix/quix-shared';\nimport {goToFile} from '../../services';\nimport {toast} from '../../lib/ui';\n\nexport const onFavoriteClick = (app: App) => (favorite: IFile) => {\n  goToFile(app, favorite);\n};\n\nexport const onLikeToggle = (store: Store) => (file: IFile) => {\n  const {id, isLiked} = file;\n\n  store\n    .dispatchAndLog(NotebookActions.toggleIsLiked(id, !isLiked))\n    .then(action =>\n      toast.showToast(\n        {\n          text: action.isLiked\n            ? 'Added notebook to favorites'\n            : 'Removed notebook from favorites',\n          type: 'success'\n        },\n        3000\n      )\n    );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/favorites/favorites-table-fields.tsx",
    "content": "import * as React from 'react';\nimport {IFile} from '@wix/quix-shared';\nimport {RowConfig} from '../../lib/ui/components/table/TableRow';\nimport classNames from 'classnames';\nimport { UserAvatarAndName } from '../../components/User/UserAvatarAndName';\n\nexport const favoritesTableFields = (onLikeToggle): RowConfig<IFile>[] => [\n  {\n    name: 'name',\n    title: 'Name',\n    filter(_, file: IFile) {\n      return (\n        <div className=\"bi-align bi-s-h\">\n          <i className=\"bi-icon bi-muted\">insert_drive_file</i>\n          <span>{file.name}</span>\n        </div>\n      );\n    }\n  },\n  {\n    name: 'ownerDetails',\n    title: 'User',\n    filter(_, file: IFile) {\n      return <UserAvatarAndName user={file.ownerDetails}></UserAvatarAndName>;\n    }\n  },\n  {\n    name: 'isLiked',\n    title: ' ',\n    filter(_, file: IFile) {\n      return (\n        <div className=\"bi-justify-right\">\n          <i\n            className={classNames(\n              {'bi-danger': file.isLiked},\n              'bi-action',\n              'bi-icon--sm'\n            )}\n            onClick={e => {\n              e.stopPropagation();\n              onLikeToggle(file);\n            }}\n          >\n            {file.isLiked ? 'favorite' : 'favorite_border'}\n          </i>\n        </div>\n      );\n    }\n  }\n];\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/favorites/favorites-testkit.ts",
    "content": "import { TableTestkit } from '../../lib/ui/components/table/table-testkit';\n\nconst enum Hooks {\n  Table = 'favorites-table'\n}\n\nexport class FavoritesTestkit extends TableTestkit {\n\n  favoritesTableExists = async () => {\n    return (await this.query.hook(Hooks.Table)) !== null;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/favorites/favorites.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n\nquix-favorites {\n\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/favorites/favorites.ts",
    "content": "import './favorites.scss';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IReactStateComponentConfig} from '../../lib/app/services/plugin-builder';\n\nimport {cache} from '../../store';\nimport {Favorites, FavoritesProps} from './FavoritesComponent';\nimport {onFavoriteClick, onLikeToggle} from './favorites-events';\nimport _noop from 'lodash/noop';\n\nexport default (app: App, store: Store): IReactStateComponentConfig => ({\n  name: 'favorites',\n  template: Favorites,\n  url: {},\n  scope: {\n    favorites: _noop,\n    error: _noop,\n    onFavoriteClick: _noop,\n    onLikeToggle: _noop\n  },\n  controller: async (scope: FavoritesProps, params, {syncUrl, setTitle}) => {\n    await cache.favorites.fetch(params.id);\n\n    syncUrl();\n    setTitle();\n\n    store.subscribe(\n      'favorites',\n      ({favorites, error}) => {\n        scope.favorites = favorites;\n        scope.error = error;\n      },\n      scope\n    );\n\n    scope.onFavoriteClick = onFavoriteClick(app);\n    scope.onLikeToggle = onLikeToggle(store);\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-events.ts",
    "content": "import { takeWhile } from 'lodash';\nimport { Store } from '../../lib/store';\nimport { utils } from '../../lib/core';\nimport { toast } from '../../lib/ui';\nimport { App } from '../../lib/app';\nimport { IScope } from './files-types';\nimport {\n  IFile,\n  FileActions,\n  NotebookActions,\n  FileType,\n  IFilePathItem,\n  TrashBinActions,\n} from '@wix/quix-shared';\nimport { addNotebook, goToNotebook } from '../../services/notebook';\nimport {\n  addFolder,\n  deleteFolder,\n  goToFile,\n  goToRoot,\n} from '../../services/files';\nimport {\n  setFolder,\n  toggleMark,\n  unmarkAll,\n} from '../../store/folder/folder-actions';\n\nexport const onNameChange = (scope: IScope, store: Store, app: App) => (\n  folder: IFile\n) => {\n  const { id, name } = folder;\n\n  store.dispatchAndLog(FileActions.updateName(id, name));\n};\n\nexport const onChildNameChange = (scope: IScope, store: Store, app: App) => (\n  file: IFile\n) => {\n  onNameChange(scope, store, app)(file);\n};\n\nexport const onDelete = (scope: IScope, store: Store, app: App) => (\n  folder: IFile\n) => {\n  deleteFolder(store, app, folder).then(() =>\n    toast.showToast(\n      {\n        text: `Deleted folder \"${folder.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onShare = (scope: IScope, store: Store, app: App) => (\n  folder: IFile\n) => {\n  const { id } = folder;\n\n  utils.copyToClipboard(app.getNavigator().getUrl(null, { id }));\n\n  toast.showToast(\n    {\n      text: 'Copied folder url to clipboard',\n      type: 'success',\n    },\n    3000\n  );\n};\n\nexport const onLikeToggle = (scope: IScope, store: Store, app: App) => (\n  file: IFile\n) => {\n  const { id, isLiked } = file;\n\n  store.dispatchAndLog(\n    file.type === FileType.folder\n      ? FileActions.toggleIsLiked(id, !isLiked)\n      : NotebookActions.toggleIsLiked(id, !isLiked)\n  );\n};\n\nexport const onBreadcrumbClick = (scope: IScope, store: Store, app: App) => (\n  file: IFilePathItem\n) => {\n  const {\n    folder: { owner, path },\n  } = scope.vm.state.value();\n\n  goToFile(app, {\n    ...file,\n    owner,\n    type: FileType.folder,\n    path: takeWhile(path, (item) => item.id !== file.id),\n  });\n};\n\nexport const onFileClick = (scope: IScope, store: Store, app: App) => (\n  file: IFile\n) => {\n  goToFile(app, file);\n};\n\nexport const onGoToRootClick = (\n  scope: IScope,\n  store: Store,\n  app: App\n) => () => {\n  goToRoot(app);\n};\n\nexport const onFolderAdd = (scope: IScope, store: Store, app: App) => () => {\n  const { folder } = scope.vm.state.value();\n\n  addFolder(store, app, folder).then(\n    (newFolder) => (scope.vm.files.get(newFolder).isNew = true)\n  );\n};\n\nexport const onNotebookAdd = (scope: IScope, store: Store, app: App) => () => {\n  const { folder } = scope.vm.state.value();\n  addNotebook(store, app, folder, { addNote: true }).then((notebook) => {\n    return goToNotebook(app, notebook, { isNew: true });\n  });\n};\n\nexport const onMarkToggle = (scope: IScope, store: Store, app: App) => (\n  file: IFile\n) => {\n  store.dispatch(toggleMark(file));\n};\n\nexport const onUnmarkAll = (scope: IScope, store: Store, app: App) => () => {\n  store.dispatch(unmarkAll());\n};\n\nexport const onMarkedDelete = (scope: IScope, store: Store, app: App) => (\n  files: IFile[]\n) => {\n  store\n    .dispatchAndLog(\n      files.map((file) =>\n        file.type === FileType.folder\n          ? TrashBinActions.moveFolderToTrashBin(file.id)\n          : TrashBinActions.moveNotebookToTrashBin(file.id)\n      )\n    )\n    .then(() =>\n      toast.showToast(\n        {\n          text: `Deleted ${files.length} items`,\n          type: 'success',\n        },\n        3000\n      )\n    );\n};\n\nexport const $onDestroy = (scope: IScope, store: Store, app: App) => () => {\n  store.dispatch(setFolder(null));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-reactions.ts",
    "content": "import {IScope} from './files-types';\nimport {initTableFields} from './files-table-fields';\nimport {IFolder, IFile} from '@wix/quix-shared';\n\nexport function setFolder(scope: IScope, folder: IFolder) {\n  scope.vm.state\n    .set('Result', !!folder, {folder})\n    .then(() => {\n      scope.vm.breadcrumbs = [...folder.path, {id: folder.id, name: folder.name}];\n\n      if (!scope.permissions.edit) {\n        scope.vm.breadcrumbs[0].name = `${folder.ownerDetails.name}'s notebooks`;\n      }\n    })\n    .else(() => scope.vm.state.value({folder}));\n}\n\nexport function setFiles(scope: IScope, files: IFile[]) {\n  scope.vm.state\n    .force('Result', !!files, {files})\n    .set('Content', () => !!files.length, {files})\n    .then(() => scope.vm.fields = initTableFields(scope));\n}\n\nexport function setError(scope: IScope, error: any) {\n  scope.vm.state.force('Error', !!error, {error});\n}\n\nexport function setMarkedMap(scope: IScope, markedMap: Record<string, IFile>) {\n  scope.vm.marked.map = markedMap;\n}\n\nexport function setMarkedList(scope: IScope, markedList: IFile[]) {\n  scope.vm.marked.list = markedList;\n  scope.vm.marked.toggle(!!markedList.length);\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-scope.ts",
    "content": "import * as Reactions from './files-reactions';\n\nexport const folder = (scope, value) => Reactions.setFolder(scope, value);\nexport const files = (scope, value) => Reactions.setFiles(scope, value);\nexport const error = (scope, value) => Reactions.setError(scope, value);\nexport const permissions = x => x;\nexport const isRoot = x => x;\n\nexport const view = {\n  fileError: (scope, value) => Reactions.setError(scope, value),\n  markedMap: (scope, value) => Reactions.setMarkedMap(scope, value),\n  markedList: (scope, value) => Reactions.setMarkedList(scope, value),\n};\n\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-table-fields.ts",
    "content": "import {IFile} from '@wix/quix-shared';\n\nexport const initTableFields = scope => {\n  const fields = [];\n\n  if (scope.permissions.edit) {\n    fields.push({\n      name: 'mark',\n      title: ' ',\n      sort: false,\n      filter(_, file, index, compile) {\n        return compile(`\n          <span class=\"quix-checkbox\" ng-click=\"$event.stopPropagation()\" data-hook=\"files-mark-column\">\n            <i\n              class=\"bi-action bi-icon bi-fade-in checked\"\n              ng-if=\"vm.marked.map[file.id]\"\n              ng-click=\"$event.stopPropagation(); events.onMarkToggle(file)\"\n            >\n              check_box_outline\n            </i>\n            <i\n              class=\"bi-action bi-icon bi-fade-in\"\n              ng-if=\"!vm.marked.map[file.id]\"\n              ng-click=\"$event.stopPropagation(); events.onMarkToggle(file)\"\n            >\n              check_box_outline_blank\n            </i>\n          </span>  \n        `, {file}, scope);\n      }\n    });\n  }\n\n  return [...fields, ...[{\n    name: 'name',\n    sort(_, file) {\n      return `${file.type === 'folder' ? 0 : 1}${file.name}`;\n    },\n    filter(_, file: IFile, index, compile) {\n      return compile(`\n        <div class=\"bi-align bi-s-h\">\n          <i class=\"bi-icon bi-muted\">{{::file.type === 'folder' ? 'folder' : 'insert_drive_file'}}</i>\n\n          <span ng-if=\"!vm.get(file).isNew\">{{::file.name}}</span>\n          \n          <span\n            ng-if=\"vm.get(file).isNew\"\n            contenteditable=\"{{vm.get(file).isNew}}\"\n            ce-options=\"::{autoEdit: true}\"\n            ng-model=\"file.name\"\n            ng-blur=\"vm.get(file).isNew = false\"\n            on-change=\"events.onChildNameChange(file)\"\n          ></span>\n        </div>\n      `, {file, vm: scope.vm.files}, scope);\n    }\n  }, {\n    name: 'dateCreated',\n    filter(_, file: IFile, index, compile) {\n      return compile(`\n        <span class=\"bi-text--sm bi-muted\">{{::file.dateCreated | biRelativeDate}}</span>\n      `, {file}, scope);\n    }\n  }, {\n    name: 'dateUpdated',\n    filter(_, file: IFile, index, compile) {\n      return compile(`\n        <span class=\"bi-text--sm bi-muted\">{{::file.dateUpdated | biRelativeDate}}</span>\n      `, {file}, scope);\n    }\n  }\n  // {\n  //   name: 'liked',\n  //   title: ' ',\n  //   sort: false,\n  //   filter(_, file: IFile, index, compile) {\n  //     return compile(`\n  //       <div class=\"bi-justify-right\">\n  //         <i \n  //           class=\"bi-action bi-icon--sm\"\n  //           ng-class=\"{'bi-danger': file.isLiked}\"\n  //           ng-click=\"$event.stopPropagation(); events.onLikeToggle(file)\"\n  //         >{{::file.isLiked ? 'favorite' :'favorite_border'}}</i>\n  //       </div>\n  //     `, {file}, scope);\n  //   }\n  // }\n]];\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\nimport {BreadcrumbsTestkit} from '../../components/breadcrumbs/breadcrumbs-testkit';\nimport {ActionsTestkit} from '../../components/actions/actions-testkit';\n\nconst enum Hooks {\n  Empty = 'files-empty',\n  Error = 'files-error',\n  Content = 'files-content',\n  AddFolder = 'files-add-folder',\n  AddNotebook = 'files-add-notebook',\n}\n\nexport class FilesTestkit extends Testkit {\n  async getBreadcrumbsTestkit() {\n    return new BreadcrumbsTestkit(await this.query.$('quix-breadcrumbs'));\n  }\n\n  async getActionsTestkit() {\n    return new ActionsTestkit(await this.query.$('quix-actions'));\n  }\n\n  async hasEmptyState() {\n    return (await this.query.hook(Hooks.Empty)) !== null;\n  }\n\n  async hasErrorState() {\n    return (await this.query.hook(Hooks.Error)) !== null;\n  }\n\n  async hasContent() {\n    return (await this.query.hook(Hooks.Content)) !== null;\n  }\n\n  async clickAddFolder() {\n    return this.click.hook(Hooks.AddFolder);\n  }\n\n  async clickAddNotebook() {\n    return this.click.hook(Hooks.AddNotebook);\n  }\n\n  async clickFile(index) {\n    return this.click.attr('bi-tbl-row', `:nth-child(${index})`);\n  }\n\n  async numOfFiles() {\n    return (await this.query.attrs('bi-tbl-row')).length;\n  }\n\n  async isAddFolderEnabled() {\n    return this.evaluate.hook(Hooks.AddFolder, el => !el.hasAttribute('disabled'));\n  }\n\n  async isAddNotebookEnabled() {\n    return this.evaluate.hook(Hooks.AddNotebook, el => !el.hasAttribute('disabled'));\n  }\n\n  async isBulkSelectEnabled() {\n    return this.evaluate.attr('bi-tbl-row', el => el.querySelector('[data-hook=\"files-mark-column\"]') !== null);\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-types.ts",
    "content": "export interface IScope extends angular.IScope {\n  notebooks: any[];\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-url.ts",
    "content": "\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files-vm.ts",
    "content": "import {StateManager} from '../../services/state';\n\nenum States {\n  Initial,\n  Error,\n  Result,\n  Content\n}\n\nexport default () => ({\n  fields: null,\n  breadcrumbs: [{name: 'My notebooks'}],\n  marked: {},\n  $init() {\n    this.state = new StateManager(States);\n    this.marked.map = {};\n    this.marked.list = [];\n\n    this.files = this.createItemsVm({\n      isNew: null\n    });\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files.html",
    "content": "<div class=\"bi-section bi-c-h bi-grow\">\n  <div class=\"bi-section-header\">\n    <div>\n      <div class=\"bi-section-title bi-r-h bi-align bi-s-h bi-fade-in\" ng-if=\"vm.state.is('Result') || vm.state.after('Result')\">\n        <img\n          class=\"quix-user-avatar bi-fade-in\"\n          ng-if=\"(vm.state.is('Result') || vm.state.after('Result')) && vm.state.value().folder.ownerDetails.avatar\"\n          ng-src=\"{{::vm.state.value().folder.ownerDetails.avatar}}\"\n        >\n\n        <quix-breadcrumbs\n          class=\"bi-dont-shrink\"\n          breadcrumbs=\"vm.breadcrumbs\"\n          quix-breadcrumbs-options=\"::{focusName: options.isNew}\"\n          on-folder-click=\"events.onBreadcrumbClick(file)\"\n          on-name-change=\"events.onNameChange(file)\"\n          readonly=\"!permissions.rename\"\n        ></bi-breadcrumbs>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"bi-section-controls bi-fade-in\" ng-if=\"(vm.state.is('Result') && permissions.edit) || vm.state.after('Result')\">\n    <div>\n      <div class=\"bi-align bi-s-h bi-fade-in\" ng-if=\"!vm.marked.enabled\">\n        <button \n          class=\"bi-button--primary\"\n          ng-disabled=\"!permissions.addFolder\"\n          ng-click=\"permissions.addFolder && events.onFolderAdd()\"\n          data-hook=\"files-add-folder\"\n        >\n          <i class=\"bi-icon--sm\">add</i>\n          <span>Add folder</span>\n        </button>\n\n        <button \n          class=\"bi-button--primary\"\n          ng-disabled=\"!permissions.addNotebook\"\n          ng-click=\"permissions.addNotebook && events.onNotebookAdd()\"\n          data-hook=\"files-add-notebook\"\n        >\n          <i class=\"bi-icon--sm\">add</i>\n          <span>Add notebook</span>\n        </button>\n      </div>\n\n      <div class=\"bi-align bi-s-h bi-fade-in\" ng-if=\"vm.marked.enabled\">\n        <quix-actions \n          type=\"item\"\n          context=\"vm.marked.list\"\n          permissions=\"::permissions.bulk\"\n          on-delete=\"events.onMarkedDelete(context)\"\n        ></quix-actions>\n  \n        <span class=\"bi-muted\">{{vm.marked.list.length}} items selected</span>\n      </div>\n    </div>\n\n    <div class=\"bi-align bi-s-h--x2\">\n      <quix-actions \n        type=\"folder\"\n        context=\"vm.state.value().folder\"\n        permissions=\"::permissions\"\n        quix-actions-options=\"{\n          reverse: true,\n          confirmOnDelete: vm.state.is('Content')\n        }\"\n        on-like-toggle=\"events.onLikeToggle(context)\"\n        on-share=\"events.onShare(context)\"\n        on-delete=\"events.onDelete(context)\"\n      ></quix-actions>\n    </div>\n  </div>\n\n  <div class=\"bi-section-content--center\" ng-if=\"vm.state.before('Content')\">\n    <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Initial')\">\n      <div class=\"bi-empty-state-content\">Loading notebooks...</div>\n    </div>\n\n    <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Error')\" data-hook=\"files-error\">\n      <quix-image class=\"bi-empty-state-image\" name=\"error_{{::vm.state.value().error.status}}.svg\"></quix-image>\n      <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n      <div class=\"bi-empty-state-content\">\n        <a class=\"bi-link\" ng-click=\"events.onGoToRootClick()\">Go to my notebooks</a>\n      </div>\n    </div>\n\n    <div\n      class=\"bi-empty-state bi-fade-in\"\n      ng-if=\"vm.state.is('Result')\"\n      data-hook=\"files-empty\"\n    >\n      <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n\n      <div class=\"bi-empty-state-header\">{{::isRoot ? 'You dont have any notebooks' : 'Folder is empty'}}</div>\n\n      <div class=\"bi-empty-state-content bi-s-h--x05\">\n        <span ng-if=\"::!isRoot && permissions.addFolder\">\n          <a class=\"bi-link\" ng-click=\"events.onFolderAdd()\">Add folder</a>\n          <span>or</span>\n        </span>\n\n        <a class=\"bi-link\" ng-if=\"::permissions.addNotebook\" ng-click=\"events.onNotebookAdd()\">Add notebook</a>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"bi-section-content bi-c-h\" ng-if=\"vm.state.is('Content')\">\n    <div class=\"bi-panel bi-c-h bi-fade-in bi-theme--lighter\" data-hook=\"files-content\">\n      <div class=\"bi-panel-content bi-c-h\">\n        <bi-tbl\n          class=\"bi-table--nav bi-c-h bi-grow\"\n          fields=\"vm.fields\"\n          rows=\"vm.state.value().files\"\n          bt-options=\"::{stickyHeader: true, trackBy: 'id'}\"\n          on-row-click=\"events.onFileClick(row)\"\n          order-by=\"name\"\n          data-hook=\"files-table\"\n        ></bi-tbl>\n      </div>\n    </div>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n\nquix-folder {\n\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/files/files.ts",
    "content": "import template from './files.html';\nimport './files.scss';\n\nimport {initNgScope} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IStateComponentConfig} from '../../lib/app/services/plugin-builder';\nimport {cache} from '../../store';\nimport {initEvents} from '../../services/scope';\nimport {IScope} from './files-types';\nimport VM from './files-vm';\n// import * as Url from './files-url';\nimport * as Scope from './files-scope';\nimport * as Events from './files-events';\n\nexport default (app: App, store: Store) => ({\n  name: 'files:id',\n  template,\n  url: {},\n  scope: Scope,\n  options: {isNew: false},\n  controller: async (scope: IScope, params, {syncUrl, setTitle}) => {\n    await cache.folder.fetch(params.id);\n  \n    syncUrl();\n\n    scope.isRoot = !params.id;\n\n    store.subscribe('folder', ({folder, files, error, view, permissions}) => {\n      scope.folder = folder;\n      scope.files = files;\n      scope.error = error;\n      scope.view = view;\n      scope.permissions = permissions;\n    }, scope);\n\n    store.subscribe('folder.folder.name', (name: string) => {\n       setTitle(() => params.id ? [name] : [app.getTitle(), 'My notebooks']);\n    }, scope);\n\n    store.subscribe('folder.error', error => {\n      if (error) {\n        setTitle(() => ['Error']);\n      }\n    }, scope);\n  },\n  link: scope => {\n    const conf = initNgScope(scope)\n      .withOptions('$stateOptions', {isNew: false})\n      .withVM(VM());\n\n    initEvents(scope, conf, app, store, Events);\n  }\n}) as IStateComponentConfig;\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/history/HistoryComponent.scss",
    "content": "@import '../../lib/ui/assets/css/def/state.def';\n@import '../../lib/ui/assets/css/text.scss';\n\n.history-component {\n  .hc-filters {\n    background-color: transparent;\n  }\n\n  .bi-table-cell-query {\n    max-width: 300px;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/state-components/history/HistoryComponent.tsx",
    "content": "import './HistoryComponent.scss';\n\nimport React, { useEffect } from 'react';\nimport { IHistory } from '@wix/quix-shared';\nimport { historyTableFields } from './history-table-fields';\nimport { User } from '../../lib/app/services/user';\nimport { useViewState } from '../../services/hooks';\nimport { debounceAsync } from '../../utils';\nimport makePagination from '../../lib/ui/components/hoc/makePagination';\nimport { Table } from '../../lib/ui/components/table/Table';\nimport { Highlighter } from '../../lib/ui/components/Highlighter';\nimport { Input } from '../../lib/ui/components/input/Input';\nimport { Autocomplete } from '../../lib/ui/components/autocomplete/Autocomplete';\nimport { FilterInitialState, InitialState, EmptyState, ErrorState } from '../../lib/ui/components/states';\n\nexport interface HistoryProps {\n  error: { message: string };\n  user: User;\n  onHistoryClicked(history: IHistory): void;\n  loadMore({ offset, limit, filters }: { offset: number; limit: number; filters: object }): Promise<IHistory[]>;\n  getUsers(): User[];\n}\n\nexport const CHUNK_SIZE = 100;\n\nconst PaginatedTable = makePagination(Table);\n\nconst search = debounceAsync((loadMore, { offset, limit, filters }) => {\n  return loadMore({ offset, limit, filters });\n});\n\nconst States = [\n  'Initial',\n  'Error',\n  'Empty',\n  'Content',\n  'FilterInitial',\n];\n\nexport function History(props: HistoryProps) {\n  const { error, onHistoryClicked, loadMore, user, getUsers: storageGetUsers } = props;\n  const [stateData, viewState] = useViewState(States, {\n    rows: [],\n    size: 0,\n    userFilter: user.getEmail(),\n    users: [],\n    queryFilter: '',\n    errorMessage: '',\n  });\n\n  const getChunk = (offset: number, limit: number) => {\n    return search(loadMore, {\n      offset,\n      limit,\n      filters: {\n        user: stateData.userFilter,\n        query: stateData.queryFilter\n      }\n    });\n  }\n\n  const getUsers = () => {\n    if (!stateData.users.length) {\n      (storageGetUsers as any)().\n        then((users: User[]) => viewState.update({users}));\n    }\n  }\n\n  useEffect(() => {\n    if (error) {\n      viewState.set('Error', { errorMessage: error.message });\n    }\n  }, [error]);\n\n  useEffect(() => {\n    if (viewState.get() !== 'Error') {\n      getChunk(0, CHUNK_SIZE + 1)(res => {\n        viewState.set(res.length > 0 ? 'Content' : 'Empty', {rows: res});\n      });\n    }\n  }, [stateData.queryFilter, stateData.userFilter]);\n\n  const highlightQuery = (columnName: string) => (term: string) => {\n    const text = term.replace(/\\s+/g,' ');\n    \n    if (columnName === 'query') {\n      return <Highlighter\n        term={term}\n        filter={stateData.queryFilter}\n      />;\n    }\n\n    return text;\n  }\n\n  const handleUserFilterChange = (option) => {\n    if (viewState.get() !== 'Error') {\n      viewState.set('FilterInitial', { userFilter: option.id });\n    }\n  }\n\n  const handleQueryFilterChange = (e) => {\n    if (viewState.get() !== 'Error') {\n      viewState.set('FilterInitial', { queryFilter: e.target.value });\n    }\n  }\n\n  const renderContentState = () => (\n    <PaginatedTable\n      hookName=\"history\"\n      initialData={stateData.rows}\n      loadMore={getChunk}\n      onRowClicked={onHistoryClicked}\n      columns={historyTableFields.map(field => ({\n        header: field.title,\n        render: row => field.filter(undefined, row, 0, highlightQuery(field.name)),\n        accessor: field.name,\n        className: field.className,\n      }))}\n      paginationSize={CHUNK_SIZE}\n      tableSize={(size) => viewState.update({ size })}\n    />\n  );\n\n  const renderFilters = () => (\n    <div className=\"hc-filters bi-theme--lighter bi-align bi-s-h--x15\">\n      <Autocomplete\n        options={stateData.users}\n        state={stateData.users.length ? 'Content' : 'Loading'}\n        defaultValue={user.getEmail()}\n        onInputFocus={() => getUsers()}\n        title=\"email\"\n        primaryOption={{email: \"All users\"}}\n        onSelect={handleUserFilterChange}\n        inputDataHook=\"history-filter-user-select\"\n        liDataHook=\"history-filter-user-select-option\"\n      />\n\n      <Input\n        className=\"bi-grow\"\n        onChange={handleQueryFilterChange}\n        placeholder=\"Filter query\"\n        data-hook=\"history-filter-query-input\"\n      />\n    </div>\n  );\n\n  return (\n    <div className=\"history-component bi-section bi-c-h bi-grow\">\n      <div className=\"bi-section-header\">\n        <div className=\"bi-section-title\">\n          <span>History {viewState.min('Empty') && <span className='bi-fade-in'>({stateData.size})</span>}</span>\n        </div>\n      </div>\n\n      <div className=\"bi-section-content bi-c-h bi-s-v--x15\">\n        {viewState.min('Error') && renderFilters()}\n\n        {\n          (() => {\n            switch(viewState.get()) {\n              case 'Initial':\n                return <InitialState entityName=\"history\" />;\n              case 'Error':\n                return <ErrorState errorMessage={error.message} />;\n              case 'Empty':\n                return <EmptyState />;\n              case 'Content':\n                return renderContentState();\n              case 'FilterInitial':\n                return <FilterInitialState entityName=\"history\" />;\n              default:\n            }\n          })()\n        }\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/history/history-events.ts",
    "content": "import { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IHistory } from '@wix/quix-shared';\nimport { openTempQuery } from '../../services/popup';\n\nexport const onHistoryClick = (scope, store: Store, app: App) => (\n  history: IHistory\n) => {\n  openTempQuery(\n    scope,\n    history.moduleType,\n    history.query.join(';\\n') + ';',\n    false,\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/history/history-table-fields.tsx",
    "content": "import * as React from 'react';\nimport { IHistory } from '@wix/quix-shared';\nimport relativeDate from '../../lib/ui/filters/relative-date';\nimport absoluteDate from '../../lib/ui/filters/absolute-date';\nimport toHumanCase from '../../lib/ui/filters/to-human-case';\nimport { HighlightedRowConfig } from '../../lib/ui/components/table/TableRow';\n\nexport const historyTableFields: HighlightedRowConfig<IHistory>[] = [\n  {\n    name: 'email',\n    title: 'User',\n    filter(_, history: IHistory, index, highlight) {\n      return <span>{highlight(history.email)}</span>;\n    }\n  },\n  {\n    name: 'query',\n    title: 'Query',\n    filter(_, history: IHistory, index, highlight) {\n      const hasQuery = history.query.length > 0;\n      const fullQuery = hasQuery ? history.query.join(';\\n') + ';' : '';\n\n      return (\n        <span className=\"bi-muted bi-text--sm\">\n          {highlight(fullQuery)}\n        </span>\n      )\n    }\n  },\n  {\n    name: 'moduleType',\n    title: 'Type',\n    filter(_, history: IHistory, index, highlight) {\n      return (\n        <span className=\"bi-tag--sm\">\n          {highlight(toHumanCase()(history.moduleType))}\n        </span>\n      );\n    }\n  },\n  {\n    name: 'startedAt',\n    title: 'Started At',\n    filter(_, history: IHistory, index) {\n      return (\n        <div className=\"bi-align bi-s-h--x05 bi-text--sm bi-muted\">\n          <span>\n            {relativeDate()(history.startedAt as any)}\n          </span>\n\n          <span>\n            ({absoluteDate()(history.startedAt as any)})\n          </span>\n        </div>\n      );\n    }\n  }\n];\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/history/history-testkit.ts",
    "content": "import { TableTestkit } from '../../lib/ui/components/table/table-testkit';\n\nconst enum Hooks {\n  Table = 'history-table',\n  UserFilterSelect = 'history-filter-user-select',\n  UserFilterSelectOption = 'history-filter-user-select-option',\n  QueryFilterInput = 'history-filter-query-input',\n}\n\nexport class HistoryTestkit extends TableTestkit {\n\n  historyTableExists = async () => {\n    return (await this.query.hook(Hooks.Table)) !== null;\n  }\n\n  userFilter = {\n    clickOnDropdown: () => {\n      return this.click.hook(Hooks.UserFilterSelect);\n    },\n\n    clickOnOption: () => {\n      return this.click.hook(Hooks.UserFilterSelectOption);\n    },\n\n    hasOptions: async () => {\n      return (await this.query.hooks(Hooks.UserFilterSelectOption)).length > 0;\n    },\n\n    value: () => {\n      return this.evaluate.hook(Hooks.UserFilterSelect, (e: HTMLInputElement) => e.value);\n    },\n  }\n\n  queryFilter = {\n    click: () => {\n      return this.click.hook(Hooks.QueryFilterInput);\n    },\n\n    set: (value: string) => {\n      return this.keyboard.type(Hooks.QueryFilterInput, value);\n    },\n\n    get: () => {\n      return this.evaluate.hook(Hooks.QueryFilterInput, (e: HTMLInputElement) => e.value);\n    },\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/history/history.ts",
    "content": "import { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IReactStateComponentConfig } from '../../lib/app/services/plugin-builder';\nimport { History, HistoryProps } from './HistoryComponent';\nimport { cache } from '../../store';\nimport { onHistoryClick } from './history-events';\n\nexport default (app: App, store: Store): IReactStateComponentConfig => ({\n  name: 'history',\n  template: History,\n  url: {},\n  scope: {\n    filter: () => {},\n    user: () => {},\n    error: () => {},\n    onHistoryClicked: () => {},\n    loadMore: () => {},\n    getUsers: () => {},\n  },\n  controller: async (scope: HistoryProps, params, { syncUrl, setTitle }) => {\n    syncUrl();\n    setTitle();\n\n    store.subscribe(\n      'history',\n      ({ error }) => {\n        scope.user = app.getUser();\n        scope.loadMore = ({ offset, limit, filters }: {offset: number; limit: number; filters: object}) => {\n          return cache.history.fetch({ offset, limit, ...filters });\n        };\n        scope.getUsers = () => {\n          return cache.users.fetch();\n        }\n        scope.error = error;\n      },\n      scope\n    );\n\n    scope.onHistoryClicked = onHistoryClick(scope, store, app);\n  }\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/home/HomeComponent.tsx",
    "content": "import * as React from 'react';\nimport './home.scss';\n\nexport interface HomeProps {\n  events: {\n    onNotebooksClick(): void;\n    onExamplesClick(): void;\n    onNotebookAdd(): void;\n  };\n  vm: any;\n}\n\nexport function Home(props: HomeProps) {\n  const {events, vm} = props;\n\n  return (\n    <div className=\"bi-section bi-c-h bi-grow bi-scroll bi-theme--dark\">\n      <div className=\"quix-home-welcome bi-section-title bi-c bi-s-v--x3\">\n        <div className=\"quix-home-welcome-title\">\n          <span className=\"bi-primary bi-text--600\">QUIX</span> <span className=\"bi-text--300\">NOTEBOOK MANAGER</span>\n        </div>\n        <div className=\"bi-text--lg bi-text--300\">\n          A shared space for your company's BI insights and know-how\n        </div>\n      </div>\n\n      <div className=\"quix-home-actions bi-center bi-grow\">\n        <button\n          className=\"bi-button bi-home-action\"\n          role=\"button\"\n          onClick={() => events.onNotebooksClick()}\n          data-hook=\"home-notebooks\"\n        >\n          <span>My notebooks</span>\n        </button>\n\n        {\n          vm.examples.enabled ? \n            <button\n              className=\"bi-button bi-home-action\"\n              role=\"button\"\n              onClick={() => events.onExamplesClick()}\n              data-hook=\"home-examples\"\n            >\n              <span>Examples</span>\n            </button> : ''\n        }\n\n        <button\n          className=\"bi-button bi-home-action\"\n          role=\"button\"\n          onClick={() => events.onNotebookAdd()}\n          data-hook=\"home-add-notebook\"\n        >\n          <i className=\"bi-icon\">add</i>\n          <span>Add notebook</span>\n        </button>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/home/home-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\n\nexport class HomeTestkit extends Testkit {\n  async hasNotebooksAction() {\n    return (await this.query.hook('home-notebooks')) !== null;\n  }\n\n  async hasAddNotebookAction() {\n    return (await this.query.hook('home-add-notebook')) !== null;\n  }\n\n  async clickNotebooks() {\n    return this.click.hook('home-notebooks');\n  }\n\n  async clickExamples() {\n    return this.click.hook('home-examples');\n  }\n\n  async clickAddNotebook() {\n    return this.click.hook('home-add-notebook');\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/state-components/home/home.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n\nquix-home {\n  .quix-home-welcome {\n    margin-bottom: 100px;\n    padding: 60px 0 60px;\n    text-align: center;\n\n    .quix-home-welcome-title {\n      font-size: 50px;\n      font-weight: 200;\n    }\n  }\n\n  .quix-home-actions {\n    > * {\n      &:not(:last-child) {\n        margin-right: 50px;\n\n        img {\n          \n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/home/home.ts",
    "content": "import {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IReactStateComponentConfig} from '../../lib/app/services/plugin-builder';\nimport {Home, HomeProps} from './HomeComponent';\nimport {initNgScope} from '../../lib/core';\nimport {addNotebook, goToExamples, goToRoot} from '../../services';\nimport { goToNotebook } from '../../services/notebook';\n\nexport default (app: App, store: Store): IReactStateComponentConfig => ({\n  name: 'home',\n  template: Home,\n  url: {},\n  scope: {\n    events: () => {},\n    vm: () => {}\n  },\n  controller: (scope: HomeProps, params, {setTitle}) => {\n    initNgScope(scope)\n      .withVM({\n        examples: {}\n      })\n      .withEvents({\n        onNotebooksClick() {\n          goToRoot(app);\n        },\n        onNotebookAdd() {\n          addNotebook(store, app, [], {addNote: true})\n            .then(notebook => goToNotebook(app, notebook, {isNew: true}));\n        },\n        onExamplesClick() {\n          goToExamples(app);\n        }\n      });\n\n    scope.vm.examples.toggle(!!app.getConfig().getMode().demo);\n\n    return setTitle();\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/import/import.html",
    "content": "<div class=\"bi-align bi-center bi-grow\">\n  <div class=\"bi-center\">\n    <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"!error\">\n      <div class=\"bi-empty-state-content\">Importing note...</div>\n    </div>\n    <div class=\"bi-empty-state bi-fade-in\" ng-if=\"error\" data-hook=\"import-error\">\n      <quix-image class=\"bi-empty-state-image\" name=\"error_404.svg\"></quix-image>\n      <div class=\"bi-empty-state-header\">\n        Failed to import note\n      </div>\n      <div class=\"bi-empty-state-content\">\n        {{::error}}\n      </div>\n    </div>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/state-components/import/import.ts",
    "content": "import template from './import.html';\n\nimport moment from 'moment';\nimport {initNgScope, utils} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IStateComponentConfig} from '../../lib/app/services/plugin-builder';\nimport {setImportType, setImportValue} from '../../store/app/app-actions';\nimport { Import, Time } from '../../config';\nimport { addNotebookByNamePath, addNote, goToNotebook } from '../../services/notebook';\nimport { showToast } from '../../lib/ui/services/toast';\nimport { pluginManager } from '../../plugins';\n\nconst importNote = async (scope, app: App, store: Store, {type, value}) => {\n  if (!type || !value) {\n    app.getNavigator().goHome();\n    return;\n  }\n\n  if (!pluginManager.module('note').plugin(type)) {\n    scope.error = `\"${type}\" doesn't match any known note type`;\n    return;\n  }\n\n  const notebook = await addNotebookByNamePath(store, app, [Import.FolderName, type]);\n  const note = await addNote(store, notebook.id, type, {\n    name: moment().format(Time.Format)\n  });\n\n  pluginManager.hooks.import.promise(store, note, value)\n    .then(() => {\n      goToNotebook(app, notebook, {note: note.id}, {location: 'replace'});\n\n      showToast({\n        text: `Imported a \"${type}\" note`,\n        type: 'success',\n        hideDelay: 3000,\n      });\n    })\n    .catch(e => utils.scope.safeDigest(scope, () => scope.error = e));\n}\n\nconst destroy = (store: Store) => store.dispatch([\n  setImportType(null),\n  setImportValue(null),\n]);\n\nexport default (app: App, store: Store) => ({\n  name: 'import',\n  template,\n  url: {\n    importType: setImportType,\n    importValue: setImportValue,\n  },\n  scope: {\n    import: (scope, imp) => importNote(scope, app, store, imp),\n  },\n  controller: (scope, params, {syncUrl}) => {\n    syncUrl();\n\n    store.subscribe('app.import', imp => {\n      scope.import = imp;\n    }, scope);\n  },\n  link: (scope) => {\n    initNgScope(scope)\n      .withEvents({});\n\n    scope.$on('$destory', () => destroy(store));\n  }\n}) as IStateComponentConfig;\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/index.ts",
    "content": "export { default as base } from './base/base';\nexport { default as embed } from './embed/embed';\nexport { default as embedNote } from './embed/note/embed-note';\nexport { default as files } from './files/files';\nexport { default as notebook } from './notebook/notebook';\nexport { default as import } from './import/import';\nexport { default as home } from './home/home';\nexport { default as user } from './users/users';\nexport { default as history } from './history/history';\nexport { default as favorites } from './favorites/favorites';\nexport { default as trashBin } from './trash-bin/trash-bin';\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-events.ts",
    "content": "import { takeWhile } from 'lodash';\nimport { utils } from '../../lib/core';\nimport { Store } from '../../lib/store';\nimport { dialog, toast } from '../../lib/ui';\nimport { App } from '../../lib/app';\nimport {\n  INote,\n  NotebookActions,\n  IFile,\n  NoteActions,\n  INotebook,\n  IFilePathItem,\n  FileType,\n} from '@wix/quix-shared';\nimport { IScope } from './notebook-types';\nimport {\n  setNotebook,\n  setNote,\n  queueNote,\n  toggleMark,\n  unmarkAll,\n} from '../../store/notebook/notebook-actions';\nimport {\n  saveQueuedNotes,\n  deleteNotebook,\n  copyNotebook,\n  goToFile,\n  goToRoot,\n  prompt,\n  copyNote,\n} from '../../services';\nimport { removeRunner, addRunner } from '../../store/app/app-actions';\nimport { addNote } from '../../services/notebook';\n\nexport const onBreadcrumbClick = (scope: IScope, store: Store, app: App) => (\n  file: IFilePathItem\n) => {\n  const {\n    notebook: { owner, path },\n  } = scope.vm.state.value();\n\n  goToFile(app, {\n    ...file,\n    owner,\n    type: FileType.folder,\n    path: takeWhile(path, (item) => item.id !== file.id),\n  });\n};\n\nexport const onGoToRootClick = (\n  scope: IScope,\n  store: Store,\n  app: App\n) => () => {\n  goToRoot(app);\n};\n\nexport const onNameChange = (scope: IScope, store: Store, app: App) => (\n  file: IFile\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  const { id, name } = file;\n\n  store.dispatchAndLog(NotebookActions.updateName(id, name));\n};\n\nexport const onDelete = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  deleteNotebook(store, app, notebook).then(() =>\n    toast.showToast(\n      {\n        text: `\"${notebook.name}\" moved to Trash Bin`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onClone = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  prompt(\n    {\n      title: 'Clone notebook',\n      subTitle: 'Choose destination folder',\n      yes: 'clone',\n      content: `<quix-destination-picker ng-model=\"model.folder\" context=\"folder\" required></quix-destination-picker>`,\n      onConfirm: ({ model: { folder } }) =>\n        copyNotebook(store, app, folder, {\n          ...notebook,\n          notes: scope.vm.state.value().notes,\n        }),\n    },\n    scope,\n    { model: { folder: null } }\n  ).then((res) =>\n    toast.showToast(\n      {\n        text: `Cloned notebook as \"${res.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onShare = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  utils.copyToClipboard(app.getNavigator().getUrl(null, { id: notebook.id }));\n\n  toast.showToast(\n    {\n      text: 'Copied notebook url to clipboard',\n      type: 'success',\n    },\n    3000\n  );\n};\n\nexport const onLikeToggle = (scope: IScope, store: Store, app: App) => (\n  notebook: INotebook\n) => {\n  const { id, isLiked } = notebook;\n\n  store\n    .dispatchAndLog(NotebookActions.toggleIsLiked(id, !isLiked))\n    .then((action) =>\n      toast.showToast(\n        {\n          text: action.isLiked\n            ? 'Added notebook to favorites'\n            : 'Removed notebook from favorites',\n          type: 'success',\n        },\n        3000\n      )\n    );\n};\n\nexport const onSave = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onRun = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onNoteSave = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onNoteRun = (scope: IScope, store: Store, app: App) => () => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  saveQueuedNotes(store);\n};\n\nexport const onNoteAdd = (scope: IScope, store: Store, app: App) => (\n  type: any = scope.vm.noteTypes[0]\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  const { notebook } = scope.vm.state.value();\n\n  addNote(store, notebook.id, type, {}, (note) => {\n    scope.vm.notes.get(note).focusName = true;\n    store.dispatch(setNote(note));\n  });\n};\n\nexport const onNoteClone = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  prompt(\n    {\n      title: 'Clone note',\n      subTitle: 'Choose destination notebook',\n      yes: 'clone',\n      content: `<quix-destination-picker ng-model=\"model.notebook\" context=\"notebook\" required></quix-destination-picker>`,\n      onConfirm: ({ model: { notebook } }) =>\n        copyNote(store, app, notebook, note),\n    },\n    scope,\n    { model: { notebook: null } }\n  ).then((res) =>\n    toast.showToast(\n      {\n        text: `Cloned note as \"${res.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onNoteShare = (scope: IScope, store: Store, app: App) => (\n  note: INote,\n  params: string\n) => {\n  const { notebook } = scope.vm.state.value();\n\n  dialog(\n    {\n      title: 'Share note',\n      html:\n        '<quix-note-share note=\"::note\" notebook=\"::notebook\", params=\"::params\"></div>',\n      icon: 'share',\n    },\n    scope,\n    {\n      note,\n      notebook,\n      params,\n    }\n  );\n};\n\nexport const onNoteDelete = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatchAndLog(NoteActions.deleteNote(note.id)).then(() =>\n    toast.showToast(\n      {\n        text: `Deleted note \"${note.name}\"`,\n        type: 'success',\n      },\n      3000\n    )\n  );\n};\n\nexport const onNoteContentChange = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatch(queueNote(note));\n};\n\nexport const onNoteNameChange = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatchAndLog(NoteActions.updateName(note.id, note.name));\n};\n\nexport const onNoteReorder = (scope: IScope, store: Store, app: App) => (\n  e: any,\n  { item }: any\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  const { model: note, dropindex: index } = item.sortable;\n\n  if (typeof index !== 'undefined') {\n    store.dispatchAndLog(NoteActions.reorderNote(note.id, index));\n  }\n};\n\nexport const onMarkToggle = (scope: IScope, store: Store, app: App) => (\n  note: INote\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store.dispatch(toggleMark(note));\n};\n\nexport const onMarkedNotesDelete = (scope: IScope, store: Store, app: App) => (\n  notes: INote[]\n) => {\n  if (!scope.permissions.edit) {\n    return;\n  }\n\n  store\n    .dispatchAndLog(notes.map((note) => NoteActions.deleteNote(note.id)))\n    .then(() =>\n      toast.showToast(\n        {\n          text: `Deleted ${notes.length} notes`,\n          type: 'success',\n        },\n        3000\n      )\n    );\n};\n\nexport const onUnmarkAll = (scope: IScope, store: Store, app: App) => () => {\n  store.dispatch(unmarkAll());\n};\n\nexport const onRunnerCreated = (scope: IScope, store: Store) => (\n  note,\n  runner\n) => {\n  store.dispatch(\n    addRunner(note.id, runner, note, scope.vm.state.value().notebook)\n  );\n};\n\nexport const onRunnerDestroyed = (scope: IScope, store: Store) => (note) => {\n  store.dispatch(removeRunner(note.id));\n};\n\nexport const $onDestroy = (scope: IScope, store: Store, app: App) => () => {\n  if (scope.permissions.edit) {\n    saveQueuedNotes(store);\n  }\n\n  store.dispatch(setNotebook(null));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-reactions.ts",
    "content": "import {IScope} from './notebook-types';\nimport {INotebook, INote} from '@wix/quix-shared';\n\nexport function setNotebook(scope: IScope, notebook: INotebook) {\n  scope.vm.state\n    .set('Result', !!notebook, {notebook})\n    .then(() => {\n      if (scope.vm.breadcrumbs.length === 1) {\n        scope.vm.breadcrumbs = [...notebook.path, {id: notebook.id, name: notebook.name}];\n\n        if (!scope.permissions.edit) {\n          scope.vm.breadcrumbs[0].name = `${notebook.ownerDetails.name}'s notebooks`;\n        }\n      }\n    })\n    .else(() => scope.vm.state.value({notebook}));\n}\n\nexport function setError(scope: IScope, error: any) {\n  scope.vm.state.force('Error', !!error, {error});\n}\n\nexport function setNotes(scope: IScope, notes: INote[]) {\n  scope.vm.state\n    .force('Result', !!notes, {notes})\n    .set('Content', () => !!notes.length, {notes})\n    .then(() => {\n      const vm = scope.vm.notes.get(notes[0]);\n      vm.fold = vm.fold === null ? notes.length > 1 : vm.fold;\n    });\n}\n\nexport function setHasChanges(scope: IScope, hasChanges: boolean) {\n  scope.vm.view.hasChanges = hasChanges;\n}\n\nexport function setSaving(scope: IScope, saving: boolean) {\n  scope.vm.view.saving = saving;\n}\n\nexport function setMarkedMap(scope: IScope, markedMap: Record<string, INote>) {\n  scope.vm.marked.map = markedMap;\n}\n\nexport function setMarkedList(scope: IScope, markedList: INote[]) {\n  scope.vm.marked.list = markedList;\n  scope.vm.marked.toggle(!!markedList.length);\n}\n\nexport function setNote(scope: IScope, note: INote) {\n  scope.vm.state.value({note});\n\n  if (note) {\n    scope.vm.notes.get(note).fold = false;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-scope.ts",
    "content": "import * as Reactions from './notebook-reactions';\n\nexport const notebook = (scope, value) => Reactions.setNotebook(scope, value);\nexport const notes = (scope, value) => Reactions.setNotes(scope, value);\nexport const error = (scope, value) => Reactions.setError(scope, value);\nexport const runners = x => x;\nexport const permissions = x => x;\n\nexport const queue = {\n  size: (scope, value) => Reactions.setHasChanges(scope, value > 0),\n};\n\nexport const view = {\n  markedMap: (scope, value) => Reactions.setMarkedMap(scope, value),\n  markedList: (scope, value) => Reactions.setMarkedList(scope, value),\n  note: (scope, value) => Reactions.setNote(scope, value),\n  saving: (scope, value) => Reactions.setSaving(scope, value),\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-testkit.ts",
    "content": "import {Testkit} from '../../../test/e2e/driver';\nimport {NoteTestkit} from '../../components/note/note-testkit';\nimport {BreadcrumbsTestkit} from '../../components/breadcrumbs/breadcrumbs-testkit';\nimport {ActionsTestkit} from '../../components/actions/actions-testkit';\n\nconst enum Hooks {\n  Empty = 'notebook-empty',\n  Error = 'notebook-error',\n  Content = 'notebook-content',\n  Note = 'notebook-note',\n  AddNote = 'notebook-add-note',\n  AddNoteDropdown = 'notebook-add-note-dropdown',\n}\n\nexport class NotebookTestkit extends Testkit {\n  async getBreadcrumbsTestkit() {\n    return new BreadcrumbsTestkit(await this.query.$('quix-breadcrumbs'));\n  }\n\n  async getActionsTestkit() {\n    return new ActionsTestkit(await this.query.$('quix-actions'));\n  }\n\n  async getNoteTestkit(index: number) {\n    return new NoteTestkit(await this.query.hook(Hooks.Note, `:nth-child(${index})`));\n  }\n\n  async hasEmptyState() {\n    return (await this.query.hook(Hooks.Empty)) !== null;\n  }\n\n  async hasErrorState() {\n    return (await this.query.hook(Hooks.Error)) !== null;\n  }\n\n\n  async hasNotes() {\n    return (await this.query.hook(Hooks.Content)) !== null;\n  }\n\n  async clickAddNote() {\n    return this.click.hook(Hooks.AddNote, ':first-child');\n  }\n\n  async clickAddNoteDropdown() {\n    await this.click.hook(Hooks.AddNoteDropdown);\n  }\n\n  async numOfNotes() {\n    return (await this.query.hooks(Hooks.Note)).length;\n  }\n\n  async isAddNoteEnabled() {\n    return this.evaluate.hook(Hooks.AddNoteDropdown, el => !el.hasAttribute('disabled'));\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-types.ts",
    "content": "import {INotebook} from '@wix/quix-shared';\n\nexport interface IScope extends angular.IScope {\n  notebook: INotebook;\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-url.ts",
    "content": "import {find} from 'lodash';\nimport {INote} from '@wix/quix-shared';\nimport {setNote} from '../../store/notebook/notebook-actions';\n\nexport const note = (id: string, notes: INote[]) => setNote(id && find(notes, {id}));"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook-vm.ts",
    "content": "import {StateManager} from '../../services/state';\nimport {App} from '../../lib/app';\nimport {pluginManager} from '../../plugins';\n\nenum States {\n  Initial,\n  Error,\n  Result,\n  Content,\n}\n\nexport default (app: App) => ({\n  note: null,\n  breadcrumbs: [{name: 'My notebooks'}],\n  view: {\n    hasChanges: false,\n    saving: false,\n  },\n  marked: {},\n  $init() {\n    this.notes = this.createItemsVm({\n      fold: null,\n      scrollTo: false,\n      focusName: false,\n    });\n\n    this.noteTypes = pluginManager\n      .module('note')\n      .plugins()\n      .filter(plugin => plugin.getConfig().canCreate)\n      .map(plugin => plugin.getId());\n\n    this.state = new StateManager(States);\n    this.marked.map = {};\n    this.marked.list = [];\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook.html",
    "content": "<div class=\"bi-section bi-c-h bi-grow\">\n  <div class=\"bi-section-header\">\n    <div>\n      <div class=\"bi-section-title bi-r-h bi-align bi-s-h bi-fade-in\" ng-if=\"vm.state.is('Result') || vm.state.after('Result')\">\n        <img\n          class=\"quix-user-avatar bi-fade-in\"\n          ng-if=\"(vm.state.is('Result') || vm.state.after('Result')) && vm.state.value().notebook.ownerDetails.avatar\"\n          ng-src=\"{{::vm.state.value().notebook.ownerDetails.avatar}}\"\n        >\n\n        <quix-breadcrumbs\n          class=\"bi-dont-shrink\"\n          breadcrumbs=\"vm.breadcrumbs\"\n          quix-breadcrumbs-options=\"::{focusName: options.isNew}\"\n          on-folder-click=\"events.onBreadcrumbClick(file)\"\n          on-name-change=\"events.onNameChange(file)\"\n          readonly=\"!permissions.rename\"\n        ></bi-breadcrumbs>\n      </div>\n    </div>\n\n    <div class=\"bi-dont-shrink\">\n      <quix-meta entity=\"vm.state.value().notebook\" ng-if=\"vm.state.is('Result') || vm.state.after('Result')\"></quix-meta>\n    </div>\n  </div>\n\n  <div class=\"bi-section-controls bi-fade-in\" ng-if=\"(vm.state.is('Result') && permissions.edit) || vm.state.after('Result')\">\n    <div>\n      <div class=\"bi-align bi-s-h bi-fade-in\" ng-if=\"!vm.marked.enabled\">\n        <button\n          class=\"bi-button--primary\"\n          ng-if=\"vm.noteTypes.length === 1\"\n          ng-disabled=\"!permissions.addNote\"\n          ng-click=\"permissions.addNote && events.onNoteAdd(vm.noteTypes[0])\"\n          data-hook=\"notebook-add-note\"\n          tabindex=\"-1\"\n        >\n          <i class=\"bi-icon--sm\">add</i>\n          <span>Add note</span>\n        </button>\n\n        <bi-dropdown\n          ng-if=\"vm.noteTypes.length > 1\"\n          bd-options=\"::{minWidth: 'toggle'}\"\n          readonly=\"!permissions.addNote\"\n        >\n          <bi-toggle>\n            <button\n              class=\"bi-button--primary\"\n              ng-disabled=\"!permissions.addNote\"\n              data-hook=\"notebook-add-note-dropdown\"\n              tabindex=\"-1\"\n            >\n              <i class=\"bi-icon--sm\">add</i>\n              <span>Add note</span>\n              <i class=\"bi-icon--sm\">arrow_drop_down</i>\n            </button>\n          </bi-toggle>\n          \n          <ul class=\"bi-dropdown-menu\">\n            <li\n              ng-repeat=\"type in ::vm.noteTypes\"\n              ng-click=\"permissions.addNote && events.onNoteAdd(type)\"\n              data-hook=\"notebook-add-note\"\n            >{{::type | biToHumanCase}}</li>\n          </ul>\n        </bi-dropdown>\n\n        <button\n          class=\"bi-button bi-fade-in\"\n          ng-if=\"vm.view.hasChanges\"\n          ng-click=\"events.onSave()\"\n          ng-disabled=\"vm.view.saving\"\n        >\n          <i class=\"bi-icon--sm\" ng-click=\"events.onSave()\">save</i>\n          <span>Save changes</span>\n        </button>\n      </div>\n\n      <div class=\"bi-align bi-s-h bi-fade-in\" ng-if=\"vm.marked.enabled\">\n        <quix-actions \n          type=\"note\"\n          context=\"vm.marked.list\"\n          permissions=\"::permissions.bulk\"\n          on-delete=\"events.onMarkedNotesDelete(context)\"\n        ></quix-actions>\n  \n        <span class=\"bi-muted\">{{vm.marked.list.length}} notes selected</span>\n      </div>\n    </div>\n\n    <div>\n      <div class=\"bi-fade-in\" ng-if=\"!vm.marked.enabled\">\n        <quix-actions\n          type=\"notebook\"\n          context=\"vm.state.value().notebook\"\n          permissions=\"::permissions\"\n          quix-actions-options=\"{\n            reverse: true,\n            confirmOnDelete: vm.state.is('Content')\n          }\"\n          on-like-toggle=\"events.onLikeToggle(context)\"\n          on-share=\"events.onShare(context)\"\n          on-clone=\"events.onClone(context)\"\n          on-delete=\"events.onDelete(context)\"\n        ></quix-actions>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"bi-section-content--center\" ng-if=\"vm.state.before('Content')\">\n    <div class=\"bi-empty-state--loading bi-fade-in\" ng-if=\"vm.state.is('Initial')\">\n      <div class=\"bi-empty-state-content\">Loading notebook...</div>\n    </div>\n\n    <div class=\"bi-empty-state bi-fade-in\" ng-if=\"vm.state.is('Error')\" data-hook=\"notebook-error\">\n      <quix-image class=\"bi-empty-state-image\" name=\"error_{{::vm.state.value().error.status}}.svg\"></quix-image>\n      <div class=\"bi-empty-state-header\">{{::vm.state.value().error.message}}</div>\n      <div class=\"bi-empty-state-content\">\n        <a class=\"bi-link\" ng-click=\"events.onGoToRootClick()\">Go to my notebooks</a>\n      </div>\n    </div>\n\n    <div\n      class=\"bi-empty-state bi-s-v bi-fade-in\"\n      ng-if=\"vm.state.is('Result')\"\n      data-hook=\"notebook-empty\"\n    >\n      <quix-image class=\"bi-empty-state-image\" name=\"no_data.svg\"></quix-image>\n\n      <div class=\"bi-empty-state-header\">Notebook is empty</div>\n      <div class=\"bi-empty-state-content bi-s-h--x05\" ng-if=\"permissions.addNote\">\n        <a class=\"bi-link\" ng-click=\"events.onNoteAdd()\">Add note</a>\n      </div>\n    </div>\n  </div>\n\n  <div \n    class=\"quix-note-container bi-section-content--list bi-s-v--x15\"\n    ng-class=\"::{'quix-note-container--editable': !!permissions.note.edit}\"\n    ng-if=\"vm.state.is('Content')\"\n    data-hook=\"notebook-content\"\n    ui-sortable=\"{\n      axis: 'y',\n      handle: '.quix-note-drag-handle',\n      opacity: '0.9',\n      disabled: !permissions.bulk.reorder,\n      stop: events.onNoteReorder\n    }\"\n    ng-model=\"vm.state.value().notes\"\n  >\n    <quix-note\n      class=\"bi-fade-in\"\n      ng-repeat=\"note in vm.state.value().notes track by note.id\"\n      note=\"note\"\n      permissions=\"::permissions.note\"\n      quix-note-options=\"{\n        fold: vm.notes.get(note).fold === null || vm.notes.get(note).fold,\n        focusName: vm.notes.get(note).focusName,\n        focusEditor: !options.isNew,\n      }\"\n      marked=\"!!vm.marked.map[note.id]\"\n      runner=\"runners[note.id]\"\n      has-changes=\"vm.view.hasChanges\"\n      saving=\"vm.view.saving\"\n      on-content-change=\"events.onNoteContentChange(note)\"\n      on-name-change=\"events.onNoteNameChange(note)\"\n      on-share=\"events.onNoteShare(note, params)\"\n      on-clone=\"events.onNoteClone(note)\"\n      on-delete=\"events.onNoteDelete(note)\"\n      on-mark-toggle=\"events.onMarkToggle(note)\"\n      on-save=\"events.onNoteSave()\"\n      on-run=\"events.onNoteRun()\"\n      on-runner-created=\"events.onRunnerCreated(note, runner)\"\n      on-runner-destroyed=\"events.onRunnerDestroyed(note, runner)\"\n      data-hook=\"notebook-note\"\n      bi-scroll-to=\"{{vm.state.value().note.id === note.id}}\"\n    ></quix-note>\n  </div>\n</div>"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook.scss",
    "content": "@import '../../lib/ui/assets/css/def/colors.def';\n\nquix-notebook {\n  .quix-note-container {\n    position: relative;\n\n    &.quix-note-container--editable {\n      padding-left: 8px;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/notebook/notebook.ts",
    "content": "import template from './notebook.html';\nimport './notebook.scss';\n\nimport {initNgScope} from '../../lib/core';\nimport {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IStateComponentConfig} from '../../lib/app/services/plugin-builder';\nimport {cache} from '../../store';\nimport {initEvents} from '../../services/scope';\nimport {IScope} from './notebook-types';\nimport VM from './notebook-vm';\nimport {getRunners} from '../../services';\nimport * as Url from './notebook-url';\nimport * as Scope from './notebook-scope';\nimport * as Events from './notebook-events';\n\nexport default (app: App, store: Store) => ({\n  name: 'notebook:id',\n  template,\n  url: Url,\n  scope: Scope,\n  options: {isNew: false},\n  controller: async (scope: IScope, params, {syncUrl, setTitle}) => {\n    await cache.notebook.fetch(params.id);\n    \n    syncUrl(() => [store.getState('notebook.notes') || []]);\n\n    store.subscribe('notebook', ({notebook, notes, error, queue, view, permissions}) => {\n      scope.notebook = notebook;\n      scope.notes = notes;\n      scope.error = error;\n      scope.queue = queue;\n      scope.view = view;\n      scope.permissions = permissions;\n    }, scope);\n\n    store.subscribe('notebook.notebook.name', name => {\n      setTitle(({stateName}) => [name]);\n    }, scope);\n\n    store.subscribe('notebook.error', error => {\n      if (error) {\n        setTitle(() => ['Error']);\n      }\n    }, scope);\n\n    store.subscribe('app.runners', () => {\n      scope.runners = getRunners();\n    }, scope);\n  },\n  link: scope => {\n    const conf = initNgScope(scope)\n      .withOptions('$stateOptions', {isNew: false})\n      .withVM(VM(app));\n\n    initEvents(scope, conf, app, store, Events);\n  }\n}) as IStateComponentConfig;\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/trash-bin/TrashBinComponent.tsx",
    "content": "import { IDeletedNotebook } from '@wix/quix-shared';\nimport React, { useEffect } from 'react';\nimport {\n  EmptyState,\n  ErrorState,\n  InitialState,\n} from '../../lib/ui/components/states';\nimport { Table } from '../../lib/ui/components/table/Table';\nimport { useViewState } from '../../services/hooks';\nimport { trashBinTableFields } from './trash-bin-table-fields';\n\nexport interface TrashBinProps {\n  deletedNotebooks: IDeletedNotebook[];\n  error: { message: string };\n  onPermanentlyDeleteClicked(deletedNotebook: IDeletedNotebook): void;\n  onRestoreClicked(deletedNotebook: IDeletedNotebook, folderId: string);\n  onEmptyTrashBinClicked();\n}\n\nconst States = ['Initial', 'Error', 'Empty', 'Content'];\n\nexport const TrashBin = (props: TrashBinProps) => {\n  const {\n    deletedNotebooks,\n    error,\n    onPermanentlyDeleteClicked,\n    onRestoreClicked,\n    onEmptyTrashBinClicked,\n  } = props;\n\n  const [stateData, viewState] = useViewState(States, {\n    deletedNotebooks: [],\n    size: 0,\n    totalDeletedNotebooks: 0,\n    errorMessage: '',\n  });\n\n  useEffect(() => {\n    if (error) {\n      viewState.set('Error', { errorMessage: error.message });\n    }\n  }, [error]);\n\n  useEffect(() => {\n    if (!error && deletedNotebooks?.length >= 0) {\n      viewState.set(deletedNotebooks?.length ? 'Content' : 'Empty', {\n        deletedNotebooks: deletedNotebooks || [],\n        size: deletedNotebooks.length || 0,\n      });\n    }\n  }, [deletedNotebooks]);\n\n  const renderContentState = () => (\n    <Table\n      hookName='deleted-notebooks'\n      columns={trashBinTableFields(\n        onPermanentlyDeleteClicked,\n        onRestoreClicked\n      ).map((field) => ({\n        header: field.title || field.name,\n        render: (row) => field.filter(undefined, row),\n        accessor: field.name,\n        className: field.className,\n      }))}\n      data={stateData.deletedNotebooks}\n    />\n  );\n\n  return (\n    <div className='bi-section bi-c-h bi-grow'>\n      <div className='bi-section-header'>\n        <div className='bi-section-title'>\n          <span>\n            Trash Bin\n            {viewState.min('Empty') && (\n              <span className='bi-fade-in'>{' '}({stateData.size})</span>\n            )}\n          </span>\n        </div>\n      </div>\n      {viewState.get() === 'Content' && (\n        <div className='bi-section-controls bi-fade-in'>\n          <div>\n            <button\n              className='bi-button--danger'\n              onClick={onEmptyTrashBinClicked}\n            >\n              <i className=\"bi-icon--sm\">delete_sweep</i>\n              <span>Empty Trash Bin</span>\n            </button>\n          </div>\n        </div>\n      )}\n      <div className='bi-section-content bi-c-h bi-s-v--x15'>\n        {(() => {\n          switch (viewState.get()) {\n            case 'Initial':\n              return <InitialState entityName='deleted notebooks' />;\n            case 'Error':\n              return <ErrorState errorMessage={error.message} />;\n            case 'Empty':\n              return <EmptyState />;\n            case 'Content':\n              return renderContentState();\n            default:\n          }\n        })()}\n      </div>\n    </div>\n  );\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/trash-bin/trash-bin-events.ts",
    "content": "import { Store } from '../../lib/store';\nimport { IDeletedNotebook, TrashBinActions } from '@wix/quix-shared';\nimport { toast } from '../../lib/ui';\nimport { confirmAction, prompt } from '../../services/dialog';\n\nexport const onPermanentlyDeleteClick = (store: Store) => (\n  deletedNotebook: IDeletedNotebook\n) => {\n  confirmAction('delete', 'notebook', deletedNotebook, '', () => {\n    store\n      .logAndDispatch(\n        TrashBinActions.permanentlyDeleteNotebook(deletedNotebook.id)\n      )\n      .then(() => successToast(`Deleted notebook \"${deletedNotebook.name}\".`));\n  });\n};\n\nexport const onEmptyTrashBinClicked = (scope, store: Store) => () => {\n  confirmAction('delete', 'notebook', scope.deletedNotebooks, '', () => {\n    store\n      .dispatchAndLog(\n        scope.deletedNotebooks.map((n) =>\n          TrashBinActions.permanentlyDeleteNotebook(n.id)\n        )\n      )\n      .then(() => successToast(`Trash Bin is empty`));\n  });\n};\n\nexport const onRestoreClick = (scope, store: Store) => (\n  deletedNotebook: IDeletedNotebook\n) => {\n  let restoreFolder = '';\n\n  prompt(\n    {\n      title: 'Restore notebook',\n      subTitle: 'Choose destination folder',\n      yes: 'restore',\n      content: /*html*/ `\n      <quix-destination-picker \n        ng-model=\"model.folder\" \n        context=\"folder\" \n        required=\"true\"\n      ></quix-destination-picker>`,\n      onConfirm: ({ model: { folder } }) => {\n        restoreFolder = folder.name;\n        return store.logAndDispatch(\n          TrashBinActions.restoreDeletedNotebook(deletedNotebook.id, folder.id)\n        );\n      },\n    },\n    scope,\n    { model: { folder: null } }\n  ).then(() =>\n    successToast(`\"${deletedNotebook.name}\" Restored to \"${restoreFolder}.\"`)\n  );\n};\n\nfunction successToast(text: string) {\n  toast.showToast(\n    {\n      text,\n      type: 'success',\n    },\n    3000\n  );\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/trash-bin/trash-bin-table-fields.tsx",
    "content": "import * as React from 'react';\nimport { IDeletedNotebook } from '@wix/quix-shared';\nimport { RowConfig } from '../../lib/ui/components/table/TableRow';\nimport relativeDate from '../../lib/ui/filters/relative-date';\nimport absoluteDate from '../../lib/ui/filters/absolute-date';\n\nexport const trashBinTableFields = (\n  onPermanentlyDeleteClicked,\n  onRestoreClicked\n): RowConfig<IDeletedNotebook>[] => {\n  return [\n    {\n      name: 'name',\n      title: 'Name',\n      filter(_, deletedNotebook: IDeletedNotebook) {\n        return (\n          <div className='bi-align bi-s-h'>\n            <i className='bi-icon bi-muted'>insert_drive_file</i>\n            <span>{deletedNotebook.name}</span>\n          </div>\n        );\n      },\n    },\n    {\n      name: 'dateDeleted',\n      title: 'Date Deleted',\n      filter(_, deletedNotebook: IDeletedNotebook) {\n        return (\n          <div className='bi-align bi-s-h--x05 bi-text--sm bi-muted'>\n            <span>{relativeDate()(deletedNotebook.dateDeleted as any)}</span>\n            <span>({absoluteDate()(deletedNotebook.dateDeleted as any)})</span>\n          </div>\n        );\n      },\n    },\n    {\n      name: '' as any,\n      title: '',\n      filter(_, deletedNotebook: IDeletedNotebook) {\n        return (\n          <div className='bi-justify-right bi-align bi-s-h'>\n            <button\n              className='bi-button--success bi-button--sm bi-s-h'\n              title='Restore Notebook to Folder'\n              onClick={(e) => {\n                e.stopPropagation();\n                onRestoreClicked(deletedNotebook);\n              }}\n            >\n              <i className='bi-icon--xs'>replay</i>\n              <span>Restore</span>\n            </button>\n            <button\n              className='bi-button--danger bi-button--sm bi-s-h'\n              title='Permanently Delete Notebook'\n              onClick={(e) => {\n                e.stopPropagation();\n                onPermanentlyDeleteClicked(deletedNotebook);\n              }}\n            >\n              <i className='bi-icon--xs'>delete_forever</i>\n              <span>Delete</span>\n            </button>\n          </div>\n        );\n      },\n    },\n  ];\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/trash-bin/trash-bin.ts",
    "content": "import { Store } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IReactStateComponentConfig } from '../../lib/app/services/plugin-builder';\nimport { TrashBin, TrashBinProps } from './TrashBinComponent';\nimport { cache } from '../../store';\nimport {\n  onEmptyTrashBinClicked,\n  onPermanentlyDeleteClick,\n  onRestoreClick,\n} from './trash-bin-events';\nimport _noop from 'lodash/noop';\n\nexport default (app: App, store: Store): IReactStateComponentConfig => ({\n  name: 'trashBin',\n  template: TrashBin,\n  url: {},\n  scope: {\n    deletedNotebooks: _noop,\n    error: _noop,\n    onPermanentlyDeleteClicked: _noop,\n    onRestoreClicked: _noop,\n    onEmptyTrashBinClicked: _noop,\n  },\n  controller: async (scope: TrashBinProps, params, { syncUrl, setTitle }) => {\n    syncUrl();\n    setTitle();\n\n    scope.onPermanentlyDeleteClicked = onPermanentlyDeleteClick(store);\n    scope.onRestoreClicked = onRestoreClick(scope, store);\n    scope.onEmptyTrashBinClicked = onEmptyTrashBinClicked(scope, store);\n\n    await cache.deletedNotebooks.fetch(params.id);\n\n    store.subscribe(\n      'deletedNotebooks',\n      ({ deletedNotebooks, error }) => {\n        scope.deletedNotebooks = deletedNotebooks;\n        scope.error = error;\n      },\n      scope\n    );\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/users/UsersComponent.tsx",
    "content": "import React, {useEffect} from 'react';\nimport _ from 'lodash';\nimport {IUser} from '@wix/quix-shared';\nimport {Highlighter} from '../../lib/ui/components/Highlighter';\nimport {Table} from '../../lib/ui/components/table/Table';\nimport {useViewState} from '../../services/hooks';\nimport {usersTableFields} from './users-table-fields';\nimport makePagination from '../../lib/ui/components/hoc/makePagination';\nimport {Input} from '../../lib/ui/components/input/Input';\nimport {FilterInitialState, InitialState, EmptyState, ErrorState} from '../../lib/ui/components/states';\nimport {debounceAsync} from '../../utils';\nimport './users.scss';\n\nexport interface UsersProps {\n  users: IUser[];\n  error: {message: string};\n  onUserClicked(user: IUser): void;\n}\n\nexport const CHUNK_SIZE = 100;\n\nconst PaginatedTable = makePagination(Table);\n\nconst search = debounceAsync((loadMore, { offset, limit, users, emailFilter }) => {\n  return new Promise(res => \n    res(users?.filter(user => user.email.includes(emailFilter)).slice(offset, offset + limit) || [])\n  );\n});\n\nconst States = [\n  'Initial',\n  'Error',\n  'Empty',\n  'Content',\n  'FilterInitial',\n];\n\nexport function Users(props: UsersProps) {\n  const {users: serverUsers, error, onUserClicked} = props;\n  const [stateData, viewState] = useViewState(States, {\n    users: [],\n    size: 0,\n    totalUsers: 0,\n    emailFilter: '',\n    errorMessage: '',\n  });\n\n  useEffect(() => {\n    if (error) {\n      viewState.set('Error', { errorMessage: error.message });\n    }\n  }, [error]);\n\n  useEffect(() => {\n    if (!error) {\n      viewState.set('Initial', {users: serverUsers?.slice(0, CHUNK_SIZE) || []});\n    }\n  },[serverUsers]);\n\n  useEffect(() => {\n    if (viewState.get() !== 'Error' && serverUsers?.length >= 0) {\n      loadMore(0, CHUNK_SIZE + 1)(res => {\n        if (!_.isEqual(res, stateData.users) || viewState.is('Initial') || viewState.is('FilterInitial')) {\n          if (res.length > 0) {\n            viewState.set('Content', {\n              users: res,\n              totalUsers: serverUsers.filter(user => user.email.includes(stateData.emailFilter)).length,\n            });\n          } else {\n            viewState.set('Empty', {\n              users: [],\n              totalUsers: 0,\n              size: 0,\n            });\n          }\n        } else if (stateData.users?.length > 0 && !viewState.is('Content')) {\n          viewState.set('Content');\n        }\n      });\n    }\n  }, [stateData.emailFilter, stateData.users]);\n\n  const highlightQuery = (columnName: string) => (term: string) => {\n    const text = term.replace(/\\s+/g,' ');\n    \n    if (columnName === 'email') {\n      return <Highlighter\n        term={term}\n        filter={stateData.emailFilter}\n      />;\n    }\n\n    return text;\n  }\n\n  const loadMore = (offset: number, limit: number) => {\n    return search(null, {\n      offset,\n      limit,\n      users: serverUsers,\n      emailFilter: stateData.emailFilter,\n    });\n  }\n\n  const renderContentState = () => (\n    <PaginatedTable\n      hookName=\"users\"\n      columns={usersTableFields.map(field => ({\n        header: field.title,\n        render: row => field.filter(undefined, row, 0, highlightQuery(field.name)),\n        accessor: field.name,\n        className: field.className,\n      }))}\n      initialData={stateData.users}\n      loadMore={loadMore}\n      onRowClicked={onUserClicked}\n      paginationSize={CHUNK_SIZE}\n      tableSize={(size) => viewState.update({ size })}\n    />\n  );\n\n  const handleEmailFilterChange = (e) => {\n    if (viewState.get() !== 'Error') {\n      viewState.set('FilterInitial', { emailFilter: e.target.value });\n    }\n  }\n\n  const renderFilter = () => (\n    <div className=\"bi-theme--lighter bi-transparent\">\n      <Input\n        onChange={handleEmailFilterChange}\n        placeholder=\"Filter users by email\"\n        data-hook=\"users-filter-users-input\"\n      />\n    </div>\n  );\n\n  return (\n    <div className=\"bi-section bi-c-h bi-grow\">\n      <div className=\"bi-section-header\">\n        <div className=\"bi-section-title\">\n          <span>Users {viewState.min('Empty') && <span className='bi-fade-in'>({stateData.size} / {stateData.totalUsers})</span>}</span>\n        </div>\n      </div>\n\n      <div className=\"bi-section-content bi-c-h bi-s-v--x15\">\n        {viewState.min('Error') && renderFilter()}\n        {\n          (() => {\n            switch(viewState.get()) {\n              case 'Initial':\n                return <InitialState entityName=\"users\" />;\n              case 'Error':\n                return <ErrorState errorMessage={error.message} />;\n              case 'Empty':\n                return <EmptyState />;\n              case 'Content':\n                return renderContentState();\n              case 'FilterInitial':\n                return <FilterInitialState entityName=\"users\" />;\n              default:\n            }\n          })()\n        }\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/users/users-events.ts",
    "content": "import {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IUser} from '@wix/quix-shared';\n\nexport const onUserClick = (scope, store: Store, app: App) => (user: IUser) => {\n  app.go('files', {id: user.rootFolder});\n};\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/users/users-table-fields.tsx",
    "content": "import * as React from 'react';\nimport {IUser} from '@wix/quix-shared';\nimport biRelativeDate from '../../../src/lib/ui/filters/relative-date';\nimport { HighlightedRowConfig } from '../../lib/ui/components/table/TableRow';\nimport { UserAvatarAndName } from '../../components/User/UserAvatarAndName';\n\nexport const usersTableFields: HighlightedRowConfig<IUser>[] = [\n  {\n    name: 'name',\n    title: 'User',\n    filter(_, user: IUser, index) {\n      return <UserAvatarAndName user={user}></UserAvatarAndName>;\n    }\n  },\n  {\n    name: 'email',\n    title: 'Email',\n    filter(_, user: IUser, index, highlight) {\n      return (\n        <div className=\"bi-align bi-s-h\">\n          <span>{highlight(user.email)}</span>\n        </div>\n      );\n    }\n  },\n  {\n    name: 'dateCreated',\n    title: 'Join Date',\n    filter(_, user: IUser, index) {\n      return (\n        <span className=\"bi-text--sm bi-muted\">\n          {biRelativeDate()(user.dateCreated as any)}\n        </span>\n      );\n    }\n  },\n  {\n    name: 'dateUpdated',\n    title: 'Last Login',\n    filter(_, user: IUser, index) {\n      return (\n        <span className=\"bi-text--sm bi-muted\">\n          {biRelativeDate()(user.dateUpdated as any)}\n        </span>\n      );\n    }\n  }\n];\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/users/users-testkit.ts",
    "content": "import { TableTestkit } from '../../lib/ui/components/table/table-testkit';\n\nconst enum Hooks {\n  Content = 'users-table',\n  FilterUsersInput = 'users-filter-users-input',\n}\n\nexport class UsersTestkit extends TableTestkit {\n\n  usersTableExists = async () => {\n    return (await this.query.hook(Hooks.Content)) !== null;\n  }\n\n  usersFilter = {\n    click: () => {\n      return this.click.hook(Hooks.FilterUsersInput);\n    },\n\n    set: (value: string) => {\n      return this.keyboard.type(Hooks.FilterUsersInput, value);\n    },\n\n    get: () => {\n      return this.evaluate.hook(Hooks.FilterUsersInput, (e: HTMLInputElement) => e.value);\n    },\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/src/state-components/users/users.scss",
    "content": "quix-users {\n  .bi-transparent {\n    background-color: transparent;\n  }\n}"
  },
  {
    "path": "quix-frontend/client/src/state-components/users/users.ts",
    "content": "import {Store} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IReactStateComponentConfig} from '../../lib/app/services/plugin-builder';\nimport {Users, UsersProps} from './UsersComponent';\nimport {cache} from '../../store';\nimport {onUserClick} from './users-events';\n\nexport default (app: App, store: Store): IReactStateComponentConfig => ({\n  name: 'users',\n  template: Users,\n  url: {},\n  scope: {\n    users: () => {},\n    error: () => {},\n    onUserClicked: () => {}\n  },\n  controller: async (scope: UsersProps, params, {syncUrl, setTitle}) => {\n    await cache.users.fetch(params.id);\n\n    syncUrl();\n    setTitle();\n\n    store.subscribe(\n      'users',\n      ({users, error}) => {\n        scope.users = users;\n        scope.error = error;\n      },\n      scope\n    );\n\n    scope.onUserClicked = onUserClick(scope, store, app);\n  },\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/app/app-actions.ts",
    "content": "import {Runner} from '../../lib/runner';\nimport {INotebook, INote} from '@wix/quix-shared';\n\nexport const setInputSearchText = (inputSearchText: string, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.setInputSearchText',\n  inputSearchText,\n  origin\n});\n\nexport const setUrlSearchText = (urlSearchText: string, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.setUrlSearchText',\n  urlSearchText,\n  origin\n});\n\nexport const setSearchPage = (searchPage: number, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.setSearchPage',\n  searchPage,\n  origin\n});\n\nexport const setImportType = (importType: string, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.setImportType',\n  importType,\n  origin\n});\n\nexport const setImportValue = (importValue: string, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.setImportValue',\n  importValue,\n  origin\n});\n\nexport const addRunner = (id: string, runner: Runner, note: INote, notebook: INotebook, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.addRunner',\n  id,\n  origin,\n  runner,\n  note,\n  notebook\n})\n\nexport const removeRunner = (id: string, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'app.removeRunner',\n  id,\n  origin\n});\n\nexport const setStats = (stats: { trashBinCount: number }) => ({\n  type: 'app.setStats',\n  stats,\n});"
  },
  {
    "path": "quix-frontend/client/src/store/app/app-branch.ts",
    "content": "import { IBranch } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { Middleware } from 'redux';\n\nimport * as Runners from '../../services/runners';\nimport { DeletedNotebookActionTypes } from '@wix/quix-shared';\n\nexport interface IApp {\n  searchPage?: number;\n  inputSearchText?: string;\n  urlSearchText?: string;\n  runners?: Record<string, any>;\n  stats: { trashBinCount: number };\n  import: {\n    type?: string;\n    value?: string;\n  };\n}\n\nexport default (app: App): IBranch<IApp> => (register) => {\n  const runnerMiddleware: Middleware = () => (next) => (action: any) => {\n    switch (action.type) {\n      case 'app.addRunner':\n        Runners.addRunner(\n          app,\n          null,\n          action.id,\n          action.runner,\n          action.note,\n          action.notebook\n        );\n        break;\n      case 'app.removeRunner':\n        Runners.removeRunner(action.id);\n        break;\n      default:\n    }\n\n    return next(action);\n  };\n\n  const appReducer = (\n    state: IApp = {\n      runners: {},\n      import: {},\n      stats: { trashBinCount: 0 },\n    },\n    action\n  ): IApp => {\n    switch (action.type) {\n      case 'app.setSearchPage':\n        return { ...state, searchPage: action.searchPage };\n      case 'app.setInputSearchText':\n        return { ...state, inputSearchText: action.inputSearchText };\n      case 'app.setUrlSearchText':\n        if (action.urlSearchText !== state.urlSearchText) {\n          return {\n            ...state,\n            urlSearchText: action.urlSearchText,\n            inputSearchText:\n              action.origin === 'machine'\n                ? action.urlSearchText\n                : state.inputSearchText,\n          };\n        }\n        break;\n      case 'app.setImportType':\n        return {\n          ...state,\n          import: { ...state.import, type: action.importType },\n        };\n      case 'app.setImportValue':\n        return {\n          ...state,\n          import: { ...state.import, value: action.importValue },\n        };\n      case 'app.setStats':\n        return { ...state, stats: { ...action.stats } };\n      case DeletedNotebookActionTypes.createDeletedNotebook:\n        return {\n          ...state,\n          stats: {\n            ...state.stats,\n            trashBinCount: state.stats.trashBinCount + 1,\n          },\n        };\n      case DeletedNotebookActionTypes.deleteDeletedNotebook:\n      case DeletedNotebookActionTypes.restoreDeletedNotebook:\n        return {\n          ...state,\n          stats: {\n            ...state.stats,\n            trashBinCount: state.stats.trashBinCount - 1,\n          },\n        };\n      case 'app.addRunner':\n      case 'app.removeRunner':\n        return { ...state, runners: {} }; // just to trigger subscribers\n      default:\n    }\n\n    return state;\n  };\n\n  register(appReducer, runnerMiddleware);\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/db/db-actions.ts",
    "content": "export const setDb = (db: any[], origin: 'user' | 'machine' = 'machine') => ({\n  type: 'db.set',\n  db,\n  origin\n});\n\nexport const setError = (error: any, origin: 'user' | 'machine' = 'machine') => ({\n  type: 'db.setError',\n  error,\n  origin\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/db/db-branch.ts",
    "content": "import {combineReducers} from 'redux';\nimport {IBranch} from '../../lib/store';\nimport {App} from '../../lib/app';\n\nexport default (app: App): IBranch => register => {\n  function db(state: any[] = null, action) {\n    switch (action.type) {\n      case 'db.set':\n        return action.db;\n      default:\n    }\n\n    return state;\n  }\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'db.set':\n        return null;\n      case 'db.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  }\n\n  register(combineReducers({db, error}));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/db/db-cache.ts",
    "content": "import {StoreCache} from '../../lib/store';\nimport {setDb, setError} from './db-actions';\nimport {db} from '../../services/resources';\n\nexport default store => new StoreCache<any>(store, 'db.db')\n  .cacheWith(setDb)\n  .catchWith(setError)\n  .fetchWith(db);\n"
  },
  {
    "path": "quix-frontend/client/src/store/deleted-notebook/deleted-notebook-actions.ts",
    "content": "import { IDeletedNotebook } from '@wix/quix-shared';\n\nexport const setDeletedNotebooks = (deletedNotebooks: IDeletedNotebook[]) => ({\n  type: 'deletedNotebooks.set',\n  deletedNotebooks\n});\n\nexport const setError = (error: any) => ({\n  type: 'deletedNotebooks.setError',\n  error\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/deleted-notebook/deleted-notebook-branch.ts",
    "content": "import { combineReducers } from 'redux';\nimport { IBranch } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport {\n  composeReducers,\n  IDeletedNotebook,\n  clientDeletedNotebookReducer,\n} from '@wix/quix-shared';\n\nexport default (app: App): IBranch => (register) => {\n  const deletedNotebooks = composeReducers(\n    clientDeletedNotebookReducer,\n    (state: IDeletedNotebook[] = [], action: any) => {\n      switch (action.type) {\n        case 'deletedNotebooks.set':\n          return action.deletedNotebooks;\n        default:\n      }\n\n      return state;\n    }\n  );\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'deletedNotebooks.set':\n        return null;\n      case 'deletedNotebooks.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  };\n\n  register(combineReducers({ deletedNotebooks, error }));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/deleted-notebook/deleted-notebook-cache.ts",
    "content": "import { StoreCache } from '../../lib/store';\nimport { IDeletedNotebook } from '@wix/quix-shared';\nimport { setDeletedNotebooks, setError } from './deleted-notebook-actions';\nimport { deletedNotebooks } from '../../services/resources';\n\n\n\nexport default store => new StoreCache<IDeletedNotebook>(store, 'deletedNotebooks.deletedNotebooks')\n  .cacheWith(setDeletedNotebooks)\n  .catchWith(setError)\n  .fetchWith(deletedNotebooks);\n"
  },
  {
    "path": "quix-frontend/client/src/store/favorites/favorites-actions.ts",
    "content": "import {IFile} from '@wix/quix-shared';\n\nexport const setFavorites = (favorites: IFile[]) => ({\n  type: 'favorites.set',\n  favorites\n});\n\nexport const setError = (error: any) => ({\n  type: 'favorites.setError',\n  error\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/favorites/favorites-branch.ts",
    "content": "import {combineReducers} from 'redux';\nimport {IBranch} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IFile, composeReducers, clientFileListReducer} from '@wix/quix-shared';\n\nexport default (app: App): IBranch => register => {\n  const favorites = composeReducers(\n    clientFileListReducer,\n    (state: IFile[] = null, action: any) => {\n    switch (action.type) {\n      case 'favorites.set':\n        return action.favorites;\n      default:\n    }\n\n    return state;\n  });\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'favorites.set':\n        return null;\n      case 'favorites.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  }\n\n  register(combineReducers({favorites, error}));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/favorites/favorites-cache.ts",
    "content": "import {StoreCache} from '../../lib/store';\nimport {setFavorites, setError} from './favorites-actions';\nimport {favorites} from '../../services/resources';\nimport {IFile} from '@wix/quix-shared';\n\nexport default store => new StoreCache<IFile[]>(store, 'favorites.favorites')\n  .cacheWith(setFavorites)\n  .catchWith(setError)\n  .fetchWith(favorites);\n"
  },
  {
    "path": "quix-frontend/client/src/store/files/files-actions.ts",
    "content": "import {IFile} from '@wix/quix-shared';\n\nexport const setFiles = (files: IFile[]) => ({\n  type: 'files.set',\n  files\n});\n\nexport const setError = (error: any) => ({\n  type: 'files.setError',\n  error\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/files/files-branch.ts",
    "content": "import {combineReducers} from 'redux';\nimport {IBranch} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {\n  IFolder,\n  clientFileListReducer,\n  composeReducers,\n} from '@wix/quix-shared';\n\nexport interface IPermissions {\n  edit: boolean;\n}\n\nexport default (app: App): IBranch => register => {\n  const files = composeReducers(\n    (state: IFolder = null, action: any) => {\n      switch (action.type) {\n        case 'files.set':\n          return action.files;\n        default:\n      }\n  \n      return state;\n    },\n    clientFileListReducer,\n  );\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'files.set':\n        return null;\n      case 'files.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  }\n\n  register(combineReducers({files, error}));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/files/files-cache.ts",
    "content": "import {StoreCache} from '../../lib/store';\nimport {setFiles, setError} from './files-actions';\nimport {files} from '../../services/resources';\nimport {IFile} from '@wix/quix-shared';\n\nexport default store => new StoreCache<IFile[]>(store, 'files.files')\n  .cacheWith(setFiles)\n  .catchWith(setError)\n  .fetchWith(files);\n"
  },
  {
    "path": "quix-frontend/client/src/store/folder/folder-actions.ts",
    "content": "import {IFile, IFolder} from '@wix/quix-shared';\n\nexport const setFolder = (folder: IFolder) => ({\n  type: 'folder.set',\n  folder\n});\n\nexport const setError = (error: any) => ({\n  type: 'folder.setError',\n  error\n});\n\nexport const setFileError = (error: any) => ({\n  type: 'folder.view.setFileError',\n  error\n});\n\nexport const toggleMark = (file: IFile) => ({\n  type: 'folder.view.toggleMark',\n  file\n});\n\nexport const unmarkAll = () => ({\n  type: 'folder.view.unmarkAll'\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/folder/folder-branch.ts",
    "content": "import {values, reject} from 'lodash';\nimport {combineReducers} from 'redux';\nimport {IBranch} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {\n  IFile,\n  IFolder,\n  NotebookActionTypes,\n  FileActionTypes,\n  clientFileReducer,\n  clientFileListReducer,\n  composeReducers\n} from '@wix/quix-shared';\n\nimport {getFolderPermissions, getDefaultPermissions, IPermissions} from '../../services';\n\nexport interface IView {\n  markedMap: Record<string, IFile>;\n  markedList: IFile[];\n}\n\nexport default (app: App): IBranch => register => {\n  const folder = composeReducers(\n    clientFileReducer,\n    (state: IFolder = null, action: any) => {\n      switch (action.type) {\n        case 'folder.set':\n          return action.folder;\n        default:\n      }\n  \n      return state;\n    },\n  );\n\n  const files = composeReducers(\n    clientFileListReducer,\n    (state: IFile[] = null, action: any) => {\n      switch (action.type) {\n        case 'folder.set':\n          return action.folder && action.folder.files;\n        case FileActionTypes.moveFile:\n        case NotebookActionTypes.moveNotebook:\n          return state && reject(state, {id: action.id});\n        default:\n      }\n  \n      return state;\n    },\n  );\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'folder.set':\n        return null;\n      case 'folder.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  }\n\n  const view = (state: IView = {\n    markedMap: {},\n    markedList: []\n  }, action: any): IView => {\n    switch (action.type) {\n      case 'folder.set':\n      case 'folder.view.unmarkAll':\n        return {\n          markedMap: {},\n          markedList: []\n        };\n      case FileActionTypes.deleteFile:\n      case NotebookActionTypes.deleteNotebook:\n        // tslint:disable-next-line: no-dynamic-delete\n        delete state.markedMap[action.id];\n        return {...state, markedList: values<IFile>(state.markedMap).filter(n => !!n)};  \n      case 'folder.view.toggleMark':\n        state.markedMap[action.file.id] = state.markedMap[action.file.id] ? undefined : action.file;\n        return {...state, markedList: values<IFile>(state.markedMap).filter(f => !!f)};\n      default:\n    }\n\n    return state;\n  }\n\n  const permissions = (state: IPermissions = getDefaultPermissions(), action: any): IPermissions => {\n    switch (action.type) {\n      case 'folder.set':\n        return action.folder ? getFolderPermissions(app, action.folder) : getDefaultPermissions();\n      default:\n    }\n\n    return state;\n  }\n\n  register(combineReducers({folder, files, error, view, permissions}));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/folder/folder-cache.ts",
    "content": "import {StoreCache} from '../../lib/store';\nimport {IFolder, createFolderPayload} from '@wix/quix-shared';\nimport {setFolder, setError} from './folder-actions';\nimport * as Resources from '../../services/resources';\nimport {createQuixFolder} from '../../data';\nimport {QuixFolder} from '../../config';\n\nexport default store => new StoreCache<IFolder>(store, 'folder.folder')\n  .cacheWith(setFolder)\n  .catchWith(setError)\n  .fetchWith(id =>  {\n    if (id) {\n      if (id === QuixFolder.id) {\n        return Promise.resolve(createQuixFolder());\n      }\n\n      return Resources.folder(id);\n    }\n    \n    return Resources.files().then(files => {\n      const root = files.find(file => !file.path.length);\n      const children = files.filter(file => file.path.length === 1);\n\n      return createFolderPayload([], {\n        ...root,\n        files: children\n      });\n    });\n  });\n"
  },
  {
    "path": "quix-frontend/client/src/store/history/history-actions.ts",
    "content": "import { IHistory } from '@wix/quix-shared';\n\nexport const setHistory = (history: IHistory[]) => ({\n  type: 'history.set',\n  history\n});\n\nexport const setError = (error: any) => ({\n  type: 'history.setError',\n  error\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/history/history-branch.ts",
    "content": "import { combineReducers } from 'redux';\nimport { IBranch } from '../../lib/store';\nimport { App } from '../../lib/app';\nimport { IHistory } from '@wix/quix-shared';\n\nexport default (app: App): IBranch => register => {\n  const history = (state: IHistory[] = null, action: any) => {\n    switch (action.type) {\n      case 'history.set':\n        return action.history;\n      default:\n    }\n\n    return state;\n  };\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'history.set':\n        return null;\n      case 'history.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  };\n\n  register(combineReducers({ history, error }));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/history/history-cache.ts",
    "content": "import { StoreCache } from '../../lib/store';\nimport { setHistory, setError } from './history-actions';\nimport { history } from '../../services/resources';\nimport { IHistory } from '@wix/quix-shared';\n\nexport default store =>\n  new StoreCache<IHistory[]>(store, 'history.history')\n    .cacheWith(setHistory)\n    .catchWith(setError)\n    .fetchWith(history);\n"
  },
  {
    "path": "quix-frontend/client/src/store/index.ts",
    "content": "import { Store } from '../lib/store';\nimport { IEntity } from '@wix/quix-shared';\nimport { default as app } from './app/app-branch';\nimport { default as notebook } from './notebook/notebook-branch';\nimport { default as deletedNotebooks } from './deleted-notebook/deleted-notebook-branch';\nimport { default as notebookCache } from './notebook/notebook-cache';\nimport { default as deletedNotebooksCache } from './deleted-notebook/deleted-notebook-cache';\nimport { default as files } from './files/files-branch';\nimport { default as foldersCache } from './files/files-cache';\nimport { default as db } from './db/db-branch';\nimport { default as dbCache } from './db/db-cache';\nimport { default as folder } from './folder/folder-branch';\nimport { default as folderCache } from './folder/folder-cache';\nimport { default as users } from './users/users-branch';\nimport { default as usersCache } from './users/users-cache';\nimport { default as history } from './history/history-branch';\nimport { default as historyCache } from './history/history-cache';\nimport { default as favorites } from './favorites/favorites-branch';\nimport { default as favoritesCache } from './favorites/favorites-cache';\n\nexport const branches = {\n  app,\n  users,\n  history,\n  notebook,\n  deletedNotebooks,\n  files,\n  db,\n  folder,\n  favorites\n};\n\nexport let cache = null;\nexport const initCache = (store: Store) => {\n  cache = {\n    users: usersCache(store),\n    history: historyCache(store),\n    notebook: notebookCache(store),\n    deletedNotebooks: deletedNotebooksCache(store),\n    files: foldersCache(store),\n    db: dbCache(store),\n    folder: folderCache(store),\n    favorites: favoritesCache(store)\n  };\n};\n\nexport const waitForEntity = (\n  scope,\n  store: Store,\n  id: string,\n  entity: string\n) =>\n  new Promise<IEntity>((resolve, reject) => {\n    const unsubscribe = store.subscribe(\n      `${entity}`,\n      state => {\n        if (\n          (state[entity] && (!id || state[entity].id === id)) ||\n          state.error\n        ) {\n          if (unsubscribe) {\n            unsubscribe();\n          }\n\n          return state[entity] ? resolve(state[entity]) : reject(state.error);\n        }\n      },\n      scope\n    );\n  });\n\n\n"
  },
  {
    "path": "quix-frontend/client/src/store/notebook/notebook-actions.ts",
    "content": "import {INotebook, INote} from '@wix/quix-shared';\n\nexport const setNotebook = (notebook: INotebook) => ({\n  type: 'notebook.set',\n  notebook\n});\n\nexport const setError = (error: any) => ({\n  type: 'notebook.setError',\n  error\n});\n\nexport const queueNote = (note: INote) => ({\n  type: 'notebook.queue.note',\n  note\n});\n\nexport const setNote = (note: INote) => ({\n  type: 'notebook.view.setNote',\n  note\n});\n\nexport const toggleMark = (note: INote) => ({\n  type: 'notebook.view.toggleMark',\n  note\n});\n\nexport const unmarkAll = () => ({\n  type: 'notebook.view.unmarkAll'\n});\n\nexport const setSaving = (saving: boolean) => ({\n  type: 'notebook.view.setSaving',\n  saving\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/notebook/notebook-branch.ts",
    "content": "import {values} from 'lodash';\nimport {combineReducers} from 'redux';\nimport {IBranch} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {\n  INotebook,\n  INote,\n  composeReducers,\n  clientNotebookReducer,\n  noteListReducer,\n  NoteActionTypes\n} from '@wix/quix-shared';\n\nimport {getNotebookPermissions, getDefaultPermissions, IPermissions} from '../../services';\n\nexport interface IQueue {\n  notes: Record<string, INote>;\n  size: number;\n}\n\nexport interface IView {\n  markedMap: Record<string, INote>;\n  markedList: INote[];\n  note: INote;\n  saving: boolean;\n}\n\nexport default (app: App): IBranch => register => {\n  const notebook = composeReducers(\n    clientNotebookReducer,\n    (state: INotebook = null, action: any) => {\n      switch (action.type) {\n        case 'notebook.set':\n          return action.notebook;\n        default:\n      }\n  \n      return state;\n    },\n  );\n\n  const notes = composeReducers(\n    noteListReducer,\n    (state: INote[] = [], action: any) => {\n      switch (action.type) {\n        case 'notebook.set':\n          return action.notebook ? action.notebook.notes : [];\n        default:\n      }\n  \n      return state;\n    },\n  );\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'notebook.set':\n        return null;\n      case 'notebook.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  }\n\n  const queue = (state: IQueue = {notes: {}, size: 0}, action: any): IQueue => {\n    switch (action.type) {\n      case 'notebook.queue.note':\n        state.notes = {...state.notes, [action.note.id]: action.note};\n        return {...state, size: Object.keys(state.notes).length};\n      case NoteActionTypes.updateContent:\n      case NoteActionTypes.deleteNote:\n        // tslint:disable-next-line: no-dynamic-delete\n        delete state.notes[action.id];\n        return {...state, size: Object.keys(state.notes).length};\n      default:\n    }\n\n    return state;\n  }\n\n  const view = (state: IView = {\n    markedMap: {},\n    markedList: [],\n    note: null,\n    saving: false,\n  }, action: any): IView => {\n    switch (action.type) {\n      case 'notebook.set':\n        return {\n          markedMap: {},\n          markedList: [],\n          note: null,\n          saving: false,\n        };\n      case 'notebook.view.unmarkAll':\n        return {\n          ...state, \n          markedMap: {},\n          markedList: []\n        };\n      case NoteActionTypes.deleteNote:\n        // tslint:disable-next-line: no-dynamic-delete\n        delete state.markedMap[action.id];\n        return {...state, markedList: values<INote>(state.markedMap).filter(n => !!n)};\n      case 'notebook.view.toggleMark':\n        state.markedMap[action.note.id] = state.markedMap[action.note.id] ? undefined : action.note;\n        return {...state, markedList: values<INote>(state.markedMap).filter(n => !!n)};\n      case 'notebook.view.setNote':\n        return {...state, note: action.note};\n      case 'notebook.view.setSaving':\n        return {...state, saving: action.saving};\n      default:\n    }\n\n    return state;\n  }\n\n  const permissions = (state: IPermissions = {\n    edit: false\n  }, action: any): IPermissions => {\n    switch (action.type) {\n      case 'notebook.set':\n        return action.notebook ? getNotebookPermissions(app, action.notebook) : getDefaultPermissions();\n      default:\n    }\n\n    return state;\n  }\n\n  register(combineReducers({notebook, notes, error, queue, view, permissions}));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/notebook/notebook-cache.ts",
    "content": "import {StoreCache} from '../../lib/store';\nimport {INotebook} from '@wix/quix-shared';\nimport {setNotebook, setError} from './notebook-actions';\nimport {notebook} from '../../services/resources';\nimport {createExamplesNotebook} from '../../data';\nimport {ExamplesNotebook} from '../../config';\n\nexport default store => new StoreCache<INotebook>(store, 'notebook.notebook')\n  .cacheWith(setNotebook)\n  .catchWith(setError)\n  .fetchWith(id => {\n    return id === ExamplesNotebook.id ? Promise.resolve(createExamplesNotebook()) : notebook(id)\n  });\n"
  },
  {
    "path": "quix-frontend/client/src/store/users/users-actions.ts",
    "content": "import {IUser} from '@wix/quix-shared';\n\nexport const setUsers = (users: IUser[]) => ({\n  type: 'users.set',\n  users\n});\n\nexport const setError = (error: any) => ({\n  type: 'users.setError',\n  error\n});\n"
  },
  {
    "path": "quix-frontend/client/src/store/users/users-branch.ts",
    "content": "import {combineReducers} from 'redux';\nimport {IBranch} from '../../lib/store';\nimport {App} from '../../lib/app';\nimport {IUser} from '@wix/quix-shared';\n\nexport default (app: App): IBranch => register => {\n  const users = (state: IUser[] = null, action: any) => {\n    switch (action.type) {\n      case 'users.set':\n        return action.users;\n      default:\n    }\n\n    return state;\n  };\n\n  const error = (state: any = null, action: any) => {\n    switch (action.type) {\n      case 'users.set':\n        return null;\n      case 'users.setError':\n        return action.error;\n      default:\n    }\n\n    return state;\n  }\n\n  register(combineReducers({users, error}));\n};\n"
  },
  {
    "path": "quix-frontend/client/src/store/users/users-cache.ts",
    "content": "import {StoreCache} from '../../lib/store';\nimport {setUsers, setError} from './users-actions';\nimport {users} from '../../services/resources';\nimport {IUser} from '@wix/quix-shared';\n\nexport default store => new StoreCache<IUser[]>(store, 'users.users')\n  .cacheWith(setUsers)\n  .catchWith(setError)\n  .fetchWith(users);\n"
  },
  {
    "path": "quix-frontend/client/src/types.ts",
    "content": "\n"
  },
  {
    "path": "quix-frontend/client/src/utils.ts",
    "content": "import { inject } from './lib/core';\n\nexport const singletone = () => {\n  let state: any[] = null;\n  \n  const instance = (getter?: (...args: any) => any, ...args) => {\n    if (typeof getter === 'undefined') {\n      return state;\n    }\n\n    if (typeof getter !== 'function') {\n      state = getter ? [getter, ...args] : null;\n      return instance;\n    }\n\n    if (state) {\n      const res = getter(...state);\n\n      if (res === null) {\n        state = null;\n      }\n\n      return res;\n    }\n\n    return instance;\n  }\n\n  return instance;\n}\n\nexport const debounceAsync = (req: Function, __id = 0) => \n    (...args) => \n      (res: Function, ___id = ++__id) => \n        inject('$timeout')(() => \n          __id === ___id && req(...args).then(dres => \n            __id === ___id && res(dres))\n        , 300);"
  },
  {
    "path": "quix-frontend/client/test/dev/localhost.crt",
    "content": "\n-----BEGIN CERTIFICATE-----\nMIIC5TCCAc2gAwIBAgIJALRUBBqde2FDMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV\nBAMMCWxvY2FsaG9zdDAeFw0xODA2MTgxMzIyMjZaFw0xODA3MTgxMzIyMjZaMBQx\nEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBALmkjGjRgddZIED9xl0qMWdVL6zEsQIFlr1XqsQcKfYLjY2HsT9z1N8mc1C8\n7dKqFwTKya6dC9PmLhJsE3Q1+kdNRDiDJMJEL+FZVZAK6q8qZMRRYw3XORgcQ5KG\nkArgZXcg+1IHTpM8SXx7h9dkngvneUXlkK8Ou0B0ZcrYG4P7smB+/+QtHOtyLhUM\nAQ9vciYFMpTvRfjx0ezgnP08+q8QaShIu5nk67TkL+FtwKAzSvcnr3Usm6xkOgsP\nnPQcWTY6l8SocDMrifcxsF+f0Js9Ak0f4FcGccr0aCCsZEmBsUoyFTOnFjsjNDyB\nii9+6OLcJoLUFUumxIXGCc0UZJcCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo\nb3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B\nAQsFAAOCAQEAejf4ByF2KYjUCDGzfqIZ3+iPJQenrG3JfOZNXv6Pet1+WlP10cX5\nesPrxI9kHl9JXMgR5KCis2bUm8psxZvdY3G8Y9lEZ1QCIM2ANQSqeu7MuJKwzqjn\nxDz8gAPPanLUjoVW8LXhovPmrJ13XVqyH1uVQnzGacfoun3fBTh3yLPjftLQ281M\nfl/VhCXZciqe7HkvRoReLfphyg9BccSdPREOcoIDDY2b9dvQ9ZjX5LlK3XcruxyR\nxkLf1SFBm27mqOuke6Tq2C/aitWPE+qZ10WvmyCSyshT38Bg6RVE3ioWfMEKwMPx\n2FfMXWaYgyfeXpwIVPuu7TbFiIRIZ7PNUQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "quix-frontend/client/test/dev/localhost.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAuaSMaNGB11kgQP3GXSoxZ1UvrMSxAgWWvVeqxBwp9guNjYex\nP3PU3yZzULzt0qoXBMrJrp0L0+YuEmwTdDX6R01EOIMkwkQv4VlVkArqrypkxFFj\nDdc5GBxDkoaQCuBldyD7UgdOkzxJfHuH12SeC+d5ReWQrw67QHRlytgbg/uyYH7/\n5C0c63IuFQwBD29yJgUylO9F+PHR7OCc/Tz6rxBpKEi7meTrtOQv4W3AoDNK9yev\ndSybrGQ6Cw+c9BxZNjqXxKhwMyuJ9zGwX5/Qmz0CTR/gVwZxyvRoIKxkSYGxSjIV\nM6cWOyM0PIGKL37o4twmgtQVS6bEhcYJzRRklwIDAQABAoIBAQCYdsvaSjaY5lnX\nBpUjbsOkWhINknzNbEmgt59H8NmFeXeIBSlNM5RgsPOEG6Y2nfrJtMJu5gwQu7qa\n5qgTiUFDzfF5eDt4UQgBy5y58D1OH0Mi+LShaWE6q/vTGzCxvhmW/T9q3xVpVtoD\nonCuNbSXkkPHZAKvwymGhhITxejTOzw++wYjKgcSiXAf5X8NWlDgm+EBW9yGYpth\n7G5yOJRJBG33nC74rFW7akMX2R6x6iMEaWhp0E9S4qJsYesGEFF830v2b1vu94e6\nNYMGmlHMiCrgn8XdT+e5vWprVe9dB5zKktduzW6hC2l+i3KXIi0Jt5qKYMGSojIp\nmvbT9SgBAoGBAPA3zOXCAbd+VViyxDrDB/nt9zeKUPkBsJxMppijPC08y7arBP4Z\nwRFA9CYrX+OxKa/Hw8JDM79YyL9XN26Y6xjKQTFDYKeztrhyb6wfUExRzY+NlsnK\nZRTfK7EK9yVzN80Wo2axOY/i+8ZrMoCJn5l//DrgN+oMEyoHnOhQiYXxAoGBAMXW\n2pAYzvZWNEJ3fEnckaMp1uBrbqwUezBt9qq2Wt+z5q4/HmuEk3/bbvrJGN3LYXpk\nmeV+aTd6oyPgkg7QGp0zbaOWAHdiJDJiraKOtMQGpfoDD8EG5ThY4wakxiozLGTg\nOs9gdtI5IjQ9HmeK/IM60vaVixDTWDkHYeY1tmsHAoGBALU6M+AGzMrFidgADmES\nsJrS+BazyEEEEFzqyykOxaCPZFUskvitL2Y37bo6MP6TsxKFkF+n2Yt7jQAl6ZEL\n1xn9xM9IuMvsnmZrF2rwuODLOl0aAe+9PSNQ9yJ7VlevpCKa+K3J+NZf9XkNeK1W\npszkrMMyU5zEfVTRJ4Rw9j/RAoGAFUB/OftwQAYClyE+uLB49I4KBxGDUfjhQtKN\nLMlp+Z3Zqd4d5m7XaWSpB0eS5EB0uDEWVxC9PLhvzerRxcWVFk3v+SKj6i8gtEjl\nXhD2Whhcu/6YMqQK+4KQ4KXSo7XbjvqHVr+GBA8fHX1zRqwnc/FduB9YUPZjA71H\nRvN+JQECgYAHwwB7dgyRiZkBWwpGsMsfcvS9tf1G0x5LNwr582YyXJ4M+3jb6tlY\nwnjSmC8kU0Mbun+4h6NWAbsnCLfTRqFw94r5fwvaShEHX2lpQbQ/1oEBXejbacPU\nKgxwOLxShe6nmZ7LHm0+CnDqK4GzOayXxIdgbiL53JPTjuG+eQft0w==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "quix-frontend/client/test/dev/server.ts",
    "content": "import express from 'express';\nimport request from 'request';\nimport http from 'http';\nimport { renderVM } from './vm';\nimport { mock, reset } from '../mocks';\nimport expressWs from 'express-ws';\nimport {setupMockWs, setupSubscriptionMockWs} from './websocket-mock';\n\nconst proxyBaseUrl = 'http://localhost:3000';\n\nexport function start(port = process.env.PORT || '3000') {\n  const app = express();\n  const server = http.createServer(app);\n  expressWs(app, server);\n\n  app.use(express.json());\n\n  app.post('/mock/pattern', (req, res) => {\n    const { pattern, payload, options } = req.body;\n    mock(pattern, payload, options);\n\n    res.status(200).send('OK');\n  });\n\n  app.get('/mock/reset', (req, res) => {\n    reset();\n\n    res.status(200).send('OK');\n  });\n\n  setupMockWs(app);\n  setupSubscriptionMockWs(app);\n\n  app.all('/api/*', async (req, res) => {\n    if (port === '3000' || port === '3100') {\n      const [status, payload] = await mock(req.path);\n\n      res.status(status).json(payload);\n    } else {\n      const url = proxyBaseUrl + req.url;\n      req.pipe(request[req.method.toLowerCase()](url)).pipe(res);\n    }\n  });\n\n  app.get('/', (req, res) => {\n    const quixConfig = {\n      modules: [\n        {\n          id: 'presto',\n          name: 'presto',\n          components: { db: {}, note: {} },\n          engine: 'presto',\n          syntax: 'presto'\n        },\n        {\n          id: 'athena',\n          name: 'athena',\n          components: { db: {}, note: {} },\n          engine: 'athena',\n          syntax: 'presto'\n        },\n        {\n          id: 'python',\n          name: 'athena',\n          components: { note: {} },\n          engine: 'python',\n          syntax: 'python'\n        }\n      ],\n      auth: { googleClientId: '' },\n      clientTopology: {\n        executeBaseUrl: `localhost:${port}/mock`,\n        staticsBaseUrl: '//localhost:3200/',\n        apiBasePath: ''\n      },\n      mode: { debug: true, demo: false }\n    };\n    res.send(\n      renderVM('./src/index.vm', {\n        quixConfig: JSON.stringify(quixConfig, null, 2)\n      })\n    );\n  });\n\n  return server.listen(port, () => {\n    console.info(`Fake server is running on port ${port}`);\n  });\n}\n"
  },
  {
    "path": "quix-frontend/client/test/dev/vm.ts",
    "content": "import * as fs from 'fs';\nimport {Engine} from 'velocity';\n\nfunction loadData(file) {\n  try {\n    return JSON.parse(fs.readFileSync(file, 'utf-8').toString());\n  } catch (ex) {\n    throw ex;\n  }\n}\n\nexport function renderVM(template, data) {\n  const engine = new Engine({template});\n  const velocityData = loadData('./velocity.data.json');\n  const velocityDataPrivate = loadData('./velocity.private.data.json');\n\n  return engine.render({...velocityData, ...velocityDataPrivate, ...data});\n}\n"
  },
  {
    "path": "quix-frontend/client/test/dev/websocket-mock.ts",
    "content": "import * as WebSocket from 'ws';\nimport {Router, Application} from 'express';\nimport {MockNoteContent} from '../mocks'\nconst successEvents = [\n  {event:'start',data:{id:'d85eed1e-fec8-4f1c-abba-5ab8593ea46b', 'numOfQueries':1}},\n  {event:'query-start',data:{id:'20190507_155320_00041_s9xam'}},\n  {event:'query-details',data:{id:'20190507_155320_00041_s9xam', code: 'first query'}},\n  {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':0}},\n  {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':0}},\n  {event:'fields',data:{id:'20190507_155320_00041_s9xam','fields':['date_created','num','category']}},\n\n  {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':30}},\n\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-01',100,'A']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-02',100,'A']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',200,'A']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',100,'A']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-04',250,'A']}},\n\n  {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':60}},\n\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-01',150,'B']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-02',150,'B']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',250,'B']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',150,'B']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-04',250,'B']}},\n\n  {event:'percentage',data:{id:'20190507_155320_00041_s9xam','percentage':100}},\n\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-01',120,'C']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-02',120,'C']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',220,'C']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-03',120,'C']}},\n  {event:'row',data:{id:'20190507_155320_00041_s9xam',values:['2019-01-04',220,'C']}},\n\n  {event: 'log', data: {id: '20190507_155320_00041_s9xa', level: 'INFO', line: 'INFO message'}},\n  {event: 'log', data: {id: '20190507_155320_00041_s9xa', level: 'ERROR', line: 'ERROR message'}},\n\n  {event:'query-end',data:{id:'20190507_155320_00041_s9xam'}},\n\n  {event:'query-start',data:{id:'second'}},\n  {event:'query-details',data:{id:'second', code: 'second query'}},\n\n  {event:'fields',data:{id:'second','fields':['a','b']}},\n  {event:'query-details',data:{id:'second','code':'select 1'}},\n  {event:'row',data:{id:'second',values:[1,2]}},\n  {event:'row',data:{id:'second',values:[3,4]}},\n  {event:'query-end',data:{id:'second'}},\n\n  {event:'end',data:{id:'d85eed1e-fec8-4f1c-abba-5ab8593ea46b'}}\n];\n\nconst failEvents = [\n  {event: 'start', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2', 'numOfQueries': 1}},\n  {event: 'query-start', data: {id: '20190506_152226_00201_xps63'}},\n  {event: 'query-details', data: {id: '20190506_152226_00201_xps63', 'code': 'select a'}},\n  {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}},\n  {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}},\n  {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,\n  b,\n  c\nFROM\n  foo.goo\nWHERE\n(1 = 0 or toDateTime(a) > now() - INTERVAL 1 DAY)\n  AND b = 'ERROR'\n . 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))\n)`}},\n  {event: 'query-end', data: {id: '20190506_152226_00201_xps63'}},\n  {event: 'end', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2'}}\n];\n\nconst permissionFailEvents = [\n  {event: 'start', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2', 'numOfQueries': 1}},\n  {event: 'query-start', data: {id: '20190506_152226_00201_xps63'}},\n  {event: 'query-details', data: {id: '20190506_152226_00201_xps63', 'code': 'select a'}},\n  {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}},\n  {event: 'percentage', data: {id: '20190506_152226_00201_xps63', 'percentage': 0}},\n  {event: 'error', data: {id: '20190506_152226_00201_xps63', 'message': 'permission denied'}},\n  {event: 'query-end', data: {id: '20190506_152226_00201_xps63'}},\n  {event: 'end', data: {id: '274370d2-6755-4d3c-8248-b573a63523d2'}}\n];\n\nconst sqlResultEvents = [\n  {'event':'start', 'data': { 'id': 'd5301f06-9c89-41f5-82e0-5974fb0de6fe', \"numOfQueries\": 1 } },\n  \n  {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': \"SELECT *\", 'level': 'INFO' } },\n  {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': \"FROM WorldHistory as h\", 'level': 'INFO' } },\n  {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': \"WHERE\", 'level': 'INFO' } },\n  {'event':'log', 'data': { 'id': '59ac9b05-13ec-4e48-a3c4-fbb99adad53a', 'line': \"h.year = 1984\", 'level': 'INFO' } },\n  \n  {'event':'end', 'data': { 'id': 'd5301f06-9c89-41f5-82e0-5974fb0de6fe' } }\n]\n\nexport const setupMockWs = (app: Application) => {\n  const router = Router();\n\n  router.ws('/:type', (ws, req) => {\n    ws.on('message', async (msg) => {\n      const payload: {data: {code: string}; event: string} = JSON.parse(msg.toString());\n      const match = payload.data.code.match(/timeout=(\\d+)/)\n      const timeout = match && match[1] ? parseInt(match[1], 10) : 0;\n\n      if (payload.event === 'execute') {\n        const code = payload.data.code;\n\n        if (code.includes(MockNoteContent.success)) {\n          sendEvents(ws, successEvents, timeout);\n        } else if (code.includes(MockNoteContent.error)) {\n          sendEvents(ws, failEvents, timeout);\n        } else if (code.includes(MockNoteContent.permissionError)) {\n          sendEvents(ws, permissionFailEvents, timeout);\n        } else if (code.includes(MockNoteContent.sql)) {\n          sendEvents(ws, sqlResultEvents, timeout);\n        } else {\n          ws.close();\n        }\n      }\n    });\n  });\n\n  app.use('/mock/api/v1/execute/', router);\n}\n\nexport const setupSubscriptionMockWs = (app: Application) => {\n  const sockets = [];\n  const router = Router();\n\n  router.ws('/', (ws, req) => {\n    ws.on('message', async (msg) => {\n      const {event} = JSON.parse(msg.toString());\n\n      if (event === 'subscribe') {\n        sockets.push(ws);\n      }\n    });\n  });\n\n  router.post('/mock-broadcast', (req, res) => {\n    const payload = req.body;\n\n    sockets.forEach(ws => {\n      sendEvents(ws, payload, 0);\n    });\n    \n    res.status(200).send('OK');\n  });\n\n  app.use('/subscription', router);\n}\n\nconst promisifiedSend = (WS: WebSocket) => (data: any) => new Promise((resolve, reject) => {\n  WS.send(data, (err) => {\n    if (err) {\n      reject(err);\n    } else {\n      resolve(void 0)\n    }\n  });\n});\n\nconst sendEvents = (WS: WebSocket, events: any[], timeout: number) => {\n  const send = promisifiedSend(WS);\n\n  events.reduce((res, event) => {\n    return new Promise(resolve => res.then(() => setTimeout(() => send(JSON.stringify(event)).then(resolve), timeout)));\n  }, Promise.resolve() as any);\n};\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/dbExplorer.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {Driver} from './driver';\nimport {createMockDbExplorer, createMockDbExplorerItem} from '../mocks';\nimport {FileExplorerTestkit} from '../../src/react-components/file-explorer/file-explorer-testkit';\nimport {ServerTreeItem} from '../../src/components/db-sidebar/db-sidebar-types';\n\nconst COMPONENT_ANIMATION_TIME = 350;\n\ndescribe('FileExplorer ::', () => {\n  let driver: Driver, testkit: FileExplorerTestkit;\n\n  const goToDbExplorer = async (items: ServerTreeItem[] = [], delay = 0) => {\n    const tree = createMockDbExplorer(items);\n\n    await driver.mock.http(`/api/db/:type/explore`, tree, {delay});\n    await driver.mock.http(`/api/db/:type/search`, tree, {delay});\n    await driver.goto('/home');\n  }\n\n  const mockTableResponse = async (tableName: string, delay = 0) => {\n    const columns = {\n      children: [{\n        dataType: 'varchar',\n        name: 'column_of_' + tableName\n      }]\n    }\n    await driver.mock.http(`/api/db/:type/explore/:catalog/:schema/:table`, columns, {delay})\n  }\n\n  const ToggleTreeItemByName = async (name: string, wait = true) => {\n    await testkit.clickOnItemByName(name);\n    if (wait) {\n      await driver.sleep(COMPONENT_ANIMATION_TIME);\n    }\n  }\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n\n    testkit = driver.createTestkit(FileExplorerTestkit);\n  });\n\n  it('should display tree', async () => {\n    await goToDbExplorer([createMockDbExplorerItem({name: 'test'})]);\n\n    await testkit.toggleFileExplorerTab();\n    expect(await testkit.numOfTreeItems()).to.eq(1);\n    expect(await testkit.isTreeItemExistsByName('test')).to.be.true;\n  });\n\n  it('should check toggle tree item works', async () => {\n    await goToDbExplorer(\n      [\n        createMockDbExplorerItem({\n          name: 'parentTest',\n          children: [\n            createMockDbExplorerItem({\n              name: 'childTest',\n              type: 'schema'\n            })\n          ]\n        })\n      ]\n    );\n\n    await testkit.toggleFileExplorerTab();\n    expect(await testkit.numOfTreeItems()).to.eq(1);\n    expect(await testkit.isTreeItemExistsByName('parentTest')).to.be.true;\n\n    await ToggleTreeItemByName('parentTest');\n    expect(await testkit.numOfTreeItems()).to.eq(2);\n    expect(await testkit.isTreeItemExistsByName('childTest')).to.be.true;\n\n\n    await ToggleTreeItemByName('parentTest');\n    expect(await testkit.numOfTreeItems()).to.eq(1);\n    expect(await testkit.isTreeItemExistsByName('parentTest')).to.be.true;\n  });\n\n  it('should check toggle tree item recursively', async () => {\n    await goToDbExplorer(\n      [\n        createMockDbExplorerItem({\n          name: 'parentTest',\n          children: [\n            createMockDbExplorerItem({\n              name: 'childTest1',\n              type: 'schema',\n              children: [\n                createMockDbExplorerItem({\n                  name: 'childTest2',\n                  type: 'table'\n                })\n              ]\n            }),\n          ]\n        })\n      ]\n    );\n\n    await testkit.toggleFileExplorerTab();\n    await ToggleTreeItemByName('parentTest');\n    expect(await testkit.numOfTreeItems()).to.eq(2);\n    await ToggleTreeItemByName('childTest1');\n    expect(await testkit.numOfTreeItems()).to.eq(3);\n    expect(await testkit.isTreeItemExistsByName('childTest2')).to.be.true;\n\n    await ToggleTreeItemByName('parentTest');\n    expect(await testkit.numOfTreeItems()).to.eq(1);\n    expect(await testkit.isTreeItemExistsByName('parentTest')).to.be.true;\n  });\n\n  it('should close all tree items when reopening fileExplorer tab', async () => {\n    await goToDbExplorer(\n      [\n        createMockDbExplorerItem({\n          name: 'parentTest',\n          children: [\n            createMockDbExplorerItem({\n              name: 'childSchemaTest1',\n              type: 'schema',\n              children: [\n                createMockDbExplorerItem({\n                  name: 'childTableTest1',\n                  type: 'table'\n                }),\n              ]\n            }),\n          ]\n        })\n      ]\n    );\n\n    await testkit.toggleFileExplorerTab();\n    await ToggleTreeItemByName('parentTest');\n    await ToggleTreeItemByName('childSchemaTest1');\n    await ToggleTreeItemByName('childTableTest1');\n\n    await testkit.toggleFileExplorerTab();\n    await driver.sleep(COMPONENT_ANIMATION_TIME);\n    await testkit.toggleFileExplorerTab();\n    expect(await testkit.numOfTreeItems()).to.eq(1);\n  });\n\n  it('should load when clicking on table', async () => {\n    await goToDbExplorer(\n      [\n        createMockDbExplorerItem({\n          name: 'parentTest',\n          children: [\n            createMockDbExplorerItem({\n              name: 'childSchemaTest1',\n              type: 'schema',\n              children: [\n                createMockDbExplorerItem({\n                  name: 'childTableTest1',\n                  type: 'table'\n                }),\n                createMockDbExplorerItem({\n                  name: 'childTableTest2',\n                  type: 'table'\n                })\n              ]\n            }),\n          ]\n        })\n      ]\n    );\n\n    mockTableResponse('childTableTest1', 1000);\n    mockTableResponse('childTableTest2', 1000);\n\n    await testkit.toggleFileExplorerTab();\n    await ToggleTreeItemByName('parentTest');\n    await ToggleTreeItemByName('childSchemaTest1');\n    await ToggleTreeItemByName('childTableTest1');\n    expect(await testkit.numOfLoadingTreeItems()).to.eq(1);\n    await ToggleTreeItemByName('childTableTest2');\n    expect(await testkit.numOfLoadingTreeItems()).to.eq(2);\n  });\n\n  it.skip(\"shouldn't load twice when clicking on same table\", async () => {\n    await goToDbExplorer(\n      [\n        createMockDbExplorerItem({\n          name: 'parentTest',\n          children: [\n            createMockDbExplorerItem({\n              name: 'childSchemaTest1',\n              type: 'schema',\n              children: [\n                createMockDbExplorerItem({\n                  name: 'childTableTest1',\n                  type: 'table'\n                }),\n              ]\n            }),\n          ]\n        })\n      ]\n    );\n\n    await testkit.toggleFileExplorerTab();\n    await ToggleTreeItemByName('parentTest');\n    await ToggleTreeItemByName('childSchemaTest1');\n    await ToggleTreeItemByName('childTableTest1');\n    expect(await testkit.numOfTreeItems()).to.eq(4);\n    await ToggleTreeItemByName('childTableTest1');\n\n    mockTableResponse('childTableTest1', 10000);\n    await ToggleTreeItemByName('childTableTest1', false);\n    expect(await testkit.numOfOpenedTreeItems()).to.eq(3);\n  });\n\n  it('should expand all tree items after searching', async () => {\n    await goToDbExplorer(\n      [\n        createMockDbExplorerItem({\n          name: 'parentTest',\n          children: [\n            createMockDbExplorerItem({\n              name: 'childTest1',\n              type: 'schema',\n              children: [\n                createMockDbExplorerItem({\n                  name: 'childTest2',\n                  type: 'table'\n                })\n              ]\n            }),\n          ]\n        })\n      ]\n    );\n\n    await testkit.toggleFileExplorerTab();\n    await driver.sleep(COMPONENT_ANIMATION_TIME);\n    await testkit.search('bla');\n    await driver.sleep(2 * COMPONENT_ANIMATION_TIME);\n    expect(await testkit.numOfTreeItems()).to.eq(4); // 3 visible and 1 hidden by angular\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/driver.ts",
    "content": "import {Browser, Page, ElementHandle} from 'puppeteer';\nimport {baseURL} from './e2e-common';\nimport fetch from 'node-fetch';\nimport { Class } from 'utility-types';\n\nconst WAIT_TIMEOUT = 5000;\n\nconst element = async (page: Page, selector) => {\n  if (page.waitForSelector) {\n    await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT});\n  }\n\n  return page.$(selector);\n}\n\nconst elements = async (page: Page, selector) => {\n  if (page.waitForSelector) {\n    await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT});\n  }\n\n  return page.$$(selector);\n}\n\nconst evalOne = async (page: Page, selector, fn: (element: Element) => any) => {\n  if (page.waitForSelector) {\n    await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT});\n  }\n\n  return page.$eval(selector, fn);\n}\n\nconst evalMany = async (page: Page, selector, fn: (elements: Element[], args) => any, args = {}) => {\n  if (page.waitForSelector) {\n    await page.waitForSelector(selector, {timeout: WAIT_TIMEOUT});\n  }\n\n  return page.$$eval(selector, fn, args);\n}\n\nexport class Driver {\n  private readonly browser: Browser = browser;\n  private page: Page;\n  public mock: Mock;\n  public url: URL;\n  public query: Query;\n  public click: Click;\n  public evaluate: Evaluate;\n  public log: Log;\n\n  async init() {\n    this.page = await this.browser.newPage();\n    this.mock = new Mock();\n    this.url = new URL(this.page);\n    this.query = new Query(this.page);\n    this.click = new Click(this.page);\n    this.evaluate = new Evaluate(this.page);\n    this.log = new Log(this.page);\n\n    await this.mock.reset();\n\n    return this;\n  }\n\n  goto(state: string) {\n    return this.page.goto(`${baseURL}/#${state}`);\n  }\n\n  sleep(ms: number) {\n    return this.page.waitFor(ms);\n  }\n\n  execute(fn: Function) {\n    return this.page.evaluate(fn as any);\n  }\n\n  createTestkit<T extends Class<any>>(TestkitCtor: T): InstanceType<T> {\n    return new TestkitCtor(this.page);\n  }\n}\n\nexport class Mock {\n  constructor () {}\n\n  async http(pattern: string, payload: any, options?: {}) {\n    return fetch(`${baseURL}/mock/pattern`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({pattern, payload, options})\n    });\n  }\n\n  async reset() {\n    return fetch(`${baseURL}/mock/reset`);\n  }\n\n  async wsBroadcast(message: any) {\n    const messages = Array.isArray(message) ? message : [message];\n\n    return fetch(`${baseURL}/subscription/mock-broadcast`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify(messages)\n    });\n  }\n}\n\nexport class URL {\n  constructor (private readonly page: Page) {}\n\n  async matches(pattern: string) {\n    const fn = (p) => {\n      const url = document.location.hash.replace('#', '');\n      return (new ((window as any).UrlPattern)(p)).match(url) !== null;\n    };\n\n    await this.page.waitForFunction(fn, {timeout: WAIT_TIMEOUT}, pattern);\n\n    return true;\n  }\n}\n\nexport class Query {\n  constructor (private readonly page: Page) {}\n\n  async hook(hook: string, pseudoClass: string = '') {\n    return element(this.page, `[data-hook=\"${hook}\"]${pseudoClass}`);\n  }\n\n  async hooks(hook: string, pseudoClass: string = '') {\n   return elements(this.page, `[data-hook=\"${hook}\"]${pseudoClass}`);\n  }\n\n  async attr(attr: string, pseudoClass: string = '') {\n    return element(this.page, `[${attr}]${pseudoClass}`);\n  }\n\n  async attrs(attr: string, pseudoClass: string = '') {\n   return elements(this.page, `[${attr}]${pseudoClass}`);\n  }\n\n  async $(selector: string) {\n    return element(this.page, selector);\n  }\n\n  async $$(selector: string) {\n    return elements(this.page, selector);\n  }\n}\n\nexport class Click {\n  constructor (private readonly page: Page) {}\n\n  async hook(hook: string, pseudoClass: string = '') {\n    const el = await element(this.page, `[data-hook=\"${hook}\"]${pseudoClass}`);\n\n    if (el) {\n      await el.click();\n    }\n  }\n\n  async attr(attr: string, pseudoClass: string = '') {\n    const el = await element(this.page, `[${attr}]${pseudoClass}`);\n\n    if (el) {\n      await el.click();\n    }\n  }\n\n  async $(selector: string) {\n    const el = await element(this.page, selector);\n\n    if (el) {\n      await el.click();\n    }\n  }\n}\n\nexport class Evaluate {\n  constructor (private readonly page: Page) {}\n\n  async hook(hook: string, fn: (element: Element) => any) {\n    return evalOne(this.page, `[data-hook=\"${hook}\"]`, fn);\n  }\n\n  async hooks(hook: string, fn: (element: Element[], args) => any, args = {}) {\n   return evalMany(this.page, `[data-hook=\"${hook}\"]`, fn, args);\n  }\n\n  async attr(attr: string, fn: (element: Element) => any) {\n    return evalOne(this.page, `[${attr}]`, fn);\n  }\n\n  async attrs(attr: string, fn: (element: Element[]) => any) {\n   return evalMany(this.page, `[${attr}]`, fn);\n  }\n\n  async $(selector: string, fn: (element: Element) => any) {\n    return evalOne(this.page, selector, fn);\n  }\n\n  async $$(selector: string, fn: (element: Element[]) => any) {\n    return evalMany(this.page, selector, fn);\n  }\n}\n\nexport class Log {\n  constructor (private readonly page: Page) {}\n\n  async url() {\n    /* tslint:disable-next-line:no-console */\n    console.log(`Current page url is \"${(await this.page.evaluate(() => document.location.hash)).replace('#', '')}\"`);\n  }\n\n  async html() {\n    /* tslint:disable-next-line:no-console */\n    console.log(await this.page.evaluate(() => document.body.innerHTML));\n  }\n}\nexport class Keyboard {\n  constructor (private readonly page: Page) {}\n\n  type(hook: string, value: string) {\n    return this.page.type(`[data-hook=\"${hook}\"]`, value, { delay: 10 });\n  }\n}\n\nexport class Testkit {\n  public query: Query;\n  public click: Click;\n  public evaluate: Evaluate;\n  public keyboard: Keyboard;\n\n  constructor(pageOrElement: Page | ElementHandle) {\n    if (!pageOrElement) {\n      throw new Error('Got null page or element');\n    }\n\n    this.query = new Query(pageOrElement as Page);\n    this.click = new Click(pageOrElement as Page);\n    this.evaluate = new Evaluate(pageOrElement as Page);\n    this.keyboard = new Keyboard(pageOrElement as Page);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/e2e-common.ts",
    "content": "import puppeteer from 'puppeteer';\nimport {start} from '../dev/server';\n\nbefore(async () => {\n  start('3100');\n  global.browser = await puppeteer.launch({\n    args: ['--no-sandbox', '--disable-setuid-sandbox'],\n    headless: true\n  });\n});\n\nafter(async () => {\n  await global.browser.close();\n});\n\nexport const baseURL = `http://localhost:3100`;\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/favorites.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {Driver} from './driver';\nimport {createMockFile} from '../mocks';\nimport {FavoritesTestkit} from '../../src/state-components/favorites/favorites-testkit';\n\ndescribe('Favorites ::', () => {\n  let driver: Driver, testkit: FavoritesTestkit;\n\n  const gotoFavoritesWithError = async () => {\n    await driver.mock.http('/api/favorites', [404, {message: 'Failed to fetch favorites'}]);\n    await driver.goto(`/favorites`);\n  }\n\n  const gotoFavorites = async (mock = [createMockFile()]) => {\n    await driver.mock.http('/api/favorites', mock);\n    await driver.goto('/favorites');\n\n    return mock;\n  }\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n\n    testkit = driver.createTestkit(FavoritesTestkit);\n  });\n\n  it('should display error state when failed to fetch favorites', async () => {\n    await gotoFavoritesWithError();\n\n    expect(await testkit.tableStates.hasError()).to.be.true;\n  });\n\n  it('should display empty state', async () => {\n    await gotoFavorites([]);\n\n    expect(await testkit.tableStates.hasEmptyResult()).to.be.true;\n  });\n\n  it('should display content', async () => {\n    await gotoFavorites();\n\n    expect(await testkit.favoritesTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(1);\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/files.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {Driver} from './driver';\nimport {createMockFiles, createMockFile, createMockFolderPayload, createMockFolder} from '../mocks';\nimport {FilesTestkit} from '../../src/state-components/files/files-testkit';\n\ndescribe('Files ::', () => {\n  let driver: Driver, testkit: FilesTestkit;\n\n  const gotoErrorFiles = async () => {\n    await driver.mock.http('/api/files', [404, {message: 'Failed to fetch files'}]);\n    await driver.goto(`/files/`);\n  }\n\n  const gotoErrorFolder = async () => {\n    await driver.mock.http('/api/files/:id', [404, {message: 'Folder not found'}]);\n    await driver.goto(`/files/1`);\n  }\n\n  const gotoEditableRootFolder = async (files = [createMockFolder(), createMockFile()]) => {\n    const mock = createMockFiles(files);\n\n    await driver.mock.http('/api/files', mock);\n    await driver.goto('/files/');\n\n    return mock;\n  }\n\n  const gotoEditableFolder = async (files = [createMockFolder(), createMockFile()]) => {\n    const mock = createMockFolderPayload(files);\n\n    await driver.mock.http('/api/files/:id', mock);\n    await driver.goto('/files/1');\n\n    return mock;\n  }\n\n  const gotoReadonlyFolder = async (files = [createMockFolder(), createMockFile()]) => {\n    const mock = createMockFolderPayload(files, {owner: 'readonly@quix.com'});\n\n    await driver.mock.http('/api/files/:id', mock);\n    await driver.goto('/files/1');\n\n    return mock;\n  }\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n\n    testkit = driver.createTestkit(FilesTestkit);\n  });\n\n  it('should display error state when failed to fetch files', async () => {\n    await gotoErrorFiles();\n\n    expect(await testkit.hasErrorState()).to.be.true;\n  });\n\n  it('should display error state when folder is not found', async () => {\n    await gotoErrorFolder();\n\n    expect(await testkit.hasErrorState()).to.be.true;\n  });\n\n  it('should display empty state in root folder when user does not have folders/notebooks', async () => {\n    await gotoEditableRootFolder([]);\n\n    const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n    expect(await breadcrumbsTestkit.numOfFiles()).to.equal(1);\n    expect(await testkit.hasEmptyState()).to.be.true;\n  });\n\n  it('should display empty state when folder does not have folders/notebooks', async () => {\n    await gotoEditableFolder([]);\n\n    const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n    expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2);\n    expect(await testkit.hasEmptyState()).to.be.true;\n  });\n\n  it('should display content in root folder when user has folders/notebooks', async () => {\n    await gotoEditableRootFolder();\n\n    expect(await testkit.hasContent()).to.be.true;\n  });\n\n  it('should display content when folder has folders/notebooks', async () => {\n    await gotoEditableFolder();\n\n    expect(await testkit.hasContent()).to.be.true;\n  });\n\n  it('should navigate to a notebook in the root folder', async () => {\n    const files = await gotoEditableRootFolder();\n\n    await testkit.clickFile(2);\n\n    expect(await driver.url.matches(`/notebook/${files[2].id}`)).to.be.true;\n  });\n\n  it('should navigate to a notebook in a folder', async () => {\n    const folder = await gotoEditableFolder();\n\n    await testkit.clickFile(2);\n\n    expect(await driver.url.matches(`/notebook/${folder.files[1].id}`)).to.be.true;\n  });\n\n  it('should navigate to a folder in the root folder', async () => {\n    const files = await gotoEditableRootFolder();\n\n    await testkit.clickFile(1);\n\n    expect(await driver.url.matches(`/files/${files[1].id}`)).to.be.true;\n  });\n\n  it('should navigate to a folder in a folder', async () => {\n    const folder = await gotoEditableFolder();\n\n    await testkit.clickFile(1);\n\n    expect(await driver.url.matches(`/files/${folder.files[0].id}`)).to.be.true;\n  });\n\n  it('should create a folder in a root folder', async () => {\n    await gotoEditableRootFolder([]);\n\n    await testkit.clickAddFolder();\n\n    expect(await testkit.numOfFiles()).to.equal(1);\n  });\n\n  it('should create a folder in a folder', async () => {\n    await gotoEditableFolder([]);\n\n    await testkit.clickAddFolder();\n\n    expect(await testkit.numOfFiles()).to.equal(1);\n  });\n\n  it('should create a notebook in a root folder and navigate to it', async () => {\n    await gotoEditableRootFolder([]);\n\n    await testkit.clickAddNotebook();\n\n    const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n    expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2);\n    expect(await driver.url.matches('/notebook/:id')).to.be.true;\n  });\n\n  it('should create a notebook in a folder and navigate to it', async () => {\n    await gotoEditableFolder([]);\n\n    await testkit.clickAddNotebook();\n\n    const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n    expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2);\n    expect(await driver.url.matches('/notebook/:id')).to.be.true;\n  });\n\n  it('should navigate to the root after navigating to a folder and clicking the root folder', async () => {\n    await gotoEditableRootFolder();\n\n    await testkit.clickFile(1);\n\n    expect(await driver.url.matches('/files/:id')).to.be.true;\n\n    const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n    await breadcrumbsTestkit.clickFile(1);\n\n    expect(await driver.url.matches('/files/')).to.be.true;\n  });\n\n  describe('Permissions ::', () => {\n    describe('Name ::', () => {\n      it('should allow to edit name if user is owner', async () => {\n        await gotoEditableFolder();\n\n        const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n        expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.true;\n      });\n\n      it('should not allow to edit name if user is not owner', async () => {\n        await gotoReadonlyFolder();\n\n        const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n        expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.false;\n      });\n    });\n\n    describe('Add folder | Add notebook ::', () => {\n      it('should enable \"Add folder\" and \"Add notebook\" buttons if user is owner', async () => {\n        await gotoEditableFolder();\n\n        expect(await testkit.isAddFolderEnabled()).to.be.true;\n        expect(await testkit.isAddNotebookEnabled()).to.be.true;\n      });\n\n      it('should disable \"Add folder\" and \"Add notebook\" buttons if user is not owner', async () => {\n        await gotoReadonlyFolder();\n\n        expect(await testkit.isAddFolderEnabled()).to.be.false;\n        expect(await testkit.isAddNotebookEnabled()).to.be.false;\n      });\n    });\n\n    describe('Delete ::', () => {\n      it('should enable the delete action if user is owner', async () => {\n        await gotoEditableFolder();\n\n        const actionsTestkit = await testkit.getActionsTestkit();\n\n        expect(await actionsTestkit.isDeleteEnabled()).to.be.true;\n      });\n\n      it('should disable the delete action if user is not owner', async () => {\n        await gotoReadonlyFolder();\n\n        const actionsTestkit = await testkit.getActionsTestkit();\n\n        expect(await actionsTestkit.isDeleteEnabled()).to.be.false;\n      });\n    });\n\n    describe('Bulk select ::', () => {\n      it('should enable bulk selection if user is owner', async () => {\n        await gotoEditableFolder();\n\n        expect(await testkit.isBulkSelectEnabled()).to.be.true;\n      });\n\n      it('should disable bulk selection if user is not owner', async () => {\n        await gotoReadonlyFolder();\n\n        expect(await testkit.isBulkSelectEnabled()).to.be.false;\n      });\n    });\n  });\n\n  describe('Synchronization ::', () => {\n    const createNotebookEvents = [\n      { \"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\" } },\n      { \"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 } } }\n    ];    \n\n    it('should subscribe to event sourcing mechanism', async function() {\n      await gotoEditableRootFolder([]);\n      expect(await testkit.hasEmptyState()).to.be.true;\n\n      await driver.mock.wsBroadcast(createNotebookEvents);\n      expect(await testkit.hasContent()).to.be.true;\n    });\n  })\n});\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/history.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {Driver} from './driver';\nimport {createMockHistory} from '../mocks';\nimport {HistoryTestkit} from '../../src/state-components/history/history-testkit';\n\ndescribe('History ::', () => {\n  let driver: Driver, testkit: HistoryTestkit;\n\n  const gotoHistoryWithError = async () => {\n    await driver.mock.http('/api/history', [404, { message: 'Failed to fetch history' }]);\n    await driver.goto(`/history`);\n  }\n\n  const gotoHistory = async (mock = [createMockHistory()]) => {\n    await driver.mock.http('/api/history', mock);\n    await driver.goto('/history');\n  }\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n\n    testkit = driver.createTestkit(HistoryTestkit);\n  });\n\n  it('should display error state when failed to fetch history', async () => {\n    await gotoHistoryWithError();\n\n    expect(await testkit.tableStates.hasError()).to.be.true;\n  });\n\n  it('should display content', async () => {\n    await gotoHistory();\n\n    expect(await testkit.historyTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(1);\n  });\n\n  it('should display empty result', async () => {\n    await gotoHistory([]);\n\n    expect(await testkit.tableStates.hasEmptyResult()).to.be.true;\n  });\n\n  it('should display user options', async () => {\n    await gotoHistory();\n    expect(await testkit.tableStates.hasLoading()).to.be.true;\n    \n    await testkit.userFilter.clickOnDropdown();\n    expect(await testkit.userFilter.hasOptions()).to.be.true;\n  });\n\n  it('should filter by user', async () => {\n    await gotoHistory();\n    expect(await testkit.historyTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(1);\n    \n    await driver.mock.reset();\n    await testkit.userFilter.clickOnDropdown();\n    await testkit.userFilter.clickOnOption();\n\n    expect(await testkit.tableStates.hasFilterLoading()).to.be.true;\n    expect(await testkit.historyTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(100);\n  });\n\n  it('should filter by query', async () => {\n    await gotoHistory();\n    expect(await testkit.historyTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(1);\n\n    await driver.mock.reset();\n    await testkit.queryFilter.click();\n\n    await testkit.queryFilter.set('example');\n    expect(await testkit.tableStates.hasFilterLoading()).to.be.true;\n    expect(await testkit.historyTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(100);\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/home.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {Driver} from './driver';\nimport {HomeTestkit} from '../../src/state-components/home/home-testkit';\nimport {NotebookTestkit} from '../../src/state-components/notebook/notebook-testkit';\n\ndescribe('Home ::', () => {\n  let driver: Driver, testkit: HomeTestkit;\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n    await driver.goto('/home');\n\n    testkit = driver.createTestkit(HomeTestkit);\n  });\n\n  it('should navigate to notebooks state', async () => {\n    await testkit.clickNotebooks();\n\n    expect(await driver.url.matches('/files/')).to.be.true;\n  });\n\n  it('should create a notebook and navigate to it', async () => {\n    await testkit.clickAddNotebook();\n\n    expect(await driver.url.matches('/notebook/:id')).to.be.true;\n  });\n\n  it('should focus the newly created notebook name', async () => {\n    await testkit.clickAddNotebook();\n\n    const notebookTestkit = driver.createTestkit(NotebookTestkit);\n    const breadcrumbsTestkit = await notebookTestkit.getBreadcrumbsTestkit();\n\n    expect(await breadcrumbsTestkit.numOfFiles()).to.equal(2);\n    expect(await breadcrumbsTestkit.isFileNameFocused()).to.be.true;\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/notebook.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {Driver} from './driver';\nimport {createMockNotebook, createMockNote, MockNoteContent} from '../mocks';\nimport {NotebookTestkit} from '../../src/state-components/notebook/notebook-testkit';\nimport {ConsoleResultTestkit} from '../../src/lib/runner/directives/results/console/console-result-testkit';\n\ndescribe('Notebook ::', () => {\n  let driver: Driver, testkit: NotebookTestkit;\n\n  const gotoEditableNotebook = async (notes = [createMockNote('1')]) => {\n    const notebook = createMockNotebook(notes);\n\n    await driver.mock.http(`/api/notebook/:id`, notebook);\n    await driver.goto('/notebook/1');\n  };\n\n  const gotoReadonlyNotebook = async () => {\n    const notebook = createMockNotebook([createMockNote('1')], { owner: 'readonly@quix.com' });\n\n    await driver.mock.http(`/api/notebook/:id`, notebook);\n    await driver.goto('/notebook/1');\n  };\n\n  const gotoErrorNotebook = async () => {\n    await driver.mock.http('/api/notebook/:id', [404, { message: 'Notebook not found' }]);\n    await driver.goto(`/notebook/1`);\n  };\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n\n    testkit = driver.createTestkit(NotebookTestkit);\n  });\n\n  it('should display error state when notebook is not found', async () => {\n    await gotoErrorNotebook();\n\n    expect(await testkit.hasErrorState()).to.be.true;\n  });\n\n  it('should display empty state when notebook is empty', async () => {\n    await gotoEditableNotebook([]);\n\n    expect(await testkit.hasEmptyState()).to.be.true;\n  });\n\n  it('should display notes if notebook has at least one note', async () => {\n    await gotoEditableNotebook();\n\n    expect(await testkit.hasNotes()).to.be.true;\n  });\n\n  it('should navigate to the files state', async () => {\n    await gotoEditableNotebook();\n\n    const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n    await breadcrumbsTestkit.clickFile(1);\n\n    expect(await driver.url.matches('/files/')).to.be.true;\n  });\n\n  it('should not focus the name input of existing note', async () => {\n    await gotoEditableNotebook();\n\n    expect(await testkit.numOfNotes()).to.equal(1);\n\n    const noteTestkit = await testkit.getNoteTestkit(1);\n    expect(await noteTestkit.isNameFocused()).to.be.false;\n  });\n\n  it('should add a note and focus the name input', async () => {\n    await gotoEditableNotebook();\n\n    expect(await testkit.numOfNotes()).to.equal(1);\n    await testkit.clickAddNoteDropdown();\n    await driver.sleep(500);\n    await testkit.clickAddNote();\n\n    expect(await testkit.numOfNotes()).to.equal(2);\n\n    const noteTestkit = await testkit.getNoteTestkit(2);\n    expect(await noteTestkit.isNameFocused()).to.be.true;\n  });\n\n  describe('Permissions ::', () => {\n    describe('Name ::', () => {\n      it('should allow to edit name if user is owner', async () => {\n        await gotoEditableNotebook();\n\n        const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n        expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.true;\n      });\n\n      it('should not allow to edit name if user is not owner', async () => {\n        await gotoReadonlyNotebook();\n\n        const breadcrumbsTestkit = await testkit.getBreadcrumbsTestkit();\n\n        expect(await breadcrumbsTestkit.isFileNameEditable()).to.be.false;\n      });\n    });\n\n    describe('Add note ::', () => {\n      it('should enable \"Add note\" button if user is owner', async () => {\n        await gotoEditableNotebook();\n\n        expect(await testkit.isAddNoteEnabled()).to.be.true;\n      });\n\n      it('should disable \"Add note\" button if user is not owner', async () => {\n        await gotoReadonlyNotebook();\n\n        expect(await testkit.isAddNoteEnabled()).to.be.false;\n      });\n    });\n\n    describe('Delete ::', () => {\n      it('should enable the delete action if user is owner', async () => {\n        await gotoEditableNotebook();\n\n        const actionsTestkit = await testkit.getActionsTestkit();\n\n        expect(await actionsTestkit.isDeleteEnabled()).to.be.true;\n      });\n\n      it('should disable the delete action if user is not owner', async () => {\n        await gotoReadonlyNotebook();\n\n        const actionsTestkit = await testkit.getActionsTestkit();\n\n        expect(await actionsTestkit.isDeleteEnabled()).to.be.false;\n      });\n    });\n\n    describe('Note ::', () => {\n      describe('Name ::', () => {\n        it('should allow to edit note name if user is owner', async () => {\n          await gotoEditableNotebook();\n\n          const noteTestkit = await testkit.getNoteTestkit(1);\n\n          expect(await noteTestkit.isNameEditable()).to.be.true;\n        });\n\n        it('should not allow to edit note name if user is not owner', async () => {\n          await gotoReadonlyNotebook();\n\n          const noteTestkit = await testkit.getNoteTestkit(1);\n\n          expect(await noteTestkit.isNameEditable()).to.be.false;\n        });\n      });\n\n      describe('Select ::', () => {\n        it('should allow to select note if user is owner', async () => {\n          await gotoEditableNotebook();\n\n          const noteTestkit = await testkit.getNoteTestkit(1);\n\n          expect(await noteTestkit.isSelectEnabled()).to.be.true;\n        });\n\n        it('should not allow to select note if user is not owner', async () => {\n          await gotoReadonlyNotebook();\n\n          const noteTestkit = await testkit.getNoteTestkit(1);\n\n          expect(await noteTestkit.isSelectEnabled()).to.be.false;\n        });\n      });\n\n      describe('Delete ::', () => {\n        it('should allow to delete note if user is owner', async () => {\n          await gotoEditableNotebook();\n\n          const noteTestkit = await testkit.getNoteTestkit(1);\n          const actionsTestkit = await noteTestkit.getActionsTestkit();\n\n          expect(await actionsTestkit.isDeleteEnabled()).to.be.true;\n        });\n\n        it('should not allow to delete note if user is not owner', async () => {\n          await gotoReadonlyNotebook();\n\n          const noteTestkit = await testkit.getNoteTestkit(1);\n          const actionsTestkit = await noteTestkit.getActionsTestkit();\n\n          expect(await actionsTestkit.isDeleteEnabled()).to.be.false;\n        });\n      });\n\n      describe('Result ::', () => {\n        describe('Console ::', () => {\n          it('should merge lines with same timestamp into group', async () => {\n            await gotoEditableNotebook([\n              createMockNote('1', {\n                type: 'python',\n                content: MockNoteContent.sql,\n              }),\n            ]);\n\n            const noteTestkit = await testkit.getNoteTestkit(1);\n            const runnerTestkit = await noteTestkit.getRunnerTestkit();\n\n            await runnerTestkit.clickRun();\n\n            const consoleResultTestkit = driver.createTestkit(ConsoleResultTestkit);\n            expect(await consoleResultTestkit.getTimestampsCount()).to.equal(2);\n            expect(await consoleResultTestkit.getValueRowsCount()).to.equal(4);\n          });\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/test/e2e/users.e2e.ts",
    "content": "import {expect} from 'chai';\nimport {IUser} from '@wix/quix-shared';\nimport {Driver} from './driver';\nimport {createMockUser} from '../mocks';\nimport {UsersTestkit} from '../../src/state-components/users/users-testkit';\n\ndescribe('Users ::', () => {\n  let driver: Driver, testkit: UsersTestkit;\n\n  const gotoUsersWithError = async () => {\n    await driver.mock.http('/api/users', [404, {message: 'Failed to fetch users'}]);\n    await driver.goto(`/users`);\n  }\n\n  const gotoUsers = async (mock: Partial<IUser>[] = [createMockUser()]) => {\n    await driver.mock.http('/api/users', mock);\n    await driver.goto('/users');\n\n    return mock;\n  }\n\n  beforeEach(async () => {\n    driver = new Driver();\n    await driver.init();\n\n    testkit = driver.createTestkit(UsersTestkit);\n  });\n\n  it('should display error state when failed to fetch users', async () => {\n    await gotoUsersWithError();\n\n    expect(await testkit.tableStates.hasError()).to.be.true;\n  });\n\n  it('should display content', async () => {\n    await gotoUsers();\n\n    expect(await testkit.usersTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(1);\n  });\n\n  it('should display empty result', async () => {\n    await gotoUsers([]);\n\n    expect(await testkit.tableStates.hasEmptyResult()).to.be.true;\n  });\n\n  it('should filter by users', async () => {\n    await gotoUsers([\n      {email: 'email0@bla.bla'},\n      {email: 'email1@bla.bla'},\n      {email: 'email2@bla.bla'},\n    ]);\n\n    expect(await testkit.usersTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(3);\n\n    await driver.mock.reset();\n    await testkit.usersFilter.click();\n\n    await testkit.usersFilter.set('1');\n    expect(await testkit.tableStates.hasFilterLoading()).to.be.true;\n    expect(await testkit.usersTableExists()).to.be.true;\n    expect(await testkit.tableTotalRows()).to.equal(1);\n  });\n});\n"
  },
  {
    "path": "quix-frontend/client/test/mocha-setup.ts",
    "content": ""
  },
  {
    "path": "quix-frontend/client/test/mocks.ts",
    "content": "import UrlPattern from 'url-pattern';\nimport {\n  IUser,\n  IHistory,\n  IFile,\n  INotebook,\n  INote,\n  IFolder,\n  createUser,\n  createHistory,\n  createNotebook,\n  createFolder,\n  createFile,\n  createNote,\n  createFolderPayload,\n  createDeletedNotebook,\n} from '@wix/quix-shared';\nimport * as moment from 'moment';\nimport { ServerTreeItem } from '../src/components/db-sidebar/db-sidebar-types';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport const MockNoteContent = {\n  success: 'do success',\n  error: 'do error',\n  permissionError: 'do permission error',\n  sql: 'do SQL',\n};\n\nconst mocks = {\n  '/api/user': () => {\n    return { ...createUser(), stats: { trashBinCount: trashBin.length } };\n  },\n  '/api/events': () => [200],\n  '/api/users': () =>\n    [...Array(200).keys()].map((key) =>\n      createMockUser({\n        id: uuidv4(),\n        email: 'valery' + key + '@wix.com',\n        avatar: 'http://quix.wix.com/assets/user.svg',\n        name: 'Valery Frolov' + key,\n        rootFolder: '6c98fe9a-39f7-4674-b003-70f9061bbee5',\n        dateCreated: Date.now(),\n        dateUpdated: Date.now(),\n      })\n    ),\n  '/api/history': () => {\n    return [...Array(101).keys()].map((key) =>\n      createMockHistory({\n        id: '' + key,\n        email: 'valery' + key + '@wix.com',\n        query: ['SELECT 1', 'SELECT 2'],\n        moduleType: key % 2 ? 'presto' : 'athena',\n        startedAt: moment.utc().format(),\n      })\n    );\n  },\n  // '/api/files': () => [404, {message: 'Couldn\\'t fetch notebooks'}],\n  // '/api/files': () => [500, {message: 'Failed to fetch files'}],\n  '/api/files': () => createMockFiles(),\n  // '/api/files': () => createMockFiles([createMockFolder({id: '10'}), createMockFile({id: '11'})]),\n  '/api/files/404': () => [404, { message: 'Folder not found' }],\n  '/api/files/500': () => [500, { message: \"Couldn't fetch folder\" }],\n  '/api/files/:id': ({ id }) =>\n    createMockFolderPayload(\n      [createMockFolder({ id: '100' }), createMockFile({ id: '101' })],\n      {\n        id,\n        ownerDetails: {\n          avatar: 'http://quix.wix.com/assets/user.svg',\n        } as any,\n      }\n    ),\n  '/api/notebook/404': () => [404, { message: 'Notebook not found' }],\n  '/api/notebook/500': () => [500, { message: \"Couldn't fetch notebook\" }],\n  '/api/notebook/:id': ({ id }) => {\n    let noteId = 1001;\n    return createMockNotebook(\n      [\n        createMockNote(id, {\n          id: `${noteId++}`,\n          name: 'Runnable',\n          content: MockNoteContent.success,\n        }),\n        createMockNote(id, {\n          id: `${noteId++}`,\n          name: 'Runnable',\n          content: MockNoteContent.success,\n          type: 'python',\n        }),\n        createMockNote(id, {\n          id: `${noteId++}`,\n          name: 'Runnable (timeout)',\n          content: `${MockNoteContent.success} timeout=200`,\n        }),\n        createMockNote(id, {\n          id: `${noteId++}`,\n          name: 'Runnable (error)',\n          content: MockNoteContent.error,\n        }),\n        createMockNote(id, {\n          id: `${noteId++}`,\n          name: 'Runnable (permission error)',\n          content: MockNoteContent.permissionError,\n        }),\n        createMockNote(id, {\n          id: `${noteId++}`,\n          name: 'Runnable SQL+JSON Result (Timeout)',\n          content: MockNoteContent.sql,\n          type: 'python',\n        }),\n      ],\n      {\n        id,\n        ownerDetails: {\n          avatar: 'http://quix.wix.com/assets/user.svg',\n        } as any,\n      }\n    );\n  },\n  '/api/favorites': () => [\n    createMockFile({\n      id: '100',\n      isLiked: true,\n      ownerDetails: {\n        id: 'valery@wix.com',\n        email: 'valery@wix.com',\n        avatar: 'http://quix.wix.com/assets/user.svg',\n        name: 'Valery Frolov',\n        rootFolder: '6c98fe9a-39f7-4674-b003-70f9061bbee5',\n        dateCreated: Date.now(),\n        dateUpdated: Date.now(),\n      },\n    }),\n    createMockFile({\n      id: '101',\n      isLiked: true,\n      ownerDetails: {\n        id: 'anton@wix.com',\n        email: 'anton@wix.com',\n        avatar: 'http://quix.wix.com/assets/user.svg',\n        name: 'Anton Podolsky',\n        rootFolder: 'de6908dd-7f1e-4803-ab0d-5f9d6a496609',\n        dateCreated: Date.now(),\n        dateUpdated: Date.now(),\n      },\n    }),\n  ],\n  '/api/search/none': () => ({ count: 0, notes: [] }),\n  '/api/search/500': () => [500, { message: 'Search error' }],\n  '/api/search/:text': ({ text }) => {\n    const res = [createMockNote('1'), createMockNote('2'), createMockNote('3')];\n    const term = { fullText: text, content: [{ type: 1, text }] };\n    res.forEach(\n      (note) =>\n        (note.content = `SELECT\n    date_trunc('year', shipdate) as ${text}\n    , shipmode\n    , sum(quantity) quantity\nFROM $schema.lineitem\nGROUP BY 1, 2\nORDER BY 1\n`)\n    );\n\n    // return {notes: [], count: 0};\n    return { notes: res, count: 365, term };\n  },\n  // '/api/db/presto/explore': () => [500, {message: 'Failed to fetch DB tree'}],\n  // '/api/db/presto/explore': () => [],\n  '/api/db/:type/explore': ({ type }) => {\n    if (type === 'presto') {\n      const response = [];\n      for (let i = 0; i < 50; i++) {\n        response.push({\n          name: 'catalog' + i,\n          type: 'catalog',\n          children: [\n            {\n              name: 'schema' + i,\n              type: 'schema',\n              children: [\n                {\n                  name: 'table' + i,\n                  type: 'table',\n                  children: [],\n                },\n              ],\n            },\n          ],\n        });\n      }\n      return response;\n    }\n\n    return [\n      {\n        name: '__root',\n        type: 'catalog',\n        children: [\n          {\n            name: 'schema',\n            type: 'schema',\n            children: [\n              {\n                name: 'table_with_a_very_looooooooooooooooong_name',\n                type: 'table',\n                children: [],\n              },\n            ],\n          },\n          {\n            name: 'schema2',\n            type: 'schema',\n            children: [],\n          },\n        ],\n      },\n    ];\n  },\n  '/api/db/:type/explore/:catalog/:schema/:table': ({ table }) => ({\n    children: [\n                {name: { name: `colA`, dataType: 'varchar' }},\n                {name: { name: `colB`, dataType: 'varchar' }},\n                {name: { name: `colC`, dataType: 'varchar' }},\n                {name: { name: `colD`, dataType: 'varchar' }},\n                {name: { name: `colSmallObject`, dataType: 'row(food row(pizza varchar, pasta varchar), drinks row(beer varchar, vodka varchar))' }},\n                {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)))' }},\n              ],\n  }),\n  '/api/db/:type/autocomplete': () => ({\n    catalogs: ['catalog', 'catalog2'],\n    schemas: ['schema'],\n    tables: ['table'],\n    columns: ['column'],\n  }),\n  '/api/autocomplete/:type': () => [\n    { value: 'apollo', meta: 'table' },\n    { value: 'prod', meta: 'table' },\n    { value: 'wt_metasites', meta: 'table' },\n  ],\n  // '/api/db/:type/search': () => [],\n  '/api/db/:type/search': () => {\n    const response = [];\n    for (let i = 0; i < 10; i++) {\n      response.push({\n        name: 'catalog' + i,\n        type: 'catalog',\n        children: [\n          {\n            name: 'schema' + i,\n            type: 'schema',\n            children: [\n              {\n                name: 'table' + i,\n                type: 'table',\n                children: [],\n              },\n            ],\n          },\n        ],\n      });\n    }\n    return response;\n  },\n  '/api/deletedNotebooks': () => [...trashBin],\n};\n\nconst createMockDeletedNotebook = (name?: string) => {\n  return name\n    ? { ...createDeletedNotebook(), name }\n    : createMockDeletedNotebook();\n};\n\nconst trashBin = [];\n// We can use this loop to simulate different counts on trash bin icon badge\nfor (let i = 0; i < 1; i++) {\n  trashBin.push(\n    ...[\n      createMockDeletedNotebook('Removed 1'),\n      createMockDeletedNotebook('Bad Queries'),\n      createMockDeletedNotebook('By Mistake'),\n      createMockDeletedNotebook('Trash'),\n    ]\n  );\n}\n\nlet mockOverrides = {};\n\nexport const createMockUser = (props: Partial<IUser> = {}) => {\n  return createUser(props);\n};\n\nexport const createMockHistory = (props: Partial<IHistory> = {}) => {\n  return createHistory(props);\n};\n\nexport const createMockRootFolder = (props: Partial<IFile> = {}) => {\n  return createFolder([], {\n    id: '1',\n    name: 'My notebooks',\n    owner: 'local@quix.com',\n    ownerDetails: {\n      avatar: 'http://quix.wix.com/assets/user.svg',\n    } as any,\n    ...props,\n  });\n};\n\nexport const createMockFile = (props: Partial<IFile> = {}) => {\n  return createFile([{ id: '1', name: 'My notebooks' }], {\n    owner: 'local@quix.com',\n    ...props,\n  });\n};\n\nexport const createMockFolder = (props: Partial<IFile> = {}) => {\n  return createFolder([{ id: '1', name: 'My notebooks' }], {\n    owner: 'local@quix.com',\n    ...props,\n  });\n};\n\nexport const createMockFiles = (children = []) => {\n  return [\n    createMockRootFolder(),\n    ...children.map((child) => ({\n      ...child,\n    })),\n  ];\n};\n\nexport const createMockFolderPayload = (\n  children = [],\n  props: Partial<IFolder> = {}\n) => {\n  return createFolderPayload([{ id: '1', name: 'My notebooks' }], {\n    owner: 'local@quix.com',\n    files: children.map((child, index) => ({\n      ...child,\n      // tslint:disable-next-line: restrict-plus-operands\n      id: `${index + 100}`,\n    })),\n    ...props,\n  });\n};\n\nexport const createMockNotebook = (\n  notes = [],\n  props: Partial<INotebook> = {}\n) => {\n  return createNotebook([{ id: '1', name: 'My notebooks' }], {\n    owner: 'local@quix.com',\n    notes,\n    ...props,\n  });\n};\n\nexport const createMockNote = (\n  notebookId: string = '1',\n  props: Partial<INote> = {}\n) => {\n  return createNote(notebookId, { owner: 'local@quix.com', ...props });\n};\n\nexport const createMockDbExplorer = (\n  items: ServerTreeItem[] = []\n): ServerTreeItem[] => {\n  return items.length > 0 ? items : [createMockDbExplorerItem()];\n};\n\nexport const createMockDbExplorerItem = (\n  props: Partial<ServerTreeItem> = {}\n): ServerTreeItem => {\n  return {\n    name: props.name || 'treeItem',\n    type: props.type || 'catalog',\n    children: props.children || [],\n  };\n};\n\nexport const mock = async (\n  patternOrUrl: string,\n  patternPayload?: any,\n  options?: {}\n) => {\n  if (patternPayload) {\n    mockOverrides[patternOrUrl] = { options, getPayload: () => patternPayload };\n  } else {\n    const [status, payload, delay] = Object.keys(mocks).reduce((res, key) => {\n      if (!res) {\n        const match = new UrlPattern(key).match(patternOrUrl);\n\n        if (match) {\n          let payloadResult = (mockOverrides[key]?.getPayload || mocks[key])(\n            match\n          );\n\n          if (payloadResult && typeof payloadResult[0] !== 'number') {\n            payloadResult = [200, payloadResult];\n          }\n\n          return [...payloadResult, mockOverrides[key]?.options?.delay];\n        }\n      }\n\n      return res;\n    }, null) || [404, { message: 'Mock not found' }];\n\n    if (delay) {\n      await new Promise((res) => setTimeout(res, delay));\n    }\n    return [status, payload];\n  }\n};\n\nexport const reset = () => {\n  mockOverrides = {};\n};\n"
  },
  {
    "path": "quix-frontend/client/test/test-common.ts",
    "content": "export const baseURL = `http://localhost:5554`;\n"
  },
  {
    "path": "quix-frontend/client/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"declaration\": true,\n    \"noImplicitAny\": false,\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"target\": \"es5\",\n    \"noUnusedLocals\": true,\n    \"lib\": [\"dom\", \"es2016\"],\n    \"esModuleInterop\": true,\n    \"downlevelIteration\": true,\n    \"skipLibCheck\": true,\n    \"outDir\": \"./dist\",\n    \"jsx\": \"react\"\n  },\n  \"include\": [\n    \"./test/**/*.ts\",\n    \"./src/custom.d.ts\"\n  ],\n  \"files\": [\n    \"src/app.ts\",\n    \"./src/external-types.d.ts\"\n  ],\n  \"references\": [{\n    \"path\": \"../shared\"\n  }]\n}\n"
  },
  {
    "path": "quix-frontend/client/tslint.json",
    "content": "{\n  \"extends\": [\"tslint-config-yoshi-base\"],\n  \"linterOptions\": {\n    \"exclude\": [\"./src/lib/language-parsers/presto-grammar/lang/presto/*.ts\"]\n  },\n  \"rules\": {\n    \"prettier\": false,\n    \"no-invalid-this\": false,\n    \"no-floating-promises\": false,\n    \"restrict-plus-operands\": false\n  }\n}\n"
  },
  {
    "path": "quix-frontend/client/velocity.data.json",
    "content": "{\n  \"clientTopology\": {\n    \"staticsBaseUrl\": \"//localhost:3200/\",\n    \"executeBaseUrl\": \"//localhost:3000/mock\",\n    \"apiBasePath\": \"\"\n  },\n  \"mode\": {\n    \"debug\": true,\n    \"demo\": false\n  }\n}"
  },
  {
    "path": "quix-frontend/client/velocity.private.data.json",
    "content": "{\n\n}\n"
  },
  {
    "path": "quix-frontend/client/wallaby.js",
    "content": "module.exports = function (wallaby) {\n  return Object.assign({}, require('yoshi/config/wallaby-mocha')(wallaby), {\n    // set to undefined to let Wallaby decide the number of processes based on the system's capacity\n    workers: undefined\n  });\n};\n"
  },
  {
    "path": "quix-frontend/lerna.json",
    "content": "{\n  \"packages\": [\n    \"client\",\n    \"shared\",\n    \"service\"\n  ],\n  \"version\": \"independent\",\n  \"npmClient\": \"npm\"\n}\n"
  },
  {
    "path": "quix-frontend/npm-deploy.sh",
    "content": "#!/bin/bash\necho \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> .npmrc\nlerna publish from-package --no-verify-access -y --loglevel=debug"
  },
  {
    "path": "quix-frontend/package.json",
    "content": "{\n  \"name\": \"quix-frontend\",\n  \"private\": true,\n  \"devDependencies\": {\n    \"lerna\": \"^3.22.1\"\n  },\n  \"scripts\": {\n    \"version\": \"lerna --version\",\n    \"test\": \"lerna run test:ci --parallel false --concurrency 1\",\n    \"bootstrap\": \"lerna bootstrap --concurrency 2  --force-local\",\n    \"postinstall\": \"npm run bootstrap\",\n    \"build\": \"lerna run build --parallel false --concurrency 1\",\n    \"build:ci\": \"(cd service; npm run build)\",\n    \"clean\": \"lerna clean --yes\",\n    \"publish\": \"lerna publish from-package --no-verify-access -y --loglevel=debug\"\n  },\n  \"workspaces\": {\n    \"packages\": [\n      \"client\",\n      \"shared\",\n      \"service\"\n    ],\n    \"nohoist\": [\n      \"**/@types/**\",\n      \"**/lodash*\",\n      \"**/lodash/**\",\n      \"**/@nestjs/**\",\n      \"**/passport/**\",\n      \"**/typeorm\",\n      \"**/typeorm/**\"\n    ]\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/.gitignore",
    "content": "node_modules\ndist\nstatics\n.env\normconfig.generated*\n.fnm-node"
  },
  {
    "path": "quix-frontend/service/.npmrc",
    "content": "package-lock=true\nregistry=https://registry.npmjs.org/\n"
  },
  {
    "path": "quix-frontend/service/.nvmrc",
    "content": "14"
  },
  {
    "path": "quix-frontend/service/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"bracketSpacing\": false,\n  \"arrowParens\": \"avoid\"\n}"
  },
  {
    "path": "quix-frontend/service/.quixroot",
    "content": "magic file for scripts to get root folder"
  },
  {
    "path": "quix-frontend/service/.testenv",
    "content": "#QUIX_ENV=TEST\nDB_NAME=quixtest\nDB_USER=root\nDB_HOST=localhost\nDB_PASS=\n#DB_DEBUG=true"
  },
  {
    "path": "quix-frontend/service/.travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"11\"\nservices:\n  - mysql\ncache: npm\nbefore_install:\n  - mysql -e 'CREATE DATABASE IF NOT EXISTS Quix;'\naddons:\n  apt:\n    sources:\n      - mysql-5.7-trusty\n    packages:\n      - mysql-server\n      - mysql-client"
  },
  {
    "path": "quix-frontend/service/README.md",
    "content": "## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Test\n\n```bash\n# unit tests - against sqlite\n$ npm run test\n\n# unit tests - against mysql\n$ npm run test:mysql\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n\n\n## Configuration\nThe app expects the following enviorment variables:\n```bash\nDB_NAME=\nDB_USER=\nDB_PASS=\nDB_HOST=\nDB_PORT=\nBACKEND_INTERNAL_URL=\nBACKEND_PUBLIC_URL=\nGOOGLE_SSO_CLIENT_ID=\nGOOGLE_SSO_SECRET=\nAUTH_COOKIE=\nAUTH_SECRET=\nCOOKIE_MAX_AGE=\nDB_TYPE=\nAUTH_TYPE=\nDB_AUTO_MIGRATE=\nMINIFIED_STATICS=\n```\n\nYou can set those in `.env` file. When testing, values are read from `.testenv`.\n\n\nThis app is built using ![Nest.js](https://raw.githubusercontent.com/nestjs/docs.nestjs.com/master/src/assets/logo.png)."
  },
  {
    "path": "quix-frontend/service/ecosystem.config.js",
    "content": "module.exports = {\n  apps : [{\n    name: \"quix\",\n    script: \"./index.js\",\n    env: {\n      NODE_ENV: \"development\",\n    },\n    env_production: {\n      NODE_ENV: \"production\",\n    },\n    output: '/logs/stdout.log',\n    error: '/logs/stderr.log',\n    instances: 2\n  }]\n}"
  },
  {
    "path": "quix-frontend/service/index.js",
    "content": "const path = require('path');\nrequire(path.resolve('./', 'dist', 'main'));"
  },
  {
    "path": "quix-frontend/service/nest-cli.json",
    "content": "{\n  \"language\": \"ts\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "quix-frontend/service/nodemon-debug.json",
    "content": "{\n  \"watch\": [\"src\"],\n  \"ext\": \"ts\",\n  \"ignore\": [\"src/**/*.spec.ts\"],\n  \"exec\": \"node --inspect-brk -r tsconfig-paths/register src/main.ts\"\n}\n"
  },
  {
    "path": "quix-frontend/service/nodemon.json",
    "content": "{\n  \"watch\": [\"src\"],\n  \"ext\": \"ts\",\n  \"ignore\": [\"src/**/*.spec.ts\"], \n  \"exec\": \"ts-node --files src/main.ts\"\n}\n"
  },
  {
    "path": "quix-frontend/service/ormconfig.json",
    "content": "{\n  \"type\": \"mysql\",\n  \"host\": \"localhost\",\n  \"port\": 3306,\n  \"username\": \"root\",\n  \"password\": \"\",\n  \"database\": \"quix\",\n  \"entities\": [\"./src/**/*.entity{.ts,.js}\"],\n  \"migrations\": [\"./src/migrations/*.ts\"],\n  \"synchronize\": false,\n  \"cli\": {\n    \"migrationsDir\": \"./src/migrations\"\n  }\n}"
  },
  {
    "path": "quix-frontend/service/package.json",
    "content": "{\n  \"name\": \"@wix/quix-service\",\n  \"version\": \"1.0.33\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"build:ts\": \"tsc -b tsconfig.build.json\",\n    \"build\": \"npm run build:ts && npm run update-statics\",\n    \"build:start\": \"npm run build && npm start\",\n    \"start\": \"DB_HOST=localhost ts-node --files scripts/start.ts\",\n    \"update-statics\": \"ts-node scripts/update-statics.ts\",\n    \"start:dev\": \"nodemon\",\n    \"start:debug\": \"nodemon --config nodemon-debug.json\",\n    \"start:prod\": \"node index.js\",\n    \"lint\": \"tslint -p tsconfig.json -c tslint.json\",\n    \"lint:fix\": \"tslint -p tsconfig.json -c tslint.json --fix\",\n    \"test\": \"jest\",\n    \"test:ci\": \"npm run test && npm run test:mysql && npm run test:e2e\",\n    \"test:mysql\": \"DB_TYPE=mysql jest --runInBand\",\n    \"test:build:mysql\": \"npm run build && npm run test:mysql\",\n    \"test:watch\": \"jest --watch\",\n    \"test:cov\": \"jest --coverage\",\n    \"test:debug\": \"node --inspect-brk -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:debug:mysql\": \"DB_TYPE=mysql node --inspect-brk -r ts-node/register node_modules/.bin/jest --runInBand\",\n    \"test:e2e\": \"npm run test:e2e:sqlite && npm run test:e2e:mysql\",\n    \"test:e2e:sqlite\": \"jest --runInBand --config ./test/jest-e2e.js\",\n    \"test:e2e:mysql\": \"DB_TYPE=mysql jest --runInBand --config ./test/jest-e2e.js\",\n    \"fnm\": \"fnm exec which node | xargs -I % ln -sf % ./.fnm-node && chmod +x ./.fnm-node\",\n    \"link:shared\": \"cd ../shared && npm link && cd ../service && npm link @wix/quix-shared\"\n  },\n  \"dependencies\": {\n    \"@nestjs/common\": \"^7.0.0\",\n    \"@nestjs/core\": \"^7.0.0\",\n    \"@nestjs/jwt\": \"^7.0.0\",\n    \"@nestjs/platform-express\": \"^7.0.0\",\n    \"@nestjs/platform-ws\": \"^7.0.0\",\n    \"@nestjs/typeorm\": \"^7.0.0\",\n    \"@nestjs/websockets\": \"^7.0.0\",\n    \"@types/node-fetch\": \"^2.5.0\",\n    \"@types/ws\": \"^6.0.4\",\n    \"@wix/quix-shared\": \"^1.0.15\",\n    \"axios\": \"^0.21.0\",\n    \"cookie\": \"^0.4.1\",\n    \"cookie-parser\": \"^1.4.4\",\n    \"dotenv\": \"^7.0.0\",\n    \"fp-ts\": \"^2.0.1\",\n    \"google-auth-library\": \"^6.1.6\",\n    \"http-proxy-middleware\": \"^0.19.1\",\n    \"lodash\": \"^4.17.19\",\n    \"mysql2\": \"^2.1.0\",\n    \"node-fetch\": \"^2.6.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rimraf\": \"^2.6.2\",\n    \"rxjs\": \"^6.3.3\",\n    \"tapable\": \"^1.1.1\",\n    \"ts-node\": \"^7.0.1\",\n    \"tsconfig-paths\": \"^3.8.0\",\n    \"typeorm\": \"0.2.45\",\n    \"typescript\": \"^4.0.0\",\n    \"uuid\": \"^3.3.2\",\n    \"velocity\": \"^0.7.2\",\n    \"ws\": \"^7.2.1\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/testing\": \"^7.0.0\",\n    \"@types/chance\": \"^1.0.4\",\n    \"@types/cookie\": \"^0.4.0\",\n    \"@types/cookie-parser\": \"^1.4.1\",\n    \"@types/dotenv\": \"^6.1.1\",\n    \"@types/express\": \"^4.16.0\",\n    \"@types/http-proxy-middleware\": \"^0.19.2\",\n    \"@types/jest\": \"^26.0.0\",\n    \"@types/lodash\": \"^4.14.123\",\n    \"@types/mysql\": \"^2.15.6\",\n    \"@types/nock\": \"^9.3.1\",\n    \"@types/node\": \"^12.0.0\",\n    \"@types/shelljs\": \"^0.8.3\",\n    \"@types/supertest\": \"^2.0.7\",\n    \"@types/tapable\": \"^1.0.4\",\n    \"@types/uuid\": \"^3.4.4\",\n    \"chance\": \"^1.0.18\",\n    \"jest\": \"^26.0.0\",\n    \"nock\": \"^10.0.6\",\n    \"nodemon\": \"^1.18.9\",\n    \"prettier\": \"^2.0.0\",\n    \"shelljs\": \"^0.8.3\",\n    \"sql.js\": \"^1.0.0\",\n    \"supertest\": \"^6.0.0\",\n    \"ts-jest\": \"^26.0.0\",\n    \"tslint\": \"^6.0.0\",\n    \"tslint-config-prettier\": \"^1.18.0\",\n    \"tslint-plugin-prettier\": \"^2.0.1\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".spec.ts$\",\n    \"transform\": {\n      \"^.+\\\\.ts$\": \"ts-jest\"\n    },\n    \"transformIgnorePatterns\": [\n      \"/node_modules/\",\n      \"/quix-frontend\\\\shared/\"\n    ],\n    \"globals\": {\n      \"ts-jest\": {\n        \"tsconfig\": {\n          \"target\": \"esnext\"\n        }\n      }\n    },\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/scripts/create_migrations.sh",
    "content": "#!/usr/bin/env bash\n\nusage() {\n  printf '**** usage: ****\\n'\n  printf 'create_migrations.sh \\e[4mversion_number\\e[0m\\n'\n  exit -2\n}\n\nif [ -z $1 ]; then\n  usage\nelse\n\n  DEFAULTPORT=3306\n  DEFAULTDB=\"quix\"\n  DEFAULTPASS=\"\"\n  DEFAULTPUSER=\"root\"\n  DEFAULTHOST=\"localhost\"\n\n  export DB_HOST=${DB_HOST:-$DEFAULTHOST}\n  export DB_USER=${DB_USER:-$DEFAULTPUSER}\n  export DB_PASS=${DB_PASS:-$DEFAULTPASS}\n  export DB_NAME=${DB_NAME:-$DEFAULTDB}\n  export DB_PORT=${DB_PORT:-$DEFAULTPORT}\n\n  sed -e \"s/:dbhost:/$DB_HOST/\" \\\n    -e \"s/:dbuser:/$DB_USER/\" \\\n    -e \"s/:dbpass:/$DB_PASS/\" \\\n    -e \"s/:dbname:/$DB_NAME/\" \\\n    -e \"s/:dbport:/$DB_PORT/\" \\\n    scripts/ormconfig.json.template > ormconfig.generated.migration-generate.json\n\n  ./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\nfi\n\n"
  },
  {
    "path": "quix-frontend/service/scripts/helpers/copy-statics.ts",
    "content": "import {exec, ExecOutputReturnValue, cp} from 'shelljs';\nimport path from 'path';\n\nexport function buildAndCopyStatics(projectDir: string, clientDir: string) {\n  const build = exec('npm run build', {\n    cwd: clientDir,\n  }) as ExecOutputReturnValue;\n\n  if (build.code) {\n    process.exit(-1);\n  }\n\n  const copy = cp('-R', path.resolve(clientDir, 'dist', 'statics'), projectDir);\n  if (copy.code) {\n    process.exit(-1);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/scripts/ormconfig.json.template",
    "content": "{\n  \"type\": \"mysql\",\n  \"host\": \":dbhost:\",\n  \"port\": :dbport:,\n  \"username\": \":dbuser:\",\n  \"password\": \":dbpass:\",\n  \"database\": \":dbname:\",\n  \"entities\": [\"src/**/*.entity{.ts,.js}\"],\n  \"migrations\": [\"./src/migrations/*.ts\"],\n  \"synchronize\": false,\n  \"cli\": {\n    \"migrationsDir\": \"./src/migrations\"\n  },\n  \"logging\": true\n}"
  },
  {
    "path": "quix-frontend/service/scripts/run_migrations.sh",
    "content": "#!/usr/bin/env bash\n\nif [ ! -f .quixroot ]; then\n  echo \"This script must be run from quix/quix-frontend/service folder\"\n  exit -1\nfi\n\nDEFAULTPORT=3306\nDEFAULTDB=\"quix\"\nDEFAULTPASS=\"\"\nDEFAULTPUSER=\"root\"\nDEFAULTHOST=\"db\"\n\nexport DB_HOST=${DB_HOST:-$DEFAULTHOST}\nexport DB_USER=${DB_USER:-$DEFAULTPUSER}\nexport DB_PASS=${DB_PASS:-$DEFAULTPASS}\nexport DB_NAME=${DB_NAME:-$DEFAULTDB}\nexport DB_PORT=${DB_PORT:-$DEFAULTPORT}\n\nsed -e \"s/:dbhost:/$DB_HOST/\" \\\n  -e \"s/:dbuser:/$DB_USER/\" \\\n  -e \"s/:dbpass:/$DB_PASS/\" \\\n  -e \"s/:dbname:/$DB_NAME/\" \\\n  -e \"s/:dbport:/$DB_PORT/\" \\\n  scripts/ormconfig.json.template > ormconfig.generated.migration-run.json\n\n./node_modules/.bin/ts-node -O '{\"strict\":false}' -r tsconfig-paths/register node_modules/.bin/typeorm migration:run -f ormconfig.generated.migration-run\n"
  },
  {
    "path": "quix-frontend/service/scripts/start.ts",
    "content": "import path from 'path';\nimport fs from 'fs';\nimport {buildAndCopyStatics} from './helpers/copy-statics';\n\nasync function main() {\n  const projectDir = path.resolve(__dirname, '..');\n  const clientDir = path.resolve(__dirname, '..', '..', 'client');\n\n  const mainFile = path.resolve(projectDir, 'src', 'main.ts');\n\n  if (!fs.existsSync(path.resolve(projectDir, 'statics', 'index.vm'))) {\n    buildAndCopyStatics(projectDir, clientDir);\n  }\n  require(mainFile);\n}\n\nmain();\n"
  },
  {
    "path": "quix-frontend/service/scripts/update-statics.ts",
    "content": "import path from 'path';\nimport {buildAndCopyStatics} from './helpers/copy-statics';\n\nfunction main() {\n  const projectDir = path.resolve(__dirname, '..');\n  const clientDir = path.resolve(__dirname, '..', '..', 'client');\n  buildAndCopyStatics(projectDir, clientDir);\n}\n\nmain();\n"
  },
  {
    "path": "quix-frontend/service/src/app.controller.spec.ts",
    "content": "import {Test, TestingModule} from '@nestjs/testing';\nimport {getConnectionToken} from '@nestjs/typeorm';\nimport {AppController} from './app.controller';\nimport {ConfigModule} from './config';\nimport {ValueProvider} from '@nestjs/common/interfaces';\n\nconst fakeConnection = {\n  provide: getConnectionToken(),\n  useValue: {},\n};\n\ndescribe('AppController', () => {\n  let appController: AppController;\n  let app: TestingModule | null = null;\n\n  async function preTest(mocked?: ValueProvider) {\n    const testingModule = Test.createTestingModule({\n      controllers: [AppController],\n      providers: [fakeConnection],\n      imports: [ConfigModule.create()],\n    });\n    if (mocked) {\n      testingModule.overrideProvider(mocked.provide).useValue(mocked.useValue);\n    }\n    app = await testingModule.compile();\n\n    appController = app.get<AppController>(AppController);\n  }\n  // beforeEach(async () => preTest());\n  afterEach(async () => {\n    if (app) {\n      await app.close();\n      app = null;\n    }\n  });\n\n  describe('index.vm', () => {\n    it('should return valid render view model', async () => {\n      await preTest();\n      const vm = appController.getIndex();\n      expect(vm).toMatchObject({\n        clientTopology: {\n          staticsBaseUrl: '/',\n        },\n      });\n    });\n\n    it('should parse module configuration correctly', async () => {\n      const mockedGlobalEnv = {\n        MODULES: 'presto,was,athena',\n\n        MODULES_PRESTO_ENGINE: 'presto',\n        MODULES_PRESTO_API: 'http://presto:8181/v1/',\n\n        MODULES_WAS_ENGINE: 'jdbc',\n        MODULES_WAS_SYNTAX: 'someSqlSyntax',\n        MODULES_WAS_API: 'http://presto:8181/v1/',\n\n        MODULES_ATHENA_ENGINE: 'athena',\n        MODULES_ATHENA_SYNTAX: 'ansi_sql',\n        MODULES_ATHENA_DATABASE: 'default',\n      };\n      await preTest({provide: 'GLOBAL_ENV', useValue: mockedGlobalEnv});\n      const quixConfig = JSON.parse(appController.getIndex().quixConfig);\n      expect(quixConfig.modules).toContainEqual(\n        expect.objectContaining({\n          id: 'presto',\n          engine: 'presto',\n          syntax: 'presto',\n        }),\n      );\n      expect(quixConfig.modules).toContainEqual(\n        expect.objectContaining({\n          id: 'was',\n          engine: 'jdbc',\n          syntax: 'someSqlSyntax',\n        }),\n      );\n      expect(quixConfig.modules).toContainEqual(\n        expect.objectContaining({\n          id: 'athena',\n          engine: 'athena',\n          syntax: 'athena',\n        }),\n      );\n    });\n\n    it('should parse old style configuration correctly', async () => {\n      const mockedGlobalEnv = {\n        MODULES: 'presto,athena',\n      };\n      await preTest({provide: 'GLOBAL_ENV', useValue: mockedGlobalEnv});\n      const quixConfig = JSON.parse(appController.getIndex().quixConfig);\n      expect(quixConfig.modules).toContainEqual(\n        expect.objectContaining({\n          id: 'presto',\n          engine: 'presto',\n          syntax: 'presto',\n        }),\n      );\n      expect(quixConfig.modules).toContainEqual(\n        expect.objectContaining({\n          id: 'athena',\n          engine: 'athena',\n          syntax: 'athena',\n        }),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/app.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Render,\n  Res,\n  Req,\n  OnApplicationShutdown,\n} from '@nestjs/common';\nimport {ConfigService, EnvSettings} from './config';\nimport {InjectConnection} from '@nestjs/typeorm';\nimport {Connection} from 'typeorm';\nimport {Response} from 'express';\nimport {ClientConfigHelper} from '@wix/quix-shared';\n\n@Controller()\nexport class AppController implements OnApplicationShutdown {\n  private clientConfig: ClientConfigHelper | undefined;\n  private timer: NodeJS.Timer;\n\n  constructor(\n    private configService: ConfigService,\n    @InjectConnection() private conn: Connection,\n  ) {\n    this.fetchClientConfig();\n    this.timer = setInterval(\n      () => this.fetchClientConfig.bind(this),\n      1000 * 60 * 10,\n    );\n  }\n\n  onApplicationShutdown() {\n    clearInterval(this.timer);\n  }\n\n  private fetchClientConfig() {\n    this.clientConfig = this.configService.getClientConfig();\n  }\n\n  @Get()\n  @Render('index.vm')\n  getIndex() {\n    if (!this.clientConfig) {\n      throw new Error('Server not up yet');\n    }\n\n    const clientTopology = this.clientConfig.getClientTopology();\n    const mode = this.clientConfig.getMode();\n\n    return {\n      clientTopology,\n      mode,\n      quixConfig: this.clientConfig.serialize(),\n    };\n  }\n\n  @Get('/health/is_alive')\n  async healthCheck(@Res() response: Response) {\n    await this.conn\n      .query(`SELECT 'health-check' FROM dual LIMIT 1`)\n      .then(() => response.sendStatus(200).end())\n      .catch(() => response.sendStatus(500).end());\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/app.module.ts",
    "content": "import {Module} from '@nestjs/common';\nimport {AppController} from './app.controller';\nimport {BaseModule} from './base.module';\nimport {ConfigModule, ConfigService} from './config';\nimport {AuthModuleConfiguration} from './modules/auth/auth.module';\nimport {AuthTypes} from './modules/auth/types';\n@Module({\n  imports: [\n    BaseModule,\n    ConfigModule.create(),\n    AuthModuleConfiguration.createAsync({\n      injects: [ConfigService],\n      imports: [],\n      useFactory: (configService: ConfigService) => {\n        const env = configService.getEnvSettings();\n        if (env.AuthType === 'fake') {\n          return {\n            type: AuthTypes.FAKE,\n            cookieName: env.AuthCookieName,\n          };\n        } else if (env.AuthType === 'google') {\n          return {\n            type: AuthTypes.GOOGLE,\n            cookieEncKey: env.AuthEncKey,\n            cookieName: env.AuthCookieName,\n            cookieTTL: env.CookieAge,\n            googleAuthSecret: env.GoogleAuthSecret,\n            googleClientId: env.GoogleClientId,\n          };\n        }\n        throw new Error('unknown auth type');\n      },\n    }),\n  ],\n  controllers: [AppController],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "quix-frontend/service/src/base.module.ts",
    "content": "import {Module} from '@nestjs/common';\nimport {AppController} from './app.controller';\nimport {TypeOrmModule} from '@nestjs/typeorm';\nimport {SearchModule} from './modules/search/search.module';\nimport {EventSourcingModule} from './modules/event-sourcing/event-sourcing.module';\nimport {WebApiModule} from './modules/web-api/web-api.module';\nimport {ConfigService} from './config';\nimport {\n  DbFileTreeNode,\n  DbFolder,\n  DbNote,\n  DbNotebook,\n  DbUser,\n  DbFavorites,\n  DbMetadata,\n  DbDeletedNotebook,\n} from './entities';\nimport {DbAction} from './modules/event-sourcing/infrastructure/action-store/entities/db-action.entity';\nimport {ProxyDbApiBackend} from './modules/proxy-backend/proxy-backend.module';\n\n@Module({\n  imports: [\n    TypeOrmModule.forRootAsync({\n      imports: [],\n      useFactory: async (cs: ConfigService) =>\n        cs.getDbConnection([\n          DbFileTreeNode,\n          DbFolder,\n          DbNote,\n          DbNotebook,\n          DbDeletedNotebook,\n          DbAction,\n          DbUser,\n          DbFavorites,\n          DbMetadata,\n        ]),\n      inject: [ConfigService],\n    }),\n    EventSourcingModule,\n    WebApiModule,\n    ProxyDbApiBackend,\n    SearchModule,\n  ],\n  controllers: [AppController],\n})\nexport class BaseModule { }\n"
  },
  {
    "path": "quix-frontend/service/src/common/demo-mode-interceptor.ts",
    "content": "/* removes owner from responses */\nimport {\n  Injectable,\n  NestInterceptor,\n  ExecutionContext,\n  CallHandler,\n} from '@nestjs/common';\nimport {Observable} from 'rxjs';\nimport {map} from 'rxjs/operators';\nimport {EnvSettings} from '../config';\nimport {ConfigService} from '../config';\nimport {sanitizeUserEmail, sanitizeUserName} from './user-sanitizer';\nimport {IUser} from '@wix/quix-shared';\n\n@Injectable()\nexport class DemoModeInterceptor implements NestInterceptor {\n  private env: EnvSettings;\n  constructor(private configService: ConfigService) {\n    this.env = this.configService.getEnvSettings();\n  }\n  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n    if (!this.env.DemoMode) {\n      return next.handle();\n    }\n    const email = context.switchToHttp().getRequest().user.email;\n    return next.handle().pipe(map(removeOwnerNested.bind(null, email)));\n  }\n}\n\nfunction removeOwnerNested(user: string, item: any): any {\n  if (Array.isArray(item)) {\n    return item.map(removeOwnerNested.bind(null, user));\n  }\n  if (item && typeof item === 'object') {\n    if (item.owner) {\n      item.owner = item.owner === user ? user : sanitizeUserEmail(item.owner);\n    }\n\n    if (item.ownerDetails) {\n      const {email, id, name} = item.ownerDetails as IUser;\n\n      item.ownerDetails = Object.assign(item.ownerDetails, {\n        name: sanitizeUserName(name),\n        id: sanitizeUserEmail(id),\n        email: sanitizeUserEmail(email),\n        avatar: 'http://quix.wix.com/assets/user.svg',\n      });\n    }\n\n    for (const key of Object.keys(item)) {\n      if (typeof item === 'object') {\n        item[key] = removeOwnerNested(user, item[key]);\n      }\n    }\n  }\n  return item;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/common/entity-type.enum.ts",
    "content": "export enum EntityType {\n  Notebook = 'notebook',\n  Note = 'note',\n  Folder = 'folder',\n}\n"
  },
  {
    "path": "quix-frontend/service/src/common/user-sanitizer.ts",
    "content": "export const sanitizeUserEmail = (email: string) => {\n  const [user, domain] = (email || 'dummy@dummy.com').split('@');\n\n  return ['***', domain].join('@');\n};\n\nexport const sanitizeUserName = (name: string) => {\n  return 'Quix User';\n};\n"
  },
  {
    "path": "quix-frontend/service/src/config/config.module.ts",
    "content": "import {DynamicModule, Module} from '@nestjs/common';\nimport {ConfigService, DefaultConfigService} from './config.service';\nimport {EnvSettings} from './env';\n\nconst configServiceProvider = {\n  provide: ConfigService,\n  useClass: DefaultConfigService,\n};\n\nconst globalEnvProvider = {\n  provide: 'GLOBAL_ENV',\n  useValue: process.env,\n};\n\n@Module({\n  imports: [],\n  controllers: [],\n  providers: [configServiceProvider, globalEnvProvider],\n  exports: [configServiceProvider],\n})\nexport class ConfigModule {\n  static create(overrides: Partial<EnvSettings> = {}): DynamicModule {\n    return {\n      module: ConfigModule,\n      global: true,\n      providers: [\n        {\n          provide: 'CONFIG_OVERRIDES',\n          useValue: overrides,\n        },\n      ],\n    };\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/config/config.service.ts",
    "content": "import {Inject, Injectable, Optional} from '@nestjs/common';\nimport {ConnectionOptions} from 'typeorm';\nimport * as dbConnection from './db-connection';\nimport {EnvSettings, loadEnv, getEnv} from './env';\nimport {ClientConfigHelper} from '@wix/quix-shared';\n\nexport type DbTypes = 'mysql' | 'sqlite';\n\nloadEnv();\n\nexport abstract class ConfigService {\n  private env: EnvSettings;\n\n  constructor(\n    @Inject('GLOBAL_ENV') globalEnv: any,\n    @Inject('CONFIG_OVERRIDES') overrides: Partial<EnvSettings>,\n  ) {\n    this.env = {...getEnv(globalEnv), ...overrides};\n    /* tslint:disable-next-line */\n    console.log(`****** Current Environment:: DbType:${this.env.DbType}/AuthType:${this.env.AuthType} ******`);\n  }\n\n  getEnvSettings(): EnvSettings {\n    return this.env;\n  }\n\n  getDbType(): DbTypes {\n    const env = this.getEnvSettings();\n    return env.DbType;\n  }\n\n  getDbConnection(entities: any[]): ConnectionOptions {\n    switch (this.env.DbType) {\n      case 'sqlite':\n        return dbConnection.createInMemConf(entities, this.getEnvSettings());\n      case 'mysql': {\n        return dbConnection.createMysqlConf(entities, this.getEnvSettings());\n      }\n    }\n  }\n\n  getClientConfig() {\n    const env = this.getEnvSettings();\n    const clientConfig = new ClientConfigHelper();\n    const staticsBaseUrl = env.remoteStaticsPath\n      ? env.remoteStaticsPath\n      : `${env.MountPath}/`;\n\n    clientConfig\n      .setAuth({\n        googleClientId: env.GoogleClientId,\n      })\n      .setClientTopology({\n        executeBaseUrl: env.QuixBackendPublicUrl,\n        staticsBaseUrl,\n        apiBasePath: env.MountPath,\n      })\n      .setMode({\n        debug: !env.UseMinifiedStatics,\n        demo: env.DemoMode,\n      });\n\n    env.Modules.forEach(m =>\n      clientConfig.addModule({\n        id: m,\n        name: m,\n        components: env.moduleSettings[m].components,\n        engine: env.moduleSettings[m].engine as any,\n        syntax: env.moduleSettings[m].syntax,\n      }),\n    );\n\n    return clientConfig;\n  }\n}\n\n@Injectable()\nexport class DefaultConfigService extends ConfigService {}\n"
  },
  {
    "path": "quix-frontend/service/src/config/db-conf.ts",
    "content": "import {ColumnOptions, PrimaryColumnOptions} from 'typeorm';\nimport {getEnv} from './env/env';\nimport {FileType} from '@wix/quix-shared/entities/file';\nimport {ContentSearch, SearchTextType} from '@wix/quix-shared';\nimport {escape} from 'mysql2';\nimport {EntityType} from '../common/entity-type.enum';\n\n/* A compatibility layer between MySql and Sqlite (sqljs), should handle everything that typeorm doesn't handle for us */\ninterface DbColumnConf {\n  json: ColumnOptions;\n  shortTextField: ColumnOptions;\n  nameField: ColumnOptions;\n  noteContent: ColumnOptions;\n  dateUpdated: ColumnOptions;\n  dateCreated: ColumnOptions;\n  dateDeleted: ColumnOptions;\n  idColumn: PrimaryColumnOptions;\n  eventsTimestamp: ColumnOptions;\n  fileTypeEnum: ColumnOptions;\n  entityTypeEnum: ColumnOptions;\n  userAvatar: ColumnOptions;\n  concat: (s1: string, s2: string) => string;\n  fullTextSearch: (\n    columnName: string,\n    textToLookFor: ContentSearch[],\n  ) => string;\n}\n\nconst MySqlConf: DbColumnConf = {\n  json: {type: 'json', nullable: true},\n  shortTextField: {type: 'varchar', length: 64},\n  nameField: {type: 'varchar', length: 512},\n  noteContent: {type: 'mediumtext', nullable: true},\n  dateUpdated: {\n    transformer: {\n      from: (d?: Date) => d && d.valueOf(),\n      to: (v?: number) => (v !== undefined ? new Date(v) : undefined),\n    },\n    readonly: true,\n    name: 'date_updated',\n  },\n  dateCreated: {\n    transformer: {\n      from: (d?: Date) => d && d.valueOf(),\n      to: (v?: number) => (v !== undefined ? new Date(v) : undefined),\n    },\n    readonly: true,\n    name: 'date_created',\n  },\n  dateDeleted: {\n    transformer: {\n      from: (d?: Date) => d && d.valueOf(),\n      to: (v?: number) => (v !== undefined ? new Date(v) : undefined),\n    },\n    readonly: true,\n    name: 'date_deleted',\n  },\n  eventsTimestamp: {\n    type: 'timestamp',\n    precision: 4,\n    default: () => 'CURRENT_TIMESTAMP(4)',\n  },\n  idColumn: {nullable: false, unique: true, type: 'varchar', length: 36},\n  fileTypeEnum: {\n    type: 'enum',\n    enum: FileType,\n    default: FileType.folder,\n  },\n  entityTypeEnum: {\n    type: 'enum',\n    enum: EntityType,\n    default: EntityType.Notebook,\n  },\n  userAvatar: {nullable: true, type: 'varchar', length: 255},\n  concat: (s1, s2) => `CONCAT(${s1}, ${s2})`,\n  fullTextSearch(columnName, contentSearchList) {\n    return `MATCH(${columnName}) AGAINST (${escape(\n      contentSearchList\n        .map(contentSearch =>\n          contentSearch.type === SearchTextType.PHRASE\n            ? `\"${contentSearch.text}\"`\n            : `${contentSearch.text}*`,\n        )\n        .join(' '),\n    )} IN BOOLEAN MODE)`;\n  },\n};\n\nconst SqliteConf: DbColumnConf = {\n  json: {type: 'simple-json', nullable: true},\n  shortTextField: {type: 'varchar', length: 64},\n  nameField: {type: 'varchar', length: 512},\n  noteContent: {type: 'text', nullable: true},\n  dateUpdated: {\n    type: 'integer',\n    name: 'date_updated',\n    transformer: {\n      from: (d: number) => {\n        const date = new Date(d);\n        return Date.UTC(\n          date.getUTCFullYear(),\n          date.getUTCMonth(),\n          date.getUTCDate(),\n          date.getUTCHours(),\n          date.getUTCMinutes(),\n          date.getUTCSeconds(),\n        ).valueOf();\n      },\n      to: (v?: number) => v,\n    },\n  },\n  dateCreated: {\n    type: 'integer',\n    name: 'date_created',\n    transformer: {\n      from: (d: number) => {\n        const date = new Date(d);\n        return Date.UTC(\n          date.getUTCFullYear(),\n          date.getUTCMonth(),\n          date.getUTCDate(),\n          date.getUTCHours(),\n          date.getUTCMinutes(),\n          date.getUTCSeconds(),\n        ).valueOf();\n      },\n      to: (v?: number) => v,\n    },\n  },\n  dateDeleted: {\n    type: 'integer',\n    name: 'date_deleted',\n    transformer: {\n      from: (d: number) => {\n        const date = new Date(d);\n        return Date.UTC(\n          date.getUTCFullYear(),\n          date.getUTCMonth(),\n          date.getUTCDate(),\n          date.getUTCHours(),\n          date.getUTCMinutes(),\n          date.getUTCSeconds(),\n        ).valueOf();\n      },\n      to: (v?: number) => v,\n    },\n  },\n  eventsTimestamp: {\n    type: 'integer',\n    default: () => `CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER)`,\n    transformer: {\n      from: (d: number) => d,\n      to: (d?: Date) => d && d.valueOf(),\n    },\n  },\n  idColumn: {nullable: false, unique: true, type: 'varchar', length: 36},\n  fileTypeEnum: {type: 'varchar', length: 32, default: FileType.folder},\n  entityTypeEnum: {type: 'integer', default: EntityType.Notebook},\n  userAvatar: {nullable: true, type: 'varchar', length: 255},\n  concat: (s1, s2) => `(${s1} || ${s2})`,\n  fullTextSearch(columnName, contentSearchList) {\n    return contentSearchList\n      .map(searchItem => `${columnName} LIKE '%${searchItem.text}%'`)\n      .join(' OR ');\n  },\n};\nexport const dbConf = getEnv().DbType === 'mysql' ? MySqlConf : SqliteConf;\n"
  },
  {
    "path": "quix-frontend/service/src/config/db-connection.ts",
    "content": "import {ConnectionOptions} from 'typeorm';\nimport {EnvSettings} from './env';\nimport {isTsNode} from './utils';\n\ntype ClassConstructor = new (...args: any[]) => any;\n\nexport const createInMemConf = (\n  entities: ClassConstructor[] | string[],\n  settings: EnvSettings,\n): ConnectionOptions => {\n  return {\n    type: 'sqljs',\n    synchronize: settings.AutoMigrateDb,\n    entities,\n    logger: 'advanced-console',\n    logging: settings.DbDebug,\n  };\n};\n\nexport const createMysqlConf = (\n  entities: ClassConstructor[] | string[],\n  settings: EnvSettings,\n): ConnectionOptions => {\n  return {\n    type: 'mysql',\n    host: settings.DbHost,\n    port: settings.DbPort,\n    username: settings.DbUser,\n    password: settings.DbPass,\n    database: settings.DbName,\n    synchronize: settings.AutoMigrateDb,\n    entities,\n    logger: 'advanced-console',\n    logging: settings.DbDebug,\n    migrations: isTsNode()\n      ? ['./src/migrations/*.ts']\n      : ['./dist/migrations/*.js'],\n  };\n};\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/computed-settings.ts",
    "content": "/* tslint:disable:no-console */\nimport {ComputedSettings} from './types';\nimport {ModuleEngineType, ModuleEngineToSyntaxMap} from '@wix/quix-shared';\nimport {engineToClientComponents} from './engine-settings';\n\nexport const computedSettingsDefaults: ComputedSettings = {\n  moduleSettings: {\n    presto: {\n      syntax: 'ansi_sql',\n      engine: 'presto',\n      components: {db: {}, note: {}},\n    },\n  },\n};\n\nconst getModuleSettings = (moduleName: string, globalEnv: any) => {\n  const syntaxEnvVar = `MODULES_${moduleName.toUpperCase()}_SYNTAX`;\n  const engineEnvVar = `MODULES_${moduleName.toUpperCase()}_ENGINE`;\n  let engine = globalEnv[engineEnvVar];\n  let syntax: string = '';\n\n  /* backwards compatibility */\n  if (engine === undefined) {\n    switch (moduleName) {\n      case 'presto':\n        engine = ModuleEngineType.Presto;\n        break;\n      case 'athena':\n        engine = ModuleEngineType.Athena;\n        break;\n      default:\n    }\n  }\n  /* end */\n\n  if (!Object.values(ModuleEngineType).includes(engine)) {\n    console.error(\n      `Bad configuration. Missing or bad 'engine' declaration for module '${moduleName}'. Possible values: ${Object.values(\n        ModuleEngineType,\n      ).join(',')}`,\n    );\n    return undefined;\n  }\n\n  switch (engine) {\n    case ModuleEngineType.Presto:\n      syntax = ModuleEngineToSyntaxMap[ModuleEngineType.Presto];\n      break;\n    case ModuleEngineType.Athena:\n      syntax = ModuleEngineToSyntaxMap[ModuleEngineType.Athena];\n      break;\n    case ModuleEngineType.BigQuery:\n      syntax = ModuleEngineToSyntaxMap[ModuleEngineType.BigQuery];\n      break;\n    case ModuleEngineType.Python:\n      syntax = ModuleEngineToSyntaxMap[ModuleEngineType.BigQuery];\n      break;\n    default: {\n      syntax = globalEnv[syntaxEnvVar] as string;\n    }\n  }\n\n  if (!syntax) {\n    console.error(\n      `Bad configuration. Missing 'syntax' declaration for module '${moduleName}'`,\n    );\n    return undefined;\n  }\n  const components = engineToClientComponents(engine);\n  return {syntax, engine, components};\n};\n\nexport const getComputedSettings = (\n  modules: string[],\n  globalEnv: Record<string, string | undefined> = process.env,\n): ComputedSettings => {\n  const computedSettings: ComputedSettings = computedSettingsDefaults;\n\n  modules.forEach(moduleName => {\n    const moduleSettings = getModuleSettings(moduleName, globalEnv);\n\n    if (moduleSettings) {\n      computedSettings.moduleSettings[moduleName] = moduleSettings;\n    }\n  });\n  return computedSettings;\n};\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/engine-settings.ts",
    "content": "import {ModuleEngineType, ComponentConfiguration} from '@wix/quix-shared';\n\nexport const engineToClientComponents = (engine: string) => {\n  return moduleToComponentsMap[engine as ModuleEngineType] || {};\n};\n\nconst moduleToComponentsMap: Record<\n  ModuleEngineType,\n  ComponentConfiguration\n> = {\n  [ModuleEngineType.Athena]: {db: {}, note: {}},\n  [ModuleEngineType.BigQuery]: {db: {}, note: {}},\n  [ModuleEngineType.Jdbc]: {db: {}, note: {}},\n  [ModuleEngineType.Presto]: {db: {}, note: {}},\n  [ModuleEngineType.Python]: {note: {}},\n};\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/env.spec.ts",
    "content": "import {getEnv} from './env';\nimport {testingDefaults} from './static-settings';\n\ndescribe('configuration parsing', () => {\n  it('should override empty strings with defaults', () => {\n    const mockEnv = {\n      DB_HOST: '',\n      DB_USER: '',\n    };\n    const env = getEnv();\n    expect(env.DbHost).toBe(testingDefaults.DbHost);\n    expect(env.DbUser).toBe(testingDefaults.DbUser);\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/env.ts",
    "content": "import dotenv from 'dotenv';\nimport {isJestTest} from '../utils';\nimport path from 'path';\nimport {defaults} from 'lodash';\nimport {BaseConnectionOptions} from 'typeorm/connection/BaseConnectionOptions';\nimport {StaticSettings, EnvSettings} from './types';\nimport {\n  envSettingsMap,\n  testingDefaults,\n  envSettingsDefaults,\n} from './static-settings';\nimport {getComputedSettings} from './computed-settings';\n\nlet environmentLoaded = false;\nexport const loadEnv = () => {\n  if (!environmentLoaded) {\n    if (isJestTest()) {\n      dotenv.config({path: path.resolve(process.cwd(), '.testenv')});\n    } else {\n      dotenv.config();\n    }\n    environmentLoaded = true;\n  }\n};\n\nconst identity = <T>(x: T) => x;\nconst stringParse = (s: string | undefined) => (s === '' ? undefined : s);\nconst backendUrlParse = (s: string | undefined) => {\n  if (s === undefined) {\n    return undefined;\n  }\n  return s.replace('https://', '').replace('http://', '');\n};\n\nconst numberParse = (s: string | undefined) =>\n  s ? parseInt(s, 10) : undefined;\nconst booleanParse = (s: string | undefined) =>\n  s !== undefined\n    ? s.toLowerCase() === 'false' || s === ''\n      ? false\n      : true\n    : undefined;\nconst stringListParse = (s: string | undefined) =>\n  s !== undefined ? s.split(',') : undefined;\n\nconst transforms: {\n  [K in keyof StaticSettings]: (\n    s: string | undefined,\n  ) => StaticSettings[K] | undefined;\n} = {\n  DbType: s => {\n    switch (s) {\n      case 'sqlite':\n      case 'mysql':\n        return s;\n      case undefined:\n      case '':\n        return undefined;\n      default:\n        throw new Error('Unknown DB type.');\n    }\n  },\n  AuthType: s => {\n    switch (s) {\n      case 'google':\n      case 'fake':\n        return s;\n      case undefined:\n      case '':\n        return undefined;\n      default:\n        throw new Error('Unknown Auth type.');\n    }\n  },\n  DbName: stringParse,\n  DbUser: stringParse,\n  DbPass: identity,\n  DbHost: stringParse,\n  DbPort: numberParse,\n  QuixBackendInternalUrl: backendUrlParse,\n  QuixBackendPublicUrl: backendUrlParse,\n  GoogleClientId: stringParse,\n  GoogleAuthSecret: stringParse,\n  AuthCookieName: stringParse,\n  AuthEncKey: stringParse,\n  CookieAge: numberParse,\n  AutoMigrateDb: booleanParse,\n  UseMinifiedStatics: booleanParse,\n  DemoMode: booleanParse,\n  DbDebug: s => {\n    if (s === undefined) {\n      return undefined;\n    }\n    if (s === '') {\n      return false;\n    }\n    if (s.toLowerCase() === 'true') {\n      return true;\n    }\n    if (s.toLowerCase() === 'false') {\n      return false;\n    }\n    return s.split(',') as BaseConnectionOptions['logging'];\n  },\n  Modules: stringListParse,\n  HttpPort: numberParse,\n  MountPath: identity,\n  localStaticsPath: identity,\n  remoteStaticsPath: identity,\n};\n\nexport const getEnv = (\n  globalEnv: Record<string, string | undefined> = process.env,\n): EnvSettings => {\n  loadEnv();\n\n  const staticSettings: StaticSettings = defaults(\n    Object.entries(envSettingsMap).reduce((settings, [key, envVar]) => {\n      settings[key] = transforms[key as keyof StaticSettings](\n        globalEnv[envVar],\n      );\n      return settings;\n    }, {} as any),\n    isJestTest() ? testingDefaults : envSettingsDefaults,\n  );\n\n  const computedSettings = getComputedSettings(\n    staticSettings.Modules,\n    globalEnv,\n  );\n  const env = {...computedSettings, ...staticSettings};\n\n  return env;\n};\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/index.ts",
    "content": "export {EnvSettings} from './types';\nexport {getEnv, loadEnv} from './env';\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/static-settings.ts",
    "content": "import {BaseConnectionOptions} from 'typeorm/connection/BaseConnectionOptions';\nimport * as path from 'path';\n\nimport {StaticSettings} from './types';\n\nexport const envSettingsMap: {[K in keyof StaticSettings]: string} = {\n  DbName: 'DB_NAME',\n  DbUser: 'DB_USER',\n  DbPass: 'DB_PASS',\n  DbHost: 'DB_HOST',\n  DbPort: 'DB_PORT',\n  QuixBackendInternalUrl: 'BACKEND_INTERNAL_URL',\n  QuixBackendPublicUrl: 'BACKEND_PUBLIC_URL',\n  GoogleClientId: 'GOOGLE_SSO_CLIENT_ID',\n  GoogleAuthSecret: 'GOOGLE_SSO_SECRET',\n  AuthCookieName: 'AUTH_COOKIE',\n  AuthEncKey: 'AUTH_SECRET',\n  CookieAge: 'COOKIE_MAX_AGE',\n  DbType: 'DB_TYPE',\n  AuthType: 'AUTH_TYPE',\n  AutoMigrateDb: 'DB_AUTO_MIGRATE',\n  UseMinifiedStatics: 'MINIFIED_STATICS',\n  DemoMode: 'DEMO_MODE',\n  DbDebug: 'DB_DEBUG',\n  Modules: 'MODULES',\n  HttpPort: 'HTTP_PORT',\n  MountPath: 'MOUNT_PATH',\n  localStaticsPath: 'LOCAL_STATICS_PATH',\n  remoteStaticsPath: 'REMOTE_STATICS_PATH',\n};\n\nexport const envSettingsDefaults = {\n  DbType: 'mysql' as 'mysql' | 'sqlite',\n  AuthType: 'fake' as 'fake' | 'google',\n  DbName: 'quix',\n  DbUser: 'root',\n  DbPass: '',\n  DbHost: 'db',\n  DbPort: 3306,\n  QuixBackendInternalUrl: 'backend:8081',\n  QuixBackendPublicUrl: 'localhost:8081',\n  GoogleClientId: '',\n  GoogleAuthSecret: '',\n  AuthCookieName: '__quix',\n  AuthEncKey: '123456',\n  CookieAge: 30 * 24 * 60 * 60 * 1000 /* 30 days */,\n  AutoMigrateDb: false,\n  UseMinifiedStatics: true,\n  DemoMode: false,\n  DbDebug: ['error', 'schema', 'warn'] as BaseConnectionOptions['logging'],\n  Modules: ['presto'],\n  HttpPort: 3000,\n  MountPath: '',\n  localStaticsPath: path.resolve('.', 'statics'),\n  remoteStaticsPath: '',\n};\n\nexport const testingDefaults: StaticSettings = {\n  ...envSettingsDefaults,\n  DbName: 'quixtest',\n  DbHost: 'localhost',\n  QuixBackendInternalUrl: 'localhost:8081',\n  QuixBackendPublicUrl: 'localhost:8081',\n  AuthEncKey: '',\n  DbType: 'sqlite',\n  AuthType: 'fake',\n  AutoMigrateDb: true,\n  UseMinifiedStatics: false,\n  DbDebug: false,\n  Modules: ['presto'],\n  HttpPort: 3000,\n  MountPath: '',\n};\n"
  },
  {
    "path": "quix-frontend/service/src/config/env/types.ts",
    "content": "import {envSettingsDefaults} from './static-settings';\nimport {ComponentConfiguration} from '@wix/quix-shared';\n\nexport type StaticSettings = typeof envSettingsDefaults;\nexport interface ComputedSettings {\n  moduleSettings: Record<\n    string,\n    {\n      syntax: string;\n      engine: string;\n      components: ComponentConfiguration;\n    }\n  >;\n}\n\nexport type EnvSettings = StaticSettings & ComputedSettings;\n"
  },
  {
    "path": "quix-frontend/service/src/config/index.ts",
    "content": "export {ConfigService, DbTypes, DefaultConfigService} from './config.service';\nexport {EnvSettings} from './env';\nexport {ConfigModule} from './config.module';\n"
  },
  {
    "path": "quix-frontend/service/src/config/utils.ts",
    "content": "export function isJestTest() {\n  return process.env.JEST_WORKER_ID !== undefined;\n}\n\nexport function isTsNode() {\n  return !!require.extensions['.ts'] || __filename.slice(-2) === 'ts';\n}\n"
  },
  {
    "path": "quix-frontend/service/src/consts.ts",
    "content": "export const QUIX_SCHEMA = `QUIX_SCHEMA`;\nexport const CURRENT_QUIX_SCHEMA_VERSION = 5;\n"
  },
  {
    "path": "quix-frontend/service/src/entities/deleted-notebook/dbdeleted-notebook.entity.ts",
    "content": "import {IFilePathItem} from '@wix/quix-shared';\nimport {IDeletedNotebook} from '@wix/quix-shared';\nimport {dbConf} from '../../config/db-conf';\nimport {\n  Column,\n  CreateDateColumn,\n  Entity,\n  OneToMany,\n  OneToOne,\n  PrimaryColumn,\n  UpdateDateColumn,\n} from 'typeorm';\nimport {DbFileTreeNode} from '../filenode/filenode.entity';\nimport {convertDbNote, DbNote} from '../note/dbnote.entity';\nimport {DbUser} from '../user/user.entity';\nimport {extractOwnerDetails} from '../utils';\n\n@Entity('deleted_notebooks')\nexport class DbDeletedNotebook {\n  @PrimaryColumn({...dbConf.idColumn})\n  id!: string;\n\n  @Column(dbConf.nameField)\n  name!: string;\n\n  @Column(dbConf.shortTextField)\n  owner!: string;\n\n  ownerDetails?: DbUser;\n\n  @UpdateDateColumn(dbConf.dateUpdated)\n  dateUpdated!: number;\n\n  @CreateDateColumn(dbConf.dateCreated)\n  dateCreated!: number;\n\n  @CreateDateColumn(dbConf.dateDeleted)\n  dateDeleted!: number;\n\n  @Column({...dbConf.json, name: 'json_content'})\n  jsonContent: any;\n\n  @OneToMany(type => DbNote, n => n.notebook, {onDelete: 'CASCADE'})\n  notes?: DbNote[];\n\n  @OneToOne(type => DbFileTreeNode, node => node.notebook, {\n    onDelete: 'CASCADE',\n  })\n  fileNode?: DbFileTreeNode;\n\n  constructor(base?: DbDeletedNotebook) {\n    if (base) {\n      const {id, dateCreated, dateUpdated, name, notes, owner} = base;\n      this.id = id;\n      this.dateCreated = dateCreated;\n      this.dateUpdated = dateUpdated;\n      this.dateDeleted = this.dateDeleted;\n      this.name = name;\n      this.notes = notes;\n      this.owner = owner;\n    }\n    this.jsonContent = this.jsonContent || {};\n  }\n}\n\nexport const convertDbDeletedNotebook = (\n  dbDeletedNotebook: DbDeletedNotebook,\n  computedPath?: IFilePathItem[],\n  isLiked?: boolean,\n): IDeletedNotebook => {\n  const {\n    dateCreated,\n    dateUpdated,\n    dateDeleted,\n    id,\n    name,\n    owner,\n    notes,\n  } = dbDeletedNotebook;\n\n  const ownerDetails = extractOwnerDetails(dbDeletedNotebook);\n\n  return {\n    id,\n    dateCreated,\n    dateUpdated,\n    dateDeleted,\n    name,\n    owner,\n    isLiked: isLiked !== undefined ? isLiked : false,\n    notes: notes ? notes.map(convertDbNote) : [],\n    path: computedPath || [],\n    ownerDetails,\n  };\n};\n\nexport const covertDeletedNotebookToDb = (\n  notebook: IDeletedNotebook,\n): DbDeletedNotebook => {\n  const {\n    id,\n    name,\n    owner,\n    notes,\n    dateCreated,\n    dateUpdated,\n    dateDeleted,\n  } = notebook;\n\n  return new DbDeletedNotebook({\n    id,\n    dateCreated,\n    dateUpdated,\n    dateDeleted,\n    name,\n    owner,\n    jsonContent: {},\n  });\n};\n"
  },
  {
    "path": "quix-frontend/service/src/entities/deleted-notebook/deleted-notebook.repository.ts",
    "content": "import {EntityRepository, Repository} from 'typeorm';\nimport {DbDeletedNotebook} from './dbdeleted-notebook.entity';\n\n@EntityRepository(DbDeletedNotebook)\nexport class DeletedNotebookRepository extends Repository<DbDeletedNotebook> {}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/favorites/favorites.entity.ts",
    "content": "import {EntityType} from '../../common/entity-type.enum';\nimport {dbConf} from '../../config/db-conf';\nimport {Column, Entity, Index} from 'typeorm';\n\n@Entity({name: 'favorites'})\n@Index(['entityId'])\nexport class DbFavorites {\n  @Column({...dbConf.shortTextField, primary: true, unique: false})\n  owner!: string;\n\n  @Column({...dbConf.idColumn, unique: false, primary: true, name: 'entity_id'})\n  entityId!: string;\n\n  @Column({...dbConf.entityTypeEnum, name: 'entity_type'})\n  entityType!: EntityType;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/filenode/filenode.entity.ts",
    "content": "import {\n  Column,\n  Entity,\n  Index,\n  PrimaryColumn,\n  OneToOne,\n  JoinColumn,\n  ManyToOne,\n  CreateDateColumn,\n  UpdateDateColumn,\n} from 'typeorm';\nimport {IFile, FileType} from '@wix/quix-shared/entities/file';\nimport {DbNotebook} from '../notebook/dbnotebook.entity';\nimport {DbFolder} from '../folder/folder.entity';\nimport {dbConf} from '../../config/db-conf';\nimport {IUser} from '@wix/quix-shared';\n\n@Entity({name: 'tree_nodes'})\nexport class DbFileTreeNode {\n  constructor(id?: string, rest: Partial<DbFileTreeNode> = {}) {\n    if (id) {\n      this.id = id;\n      Object.assign(this, rest);\n    }\n  }\n  @PrimaryColumn({...dbConf.idColumn})\n  id!: string;\n\n  @Index()\n  @Column(dbConf.shortTextField)\n  owner!: string;\n\n  ownerDetails?: IUser;\n\n  @UpdateDateColumn(dbConf.dateUpdated)\n  dateUpdated!: number;\n\n  @CreateDateColumn(dbConf.dateCreated)\n  dateCreated!: number;\n\n  @Column(dbConf.fileTypeEnum)\n  type!: FileType;\n\n  @ManyToOne(type => DbFileTreeNode, {onDelete: 'CASCADE'})\n  @JoinColumn()\n  parent?: DbFileTreeNode;\n\n  @Column({nullable: true})\n  parentId?: string;\n\n  @OneToOne(type => DbNotebook, notebook => notebook.fileNode, {\n    onDelete: 'CASCADE',\n  })\n  @JoinColumn()\n  notebook?: DbNotebook;\n\n  @Column({nullable: true})\n  notebookId?: string;\n\n  @OneToOne(type => DbFolder, {\n    cascade: true,\n    onDelete: 'CASCADE',\n  })\n  @JoinColumn()\n  folder?: DbFolder;\n\n  @Column({nullable: true, type: 'varchar', length: 1024})\n  mpath!: string;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/filenode/filenode.repository.ts",
    "content": "import {\n  EntityRepository,\n  Repository,\n  SaveOptions,\n  DeepPartial,\n  EntityManager,\n} from 'typeorm';\nimport {DbFileTreeNode} from './filenode.entity';\nimport {dbConf} from '../../config/db-conf';\nimport assert from 'assert';\nimport {FileType} from '@wix/quix-shared';\nimport {DbNotebook} from '../notebook/dbnotebook.entity';\nimport {DbFolder} from '../folder/folder.entity';\nimport {DbFavorites} from '../favorites/favorites.entity';\n/**\n * This custom repository saves a tree structure in sql, using path enumeration/materialized path.\n * We don't use the built in solution by typeorm as it doesn't support moving/deletions yet.\n */\n@EntityRepository(DbFileTreeNode)\nexport class FileTreeRepository extends Repository<DbFileTreeNode> {\n  save(\n    entities: DeepPartial<DbFileTreeNode>[],\n    options?: SaveOptions & {\n      reload: false;\n    },\n  ): Promise<DbFileTreeNode[]>;\n  save(\n    entity: DeepPartial<DbFileTreeNode>,\n    options?: SaveOptions & {\n      reload: false;\n    },\n  ): Promise<DbFileTreeNode>;\n  async save(\n    itemOrItems: DeepPartial<DbFileTreeNode> | DeepPartial<DbFileTreeNode>[],\n    options?: SaveOptions,\n  ) {\n    if (Array.isArray(itemOrItems)) {\n      const items = itemOrItems;\n      for (const item of items) {\n        await this.setMpathByParent(item);\n      }\n      return super.save(items, options);\n    } else {\n      const item = itemOrItems;\n      await this.setMpathByParent(item);\n      return super.save(item, options);\n    }\n  }\n\n  private async getParentPath(item: DeepPartial<DbFileTreeNode>) {\n    if (item.parent && item.parent.mpath) {\n      return item.parent.mpath;\n    }\n    const parentId = getParentId(item);\n    if (parentId) {\n      return this.findOneOrFail(parentId)\n        .then(parent => parent.mpath)\n        .catch(() => {\n          throw new Error(\n            `saving file item ${item.id}:: Can't find parent node ${item.parentId}`,\n          );\n        });\n    }\n    return '';\n  }\n  /**\n   * Given a node with it's parent or parentId set,\n   * set the mpath correctly for it.\n   * @param item\n   */\n  private async setMpathByParent(item: DeepPartial<DbFileTreeNode>) {\n    const base = await this.getParentPath(item);\n    item.mpath = base + (base ? '.' : '') + item.id;\n  }\n\n  /**\n   * given a list of ids, return a list of matching tree nodes, joined with name from folder/notebook.\n   * @param ids\n   */\n  getNamesByIds(ids: string[]) {\n    return this.createQueryBuilder('node')\n      .select([\n        'node.id',\n        'node.type',\n        'node.parentId',\n        'notebook.name',\n        'folder.name',\n      ])\n      .leftJoin('node.notebook', 'notebook')\n      .leftJoin('node.folder', 'folder')\n      .where('node.id IN (:...ids)', {ids})\n      .getMany();\n  }\n\n  /**\n   * Get a list of first level children\n   * @returns {Promise<DbFileTreeNode[]>}\n   */\n  async getChildren(rootId: string) {\n    return this.createQueryBuilder('node')\n      .leftJoinAndSelect('node.notebook', 'notebook')\n      .leftJoinAndSelect('node.folder', 'folder')\n      .where('node.parentId = :rootId', {rootId})\n      .getMany();\n  }\n\n  /**\n   * Get a list of all children\n   * @returns {Promise<DbFileTreeNode[]>}\n   */\n  async getDeepChildren(root: DbFileTreeNode, entityManager?: EntityManager) {\n    const baseMpath = root.mpath;\n    assert(baseMpath && baseMpath.length > 0, 'mpath is empty/undefined');\n\n    const qb = entityManager\n      ? entityManager.createQueryBuilder(DbFileTreeNode, 'node')\n      : this.createQueryBuilder('node');\n\n    return qb\n      .where(`node.mpath LIKE ${dbConf.concat(`('${baseMpath}')`, `'%'`)}`)\n      .getMany();\n  }\n\n  async moveTree(root: DbFileTreeNode, newParentNode: DbFileTreeNode) {\n    if (root.id === newParentNode.id) {\n      throw new Error(\n        `Illegal request: can't move folder to itself, or to it's parent`,\n      );\n    }\n    if (root.parentId === newParentNode.id) {\n      return;\n    }\n    const baseMpath = root.mpath;\n    assert(baseMpath && baseMpath.length > 0, 'mpath is empty/undefined');\n\n    const newBasePath = newParentNode.mpath + '.' + root.id;\n    return this.manager.transaction(async em => {\n      await em\n        .createQueryBuilder()\n        .update(DbFileTreeNode)\n        .set({\n          mpath: () => `replace(\\`mpath\\`, '${baseMpath}', '${newBasePath}')`,\n        })\n        .where(`mpath LIKE ${dbConf.concat(`('${baseMpath}')`, `'%'`)}`)\n        .execute();\n\n      await em\n        .createQueryBuilder()\n        .update(DbFileTreeNode)\n        .set({parentId: newParentNode.id})\n        .where('id = :id', {id: root.id})\n        .execute();\n    });\n  }\n\n  async deleteTree(root: DbFileTreeNode) {\n    const baseMpath = root.mpath;\n    assert(baseMpath && baseMpath.length > 0, 'mpath is empty/undefined');\n    const children = await this.getDeepChildren(root);\n\n    const [foldersToDelete, notebooksToDelete] = children.reduce(\n      ([foldersIds, notebookIds], node) => {\n        (node.type === FileType.folder ? foldersIds : notebookIds).push(node);\n        return [foldersIds, notebookIds];\n      },\n      [[], []] as DbFileTreeNode[][],\n    );\n\n    return this.manager.transaction(async em => {\n      if (notebooksToDelete.length) {\n        await em\n          .createQueryBuilder()\n          .delete()\n          .from(DbNotebook)\n          .whereInIds(notebooksToDelete)\n          .execute();\n\n        await em\n          .createQueryBuilder()\n          .delete()\n          .from(DbFavorites)\n          .where('entity_id in (:...ids)', {\n            ids: notebooksToDelete.map(({id}) => id),\n          })\n          .execute();\n      }\n\n      if (foldersToDelete.length) {\n        await em\n          .createQueryBuilder()\n          .delete()\n          .from(DbFolder)\n          .whereInIds(foldersToDelete)\n          .execute();\n      }\n    });\n  }\n}\n\nfunction getParentId(node: DeepPartial<DbFileTreeNode>) {\n  return node.parent && node.parent.id !== undefined\n    ? node.parent.id\n    : node.parentId;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/folder/folder.entity.ts",
    "content": "import {\n  Column,\n  CreateDateColumn,\n  Entity,\n  PrimaryColumn,\n  UpdateDateColumn,\n} from 'typeorm';\nimport {dbConf} from '../../config/db-conf';\n\n@Entity({name: 'folders'})\nexport class DbFolder {\n  @PrimaryColumn({...dbConf.idColumn})\n  id!: string;\n\n  @Column(dbConf.nameField)\n  name!: string;\n\n  @Column(dbConf.shortTextField)\n  owner!: string;\n\n  @UpdateDateColumn(dbConf.dateUpdated)\n  dateUpdated!: number;\n\n  @CreateDateColumn(dbConf.dateCreated)\n  dateCreated!: number;\n\n  @Column({...dbConf.json, name: 'json_content'})\n  jsonContent: any = {};\n\n  isLiked!: boolean;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/index.ts",
    "content": "export {DbNote} from './note/dbnote.entity';\nexport {DbNotebook} from './notebook/dbnotebook.entity';\nexport {DbFileTreeNode} from './filenode/filenode.entity';\nexport {DbFolder} from './folder/folder.entity';\nexport {FileTreeRepository} from './filenode/filenode.repository';\nexport {NoteRepository} from './note/note.repository';\nexport {DbUser} from './user/user.entity';\nexport {DbFavorites} from './favorites/favorites.entity';\nexport {DbMetadata} from './version-metadata.entity';\nexport {NotebookRepository} from './notebook/notebook.repository';\nexport {DbAction} from '../modules/event-sourcing/infrastructure/action-store/entities/db-action.entity';\nexport {DbDeletedNotebook} from './deleted-notebook/dbdeleted-notebook.entity';\nexport {DeletedNotebookRepository} from './deleted-notebook/deleted-notebook.repository';\n"
  },
  {
    "path": "quix-frontend/service/src/entities/note/dbnote.entity.ts",
    "content": "import {\n  Column,\n  Entity,\n  Index,\n  PrimaryColumn,\n  ManyToOne,\n  UpdateDateColumn,\n  CreateDateColumn,\n} from 'typeorm';\nimport {INote, IBaseNote} from '@wix/quix-shared/entities/note';\nimport {DbNotebook} from '../notebook/dbnotebook.entity';\nimport {dbConf} from '../../config/db-conf';\n\n@Entity({name: 'notes'})\nexport class DbNote {\n  @PrimaryColumn({...dbConf.idColumn})\n  id!: string;\n\n  /** for any extra properties that might be added in the future */\n  @Column({...dbConf.json, name: 'json_content'})\n  jsonContent!: any;\n\n  /** for note data */\n  @Column({...dbConf.json, name: 'rich_content'})\n  richContent!: any;\n\n  @Index({fulltext: true})\n  @Column(dbConf.noteContent)\n  textContent!: string;\n\n  @Column(dbConf.shortTextField)\n  type!: string;\n\n  @Column(dbConf.nameField)\n  name!: string;\n\n  @Index()\n  @Column(dbConf.shortTextField)\n  owner!: string;\n\n  @UpdateDateColumn(dbConf.dateUpdated)\n  dateUpdated!: number;\n\n  @CreateDateColumn(dbConf.dateCreated)\n  dateCreated!: number;\n\n  @ManyToOne(type => DbNotebook, n => n.notes, {\n    createForeignKeyConstraints: false,\n  })\n  notebook?: DbNotebook;\n\n  @Column()\n  notebookId!: string;\n\n  @Column({type: 'integer'})\n  rank?: number;\n\n  constructor(base?: DbNote) {\n    if (base) {\n      Object.assign(this, base);\n    }\n  }\n}\n\nexport const convertDbNote = (dbNote: DbNote): INote => {\n  const {\n    dateCreated,\n    dateUpdated,\n    id,\n    name,\n    notebookId,\n    owner,\n    textContent,\n    jsonContent,\n    richContent,\n    type,\n  } = dbNote;\n\n  return {\n    type,\n    id,\n    content: textContent,\n    richContent: richContent || {},\n    dateCreated,\n    dateUpdated,\n    name,\n    notebookId,\n    owner,\n  };\n};\n\nexport const convertNoteToDb = (note: INote): DbNote => {\n  const {\n    id,\n    name,\n    notebookId,\n    owner,\n    type,\n    content,\n    dateCreated,\n    dateUpdated,\n    richContent,\n  } = note;\n\n  return new DbNote({\n    type,\n    id,\n    textContent: note.content,\n    jsonContent: {},\n    richContent,\n    name,\n    notebookId,\n    owner,\n    dateCreated,\n    dateUpdated,\n    rank: undefined,\n  });\n};\n"
  },
  {
    "path": "quix-frontend/service/src/entities/note/note.repository.ts",
    "content": "import {EntityRepository, Repository} from 'typeorm';\nimport {DbNote} from './dbnote.entity';\n\n@EntityRepository(DbNote)\nexport class NoteRepository extends Repository<DbNote> {\n  async insertNewWithRank(note: DbNote) {\n    const currentCount = await this.count({notebookId: note.notebookId});\n    note.rank = currentCount;\n    return this.insert(note);\n  }\n\n  async deleteOneAndOrderRank(item: string | DbNote) {\n    const note =\n      typeof item === 'string' ? await this.findOneOrFail(item) : item;\n\n    return this.manager.transaction(async em => {\n      await em\n        .createQueryBuilder()\n        .update(DbNote)\n        .set({\n          rank: () => '`rank` - 1',\n        })\n        .where(`notebookId = :notebookId`, {notebookId: note.notebookId})\n        .andWhere(`\\`rank\\` > :rank`, {rank: note.rank})\n        .execute();\n      await em.delete(DbNote, note.id);\n    });\n  }\n\n  async reorder(note: DbNote, to: number) {\n    return this.manager.transaction(async em => {\n      const from = note.rank;\n      if (from === undefined) {\n        throw new Error('invalid note state, missing rank property');\n      }\n\n      if (from === to) {\n        return;\n      }\n\n      if (from > to) {\n        await em\n          .createQueryBuilder()\n          .update(DbNote)\n          .set({\n            rank: () => '`rank` + 1',\n          })\n          .where(`notebookId = :notebookId`, {notebookId: note.notebookId})\n          .andWhere(`\\`rank\\` between :to and :from`, {from: from - 1, to})\n          \n          .execute();\n      } else if (from < to) {\n        await em\n          .createQueryBuilder()\n          .update(DbNote)\n          .set({\n            rank: () => '`rank` - 1',\n          })\n          .where(`notebookId = :notebookId`, {notebookId: note.notebookId})\n          .andWhere(`\\`rank\\` between :from and :to`, {from: from + 1, to})\n          .execute();\n      }\n\n      await em.update(DbNote, note.id, {rank: to});\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/notebook/dbnotebook.entity.ts",
    "content": "import {IFilePathItem, INotebook} from '@wix/quix-shared';\nimport {\n  BeforeInsert,\n  BeforeUpdate,\n  Column,\n  CreateDateColumn,\n  Entity,\n  OneToMany,\n  OneToOne,\n  PrimaryColumn,\n  UpdateDateColumn,\n} from 'typeorm';\nimport {dbConf} from '../../config/db-conf';\nimport {convertDbNote, convertNoteToDb, DbNote} from '../note/dbnote.entity';\nimport {DbFileTreeNode} from '../filenode/filenode.entity';\nimport {DbUser} from '../user/user.entity';\nimport {extractOwnerDetails} from '../utils';\n\n@Entity({name: 'notebooks'})\nexport class DbNotebook {\n  @PrimaryColumn({...dbConf.idColumn})\n  id!: string;\n\n  @Column(dbConf.nameField)\n  name!: string;\n\n  @Column(dbConf.shortTextField)\n  owner!: string;\n\n  ownerDetails?: DbUser;\n\n  @UpdateDateColumn(dbConf.dateUpdated)\n  dateUpdated!: number;\n\n  @CreateDateColumn(dbConf.dateCreated)\n  dateCreated!: number;\n\n  @Column({...dbConf.json, name: 'json_content'})\n  jsonContent: any;\n\n  @OneToMany(type => DbNote, n => n.notebook, {\n    createForeignKeyConstraints: false,\n  })\n  notes?: DbNote[];\n\n  @OneToOne(type => DbFileTreeNode, node => node.notebook, {\n    onDelete: 'CASCADE',\n  })\n  fileNode?: DbFileTreeNode;\n\n  constructor(base?: DbNotebook) {\n    if (base) {\n      const {id, dateCreated, dateUpdated, name, notes, owner} = base;\n      this.id = id;\n      this.dateCreated = dateCreated;\n      this.dateUpdated = dateUpdated;\n      this.name = name;\n      this.notes = notes;\n      this.owner = owner;\n    }\n    this.jsonContent = this.jsonContent || {};\n  }\n}\n\nexport const convertDbNotebook = (\n  dbNotebook: DbNotebook,\n  computedPath?: IFilePathItem[],\n  isLiked?: boolean,\n): INotebook => {\n  const {dateCreated, dateUpdated, id, name, owner, notes} = dbNotebook;\n\n  const ownerDetails = extractOwnerDetails(dbNotebook);\n\n  return {\n    id,\n    dateCreated,\n    dateUpdated,\n    name,\n    owner,\n    isLiked: isLiked !== undefined ? isLiked : false,\n    notes: notes ? notes.map(convertDbNote) : [],\n    path: computedPath || [],\n    ownerDetails,\n  };\n};\n\nexport const covertNotebookToDb = (notebook: INotebook): DbNotebook => {\n  const {id, name, owner, notes, dateCreated, dateUpdated} = notebook;\n\n  return new DbNotebook({\n    id,\n    dateCreated,\n    dateUpdated,\n    name,\n    owner,\n    jsonContent: {},\n  });\n};\n"
  },
  {
    "path": "quix-frontend/service/src/entities/notebook/notebook.repository.ts",
    "content": "import {EntityRepository, Repository} from 'typeorm';\nimport {DbNotebook} from './dbnotebook.entity';\n\n@EntityRepository(DbNotebook)\nexport class NotebookRepository extends Repository<DbNotebook> {}\n"
  },
  {
    "path": "quix-frontend/service/src/entities/user/user.entity.ts",
    "content": "import {\n  Column,\n  Entity,\n  PrimaryColumn,\n  UpdateDateColumn,\n  CreateDateColumn,\n} from 'typeorm';\nimport {dbConf} from '../../config/db-conf';\nimport {IUser} from '@wix/quix-shared';\n\n@Entity({name: 'users'})\nexport class DbUser {\n  @PrimaryColumn('varchar', {length: 64})\n  id!: string;\n\n  @Column({...dbConf.shortTextField, nullable: true})\n  name?: string;\n\n  @Column(dbConf.userAvatar)\n  avatar?: string;\n\n  @Column({...dbConf.idColumn, name: 'root_folder', unique: false})\n  rootFolder!: string;\n\n  @Column({...dbConf.json, name: 'json_content'})\n  jsonContent?: any;\n\n  @UpdateDateColumn(dbConf.dateUpdated)\n  dateUpdated!: number;\n\n  @CreateDateColumn(dbConf.dateCreated)\n  dateCreated!: number;\n\n  constructor(base: Partial<DbUser>) {\n    Object.assign(this, base);\n  }\n}\n\nexport const dbUserToUser = (dbUser: DbUser): IUser => {\n  const {\n    jsonContent,\n    avatar,\n    name,\n    rootFolder,\n    id,\n    dateCreated,\n    dateUpdated,\n  } = dbUser;\n  return {\n    id,\n    avatar: avatar || '',\n    name: name || '',\n    rootFolder,\n    email: id,\n    dateCreated,\n    dateUpdated,\n  };\n};\n\nexport const userToDbUser = (user: IUser) => {\n  const {avatar, email, id, name, rootFolder, dateCreated, dateUpdated} = user;\n  const dbUser = new DbUser({\n    avatar,\n    id,\n    name,\n    rootFolder,\n  });\n  if (dateCreated !== undefined) {\n    dbUser.dateCreated = dateCreated;\n  }\n  if (dateUpdated !== undefined) {\n    dbUser.dateUpdated = dateUpdated;\n  }\n  return dbUser;\n};\n"
  },
  {
    "path": "quix-frontend/service/src/entities/utils.ts",
    "content": "import {DbUser, dbUserToUser} from './user/user.entity';\nimport {\n  fromNullable,\n  getOrElse,\n  option,\n  some,\n  none,\n  chain,\n  map,\n} from 'fp-ts/lib/Option';\nimport {pipe} from 'fp-ts/lib/pipeable';\nimport {createEmptyIUser, IUser} from '@wix/quix-shared';\n\ninterface IMaybeHasOwnerDetails {\n  owner: string;\n  ownerDetails?: DbUser;\n}\n\nexport const extractOwnerDetails = ({\n  owner: ownerId,\n  ownerDetails,\n}: IMaybeHasOwnerDetails): IUser => {\n  const userDetails: IUser = pipe(\n    fromNullable(ownerDetails),\n    chain(dbUser => (dbUser.id ? some(dbUser) : none)), // make sure Id is set\n    map(dbUser => dbUserToUser(dbUser)),\n    getOrElse(() => createEmptyIUser(ownerId)),\n  );\n  return userDetails;\n};\n"
  },
  {
    "path": "quix-frontend/service/src/entities/version-metadata.entity.ts",
    "content": "import {Column, Entity, PrimaryGeneratedColumn} from 'typeorm';\nimport {dbConf} from '../config/db-conf';\n\n@Entity({name: 'version_metadata'})\nexport class DbMetadata {\n  @PrimaryGeneratedColumn()\n  id!: number;\n\n  @Column()\n  name!: string;\n\n  @Column({type: 'double'})\n  version!: number;\n\n  @Column(dbConf.json)\n  jsonContent: any = {};\n\n  constructor(name: string, version: number, jsonContent = {}) {\n    this.name = name;\n    this.version = version;\n    this.jsonContent = jsonContent;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/errors/exceptions.ts",
    "content": "type Ctor = new (...args: any[]) => any;\n\nclass ItemNotFoundT extends Error {\n  private itemType: string;\n  constructor(type: Ctor | string, private id: string) {\n    super();\n    if (typeof type === 'string') {\n      this.itemType = type;\n    } else {\n      this.itemType = type.name;\n    }\n    this.message = `item of type:${this.itemType} and id:${id} not found.`;\n    this.name = `ITEM_NOT_FOUND`;\n  }\n}\n\nexport const ItemNotFound = (type: Ctor | string, id: string) =>\n  new ItemNotFoundT(type, id);\n\nclass BadActionT extends Error {\n  constructor(type: string, customMsg: string) {\n    super();\n    this.message = `type ${type}. ${customMsg}`;\n    this.name = `BAD_ACTION`;\n  }\n}\n\nexport const BadAction = (type: string, msg: string) =>\n  new BadActionT(type, msg);\n"
  },
  {
    "path": "quix-frontend/service/src/errors/index.ts",
    "content": "export {ItemNotFound, BadAction} from './exceptions';\n"
  },
  {
    "path": "quix-frontend/service/src/main.ts",
    "content": "import {json} from 'express';\nimport {NestFactory} from '@nestjs/core';\nimport {AppModule} from './app.module';\nimport {NestExpressApplication} from '@nestjs/platform-express';\nimport velocityEngine from './template-engine/velocity';\nimport cookieParser from 'cookie-parser';\nimport {createConnection} from 'typeorm';\nimport {createMysqlConf} from './config/db-connection';\nimport {getEnv} from './config/env/env';\nimport {DbMetadata} from './entities/version-metadata.entity';\nimport {Logger} from '@nestjs/common';\nimport {\n  checkSchemaVersion,\n  createInitialSchemaIfNeeded,\n  isMasterProcess,\n} from './utils/create-schema-helpers';\nimport {retry} from './utils/retry-promise';\nimport {WsAdapter} from '@nestjs/platform-ws';\n\nasync function bootstrap() {\n  const logger = new Logger();\n  const env = getEnv();\n\n  if (isMasterProcess()) {\n    if (!env.AutoMigrateDb && env.DbType === 'mysql') {\n      const conf = createMysqlConf([DbMetadata], env);\n      const conn = await retry(() => createConnection(conf))\n        .forNTimes(5)\n        .andWaitXMilliseconds(2000);\n\n      await createInitialSchemaIfNeeded(conn, env.DbName, logger);\n      await checkSchemaVersion(conn, logger);\n\n      await conn.close();\n    }\n  } else {\n    await new Promise(resolve => setTimeout(resolve, 3000)); // let master process do it's thing, create schema and all;\n  }\n\n  const app = await NestFactory.create<NestExpressApplication>(AppModule, {\n    bodyParser: false,\n  });\n\n  app.useStaticAssets(env.localStaticsPath);\n  app.setBaseViewsDir(env.localStaticsPath);\n  app.engine('.vm', velocityEngine());\n  app.use(cookieParser());\n  app.use(json({limit: '2mb'}));\n  app.useWebSocketAdapter(new WsAdapter(app));\n\n  await app.listen(env.HttpPort);\n}\n\nbootstrap();\n"
  },
  {
    "path": "quix-frontend/service/src/migrations/1558528771647-v1.ts",
    "content": "/* tslint:disable */\nimport {MigrationInterface, QueryRunner} from \"typeorm\";\n\nexport class v11558528771647 implements MigrationInterface {\n\n    public async up(queryRunner: QueryRunner): Promise<any> {\n        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\");\n        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\");\n        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\");\n        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\");\n        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\");\n        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\");\n        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\");\n        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\");\n        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\");\n        await queryRunner.query(\"ALTER TABLE `tree_nodes` ADD CONSTRAINT `FK_88797ade322e1717a3824fa0eca` FOREIGN KEY (`notebookId`) REFERENCES `notebooks`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION\");\n        await queryRunner.query(\"ALTER TABLE `tree_nodes` ADD CONSTRAINT `FK_cf0b457e67294f4b11555684416` FOREIGN KEY (`folderId`) REFERENCES `folders`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION\");\n        await queryRunner.query(\"ALTER TABLE `notes` ADD CONSTRAINT `FK_d84382f58ca053c3532fe78b05b` FOREIGN KEY (`notebookId`) REFERENCES `notebooks`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION\");\n    }\n\n    public async down(queryRunner: QueryRunner): Promise<any> {\n        // await queryRunner.query(\"ALTER TABLE `notes` DROP FOREIGN KEY `FK_d84382f58ca053c3532fe78b05b`\");\n        // await queryRunner.query(\"ALTER TABLE `tree_nodes` DROP FOREIGN KEY `FK_cf0b457e67294f4b11555684416`\");\n        // await queryRunner.query(\"ALTER TABLE `tree_nodes` DROP FOREIGN KEY `FK_88797ade322e1717a3824fa0eca`\");\n        // await queryRunner.query(\"ALTER TABLE `tree_nodes` DROP FOREIGN KEY `FK_8aff7aa6aa930ffd5f259b27da7`\");\n        await queryRunner.query(\"DROP INDEX `IDX_28d49fb1d1f565ea98929f69a0` ON `actions`\");\n        await queryRunner.query(\"DROP INDEX `IDX_733a22dda689fe10e5fa29d93f` ON `actions`\");\n        await queryRunner.query(\"DROP TABLE `actions`\");\n        await queryRunner.query(\"DROP TABLE `version_metadata`\");\n        await queryRunner.query(\"DROP INDEX `IDX_22bc9f47a6d39a6c3a868321ba` ON `users`\");\n        await queryRunner.query(\"DROP TABLE `users`\");\n        await queryRunner.query(\"DROP INDEX `IDX_e42953e6be13870839a04a3fa8` ON `favorites`\");\n        await queryRunner.query(\"DROP TABLE `favorites`\");\n        await queryRunner.query(\"DROP INDEX `IDX_8e91b277f0f9ca503d8bf88390` ON `notes`\");\n        await queryRunner.query(\"DROP INDEX `IDX_5c83f1c4e3f3db5ea424438946` ON `notes`\");\n        await queryRunner.query(\"DROP TABLE `notes`\");\n        await queryRunner.query(\"DROP TABLE `notebooks`\");\n        await queryRunner.query(\"DROP INDEX `REL_cf0b457e67294f4b1155568441` ON `tree_nodes`\");\n        await queryRunner.query(\"DROP INDEX `REL_88797ade322e1717a3824fa0ec` ON `tree_nodes`\");\n        await queryRunner.query(\"DROP INDEX `IDX_8954b75175bd5cbc43630e1c52` ON `tree_nodes`\");\n        await queryRunner.query(\"DROP TABLE `tree_nodes`\");\n        await queryRunner.query(\"DROP TABLE `folders`\");\n    }\n\n}\n"
  },
  {
    "path": "quix-frontend/service/src/migrations/1558528771648-v1-metadata.ts",
    "content": "import {MigrationInterface, QueryRunner} from 'typeorm';\nimport {DbMetadata} from '../entities/version-metadata.entity';\nimport {QUIX_SCHEMA} from '../consts';\nconst PREVIOUS_QUIX_SCHEMA = 0;\nconst CURRENT_QUIX_SCHEMA_VERSION = 1;\n\nexport class VersionMetadata1558528771648 implements MigrationInterface {\n  public async up(queryRunner: QueryRunner): Promise<any> {\n    const metadata = new DbMetadata(QUIX_SCHEMA, CURRENT_QUIX_SCHEMA_VERSION);\n    const manager = queryRunner.manager;\n    await manager.save(DbMetadata, metadata);\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<any> {\n    const metadata = new DbMetadata(QUIX_SCHEMA, PREVIOUS_QUIX_SCHEMA);\n    const manager = queryRunner.manager;\n    await manager.save(DbMetadata, metadata);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/migrations/1562174176877-v2.ts",
    "content": "import {MigrationInterface, QueryRunner} from 'typeorm';\nimport {DbMetadata} from '../entities/version-metadata.entity';\nimport {QUIX_SCHEMA} from '../consts';\nconst PREVIOUS_QUIX_SCHEMA = 1;\nconst CURRENT_QUIX_SCHEMA_VERSION = 2;\n\nexport class v21562174176877 implements MigrationInterface {\n  public async up(queryRunner: QueryRunner): Promise<any> {\n    await queryRunner.query(\n      'ALTER TABLE `users` ADD `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `users` ADD `date_created` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n\n    await queryRunner.query(\n      'DROP INDEX `IDX_22bc9f47a6d39a6c3a868321ba` ON `users`',\n    );\n\n    await queryRunner.query(\n      'ALTER TABLE `users` DROP primary key, ADD primary key(`id`)',\n    );\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: CURRENT_QUIX_SCHEMA_VERSION},\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<any> {\n    await queryRunner.query(\n      'ALTER TABLE `users` DROP primary key, ADD primary key(`id`, `root_folder`)',\n    );\n\n    await queryRunner.query(\n      'CREATE UNIQUE INDEX `IDX_22bc9f47a6d39a6c3a868321ba` ON `users` (`root_folder`)',\n    );\n    await queryRunner.query('ALTER TABLE `users` DROP COLUMN `date_created`');\n    await queryRunner.query('ALTER TABLE `users` DROP COLUMN `date_updated`');\n\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: PREVIOUS_QUIX_SCHEMA},\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/migrations/1614173960671-v3.ts",
    "content": "import {MigrationInterface, QueryRunner} from 'typeorm';\nimport {DbMetadata} from '../entities/version-metadata.entity';\nimport {QUIX_SCHEMA} from '../consts';\nconst PREVIOUS_QUIX_SCHEMA = 2;\nconst CURRENT_QUIX_SCHEMA_VERSION = 3;\n\nexport class v31614173960671 implements MigrationInterface {\n  name = 'v31614173960671';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query('ALTER TABLE `notes` ADD `rich_content` json NULL');\n    await queryRunner.query(\n      'ALTER TABLE `notes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `users` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `notebooks` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `folders` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `tree_nodes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)',\n    );\n\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: CURRENT_QUIX_SCHEMA_VERSION},\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      'ALTER TABLE `tree_nodes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `folders` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `notebooks` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `users` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `notes` CHANGE `date_updated` `date_updated` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6)',\n    );\n    await queryRunner.query('ALTER TABLE `notes` DROP COLUMN `rich_content`');\n\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: PREVIOUS_QUIX_SCHEMA},\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/migrations/1614712161318-v4.ts",
    "content": "import {MigrationInterface, QueryRunner} from 'typeorm';\nimport {DbMetadata} from '../entities/version-metadata.entity';\nimport {QUIX_SCHEMA} from '../consts';\nconst PREVIOUS_QUIX_SCHEMA = 3;\nconst CURRENT_QUIX_SCHEMA_VERSION = 4;\n\nexport class v41614712161318 implements MigrationInterface {\n  name = 'v41614712161318';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      'ALTER TABLE `notes` MODIFY COLUMN `name` varchar(512) NOT NULL',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `notebooks` MODIFY COLUMN `name` varchar(512) NOT NULL',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `folders` MODIFY COLUMN `name` varchar(512) NOT NULL',\n    );\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: CURRENT_QUIX_SCHEMA_VERSION},\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      'ALTER TABLE `notes` MODIFY COLUMN `name` varchar(64) NOT NULL',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `notebooks` MODIFY COLUMN `name` varchar(64) NOT NULL',\n    );\n    await queryRunner.query(\n      'ALTER TABLE `folders` MODIFY COLUMN `name` varchar(64) NOT NULL',\n    );\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: PREVIOUS_QUIX_SCHEMA},\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/migrations/1634023683491-v5.ts",
    "content": "import {DbMetadata} from '../entities/version-metadata.entity';\nimport {MigrationInterface, QueryRunner} from 'typeorm';\nimport {QUIX_SCHEMA} from '../consts';\nconst PREVIOUS_QUIX_SCHEMA = 4;\nconst CURRENT_QUIX_SCHEMA_VERSION = 5;\nexport class v51634023683491 implements MigrationInterface {\n  name = 'v51634023683491';\n\n  public async up(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(\n      `ALTER TABLE \\`notes\\` DROP FOREIGN KEY \\`FK_d84382f58ca053c3532fe78b05b\\``,\n    );\n\n    await queryRunner.query(\n      `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`,\n    );\n\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: CURRENT_QUIX_SCHEMA_VERSION},\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise<void> {\n    await queryRunner.query(`DROP TABLE \\`deleted_notebooks\\``);\n    await queryRunner.query(\n      `ALTER TABLE \\`notes\\` ADD CONSTRAINT \\`FK_d84382f58ca053c3532fe78b05b\\` FOREIGN KEY (\\`notebookId\\`) REFERENCES \\`quix\\`.\\`notebooks\\`(\\`id\\`) ON DELETE CASCADE ON UPDATE NO ACTION`,\n    );\n\n    const manager = queryRunner.manager;\n    await manager.update(\n      DbMetadata,\n      {name: QUIX_SCHEMA},\n      {version: PREVIOUS_QUIX_SCHEMA},\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/auth.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Logger,\n  Query,\n  Res,\n  Req,\n  UseGuards,\n} from '@nestjs/common';\nimport {AuthGuard} from './user-decorator';\nimport {Response, Request} from 'express';\nimport {LoginService} from './login.service';\nimport {IExternalUser} from './types';\nimport {User} from './user-decorator';\nimport {UsersService} from './users.service';\nimport {DeletedNotebooksService} from '../web-api/deleted-notebooks/deleted-notebook.service';\n\n@Controller('/api/')\nexport class AuthController {\n  private readonly logger = new Logger(AuthController.name);\n  constructor(\n    private readonly authService: LoginService,\n    private readonly userService: UsersService,\n    private readonly deletedNotebooksService: DeletedNotebooksService,\n  ) {}\n\n  @Get('user')\n  @UseGuards(AuthGuard)\n  async getUser(@User() user: IExternalUser) {\n    this.userService.doUserLogin(user).catch(e => {\n      this.logger.error('error updating user', e);\n    });\n\n    const count =\n      await this.deletedNotebooksService.getCountDeletedNotebooksForUser(\n        user.email,\n      );\n\n    return {...user, stats: {trashBinCount: count}};\n  }\n\n  @Get('authenticate')\n  async doAuth(\n    @Query('code') code: string,\n    @Req() req: Request,\n    @Res() res: Response,\n  ) {\n    try {\n      const up = await this.authService.login(code, req, res);\n      if (up) {\n        await this.userService.doUserLogin(up);\n        res.json(up);\n        return;\n      }\n      res.sendStatus(401).send();\n    } catch (e) {\n      this.logger.error(e);\n      res.sendStatus(500).send();\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/auth.module.ts",
    "content": "import {DynamicModule, Module} from '@nestjs/common';\nimport {JwtModule, JwtService} from '@nestjs/jwt';\nimport {TypeOrmModule} from '@nestjs/typeorm';\nimport {\n  DbDeletedNotebook,\n  DbUser,\n  DeletedNotebookRepository,\n} from '../../entities';\nimport {EventSourcingModule} from '../../modules/event-sourcing/event-sourcing.module';\nimport {DeletedNotebooksService} from '../web-api/deleted-notebooks/deleted-notebook.service';\nimport {AuthController} from './auth.controller';\nimport {\n  CustomLoginService,\n  FakeLoginService,\n  GoogleLoginService,\n  LoginService,\n} from './login.service';\nimport {AuthAsyncOptions, AuthOptions, AuthTypes} from './types';\nimport {UsersService} from './users.service';\n\n/** read about nest.js dynamic modules to understand this */\n\n@Module({})\nexport class AuthModuleConfiguration {\n  static createAsync(authAsyncOptions: AuthAsyncOptions): DynamicModule {\n    return {\n      global: true, // feels like workaround, couldn't get injection to work otherwise\n      module: AuthModuleConfiguration,\n      imports: authAsyncOptions.imports,\n      providers: [\n        {\n          provide: AuthOptions,\n          inject: authAsyncOptions.injects,\n          useFactory: authAsyncOptions.useFactory,\n        },\n      ],\n      exports: [AuthOptions],\n    };\n  }\n  static create(authOption: AuthOptions): DynamicModule {\n    return {\n      global: true,\n      module: AuthModuleConfiguration,\n      providers: [\n        {\n          provide: AuthOptions,\n          useValue: authOption,\n        },\n      ],\n      exports: [AuthOptions],\n    };\n  }\n}\n\n@Module({\n  imports: [\n    TypeOrmModule.forFeature([DbUser, DbDeletedNotebook]),\n    EventSourcingModule,\n    AuthModuleConfiguration,\n    JwtModule.registerAsync({\n      imports: [AuthModuleConfiguration],\n      inject: [AuthOptions],\n      useFactory: (authOptions: AuthOptions) => {\n        switch (authOptions.type) {\n          case AuthTypes.GOOGLE:\n            return {\n              secret: authOptions.cookieEncKey,\n              signOptions: {\n                algorithm: 'HS256',\n                expiresIn: authOptions.cookieTTL,\n              },\n            };\n          case AuthTypes.CUSTOM:\n            return authOptions.jwtServiceOptions || {secret: '12345'};\n          case AuthTypes.FAKE:\n          default:\n            return {secret: '12345'};\n        }\n      },\n    }),\n  ],\n  controllers: [AuthController],\n  providers: [UsersService, DeletedNotebooksService],\n  exports: [UsersService],\n})\nexport class AuthModule {\n  static create(): DynamicModule {\n    return {\n      module: AuthModule,\n      providers: [\n        {\n          provide: LoginService,\n          inject: [AuthOptions, JwtService],\n          useFactory: (authOptions: AuthOptions, jwtService: JwtService) => {\n            switch (authOptions.type) {\n              case AuthTypes.CUSTOM:\n                return new CustomLoginService(authOptions);\n              case AuthTypes.GOOGLE:\n                return new GoogleLoginService(authOptions, jwtService);\n              case AuthTypes.FAKE:\n                return new FakeLoginService(authOptions);\n            }\n          },\n        },\n      ],\n      exports: [LoginService],\n    };\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/common-auth.ts",
    "content": "import {IExternalUser} from './types';\nimport {isJestTest} from '../../config/utils';\n\nconst defaultUser: IExternalUser = {\n  email: 'user@quix.com',\n  id: '1',\n  name: 'Default User',\n};\n\nexport const fakeAuth = (token: string): IExternalUser | undefined => {\n  try {\n    const user = JSON.parse(Buffer.from(token, 'base64').toString());\n\n    return user;\n  } catch (e) {\n    if (isJestTest()) {\n      return undefined;\n    }\n    // tslint:disable-next-line: no-console\n    console.debug(`Can't parse cookie, using default user.`);\n    return defaultUser;\n  }\n};\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/index.ts",
    "content": "export {IExternalUser} from './types';\nexport {User, AuthGuard} from './user-decorator';\nexport {UsersService} from './users.service';\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/login.service.ts",
    "content": "import {Injectable, Inject} from '@nestjs/common';\nimport {Response, Request} from 'express';\nimport {ConfigService} from '../../config';\nimport {JwtService} from '@nestjs/jwt';\nimport {\n  AuthOptions,\n  AuthTypes,\n  CustomAuthOptions,\n  FakeAuthOptions,\n  GoogleAuthOptions,\n  IExternalUser,\n} from './types';\nimport {OAuth2Client} from 'google-auth-library';\nimport {fakeAuth} from './common-auth';\n\nexport abstract class LoginService {\n  abstract login(\n    clientPayload: string,\n    req: Request,\n    res: Response,\n  ): Promise<IExternalUser | undefined>;\n\n  abstract verify(token: string): IExternalUser | undefined;\n}\n\nexport class FakeLoginService extends LoginService {\n  constructor(\n    @Inject(AuthOptions) private readonly authOptions: FakeAuthOptions,\n  ) {\n    super();\n  }\n\n  verify(token: string) {\n    return fakeAuth(token);\n  }\n\n  login(\n    authCode: string,\n    req: Request,\n    res: Response,\n  ): Promise<IExternalUser | undefined> {\n    const up: IExternalUser = JSON.parse(authCode);\n\n    res.cookie(\n      this.authOptions.cookieName,\n      Buffer.from(JSON.stringify(up)).toString('base64'),\n      {\n        maxAge: 24 * 60 * 1000,\n      },\n    );\n    return Promise.resolve(up);\n  }\n}\n\nexport class CustomLoginService extends LoginService {\n  constructor(\n    @Inject(AuthOptions) private readonly authOptions: CustomAuthOptions,\n  ) {\n    super();\n  }\n\n  verify(token: string) {\n    return this.authOptions.auth.verify(token);\n  }\n\n  login(\n    authCode: string,\n    req: Request,\n    res: Response,\n  ): Promise<IExternalUser | undefined> {\n    return this.authOptions.auth.login(authCode, req, res);\n  }\n}\n\nexport class GoogleLoginService extends LoginService {\n  constructor(\n    @Inject(AuthOptions) private readonly authOptions: GoogleAuthOptions,\n    private jwtService: JwtService,\n  ) {\n    super();\n  }\n\n  verify(token: string) {\n    return this.jwtService.verify(token);\n  }\n\n  async login(\n    authCode: string,\n    req: Request,\n    res: Response,\n  ): Promise<IExternalUser | undefined> {\n    {\n      const clientId = this.authOptions.googleClientId;\n      const clientSecret = this.authOptions.googleAuthSecret;\n\n      const authClient = new OAuth2Client({\n        clientId,\n        clientSecret,\n        redirectUri: 'postmessage',\n      });\n      const r = await authClient.getToken(authCode);\n      authClient.setCredentials(r.tokens);\n\n      const verify = await authClient.verifyIdToken({\n        idToken: r.tokens.id_token || '',\n        audience: clientId,\n      });\n\n      const payload = (verify && verify.getPayload()) || null;\n\n      if (payload && payload.email && payload.sub) {\n        const up: IExternalUser = {\n          avatar: payload.picture,\n          name: payload.name,\n          email: payload.email,\n          id: payload.sub,\n        };\n        const jwtToken = await this.jwtService.signAsync(up);\n\n        res.cookie(this.authOptions.cookieName, jwtToken, {\n          maxAge: this.authOptions.cookieTTL,\n        });\n        return up;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/types.ts",
    "content": "import {ModuleMetadata, Type} from '@nestjs/common';\nimport {Response, Request} from 'express';\nimport {JwtModuleOptions} from '@nestjs/jwt';\nimport http from 'http';\n/**\n * Quix authentication works by authenticating the user vs some external service (currently just google, openconnect in the future)\n * Then writing this identity into a cookie (JWT or otherwise) and into an internal user entity persisted in db\n * This is the payload we expect from an external service\n */\nexport interface IExternalUser {\n  id: string;\n  email: string;\n  avatar?: string;\n  name?: string;\n}\n\nexport interface CustomAuth {\n  login(\n    clientPayload: string,\n    req: Request,\n    res: Response,\n  ): Promise<IExternalUser | undefined>;\n  verify(token: string): IExternalUser | undefined; // currently websocket code prevent us from using promise here\n  getTokenFromRequest(request: http.IncomingMessage): string;\n}\n\nexport enum AuthTypes {\n  CUSTOM = 0,\n  FAKE = 1,\n  GOOGLE = 2,\n}\n\nexport type FakeAuthOptions = {\n  type: AuthTypes.FAKE;\n  cookieName: string;\n};\nexport type GoogleAuthOptions = {\n  type: AuthTypes.GOOGLE;\n  cookieName: string;\n  cookieTTL: number;\n  cookieEncKey: string;\n  googleClientId: string;\n  googleAuthSecret: string;\n};\n\nexport type CustomAuthOptions = {\n  type: AuthTypes.CUSTOM;\n  auth: CustomAuth;\n  jwtServiceOptions?: JwtModuleOptions;\n};\n\nexport type AuthOptions =\n  | FakeAuthOptions\n  | GoogleAuthOptions\n  | CustomAuthOptions;\n\n// export interface AuthOptionsFactory {\n//   createAuthOptions(): Promise<AuthOptions> | AuthOptions;\n// }\nexport interface AuthAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n  // useExisting?: Type<AuthOptionsFactory>; //To implement later, if needed\n  // useClass?: Type<AuthOptionsFactory>;\n  useFactory: (...args: any[]) => Promise<AuthOptions> | AuthOptions;\n  injects?: any[];\n}\n\nexport const AuthOptions = 'AuthOptions';\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/user-decorator.ts",
    "content": "import {\n  CanActivate,\n  createParamDecorator,\n  ExecutionContext,\n  Inject,\n  Injectable,\n} from '@nestjs/common';\nimport {Request} from 'express';\nimport {LoginService} from './login.service';\nimport {AuthOptions, AuthTypes, IExternalUser} from './types';\nexport const User = createParamDecorator((data, ctx: ExecutionContext) => {\n  return ctx.switchToHttp().getRequest().user;\n});\n\nconst getTokenFromRequestByCookie = (cookieName: string) => (req: Request) =>\n  req.cookies[cookieName];\n@Injectable()\nexport class AuthGuard implements CanActivate {\n  private getTokenFromRequest: (req: Request) => string;\n\n  constructor(\n    @Inject(AuthOptions) authOptions: AuthOptions,\n    private loginService: LoginService,\n  ) {\n    if (authOptions.type === AuthTypes.CUSTOM) {\n      this.getTokenFromRequest = authOptions.auth.getTokenFromRequest;\n    } else {\n      this.getTokenFromRequest = getTokenFromRequestByCookie(\n        authOptions.cookieName,\n      );\n    }\n  }\n\n  canActivate(context: ExecutionContext): boolean | Promise<boolean> {\n    const request: Request = context.switchToHttp().getRequest();\n    const token = this.getTokenFromRequest(request);\n    return Promise.resolve(this.loginService.verify(token)).then(user => {\n      request.user = user;\n      return !!user;\n    });\n  }\n}\ndeclare module 'express' {\n  interface Request {\n    user?: IExternalUser;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/auth/users.service.ts",
    "content": "import {Injectable, Logger} from '@nestjs/common';\nimport {QuixEventBus} from '../../modules/event-sourcing/quix-event-bus';\nimport {Repository} from 'typeorm';\nimport {DbUser} from '../../entities';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {dbUserToUser} from '../../entities/user/user.entity';\nimport {IExternalUser} from './types';\nimport {FileActions, createFolder} from '@wix/quix-shared/entities/file';\nimport uuid from 'uuid/v4';\nimport {UserActions, createUser} from '@wix/quix-shared/entities/user';\n\n@Injectable()\nexport class UsersService {\n  private logger = new Logger('UsersService');\n\n  constructor(\n    @InjectRepository(DbUser) private userRepo: Repository<DbUser>,\n    private quixEventBus: QuixEventBus,\n  ) {}\n\n  async doUserLogin(userFromLogin: IExternalUser) {\n    const user = await this.userRepo.findOne({id: userFromLogin.email});\n    if (!user) {\n      await this.doFirstTimeLogin(userFromLogin);\n    } else {\n      await this.doLogin(userFromLogin, user);\n    }\n  }\n\n  private async doFirstTimeLogin(userFromLogin: IExternalUser) {\n    const rootFolderId = await this.createRootFolder(userFromLogin.email);\n    const {avatar, email: id, email, name} = userFromLogin;\n    const user = createUser({\n      avatar,\n      email,\n      id,\n      name,\n      rootFolder: rootFolderId,\n    });\n\n    return this.quixEventBus.emit({\n      ...UserActions.createNewUser(id, user),\n      user: id,\n      ethereal: true,\n    });\n  }\n\n  private async doLogin(userFromLogin: IExternalUser, dbUser: DbUser) {\n    const {avatar, name, email: id, email} = userFromLogin;\n    /* small hack when migrating users, creating users with epoch 1000 (1970-01-01 00:00:01) */\n    /* once they login, change dateCreated */\n    const changeUserCreated =\n      dbUser.dateCreated.valueOf() === 1000 ? new Date() : undefined;\n\n    return this.quixEventBus.emit({\n      ...UserActions.updateUser(\n        id,\n        avatar || '',\n        name || '',\n        email,\n        changeUserCreated,\n      ),\n      user: id,\n      ethereal: true,\n    });\n  }\n\n  private async createRootFolder(user: string) {\n    const id = uuid();\n    await this.quixEventBus.emit({\n      ...FileActions.createFile(\n        id,\n        createFolder([], {id, name: 'My notebooks'}),\n      ),\n      user,\n      reason: 'first login',\n    });\n    return id;\n  }\n\n  async getListOfUsers() {\n    const dbUsers = await this.userRepo.find();\n    return dbUsers.map(dbUserToUser);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/base-action-validation.ts",
    "content": "import {PipeTransform, Injectable, ArgumentMetadata} from '@nestjs/common';\n\nconst isValidAction = (maybeAction: any) => {\n  if (\n    typeof maybeAction.type !== 'string' &&\n    typeof maybeAction.id !== 'string'\n  ) {\n    throw new Error('Invalid action ' + JSON.stringify(maybeAction));\n  }\n};\n\n@Injectable()\nexport class BaseActionValidation implements PipeTransform {\n  transform(action: any, metadata: ArgumentMetadata) {\n    if (metadata.type === 'query' && metadata.data === 'sessionId') {\n      return action;\n    }\n\n    if (Array.isArray(action)) {\n      action.forEach(isValidAction);\n    } else {\n      isValidAction(action);\n    }\n    return action;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/event-sourcing.module.ts",
    "content": "import {Module} from '@nestjs/common';\nimport {TypeOrmModule} from '@nestjs/typeorm';\nimport {\n  DbFileTreeNode,\n  DbFolder,\n  DbNote,\n  DbNotebook,\n  FileTreeRepository,\n  NoteRepository,\n  DbFavorites,\n  DbUser,\n  DbDeletedNotebook,\n  DeletedNotebookRepository,\n} from '../../entities';\nimport {QuixEventBus} from './quix-event-bus';\nimport {DbActionStore} from './infrastructure/action-store';\nimport {DbAction} from './infrastructure/action-store/entities/db-action.entity';\nimport {NotePlugin} from './plugins/note-plugin';\nimport {NotebookPlugin} from './plugins/notebook-plugin';\nimport {DeletedNotebookPlugin} from './plugins/deleted-notebook-plugin';\nimport {FileTreePlugin} from './plugins/file-tree-plugin';\nimport {FavoritesPlugin} from './plugins/favorites-plugin';\nimport {UserPlugin} from './plugins/user-plugin';\nimport {NotebookRepository} from '../../entities/notebook/notebook.repository';\nimport {EventsService} from './events.service';\nimport {EventsPlugin} from './plugins/events-plugin';\nimport {TrashBinPlugin} from './plugins/trash-bin-plugin';\n\n@Module({\n  imports: [\n    TypeOrmModule.forFeature([\n      DbFileTreeNode,\n      DbFolder,\n      DbNote,\n      DbNotebook,\n      DbDeletedNotebook,\n      DbAction,\n      FileTreeRepository,\n      NoteRepository,\n      DbFavorites,\n      NotebookRepository,\n      DbUser,\n      DeletedNotebookRepository,\n    ]),\n  ],\n  controllers: [],\n  providers: [\n    QuixEventBus,\n    DbActionStore,\n    NotePlugin,\n    NotebookPlugin,\n    DeletedNotebookPlugin,\n    TrashBinPlugin,\n    FileTreePlugin,\n    FavoritesPlugin,\n    UserPlugin,\n    EventsPlugin,\n    EventsService,\n  ],\n  exports: [QuixEventBus, DbActionStore, EventsService],\n})\nexport class EventSourcingModule {}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/events.service.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {IAction} from './infrastructure/types';\nimport {Observable, Subscriber} from 'rxjs';\n\n@Injectable()\nexport class EventsService {\n  userIdToSessionIds: {[userId: string]: string[]} = {};\n  subscribers: {[sessionId: string]: Subscriber<IAction>} = {};\n\n  logEvent(action: IAction) {\n    this.sendMessage(action);\n  }\n\n  getEventStream(sessionId: string, userId: string): Observable<IAction> {\n    return new Observable(subscriber => {\n      this.subscribers[sessionId] = subscriber;\n      this.associateSessionIdWithUserId(sessionId, userId);\n    });\n  }\n\n  closeEventStream(sessionId: string, userId: string) {\n    const subscriber = this.subscribers[sessionId];\n    if (subscriber) {\n      subscriber.complete();\n      delete this.subscribers[sessionId];\n    }\n    if (this.userIdToSessionIds[userId]) {\n      const subscribers = this.userIdToSessionIds[userId].filter(\n        s => s !== sessionId,\n      );\n      if (subscribers.length) {\n        this.userIdToSessionIds[userId] = subscribers;\n      } else {\n        delete this.userIdToSessionIds[userId];\n      }\n    }\n  }\n\n  associateSessionIdWithUserId(sessionId: string, userId: string) {\n    if (!this.userIdToSessionIds[userId]) {\n      this.userIdToSessionIds[userId] = [];\n    }\n    this.userIdToSessionIds[userId].push(sessionId);\n  }\n\n  sendMessage(data: IAction) {\n    const {userId, sessionId: sessionIdToExclude} = data;\n\n    if (userId && this.userIdToSessionIds[userId]) {\n      this.userIdToSessionIds[userId]\n        .filter(sessionId => sessionId !== sessionIdToExclude)\n        .forEach(sessionId => {\n          this.subscribers[sessionId].next(data);\n        });\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/action-store.spec.ts",
    "content": "import {Test, TestingModule} from '@nestjs/testing';\nimport {getRepositoryToken, TypeOrmModule} from '@nestjs/typeorm';\nimport 'reflect-metadata';\nimport {Repository} from 'typeorm';\nimport * as uuid from 'uuid';\nimport {ConfigService, ConfigModule} from '../../../../config';\nimport {DbActionStore} from './action-store';\nimport {DbAction} from './entities/db-action.entity';\nimport {IActionStore} from './types';\n\ndescribe('action store', () => {\n  let actionStore: IActionStore;\n  let module: TestingModule;\n\n  beforeEach(async () => {\n    module = await Test.createTestingModule({\n      imports: [\n        ConfigModule.create(),\n        TypeOrmModule.forRootAsync({\n          imports: [],\n          useFactory: async (configService: ConfigService) =>\n            configService.getDbConnection([DbAction]),\n          inject: [ConfigService],\n        }),\n        TypeOrmModule.forFeature([DbAction]),\n      ],\n      providers: [DbActionStore],\n      exports: [DbActionStore],\n    }).compile();\n\n    actionStore = module.get(DbActionStore);\n    await module\n      .get<Repository<DbAction>>(getRepositoryToken(DbAction))\n      .clear();\n  });\n\n  afterEach(() => {\n    module.close();\n  });\n\n  it('should store and retrieve the action correctly', async () => {\n    const id = uuid.v4();\n    const base = {\n      id,\n      user: 'foo@wix.com',\n      type: 'bla.bla',\n      isDeleted: false,\n    };\n    await actionStore.pushAction(base);\n    const fromDb = await actionStore.get(id);\n    expect(fromDb).toHaveLength(1);\n    const {dateCreated, ...rest} = fromDb[0];\n    expect(rest).toEqual(base);\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/action-store.ts",
    "content": "import {Repository, In} from 'typeorm';\nimport {IAction} from '../types';\nimport {DbAction} from './entities/db-action.entity';\nimport {IActionStore, IDBAction} from './types';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {Injectable} from '@nestjs/common';\n\nconst convertDbActionToAction = (input: IDBAction): IAction => {\n  const {data, ...rest} = input;\n  return {...rest, ...data};\n};\n\nconst convertActionToDbAction = (input: IAction): IDBAction => {\n  const {id, dateCreated, type, user, ...rest} = input;\n  return {\n    data: rest,\n    id,\n    type,\n    user,\n    dateCreated: input.dateCreated || new Date(),\n  }; // TODO: fix me, happens because of typeorm change\n  // Prefer to use db default value time rather than setting it in app\n};\n\n@Injectable()\nexport class DbActionStore implements IActionStore {\n  constructor(@InjectRepository(DbAction) private repo: Repository<DbAction>) {}\n\n  async pushAction(action: IAction | IAction[]) {\n    const actions: IAction[] = Array.isArray(action) ? action : [action];\n\n    // not using simple .insert() or .save() to suppress excessive select typeorm does\n    await this.repo\n      .createQueryBuilder()\n      .insert()\n      .values(actions.map(convertActionToDbAction))\n      .updateEntity(false)\n      .execute();\n\n    // await this.repo.insert(actions.map(convertActionToDbAction));\n    return actions;\n  }\n\n  // TODO: implement orderBy\n  async get(aggId?: string | string[], orderBy?: string) {\n    const ids = !!aggId ? (Array.isArray(aggId) ? aggId : [aggId]) : undefined;\n    const results = await (!ids\n      ? this.repo.find()\n      : this.repo.find({id: In(ids)}));\n\n    return results.map(convertDbActionToAction);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/entities/db-action.entity.ts",
    "content": "import {Column, Entity, Index} from 'typeorm';\nimport {IAction, IEventData} from '../../types';\nimport {IDBAction} from '../types';\nimport {dbConf} from '../../../../../config/db-conf';\n\n@Entity({name: 'actions'})\n@Index(['id', 'type'], {unique: false})\nexport class DbAction<T = IEventData, N extends string = string>\n  implements IDBAction {\n  @Column({...dbConf.idColumn, primary: true, unique: false})\n  id!: string;\n\n  @Column(dbConf.json)\n  // @ts-ignore\n  data!: T;\n\n  @Column(dbConf.shortTextField)\n  user!: string;\n\n  @Index()\n  @Column({...dbConf.eventsTimestamp, primary: true, name: 'date_created'})\n  dateCreated?: Date;\n\n  @Column({type: 'varchar', width: 64})\n  type!: N;\n\n  constructor(base?: IAction<T, N>) {\n    if (base) {\n      const {id, dateCreated, user, type, ...data} = base;\n      this.dateCreated = dateCreated;\n      this.user = user;\n      this.type = type;\n      this.data = data as any;\n      this.id = id;\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/index.ts",
    "content": "export {IActionStore} from './types';\nimport {DbActionStore} from './action-store';\nimport {DbAction} from './entities/db-action.entity';\nexport {DbActionStore};\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/action-store/types.ts",
    "content": "import {IAction, IEventData} from '../types';\nexport abstract class IActionStore {\n  abstract pushAction(action: IAction | IAction[]): Promise<IAction[]>;\n  abstract get(aggId?: string | string[], orderBy?: string): Promise<IAction[]>;\n}\nexport interface IDBAction<T = IEventData, N extends string = string> {\n  id: string;\n  user: string;\n  dateCreated?: Date;\n  type: N;\n  data: T;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/api.ts",
    "content": "import {\n  HookFn,\n  IPluginApi as IMiddlewareApi,\n  HookApi,\n  PluginDescriptor,\n  EventFilter,\n  PluginOptions,\n} from './types';\nimport {ContextFactory} from './context';\nimport {Dictionary} from '../../../../types';\nimport {IAction} from '../types';\n\nexport class RegisterApi {\n  constructor(private descriptor: PluginDescriptor) {}\n  hooks = {\n    listen: <A extends IAction = IAction>(\n      name: string,\n      fn: HookFn<A>,\n    ): RegisterApi => {\n      this.descriptor.hooks.set(name, {name, fn});\n      return this;\n    },\n  };\n  setPluginOptions(options: PluginOptions) {\n    Object.assign(this.descriptor.options, options);\n    return this;\n  }\n  setEventFilter(fn: EventFilter) {\n    this.descriptor.eventFilter = fn;\n  }\n}\n\nexport class MiddlewareApi implements IMiddlewareApi {\n  private contextFactory: ContextFactory;\n  private loggedActions: IAction[] = [];\n\n  constructor(\n    private plugins: PluginDescriptor[],\n    baseContext: Dictionary<any>,\n  ) {\n    this.contextFactory = new ContextFactory(baseContext);\n  }\n\n  getLoggedActions() {\n    return [...this.loggedActions];\n  }\n\n  pushLoggedActions(actions: IAction[]) {\n    this.loggedActions.push(...actions);\n  }\n  hooks = {\n    call: <A extends IAction = IAction>(\n      name: string,\n      action: A,\n      extraContext?: Dictionary<any>,\n    ) => {\n      const promises = this.plugins\n        .filter(plugin => plugin.eventFilter(action.type))\n        .map(plugin => {\n          const hook = plugin.hooks.get(name);\n\n          if (hook) {\n            const hookApi: HookApi = {\n              context: this.contextFactory.setExtra(extraContext).create(),\n            };\n\n            try {\n              return Promise.resolve(hook.fn(action, hookApi));\n            } catch (e) {\n              return Promise.reject(e);\n            }\n          }\n          return Promise.resolve(action);\n        });\n      return Promise.all(promises);\n    },\n  };\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/context.ts",
    "content": "export class ContextFactory {\n  private extra: object = {};\n  constructor(private base: object = {}) {}\n\n  setExtra(extra?: object) {\n    if (extra) {\n      this.extra = extra;\n    }\n    return this;\n  }\n\n  create() {\n    return new Context(this.base, this.extra);\n  }\n}\n\nexport class Context {\n  constructor(private base: object, private extra: object) {}\n\n  set(data: object) {\n    return Object.assign(this.base, data);\n  }\n\n  get(): any {\n    return {...this.extra, ...this.base};\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus-builder.ts",
    "content": "import {RegisterApi} from './api';\nimport {\n  EventBusMiddleware,\n  EventBusMiddlewareDescriptor,\n  PluginDescriptor,\n  EventBusPluginFn,\n  defaultPluginDescriptor,\n  EventBusPlugin,\n} from './types';\nimport {EventBus} from './event-bus';\nimport {Dictionary} from '../../../../types';\n\ninterface AddPluginOptions {\n  priority?: number;\n}\n\nconst isPlugin = (obj: any): obj is EventBusPlugin =>\n  typeof obj.name === 'string' && typeof obj.registerFn === 'function';\n\nexport const EventBusBuilder = () => new EventBusBuilderT();\n\nclass EventBusBuilderT {\n  private middlewares: EventBusMiddlewareDescriptor[] = [];\n  private plugins: PluginDescriptor[] = [];\n\n  addPlugin(\n    plugins: Dictionary<EventBusPlugin> | EventBusPlugin,\n  ): EventBusBuilderT;\n\n  addPlugin(name: string, registerCB: EventBusPluginFn): EventBusBuilderT;\n\n  addPlugin(\n    arg1: string | Dictionary<EventBusPlugin> | EventBusPlugin,\n    registerCB?: EventBusPluginFn,\n  ) {\n    let plugins: Dictionary<EventBusPlugin> = {};\n    if (typeof arg1 === 'string') {\n      plugins = registerCB\n        ? {[arg1]: {name: arg1, registerFn: registerCB}}\n        : {};\n    } else {\n      if (isPlugin(arg1)) {\n        plugins = {[arg1.name]: arg1};\n      } else {\n        /* dictionary of plugins */\n        plugins = arg1;\n      }\n    }\n\n    Object.entries(plugins).forEach(([_, plugin]) => {\n      const pluginDescriptor = defaultPluginDescriptor(plugin.name);\n      const api = new RegisterApi(pluginDescriptor);\n      plugin.registerFn(api);\n      this.plugins.push(pluginDescriptor);\n    });\n    return this;\n  }\n\n  addMiddleware(\n    middleware: EventBusMiddleware,\n    options: AddPluginOptions = {},\n  ) {\n    let {priority} = options;\n    priority = this.computeMiddlewarePriority(priority);\n\n    this.middlewares.push({fn: middleware, priority});\n    return this;\n  }\n\n  private computeMiddlewarePriority(priority?: number) {\n    priority =\n      typeof priority === 'number'\n        ? priority\n        : (Object.keys(this.middlewares).length > 0\n            ? Math.max.apply(\n                null,\n                this.middlewares.map(m => m.priority),\n              )\n            : 0) + 1;\n    return priority;\n  }\n\n  build(options: {timeout: number} = {timeout: 30000}) {\n    return new EventBus(this.middlewares, this.plugins, options.timeout);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus.drawio",
    "content": "<mxfile host=\"65bd71144e\">\n    <diagram id=\"9kxZtDrnx1mr4oe_lj4n\" name=\"Page-1\">\n        <mxGraphModel dx=\"616\" dy=\"1754\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"850\" pageHeight=\"1100\" math=\"0\" shadow=\"0\">\n            <root>\n                <mxCell id=\"0\"/>\n                <mxCell id=\"1\" parent=\"0\"/>\n                <mxCell id=\"2\" value=\"Event Bus\" style=\"rounded=1;whiteSpace=wrap;html=1;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"190\" width=\"390\" height=\"610\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"3\" value=\"Plugin\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"230\" y=\"70\" width=\"315\" height=\"40\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"4\" value=\"Plugin\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"230\" y=\"141\" width=\"315\" height=\"40\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"5\" value=\"Plugin\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"230\" y=\"208\" width=\"315\" height=\"40\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"6\" value=\"Middleware\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"230\" y=\"340\" width=\"315\" height=\"40\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"7\" value=\"Middleware\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"230\" y=\"410\" width=\"315\" height=\"40\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"8\" value=\"Middleware\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=23;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"230\" y=\"482\" width=\"315\" height=\"40\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"9\" value=\"\" style=\"endArrow=classic;html=1;fontSize=23;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\" parent=\"1\" source=\"5\" target=\"6\" edge=\"1\">\n                    <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n                        <mxPoint x=\"460\" y=\"380\" as=\"sourcePoint\"/>\n                        <mxPoint x=\"510\" y=\"330\" as=\"targetPoint\"/>\n                    </mxGeometry>\n                </mxCell>\n                <mxCell id=\"10\" value=\"...\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=29;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"370\" y=\"181\" width=\"40\" height=\"20\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"11\" value=\"...\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=29;\" parent=\"1\" vertex=\"1\">\n                    <mxGeometry x=\"365\" y=\"451\" width=\"40\" height=\"20\" as=\"geometry\"/>\n                </mxCell>\n                <mxCell id=\"12\" value=\"\" style=\"endArrow=classic;html=1;fontSize=23;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\" parent=\"1\" source=\"3\" edge=\"1\" target=\"4\">\n                    <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n                        <mxPoint x=\"460\" y=\"258\" as=\"sourcePoint\"/>\n                        <mxPoint x=\"450\" y=\"140\" as=\"targetPoint\"/>\n                    </mxGeometry>\n                </mxCell>\n                <mxCell id=\"13\" value=\"\" style=\"endArrow=classic;html=1;fontSize=23;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\" parent=\"1\" source=\"6\" target=\"7\" edge=\"1\">\n                    <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n                        <mxPoint x=\"460\" y=\"368\" as=\"sourcePoint\"/>\n                        <mxPoint x=\"460\" y=\"398\" as=\"targetPoint\"/>\n                    </mxGeometry>\n                </mxCell>\n            </root>\n        </mxGraphModel>\n    </diagram>\n</mxfile>"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus.spec.ts",
    "content": "import {EventBusBuilder} from './event-bus-builder';\nimport {\n  EventBusPluginFn,\n  EventBusMiddleware as Middleware,\n  HookFn,\n} from './types';\nimport {Dictionary} from '../../../../types';\nimport {Context} from './context';\n\ndescribe('event bus', () => {\n  describe('basic functionality', () => {\n    it('should call handler on emit', async () => {\n      const spy = jest.fn();\n      const bus = EventBusBuilder().build();\n      bus.on('foo.create', spy);\n      await bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n      expect(spy.mock.calls).toHaveLength(1);\n    });\n  });\n\n  const expectedMiddlewareArgs = (action: any) => [\n    {type: 'foo.create', id: '1'},\n    expect.objectContaining({hooks: {call: expect.any(Function)}}),\n    expect.any(Function),\n  ];\n\n  describe('middlewares', () => {\n    it('should call a middleware', async () => {\n      const spy = jest.fn((action, api, next) => next(action));\n      const bus = EventBusBuilder().addMiddleware(spy).build();\n      await bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      expect(spy.mock.calls).toHaveLength(1);\n      expect(spy.mock.calls[0]).toMatchObject(\n        expectedMiddlewareArgs({type: 'foo.create', id: '1', user: 'foo'}),\n      );\n    });\n\n    it('should reject on timeout if callback is not called', async () => {\n      const spy = jest.fn();\n      const bus = EventBusBuilder().addMiddleware(spy).build({timeout: 300});\n      const rv = bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      return rv.catch((e: Error) => {\n        expect(e.message).toEqual('Event Bus: timeout');\n      });\n    });\n\n    it('should pass exceptions upwards', () => {\n      const bus = EventBusBuilder()\n        .addMiddleware(() => {\n          throw new Error('Some Error msg');\n        })\n        .build();\n      const rv = bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      return rv.catch((e: Error) => {\n        expect(e.message).toEqual('Some Error msg');\n      });\n    });\n\n    it('calling next() should pass the action to the next middleware', async () => {\n      const middleware1 = jest.fn((arg, api, next) => next());\n      const middleware2 = jest.fn((arg, api, next) => next());\n\n      const bus = EventBusBuilder()\n        .addMiddleware(middleware1)\n        .addMiddleware(middleware2)\n        .build();\n      await bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      expect(middleware2.mock.calls).toHaveLength(1);\n      expect(middleware2.mock.calls[0]).toMatchObject(\n        expectedMiddlewareArgs({type: 'foo.create', id: '1'}),\n      );\n    });\n\n    it('calling next(result) should pass `result` of one middleware to the next', async () => {\n      const middleware1 = jest.fn((arg, api, next) =>\n        next({...arg, foo: 'bar'}),\n      );\n      const middleware2 = jest.fn((arg, api, next) => next(arg));\n\n      const bus = EventBusBuilder()\n        .addMiddleware(middleware1)\n        .addMiddleware(middleware2)\n        .build();\n      await bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      expect(middleware2.mock.calls).toHaveLength(1);\n      expect(middleware2.mock.calls[0]).toMatchObject(\n        expectedMiddlewareArgs({\n          type: 'foo.create',\n          id: '1',\n          foo: 'bar',\n          user: 'foo',\n        }),\n      );\n    });\n\n    it('calling next(error) should stop middlewares and return a rejected promise', () => {\n      const bus = EventBusBuilder()\n        .addMiddleware((arg, api, next) => {\n          next(new Error('Some Error msg'));\n        })\n        .build();\n      const rv = bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      return rv.catch((e: Error) => {\n        expect(e.message).toEqual('Some Error msg');\n      });\n    });\n\n    it('should call lower priority middlewares first', async () => {\n      const middleware1 = jest.fn((arg, api, next) =>\n        next({...arg, foo: 'bar'}),\n      );\n      const middleware2 = jest.fn((arg, api, next) => next(arg));\n\n      const bus = EventBusBuilder()\n        .addMiddleware(middleware2, {priority: 1})\n        .addMiddleware(middleware1, {priority: 0})\n        .build();\n      await bus.emit({type: 'foo.create', id: '1', user: 'foo'});\n\n      expect(middleware2.mock.calls).toHaveLength(1);\n      expect(middleware2.mock.calls[0]).toMatchObject(\n        expectedMiddlewareArgs({type: 'foo.create', id: '1', foo: 'bar'}),\n      );\n    });\n  });\n\n  describe('plugins + hooks', () => {\n    let busBuilder: ReturnType<typeof EventBusBuilder>;\n    let mockStorage: any[];\n    const exampleHooks: Dictionary<HookFn> = {\n      validateHook: (action, hookApi) => {\n        switch (action.type) {\n          case 'doError':\n            throw new Error('some validation failed');\n          default:\n            return;\n        }\n      },\n      saveHook: (action, hookApi) => {\n        mockStorage.push(action);\n      },\n    };\n    const validateSpy = jest.spyOn(exampleHooks, 'validateHook');\n    const saveSpy = jest.spyOn(exampleHooks, 'saveHook');\n\n    beforeEach(() => {\n      mockStorage = [];\n\n      const plugin: EventBusPluginFn = api => {\n        api.hooks\n          .listen('validate', exampleHooks.validateHook)\n          .hooks.listen('save', exampleHooks.saveHook);\n      };\n\n      const validationMiddleware: Middleware = async (action, api, next) => {\n        api.hooks\n          .call('validate', action)\n          .then(() => next(action))\n          .catch(e => next(e));\n      };\n\n      busBuilder = EventBusBuilder()\n        .addPlugin('someEntity', plugin)\n        .addMiddleware(validationMiddleware);\n    });\n\n    afterEach(() => {\n      validateSpy.mockClear();\n      saveSpy.mockClear();\n    });\n\n    it('middleware should be able to call plugin hooks', async () => {\n      const action = {type: 'bla', id: '1', user: 'foo'};\n      const bus = busBuilder.build();\n      await bus.emit(action);\n\n      expect(validateSpy.mock.calls).toHaveLength(1);\n      expect(validateSpy.mock.calls[0]).toMatchObject([\n        action,\n        {context: expect.any(Context)},\n      ]);\n    });\n\n    describe('hook failure/errors', () => {\n      it('on error, emit() should return rejected promise', async () => {\n        const action = {type: 'doError', id: '1', user: 'foo'};\n        const bus = busBuilder.build();\n        const error: Error = await bus.emit(action).catch(e => e);\n        expect(error.message).toBe('some validation failed');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/event-bus.ts",
    "content": "import {EventEmitter} from 'events';\nimport {defer} from '../../../../utils/deferred-promise';\nimport {\n  EventBusMiddlewareDescriptor,\n  PluginDescriptor,\n  EventBusNextFn,\n} from './types';\nimport {MiddlewareApi} from './api';\nimport {IAction} from '../types';\n\n/**\n * @name EventBus\n * @description\n * acts as an enhanced event emitter, with the added notion of middlewares, and plugins.\n * - event will be emitted only if all middlewares pass (== don't throw) the event\n * - all middlewares are called for all events, in a row.\n * - every middleware gets the action and can:\n *     ## call the next middleware with next() function\n *     ## can pass a new action to next function\n *     ## can call a \"hook\" on all registered plugins\n *\n * - a plugin is a collection of hooks - different phases that can be called by middlewares\n *   a hook gets a context object, where it can pass data to the next hook.\n *   use case: avoid fetching data twice, if fetch data from DB on Validation, use it later.\n */\nexport class EventBus {\n  private middlewares: EventBusMiddlewareDescriptor[];\n\n  constructor(\n    middlewaresUnsorted: EventBusMiddlewareDescriptor[],\n    private plugins: PluginDescriptor[],\n    private timeout = 4000,\n  ) {\n    this.middlewares = middlewaresUnsorted.sort(\n      (m1, m2) => m1.priority - m2.priority,\n    );\n  }\n  private emitter = new EventEmitter();\n\n  emit<A extends IAction = IAction>(action: A) {\n    const {promise, reject, resolve} = defer();\n    const context: any = {};\n    const loggedEvents: IAction[] = [];\n\n    const waitForResolution = setTimeout(() => {\n      reject(new Error('Event Bus: timeout'));\n    }, this.timeout);\n\n    let cachedAction = action;\n\n    const next = (i: number) => {\n      return (nextAction?: A | Error) => {\n        if (nextAction instanceof Error) {\n          reject(nextAction);\n          clearTimeout(waitForResolution);\n          return;\n        }\n\n        cachedAction = nextAction ? nextAction : cachedAction;\n\n        if (i === this.middlewares.length) {\n          resolve(cachedAction);\n          clearTimeout(waitForResolution);\n          return;\n        }\n\n        setImmediate(() => {\n          const middleware = this.middlewares[i];\n          try {\n            const api = new MiddlewareApi(this.plugins, context);\n            middleware.fn(cachedAction, api, (...args) => {\n              loggedEvents.push(...api.getLoggedActions());\n              return next(i + 1)(...(args as any));\n            });\n          } catch (e) {\n            reject(e);\n            clearTimeout(waitForResolution);\n          }\n        });\n      };\n    };\n\n    next(0)(action);\n\n    return promise.then((finalAction: A) => {\n      this.emitter.emit(finalAction.type, finalAction);\n\n      return loggedEvents;\n    });\n  }\n\n  on(type: string, handler: (...args: any[]) => any) {\n    this.emitter.on(type, handler);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/index.ts",
    "content": "export {\n  EventBusNextFn,\n  EventBusPluginFn,\n  EventBusMiddleware,\n  EventBusPlugin,\n} from './types';\nexport {EventBus} from './event-bus';\nexport {EventBusBuilder} from './event-bus-builder';\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/event-bus/types.ts",
    "content": "import {RegisterApi, MiddlewareApi} from './api';\nimport {Context} from './context';\nimport {IAction} from '../types';\n\nexport type EventBusMiddleware = <A extends IAction = IAction>(\n  action: A,\n  api: MiddlewareApi,\n  next: EventBusNextFn,\n) => any;\nexport type EventBusNextFn = <A extends IAction = IAction>(\n  action?: A | Error,\n) => void;\nexport type EventBusPluginFn = (api: RegisterApi) => void;\nexport interface EventBusPlugin {\n  name: string;\n  registerFn: EventBusPluginFn;\n}\n\n/**** Middleware  ****/\nexport interface EventBusMiddlewareDescriptor {\n  fn: EventBusMiddleware;\n  priority: number;\n}\n\n/**** Plugins ****/\nexport type EventFilter = (type: string) => boolean;\n\nexport interface PluginDescriptor {\n  name: string;\n  eventFilter: EventFilter;\n  options: PluginOptions;\n  hooks: Map<string, Hook<any>>;\n}\nexport const defaultPluginDescriptor = (name: string): PluginDescriptor => ({\n  name,\n  eventFilter: () => true,\n  options: {\n    isTransaction: true,\n  },\n  hooks: new Map(),\n});\n\nexport interface PluginOptions {\n  isTransaction: boolean;\n}\n\nexport type Plugins = Map<string, PluginDescriptor>;\n\n/**** PluginApi ****/\nexport interface IPluginApi {\n  hooks: {\n    call<A extends IAction = IAction>(\n      name: string,\n      action: A,\n      extraContext?: Record<string, any>,\n    ): Promise<any>;\n  };\n}\n\n/**** Hooks ****/\nexport type HookFn<A extends IAction = IAction> = (\n  action: A,\n  api: HookApi,\n) => PromiseLike<any> | any;\n\ninterface Hook<A extends IAction = IAction> {\n  name: string;\n  fn: HookFn<A>;\n}\n\nexport interface HookApi {\n  context: Context;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/infrastructure/types.ts",
    "content": "import {BaseAction} from '@wix/quix-shared/entities/common/common-types';\nexport interface IEventData {\n  [key: string]: any;\n}\n\nexport interface HasId {\n  id: string;\n}\n\ninterface ServerFields {\n  dateCreated?: Date;\n  user: string;\n  userId?: string;\n  sessionId?: string;\n}\n\nexport type IAction<T = IEventData, N extends string = string> = BaseAction & {\n  type: N;\n  ethereal?: boolean;\n  syncClients?: boolean;\n} & T &\n  ServerFields;\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/deleted-notebook-plugin.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectEntityManager} from '@nestjs/typeorm';\nimport {DbDeletedNotebook} from '../../../entities';\nimport {\n  convertDbDeletedNotebook,\n  covertDeletedNotebookToDb,\n} from '../../../entities/deleted-notebook/dbdeleted-notebook.entity';\nimport {\n  DeletedNotebookActions,\n  DeletedNotebookActionTypes,\n  deletedNotebookReducer,\n} from '@wix/quix-shared';\nimport {EntityManager} from 'typeorm';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {IAction} from '../infrastructure/types';\nimport {QuixHookNames} from '../types';\nimport {assertOwner} from './utils';\n\n@Injectable()\nexport class DeletedNotebookPlugin implements EventBusPlugin {\n  name = 'deletedNotebook';\n\n  constructor(@InjectEntityManager() private em: EntityManager) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = [\n      DeletedNotebookActionTypes.createDeletedNotebook,\n      DeletedNotebookActionTypes.deleteDeletedNotebook,\n    ];\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.VALIDATION,\n      async (action: IAction<DeletedNotebookActions>) => {\n        switch (action.type) {\n          case DeletedNotebookActionTypes.deleteDeletedNotebook: {\n            const deletedNotebook = await this.em.findOneOrFail(\n              DbDeletedNotebook,\n              action.id,\n            );\n            assertOwner(deletedNotebook, action);\n            break;\n          }\n        }\n      },\n    );\n\n    api.hooks.listen(\n      QuixHookNames.PROJECTION,\n      async (action: IAction<DeletedNotebookActions>) =>\n        this.em.transaction(async transactionManager => {\n          await this.projectDeletedNotebook(action, transactionManager);\n        }),\n    );\n  };\n\n  private async projectDeletedNotebook(\n    action: IAction<DeletedNotebookActions>,\n    entityManager: EntityManager,\n  ) {\n    const dbModel =\n      action.type === DeletedNotebookActionTypes.createDeletedNotebook\n        ? undefined\n        : await entityManager.findOne(DbDeletedNotebook, action.id);\n    const model = dbModel ? convertDbDeletedNotebook(dbModel) : undefined;\n\n    const newModel = deletedNotebookReducer(model, action);\n    if (newModel && model !== newModel) {\n      return entityManager.save(covertDeletedNotebookToDb(newModel), {\n        reload: false,\n      });\n    } else if (\n      action.type === DeletedNotebookActionTypes.deleteDeletedNotebook\n    ) {\n      await entityManager.delete(DbDeletedNotebook, {id: action.id});\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/events-plugin.ts",
    "content": "import {Inject, Injectable} from '@nestjs/common';\nimport {EventsService} from '../events.service';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {IAction} from '../infrastructure/types';\nimport {QuixHookNames} from '../types';\n\n@Injectable()\nexport class EventsPlugin implements EventBusPlugin {\n  name = 'events';\n\n  constructor(@Inject(EventsService) private eventsService: EventsService) {}\n\n  registerFn: EventBusPluginFn = api => {\n    api.hooks.listen(QuixHookNames.PROJECTION, async (action: IAction) => {\n      if (!action.ethereal && action.syncClients !== false) {\n        this.eventsService.logEvent(action);\n      }\n    });\n  };\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/favorites-plugin.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectEntityManager} from '@nestjs/typeorm';\nimport {EntityType} from '../../../common/entity-type.enum';\nimport {DbFavorites} from '../../../entities';\nimport {\n  NotebookActions,\n  NotebookActionTypes,\n} from '@wix/quix-shared/entities/notebook';\nimport {EntityManager} from 'typeorm';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {QuixHookNames} from '../types';\nimport {IAction} from '../infrastructure/types';\n\n@Injectable()\nexport class FavoritesPlugin implements EventBusPlugin {\n  name = 'favorites';\n\n  constructor(@InjectEntityManager() private em: EntityManager) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = [NotebookActionTypes.toggleIsLiked];\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.VALIDATION,\n      (action: IAction<NotebookActions>) => {\n        switch (action.type) {\n          case NotebookActionTypes.toggleIsLiked:\n        }\n      },\n    );\n\n    api.hooks.listen(\n      QuixHookNames.PROJECTION,\n      async (action: IAction<NotebookActions>) =>\n        this.em.transaction(async transactionManager => {\n          await this.projectFavorites(action, transactionManager);\n        }),\n    );\n  };\n\n  private async projectFavorites(\n    action: IAction<NotebookActions>,\n    tm: EntityManager,\n  ) {\n    switch (action.type) {\n      case NotebookActionTypes.toggleIsLiked: {\n        const favorite = {\n          entityId: action.id,\n          entityType: EntityType.Notebook,\n          owner: (action as any).user,\n        };\n\n        if (action.isLiked) {\n          return tm.save(Object.assign(new DbFavorites(), favorite));\n        } else {\n          return tm.delete(DbFavorites, favorite);\n        }\n      }\n      default:\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/file-tree-plugin.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {DbFolder, DbFileTreeNode} from '../../../entities';\nimport {Repository} from 'typeorm';\nimport {\n  FileActions,\n  FileActionTypes,\n  IFile,\n} from '@wix/quix-shared/entities/file';\nimport {\n  NotebookActions,\n  NotebookActionTypes,\n} from '@wix/quix-shared/entities/notebook';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {QuixHookNames} from '../types';\nimport {last} from 'lodash';\nimport {FileType} from '@wix/quix-shared/entities/file';\nimport {FileTreeRepository} from '../../../entities/filenode/filenode.repository';\nimport {IAction} from '../infrastructure/types';\nimport {\n  extractEventNames,\n  assertOwner,\n  lastAndAssertExist,\n  assert,\n} from './utils';\n@Injectable()\nexport class FileTreePlugin implements EventBusPlugin {\n  name = 'fileTree';\n\n  constructor(\n    @InjectRepository(DbFolder)\n    private folderRepo: Repository<DbFolder>,\n    @InjectRepository(FileTreeRepository)\n    private fileTreeNodeRepo: FileTreeRepository,\n  ) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = extractEventNames(\n      FileActionTypes,\n      NotebookActionTypes,\n    );\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.VALIDATION,\n      async (action: IAction<FileActions | NotebookActions>, hookApi) => {\n        switch (action.type) {\n          case FileActionTypes.createFile: {\n            const {file} = action;\n\n            assertNodeNotNotebook(\n              file,\n              action,\n              'Notebooks should be created directly',\n            );\n\n            const parentPath = last(file.path);\n            const parent = parentPath\n              ? await this.fileTreeNodeRepo.findOneOrFail({id: parentPath.id})\n              : undefined;\n\n            if (parent) {\n              assertOwner(\n                parent,\n                action,\n                `Can't add folder, parent folder owner is a different user`,\n              );\n            }\n\n            hookApi.context.set({parent});\n            break;\n          }\n\n          case FileActionTypes.deleteFile: {\n            const node = await this.fileTreeNodeRepo.findOneOrFail(action.id);\n            assertOwner(node, action);\n            assertNodeNotNotebook(\n              node,\n              action,\n              'Notebooks should be deleted directly',\n            );\n\n            hookApi.context.set({fileNode: node});\n            break;\n          }\n\n          case FileActionTypes.moveFile: {\n            const node = await this.fileTreeNodeRepo.findOneOrFail(action.id);\n            assertOwner(node, action);\n            assertNodeNotNotebook(\n              node,\n              action,\n              'Notebooks should be moved directly',\n            );\n            hookApi.context.set({fileNode: node});\n            break;\n          }\n          default:\n        }\n      },\n    );\n\n    api.hooks.listen(\n      QuixHookNames.PROJECTION,\n      async (action: IAction<FileActions | NotebookActions>, hookApi) => {\n        switch (action.type) {\n          case FileActionTypes.createFile: {\n            const {file} = action;\n            const parent: DbFileTreeNode | undefined =\n              hookApi.context.get().parent;\n            const folder = new DbFolder();\n\n            Object.assign(folder, {\n              id: file.id,\n              owner: action.user,\n              name: file.name,\n              dateCreated: action.dateCreated,\n              dateUpdated: action.dateCreated,\n            });\n            const node = new DbFileTreeNode();\n\n            Object.assign(node, {\n              id: file.id,\n              owner: action.user,\n              parent,\n              folder,\n            });\n\n            // we should use .insert() here, but looks like it doesn't cascade folder row\n            return this.fileTreeNodeRepo.save(node, {reload: false});\n          }\n\n          case FileActionTypes.updateName: {\n            const {id} = action;\n            const folder = await this.folderRepo.findOneOrFail(id, {\n              loadRelationIds: true,\n            });\n\n            folder.name = action.name;\n            return this.folderRepo.save(folder, {reload: false});\n          }\n\n          case NotebookActionTypes.moveNotebook: {\n            const {id, path} = action;\n            const parent = lastAndAssertExist(path, action);\n\n            const node = new DbFileTreeNode(id, {parentId: parent.id});\n            return this.fileTreeNodeRepo.save(node, {reload: false});\n          }\n\n          case FileActionTypes.moveFile: {\n            const {id, path} = action;\n            const parent = lastAndAssertExist(path, action);\n            const parentNode = await this.fileTreeNodeRepo.findOneOrFail(\n              parent.id,\n            );\n            const fileNode: DbFileTreeNode = hookApi.context.get().fileNode;\n            return this.fileTreeNodeRepo.moveTree(fileNode, parentNode);\n          }\n\n          case FileActionTypes.toggleIsLiked:\n            break;\n\n          case FileActionTypes.deleteFile: {\n            const fileNode: DbFileTreeNode = hookApi.context.get().fileNode;\n            return this.fileTreeNodeRepo.deleteTree(fileNode);\n          }\n        }\n      },\n    );\n  };\n}\n\nfunction assertNodeNotNotebook(\n  node: DbFileTreeNode | IFile,\n  action: IAction,\n  msg: string,\n) {\n  assert(node, action, ({type}) => type !== FileType.notebook, msg);\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/note-plugin.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {DbNote, NoteRepository, DbNotebook} from '../../../entities';\nimport {\n  convertDbNote,\n  convertNoteToDb,\n} from '../../../entities/note/dbnote.entity';\nimport {\n  IBaseNote,\n  NoteActions,\n  NoteActionTypes,\n  noteReducer,\n} from '@wix/quix-shared/entities/note';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {QuixHookNames} from '../types';\nimport {IAction} from '../infrastructure/types';\nimport {extractEventNames, assertOwner} from './utils';\nimport {NotebookRepository} from '../../../entities/notebook/notebook.repository';\nimport {isEqual, omit} from 'lodash';\n\n@Injectable()\nexport class NotePlugin implements EventBusPlugin {\n  name = 'note';\n\n  constructor(\n    @InjectRepository(NoteRepository)\n    private noteRepository: NoteRepository,\n    @InjectRepository(NotebookRepository)\n    private notebookRepository: NotebookRepository,\n  ) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = extractEventNames(NoteActionTypes);\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.VALIDATION,\n      async (action: IAction<NoteActions>) => {\n        let entity: DbNotebook | DbNote | null = null;\n        switch (action.type) {\n          case NoteActionTypes.addNote:\n            entity = await this.notebookRepository.findOneOrFail(\n              action.note.notebookId,\n            );\n\n            break;\n          case NoteActionTypes.deleteNote:\n          case NoteActionTypes.move:\n          case NoteActionTypes.updateContent:\n          case NoteActionTypes.updateName:\n            entity = await this.noteRepository.findOneOrFail(action.id);\n        }\n        if (entity) {\n          assertOwner(entity, action);\n        }\n      },\n    );\n\n    api.hooks.listen(\n      QuixHookNames.PROJECTION,\n      async (action: IAction<NoteActions>) => {\n        if (action.type === NoteActionTypes.addNote) {\n          const note = await noteReducer(undefined, action);\n          if (note) {\n            return this.noteRepository.insertNewWithRank(convertNoteToDb(note));\n          }\n          return;\n        }\n\n        const dbModel = await this.noteRepository.findOneOrFail(action.id);\n\n        switch (action.type) {\n          case NoteActionTypes.reorderNote: {\n            return this.noteRepository.reorder(dbModel, action.to);\n          }\n\n          case NoteActionTypes.deleteNote: {\n            return this.noteRepository.deleteOneAndOrderRank(dbModel);\n          }\n          default: {\n            const model = convertDbNote(dbModel);\n            const newModel = noteReducer(model, action);\n\n            if (newModel && this.modelHasChanged(action, model, newModel)) {\n              return await this.noteRepository.save(convertNoteToDb(newModel), {\n                reload: false,\n              });\n            }\n          }\n        }\n      },\n    );\n  };\n\n  modelHasChanged = (\n    action: IAction<NoteActions>,\n    model: IBaseNote,\n    newModel: IBaseNote,\n  ) => {\n    switch (action.type) {\n      case NoteActionTypes.updateContent: {\n        const contentChanged =\n          newModel.content && model.content !== newModel.content;\n        const richContentChanged =\n          newModel.richContent &&\n          !isEqual(model.richContent, newModel.richContent);\n\n        return contentChanged || richContentChanged;\n      }\n\n      default: {\n        const valuesToOmit = ['dateUpdated', 'content', 'richContent'];\n        const modelToCompare = omit(model, valuesToOmit);\n        const newModelToCompare = omit(newModel, valuesToOmit);\n        return !isEqual(modelToCompare, newModelToCompare);\n      }\n    }\n  };\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/notebook-plugin.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectEntityManager} from '@nestjs/typeorm';\nimport {\n  DbFavorites,\n  DbFileTreeNode,\n  DbNote,\n  DbNotebook,\n} from '../../../entities';\nimport {FileTreeRepository} from '../../../entities/filenode/filenode.repository';\nimport {\n  convertDbNotebook,\n  covertNotebookToDb,\n} from '../../../entities/notebook/dbnotebook.entity';\nimport {last} from 'lodash';\nimport {FileType} from '@wix/quix-shared/entities/file';\nimport {\n  NotebookActions,\n  NotebookActionTypes,\n  notebookReducer,\n} from '@wix/quix-shared/entities/notebook';\nimport {EntityManager} from 'typeorm';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {IAction} from '../infrastructure/types';\nimport {QuixHookNames} from '../types';\nimport {assertOwner} from './utils';\n\n@Injectable()\nexport class NotebookPlugin implements EventBusPlugin {\n  name = 'notebook';\n\n  constructor(@InjectEntityManager() private em: EntityManager) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = [\n      NotebookActionTypes.createNotebook,\n      NotebookActionTypes.deleteNotebook,\n      NotebookActionTypes.deleteNotebookNotes,\n      NotebookActionTypes.updateName,\n    ];\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.VALIDATION,\n      async (action: IAction<NotebookActions>) => {\n        switch (action.type) {\n          case NotebookActionTypes.updateName:\n          case NotebookActionTypes.deleteNotebook:\n          case NotebookActionTypes.deleteNotebookNotes: {\n            const notebook = await this.em.findOneOrFail(DbNotebook, action.id);\n            assertOwner(notebook, action);\n            break;\n          }\n          case NotebookActionTypes.createNotebook:\n        }\n      },\n    );\n\n    api.hooks.listen(\n      QuixHookNames.PROJECTION,\n      async (action: IAction<NotebookActions>) =>\n        this.em.transaction(async transactionManager => {\n          await this.projectNotebook(action, transactionManager);\n          await this.projectNote(action, transactionManager);\n          await this.projectFileTree(action, transactionManager);\n          await this.projectFavorites(action, transactionManager);\n        }),\n    );\n  };\n\n  private async projectNotebook(\n    action: IAction<NotebookActions>,\n    tm: EntityManager,\n  ) {\n    const dbModel =\n      action.type === NotebookActionTypes.createNotebook\n        ? undefined\n        : await tm.findOne(DbNotebook, action.id);\n\n    const model = dbModel ? convertDbNotebook(dbModel) : undefined;\n\n    const newModel = notebookReducer(model, action);\n\n    if (newModel && model !== newModel) {\n      return tm.save(covertNotebookToDb(newModel), {reload: false});\n    } else if (action.type === NotebookActionTypes.deleteNotebook) {\n      await tm.delete(DbNotebook, {id: action.id});\n    }\n  }\n\n  async projectNote(\n    action: IAction<NotebookActions, string>,\n    tm: EntityManager,\n  ) {\n    switch (action.type) {\n      case NotebookActionTypes.deleteNotebookNotes: {\n        const {id} = action;\n        await tm.delete(DbNote, {notebookId: id});\n      }\n    }\n  }\n\n  private async projectFileTree(\n    action: IAction<NotebookActions>,\n    tm: EntityManager,\n  ) {\n    switch (action.type) {\n      case NotebookActionTypes.createNotebook: {\n        const {notebook} = action;\n        const parent = last(notebook.path);\n        const node = new DbFileTreeNode();\n\n        node.id = notebook.id;\n        node.notebookId = notebook.id;\n        node.owner = action.user;\n        node.type = FileType.notebook;\n        node.parent = parent ? new DbFileTreeNode(parent.id) : undefined;\n\n        return tm\n          .getCustomRepository(FileTreeRepository)\n          .save(node, {reload: false});\n      }\n    }\n  }\n\n  private async projectFavorites(\n    action: IAction<NotebookActions>,\n    tm: EntityManager,\n  ) {\n    switch (action.type) {\n      case NotebookActionTypes.deleteNotebook: {\n        return tm.delete(DbFavorites, {\n          entityId: action.id,\n        });\n      }\n      default:\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/trash-bin-plugin.ts",
    "content": "import {Inject, Injectable} from '@nestjs/common';\nimport {InjectEntityManager, InjectRepository} from '@nestjs/typeorm';\n\nimport {\n  DeletedNotebookActions,\n  FileActions,\n  FileType,\n  IDeletedNotebook,\n  NoteActions,\n  NotebookActions,\n  TrashBinActionTypes,\n} from '@wix/quix-shared';\nimport {\n  DbDeletedNotebook,\n  DbFolder,\n  DbNote,\n  DbNotebook,\n  FileTreeRepository,\n} from '../../../entities';\nimport {convertDbNotebook} from '../../../entities/notebook/dbnotebook.entity';\nimport {EntityManager} from 'typeorm';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {IAction} from '../infrastructure/types';\nimport {QuixHookNames} from '../types';\nimport {asUser} from './utils';\n\n@Injectable()\nexport class TrashBinPlugin implements EventBusPlugin {\n  name = 'trashBin';\n\n  constructor(\n    @InjectEntityManager() private em: EntityManager,\n    @InjectRepository(FileTreeRepository)\n    private fileTreeNodeRepo: FileTreeRepository,\n  ) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = [\n      TrashBinActionTypes.moveNotebookToTrashBin,\n      TrashBinActionTypes.moveFolderToTrashBin,\n      TrashBinActionTypes.restoreDeletedNotebook,\n      TrashBinActionTypes.permanentlyDeleteNotebook,\n    ];\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.REACTION,\n      async (action: IAction<TrashBinActionTypes>) => {\n        switch (action.type) {\n          case TrashBinActionTypes.moveNotebookToTrashBin:\n            return this.addNotebookReactions(action);\n          case TrashBinActionTypes.moveFolderToTrashBin:\n            return this.addFolderReactions(action);\n          case TrashBinActionTypes.restoreDeletedNotebook:\n            return this.restoreNotebookReactions(action);\n          case TrashBinActionTypes.permanentlyDeleteNotebook:\n            return this.permanentlyDeleteReactions(action);\n        }\n      },\n    );\n  };\n\n  private async restoreNotebookReactions(\n    action: IAction<TrashBinActionTypes, string>,\n  ) {\n    const deletedNotebook = await this.em.findOneOrFail(\n      DbDeletedNotebook,\n      action.id,\n    );\n\n    const folder = await this.em.findOneOrFail(DbFolder, {\n      id: (action as any).folderId,\n    });\n\n    const folderNode = await this.fileTreeNodeRepo.findOneOrFail(folder.id);\n    const path = folderNode.mpath.split('.').map(n => ({id: n, name: ''}));\n\n    const notebook = convertDbNotebook(\n      {\n        ...deletedNotebook,\n      },\n      path,\n    );\n\n    return [\n      asUser(\n        NotebookActions.createNotebook(notebook.id, notebook),\n        action.user,\n        action.userId,\n      ),\n      asUser(\n        DeletedNotebookActions.deleteDeletedNotebook(notebook.id),\n        action.user,\n        action.userId,\n      ),\n    ];\n  }\n\n  private async addNotebookReactions(\n    action: IAction<TrashBinActionTypes, string>,\n  ) {\n    return this.addNotebook(action.id, action.user, action.userId);\n  }\n\n  private async addNotebook(notebookId: string, user: string, userId?: string) {\n    const notebook = await this.em.findOneOrFail(DbNotebook, notebookId);\n    const deletedNotebook = {\n      ...convertDbNotebook(notebook),\n      dateDeleted: Date.now(),\n    } as IDeletedNotebook;\n\n    return [\n      asUser(\n        DeletedNotebookActions.createDeletedNotebook(\n          notebookId,\n          deletedNotebook,\n        ),\n        user,\n        userId,\n      ),\n      asUser(NotebookActions.deleteNotebook(notebookId), user, userId),\n    ];\n  }\n\n  async addFolderReactions(\n    action: IAction<TrashBinActionTypes, string>,\n  ): Promise<any> {\n    const node = await this.fileTreeNodeRepo.findOneOrFail({id: action.id});\n    const children = await this.fileTreeNodeRepo.getDeepChildren(node, this.em);\n    const notebooks = children\n      .filter(c => c.type === FileType.notebook)\n      .map(n => this.addNotebook(n.id, action.user, action.userId));\n\n    const actions: any[] = [];\n\n    for await (const a of notebooks) {\n      actions.push(...a);\n    }\n\n    return [\n      ...actions,\n      asUser(FileActions.deleteFile(action.id), action.user, action.userId),\n    ];\n  }\n\n  private async permanentlyDeleteReactions(\n    action: IAction<TrashBinActionTypes, string>,\n  ) {\n    let result: any[] = [\n      asUser(\n        DeletedNotebookActions.deleteDeletedNotebook(action.id),\n        action.user,\n        action.userId,\n      ),\n      asUser(\n        NotebookActions.toggleIsLiked(action.id, false),\n        action.user,\n        action.userId,\n      ),\n    ];\n\n    const notes = await this.em.find(DbNote, {notebookId: action.id});\n\n    result = [\n      ...result,\n      ...notes.map(n =>\n        asUser(NoteActions.deleteNote(n.id), action.user, action.userId),\n      ),\n    ];\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/user-plugin.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {DbUser, userToDbUser} from '../../../entities/user/user.entity';\nimport {UserActions, UserActionTypes} from '@wix/quix-shared/entities/user';\nimport {Repository} from 'typeorm';\nimport {EventBusPlugin, EventBusPluginFn} from '../infrastructure/event-bus';\nimport {IAction} from '../infrastructure/types';\nimport {QuixHookNames} from '../types';\nimport {extractEventNames} from './utils';\n\n@Injectable()\nexport class UserPlugin implements EventBusPlugin {\n  name = 'user';\n\n  constructor(\n    @InjectRepository(DbUser)\n    private userRepository: Repository<DbUser>,\n  ) {}\n\n  registerFn: EventBusPluginFn = api => {\n    const handledEvents: string[] = extractEventNames(UserActionTypes);\n\n    api.setEventFilter(type => handledEvents.includes(type));\n\n    api.hooks.listen(\n      QuixHookNames.VALIDATION,\n      async (action: IAction<UserActions>) => {\n        switch (action.type) {\n          case UserActionTypes.createNewUser:\n          case UserActionTypes.updateUser:\n        }\n      },\n    );\n\n    api.hooks.listen(\n      QuixHookNames.PROJECTION,\n      async (action: IAction<UserActions>) => {\n        switch (action.type) {\n          case UserActionTypes.createNewUser: {\n            const dbUser = userToDbUser(action.newUser);\n            return this.userRepository.insert(dbUser);\n          }\n          case UserActionTypes.updateUser: {\n            const {id, avatar, email, name, changeUserCreated} = action;\n            const dbUser = new DbUser({\n              id,\n              avatar,\n              name,\n            });\n            if (changeUserCreated) {\n              dbUser.dateCreated = changeUserCreated.valueOf();\n            }\n            return this.userRepository.save(dbUser, {reload: false});\n          }\n        }\n      },\n    );\n  };\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/plugins/utils.ts",
    "content": "import {IAction} from '../infrastructure/types';\nimport {BadAction} from '../../../errors';\nimport {last} from 'lodash';\n\n/**\n * gets enums, and extracts only the actual values from them\n * @param enums Enums or \"Fake enums\" (Record<string, string>)\n */\nexport const extractEventNames = (...enums: Record<string, string>[]) =>\n  enums\n    .reduce(\n      (result, anEnum) => result.concat(Object.entries<string>(anEnum)),\n      [] as [string, string][],\n    )\n    .map(([typeSymbol, typeString]) => typeString);\n\nexport function lastAndAssertExist<T>(\n  arr: T[],\n  action: IAction,\n  error?: string,\n): T {\n  const item = last(arr);\n  if (!item) {\n    throw BadAction(action.type, error || 'path property should be an array');\n  }\n  return item;\n}\n\nexport function assertOwner<T extends {owner: string}>(\n  obj: T,\n  action: IAction,\n  error?: string,\n) {\n  if (obj.owner !== action.user) {\n    throw BadAction(\n      action.type,\n      error || 'entity owner is not the user dispatching the action',\n    );\n  }\n}\n\nexport function assert<T, A extends IAction>(\n  t: T,\n  action: A,\n  fn: (t: T, action: A) => boolean,\n  error: string,\n) {\n  if (!fn(t, action)) {\n    throw BadAction(action.type, error);\n  }\n}\n\nexport function asUser(reAction: any, user: string, userId?: string) {\n  return {...reAction, user: user, userId: userId};\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/quix-event-bus.driver.ts",
    "content": "/* Helper driver for event-bus tests */\n/* tslint:disable:no-non-null-assertion */\n\nimport {Test, TestingModule} from '@nestjs/testing';\nimport {\n  getConnectionToken,\n  getRepositoryToken,\n  TypeOrmModule,\n} from '@nestjs/typeorm';\nimport {ConfigModule, ConfigService} from '../../config';\nimport {\n  DbFileTreeNode,\n  DbFolder,\n  DbNote,\n  DbNotebook,\n  FileTreeRepository,\n  DbFavorites,\n  DbUser,\n  DbDeletedNotebook,\n} from '../../entities';\nimport {MockDataBuilder} from '../../../test/builder';\nimport {Connection, Repository} from 'typeorm';\nimport {EventSourcingModule} from './event-sourcing.module';\nimport {DbAction} from './infrastructure/action-store/entities/db-action.entity';\nimport {QuixEventBus} from './quix-event-bus';\nimport {EntityType} from '../../common/entity-type.enum';\nimport {EntityClassOrSchema} from '@nestjs/typeorm/dist/interfaces/entity-class-or-schema.type';\n\nexport class QuixEventBusDriver {\n  public mockBuilder: MockDataBuilder;\n\n  constructor(\n    public eventBus: QuixEventBus,\n    public module: TestingModule,\n    public noteRepo: Repository<DbNote>,\n    public notebookRepo: Repository<DbNotebook>,\n    public deletedNotebookRepo: Repository<DbDeletedNotebook>,\n    public eventsRepo: Repository<DbAction>,\n    public folderRepo: Repository<DbFolder>,\n    public fileTreeRepo: Repository<DbFileTreeNode>,\n    public favoritesRepo: Repository<DbFavorites>,\n    public userRepo: Repository<DbUser>,\n    private conn: Connection,\n    private configService: ConfigService,\n    private defaultUserId: string,\n  ) {\n    this.mockBuilder = new MockDataBuilder(defaultUserId);\n  }\n\n  static async create(defaultUserId: string) {\n    const module = await Test.createTestingModule({\n      imports: [\n        ConfigModule.create(),\n        TypeOrmModule.forRootAsync({\n          imports: [],\n          useFactory: async (cs: ConfigService) =>\n            cs.getDbConnection([\n              DbFileTreeNode,\n              DbFolder,\n              DbNote,\n              DbNotebook,\n              DbDeletedNotebook,\n              DbAction,\n              DbFavorites,\n              DbUser,\n            ]),\n          inject: [ConfigService],\n        }),\n        EventSourcingModule,\n      ],\n      providers: [],\n      exports: [],\n    }).compile();\n\n    const getRepository = (entity: EntityClassOrSchema) =>\n      module.get(getRepositoryToken(entity));\n\n    const eventBus: QuixEventBus = module.get(QuixEventBus);\n    const notebookRepo: Repository<DbNotebook> = getRepository(DbNotebook);\n\n    const deletedNotebookRepo: Repository<DbDeletedNotebook> =\n      getRepository(DbDeletedNotebook);\n\n    const noteRepo: Repository<DbNote> = getRepository(DbNote);\n    const eventsRepo: Repository<DbAction> = getRepository(DbAction);\n\n    const fileTreeRepo: FileTreeRepository = getRepository(FileTreeRepository);\n\n    const folderRepo: Repository<DbFolder> = getRepository(DbFolder);\n    const favoritesRepo: Repository<DbFavorites> = getRepository(DbFavorites);\n\n    const userRepo: Repository<DbUser> = getRepository(DbUser);\n    const conn: Connection = module.get(getConnectionToken());\n    const configService: ConfigService = module.get(ConfigService);\n\n    return new QuixEventBusDriver(\n      eventBus,\n      module,\n      noteRepo,\n      notebookRepo,\n      deletedNotebookRepo,\n      eventsRepo,\n      folderRepo,\n      fileTreeRepo,\n      favoritesRepo,\n      userRepo,\n      conn,\n      configService,\n      defaultUserId,\n    );\n  }\n\n  async clearDb() {\n    const dbType = this.configService.getDbType();\n    await this.clearEvents();\n    await this.clearNotes();\n    await this.clearFolders();\n    await this.clearNotebooks();\n    await this.clearDeletedNotebooks();\n    await this.clearFavorites();\n    await this.userRepo.clear();\n  }\n\n  getNotebook(id: string) {\n    return {\n      and: {\n        expectToBeDefined: async () => {\n          const notebook = await this.notebookRepo.findOneOrFail(id);\n          expect(notebook).toBeDefined();\n          return notebook;\n        },\n        expectToBeUndefined: async () => {\n          const notebook = await this.notebookRepo.findOne(id);\n          expect(notebook).not.toBeDefined();\n          return undefined;\n        },\n      },\n    };\n  }\n\n  getDeletedNotebook(id: string) {\n    return {\n      and: {\n        expectToBeDefined: async () => {\n          const deletedNotebook = await this.deletedNotebookRepo.findOneOrFail(\n            id,\n          );\n          expect(deletedNotebook).toBeDefined();\n          return deletedNotebook;\n        },\n        expectToBeUndefined: async () => {\n          const deletedNotebook = await this.deletedNotebookRepo.findOne(id);\n          expect(deletedNotebook).not.toBeDefined();\n          return undefined;\n        },\n      },\n    };\n  }\n\n  getFavorite(owner: string, entityId: string, entityType: EntityType) {\n    return {\n      and: {\n        expectToBeDefined: async () => {\n          const favorite = await this.favoritesRepo.findOneOrFail({\n            entityId,\n            entityType,\n            owner,\n          });\n\n          expect(favorite).toBeDefined();\n\n          return favorite;\n        },\n        expectToBeUndefined: async () => {\n          const favorite = await this.favoritesRepo.findOne({\n            entityId,\n            entityType,\n            owner,\n          });\n\n          expect(favorite).not.toBeDefined();\n\n          return undefined;\n        },\n      },\n    };\n  }\n\n  async getNotebookWithNotes(id: string) {\n    const notebook = (await this.notebookRepo.findOne(id, {\n      relations: ['notes'],\n    }))!;\n    return notebook;\n  }\n\n  async getNote(id: string) {\n    return this.noteRepo.findOne(id);\n  }\n\n  async getNotesForNotebook(notebookId: string) {\n    return this.noteRepo.find({notebookId});\n  }\n\n  async getUsers() {\n    return this.userRepo.find();\n  }\n\n  async getUserFileTree(user: string) {\n    const q = this.fileTreeRepo\n      .createQueryBuilder('node')\n      .where('node.owner = :user', {user})\n      .leftJoinAndSelect('node.folder', 'folder')\n      .leftJoinAndSelect('node.notebook', 'notebook');\n\n    return q.getMany();\n  }\n\n  clearEvents() {\n    return this.eventsRepo.clear();\n  }\n\n  async clearNotes() {\n    return this.noteRepo.delete({});\n  }\n\n  async clearNotebooks() {\n    return this.notebookRepo.delete({});\n  }\n  async clearDeletedNotebooks() {\n    return this.deletedNotebookRepo.delete({});\n  }\n\n  async clearFavorites() {\n    return this.favoritesRepo.delete({});\n  }\n\n  emitAsUser(\n    eventBus: QuixEventBus,\n    actions: any[],\n    user = this.defaultUserId,\n  ) {\n    return eventBus.emit(actions.map(a => Object.assign(a, {user})));\n  }\n\n  async clearFolders() {\n    await this.folderRepo.delete({});\n    await this.fileTreeRepo.delete({});\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/quix-event-bus.spec.ts",
    "content": "/* tslint:disable:no-shadowed-variable */\n/* tslint:disable:no-non-null-assertion */\n\nimport {TestingModule} from '@nestjs/testing';\nimport 'reflect-metadata';\nimport {INote, NoteActions, createNote} from '@wix/quix-shared/entities/note';\nimport {NoteActionT} from '@wix/quix-shared/entities/note/actions';\nimport {NotebookActions} from '@wix/quix-shared/entities/notebook';\nimport {FileActions, FileType} from '@wix/quix-shared/entities/file';\nimport {QuixEventBus} from './quix-event-bus';\nimport {QuixEventBusDriver} from './quix-event-bus.driver';\nimport {range, reject, find} from 'lodash';\nimport {EntityType} from '../../common/entity-type.enum';\nimport {MockDataBuilder} from 'test/builder';\nimport {IAction, IEventData} from './infrastructure/types';\nimport {\n  DeletedNotebookActions,\n  TrashBinActions,\n  UserActions,\n} from '@wix/quix-shared';\n\njest.setTimeout(300000);\n\nconst defaultUser = 'someUser@wix.com';\n\ndescribe('event sourcing', () => {\n  let driver: QuixEventBusDriver;\n  let eventBus: QuixEventBus;\n  let module: TestingModule;\n  let mockBuilder: MockDataBuilder;\n\n  beforeAll(async () => {\n    driver = await QuixEventBusDriver.create(defaultUser);\n    ({eventBus, module, mockBuilder} = driver);\n  });\n\n  beforeEach(() => driver.clearDb());\n\n  afterAll(() => driver.clearDb());\n  afterAll(() => module.close());\n\n  const createNoteAction = (notebookId: string): IAction<IEventData, string> =>\n    mockBuilder.createNoteAction(notebookId);\n\n  describe('deleted-notebooks::', () => {\n    let notebookId: string;\n    let createDeletedNotebookAction: IAction<DeletedNotebookActions>;\n\n    beforeEach(() => {\n      [notebookId, createDeletedNotebookAction] =\n        mockBuilder.createDeletedNotebookAction();\n    });\n\n    it('create deleted-notebook', async () => {\n      await driver.emitAsUser(eventBus, [createDeletedNotebookAction]);\n      driver.getDeletedNotebook(notebookId).and.expectToBeDefined();\n    });\n\n    it('delete deleted-notebook', async () => {\n      await driver.emitAsUser(eventBus, [\n        createDeletedNotebookAction,\n        DeletedNotebookActions.deleteDeletedNotebook(notebookId),\n      ]);\n\n      await driver.getDeletedNotebook(notebookId).and.expectToBeUndefined();\n    });\n  });\n\n  describe('trash-bin::', () => {\n    describe('move notebook to Trash Bin', () => {\n      let notebookId: string;\n      let rootFolderId: string;\n      let createRootFolderAction: any;\n      let createNotebookAction: IAction<NotebookActions>;\n\n      let addToTrashBinAction: IAction<TrashBinActions>;\n\n      beforeEach(() => {\n        [rootFolderId, createRootFolderAction] = mockBuilder.createFolderAction(\n          `rootFolder`,\n          [],\n        );\n\n        [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([\n          {id: rootFolderId},\n        ]);\n\n        [notebookId, addToTrashBinAction] =\n          mockBuilder.moveNotebookToTrashBinAction(undefined, notebookId);\n      });\n\n      it('creates deleted notebook', async () => {\n        await driver.emitAsUser(eventBus, [\n          createRootFolderAction,\n          createNotebookAction,\n          addToTrashBinAction,\n        ]);\n        await driver.getDeletedNotebook(notebookId).and.expectToBeDefined();\n      });\n\n      it('deletes notebook', async () => {\n        await driver.emitAsUser(eventBus, [\n          createRootFolderAction,\n          createNotebookAction,\n          addToTrashBinAction,\n        ]);\n        await driver.getNotebook(notebookId).and.expectToBeUndefined();\n      });\n\n      it('keeps notes', async () => {\n        await driver.emitAsUser(eventBus, [\n          createRootFolderAction,\n          createNotebookAction,\n          createNoteAction(notebookId),\n          createNoteAction(notebookId),\n        ]);\n\n        let notes = await driver.getNotesForNotebook(notebookId);\n        expect(notes).toHaveLength(2);\n\n        await driver.emitAsUser(eventBus, [addToTrashBinAction]);\n        notes = await driver.getNotesForNotebook(notebookId);\n        expect(notes).toHaveLength(2);\n      });\n\n      it('deletes file tree nodes', async () => {\n        await driver.emitAsUser(eventBus, [\n          createRootFolderAction,\n          createNotebookAction,\n        ]);\n\n        expect(await driver.fileTreeRepo.find({notebookId})).toHaveLength(1);\n        await driver.emitAsUser(eventBus, [addToTrashBinAction]);\n\n        expect(await driver.fileTreeRepo.find({notebookId})).toHaveLength(0);\n      });\n    });\n\n    describe('move folder to Trash Bin', () => {\n      let rootFolderId: string;\n      let createFolderAction: any;\n\n      let notebooksIds: string[];\n      let createNotebooksActions: any[];\n\n      let subFolders: string[];\n      let createSubFolderActions: any[];\n\n      beforeEach(() => {\n        notebooksIds = [];\n        createNotebooksActions = [];\n        subFolders = [];\n        createSubFolderActions = [];\n\n        [rootFolderId, createFolderAction] = mockBuilder.createFolderAction(\n          `rootFolder`,\n          [],\n        );\n\n        for (let i = 0; i < 3; i++) {\n          [subFolders[i], createSubFolderActions[i]] =\n            mockBuilder.createFolderAction(`subFolder${i}`, [\n              {id: rootFolderId},\n            ]);\n\n          [notebooksIds[i], createNotebooksActions[i]] =\n            mockBuilder.createNotebookAction([{id: subFolders[i]}]);\n        }\n      });\n\n      it('moves all child notebooks to Trash Bin', async () => {\n        await driver.emitAsUser(eventBus, [\n          createFolderAction,\n          ...createSubFolderActions,\n          ...createNotebooksActions,\n          TrashBinActions.moveFolderToTrashBin(rootFolderId),\n        ]);\n\n        await notebooksIds.forEach(async notebookId => {\n          await driver.getNotebook(notebookId).and.expectToBeUndefined();\n        });\n      });\n\n      it('deletes all sub folders', async () => {\n        await driver.emitAsUser(eventBus, [\n          createFolderAction,\n          ...createSubFolderActions,\n          ...createNotebooksActions,\n          TrashBinActions.moveFolderToTrashBin(rootFolderId),\n        ]);\n\n        subFolders.forEach(async folderId => {\n          const folder = await driver.folderRepo.findOne({id: folderId});\n          expect(folder).toBeUndefined();\n        });\n      });\n\n      it('deletes tree', async () => {\n        await driver.emitAsUser(eventBus, [\n          createFolderAction,\n          ...createSubFolderActions,\n          ...createNotebooksActions,\n          TrashBinActions.moveFolderToTrashBin(rootFolderId),\n        ]);\n\n        [...subFolders, ...notebooksIds].forEach(async nodeId => {\n          const node = await driver.fileTreeRepo.findOne({id: nodeId});\n          expect(node).toBeUndefined();\n        });\n      });\n    });\n\n    it('restores notebook from Trash Bin', async () => {\n      let rootFolderId: string;\n      let createFolderAction: any;\n      let notebookId: string;\n      let createNotebookAction: any;\n\n      [rootFolderId, createFolderAction] = mockBuilder.createFolderAction(\n        'rootFolder',\n        [],\n      );\n\n      [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([\n        {id: rootFolderId},\n      ]);\n\n      let addToTrashBinAction: IAction<TrashBinActions>;\n      [notebookId, addToTrashBinAction] =\n        mockBuilder.moveNotebookToTrashBinAction(undefined, notebookId);\n\n      await driver.emitAsUser(eventBus, [\n        createFolderAction,\n        createNotebookAction,\n        addToTrashBinAction,\n      ]);\n\n      let restoreFromTrashBinAction: IAction<TrashBinActions>;\n      [notebookId, restoreFromTrashBinAction] =\n        mockBuilder.restoreNotebookFromTrashBinAction(\n          undefined,\n          rootFolderId,\n          notebookId,\n        );\n      await driver.emitAsUser(eventBus, [restoreFromTrashBinAction]);\n\n      await driver.getNotebook(notebookId).and.expectToBeDefined();\n      await driver.getDeletedNotebook(notebookId).and.expectToBeUndefined();\n\n      const tree = await driver.getUserFileTree(defaultUser);\n      const node = tree.find(n => n.notebookId === notebookId);\n\n      expect(node).toBeDefined();\n      expect(node?.parentId).toEqual(rootFolderId);\n    });\n\n    describe('permanently delete notebook', () => {\n      let notebookId: string;\n      let createNotebookAction: IAction<NotebookActions>;\n      let permanentlyDeleteTrashBinAction: IAction<TrashBinActions>;\n      let addToTrashBinAction: IAction<TrashBinActions>;\n\n      beforeEach(() => {\n        [notebookId, createNotebookAction] = mockBuilder.createNotebookAction();\n        [notebookId, addToTrashBinAction] =\n          mockBuilder.moveNotebookToTrashBinAction(undefined, notebookId);\n\n        [notebookId, permanentlyDeleteTrashBinAction] =\n          mockBuilder.permanentlyDeleteDeletedNotebookAction(\n            undefined,\n            notebookId,\n          );\n      });\n\n      it('deletes the Deleted Notebook', async () => {\n        await driver.emitAsUser(eventBus, [\n          createNotebookAction,\n          addToTrashBinAction,\n          permanentlyDeleteTrashBinAction,\n        ]);\n\n        await driver.getDeletedNotebook(notebookId).and.expectToBeUndefined();\n      });\n\n      it('deletes notes of the notebook', async () => {\n        await driver.emitAsUser(eventBus, []);\n\n        await eventBus.emit([\n          createNotebookAction,\n          createNoteAction(notebookId),\n          createNoteAction(notebookId),\n          addToTrashBinAction,\n          permanentlyDeleteTrashBinAction,\n        ]);\n\n        const notes = await driver.noteRepo.find({notebookId});\n        expect(notes).toHaveLength(0);\n      });\n    });\n  });\n\n  describe('notebooks::', () => {\n    let notebookId: string;\n    let createNotebookAction: IAction<NotebookActions>;\n\n    beforeEach(() => {\n      [notebookId, createNotebookAction] = mockBuilder.createNotebookAction();\n    });\n\n    it('create notebook', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction]);\n      const notebook = await driver\n        .getNotebook(notebookId)\n        .and.expectToBeDefined();\n\n      expect(notebook.id).toBe(createNotebookAction.id);\n    });\n\n    it('set owner correctly', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction]);\n      const notebook = await driver\n        .getNotebook(notebookId)\n        .and.expectToBeDefined();\n\n      expect(notebook.owner).toBe(defaultUser);\n    });\n\n    it('update name', async () => {\n      const note = createNote(notebookId);\n      const addNoteAction = NoteActions.addNote(note.id, note);\n\n      await driver.emitAsUser(eventBus, [\n        createNotebookAction,\n        addNoteAction,\n        NotebookActions.updateName(notebookId, 'newName'),\n      ]);\n\n      const notebook = await driver\n        .getNotebook(notebookId)\n        .and.expectToBeDefined();\n\n      expect(notebook.name).toBe('newName');\n    });\n\n    it('toggle isLiked', async () => {\n      await driver.emitAsUser(eventBus, [\n        createNotebookAction,\n        NotebookActions.toggleIsLiked(notebookId, true),\n      ]);\n\n      await driver\n        .getFavorite(defaultUser, notebookId, EntityType.Notebook)\n        .and.expectToBeDefined();\n\n      await driver.emitAsUser(eventBus, [\n        NotebookActions.toggleIsLiked(notebookId, false),\n      ]);\n\n      await driver\n        .getFavorite(defaultUser, notebookId, EntityType.Notebook)\n        .and.expectToBeUndefined();\n    });\n\n    describe('delete', () => {\n      it('deletes notebook and keep notes', async () => {\n        await driver.emitAsUser(eventBus, [\n          createNotebookAction,\n          createNoteAction(notebookId),\n          createNoteAction(notebookId),\n          NotebookActions.deleteNotebook(notebookId),\n        ]);\n\n        await driver.getNotebook(notebookId).and.expectToBeUndefined();\n\n        const notes = await driver.getNotesForNotebook(notebookId);\n        expect(notes).toHaveLength(2);\n      });\n\n      it('delete notes', async () => {\n        await driver.emitAsUser(eventBus, [\n          createNotebookAction,\n          createNoteAction(notebookId),\n          createNoteAction(notebookId),\n          NotebookActions.deleteNotebookNotes(notebookId),\n        ]);\n\n        await driver.getNotebook(notebookId).and.expectToBeDefined();\n\n        const notes = await driver.getNotesForNotebook(notebookId);\n        expect(notes).toHaveLength(0);\n      });\n\n      it('delete favorite after deleting the notebook', async () => {\n        await driver.emitAsUser(eventBus, [\n          createNotebookAction,\n          NotebookActions.toggleIsLiked(notebookId, true),\n        ]);\n\n        await driver\n          .getFavorite(defaultUser, notebookId, EntityType.Notebook)\n          .and.expectToBeDefined();\n\n        await driver.emitAsUser(eventBus, [\n          NotebookActions.deleteNotebook(notebookId),\n        ]);\n\n        await driver\n          .getFavorite(defaultUser, notebookId, EntityType.Notebook)\n          .and.expectToBeUndefined();\n      });\n\n      it('delete only the favorite of the deleted notebook', async () => {\n        const [id1, createAction1] = mockBuilder.createNotebookAction();\n        const [id2, createAction2] = mockBuilder.createNotebookAction();\n\n        await eventBus.emit([createAction1, createAction2]);\n\n        await driver.emitAsUser(eventBus, [\n          NotebookActions.toggleIsLiked(id1, true),\n          NotebookActions.toggleIsLiked(id2, true),\n        ]);\n\n        await driver.emitAsUser(eventBus, [\n          NotebookActions.deleteNotebook(id1),\n        ]);\n\n        await driver\n          .getFavorite(defaultUser, id1, EntityType.Notebook)\n          .and.expectToBeUndefined();\n\n        await driver\n          .getFavorite(defaultUser, id2, EntityType.Notebook)\n          .and.expectToBeDefined();\n      });\n    });\n  });\n\n  describe('notes::', () => {\n    let notebookId: string;\n    let createNotebookAction: NotebookActions;\n    let addNoteAction: NoteActionT<'note.create'>;\n    let note: INote;\n\n    beforeEach(() => {\n      [notebookId, createNotebookAction] = mockBuilder.createNotebookAction();\n      note = createNote(notebookId);\n      addNoteAction = NoteActions.addNote(note.id, note);\n    });\n\n    it('create note', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction]);\n      await driver.emitAsUser(eventBus, [addNoteAction]);\n\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n\n      expect(notebook.notes).toHaveLength(1);\n    });\n\n    it('create note, with content', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction]);\n      addNoteAction = NoteActions.addNote(\n        note.id,\n        createNote(notebookId, {content: 'bla bla bla'}),\n      );\n      await driver.emitAsUser(eventBus, [addNoteAction]);\n\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n\n      expect(notebook.notes).toHaveLength(1);\n      expect(notebook.notes![0].textContent).toBe('bla bla bla');\n    });\n\n    it('create note with bulk actions', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]);\n\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n\n      expect(notebook.notes).toHaveLength(1);\n      const {id, name, notebookId: parent, type} = note;\n      expect(notebook.notes![0]).toMatchObject(\n        expect.objectContaining({\n          id,\n          name,\n          notebookId: parent,\n          owner: defaultUser,\n          type,\n        }),\n      );\n    });\n\n    it('update name', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]);\n\n      await driver.emitAsUser(eventBus, [\n        NoteActions.updateName(note.id, 'changedName'),\n      ]);\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n\n      expect(notebook.notes![0].name).toBe('changedName');\n    });\n\n    it('delete note', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]);\n\n      await driver.emitAsUser(eventBus, [NoteActions.deleteNote(note.id)]);\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n\n      expect(notebook.notes).toHaveLength(0);\n    });\n\n    it('update content', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]);\n\n      await driver.emitAsUser(eventBus, [\n        NoteActions.updateContent(note.id, 'select foo from bar'),\n      ]);\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n\n      expect(notebook.notes![0].textContent).toBe('select foo from bar');\n    });\n\n    describe('note update', () => {\n      beforeEach(async () => {\n        await driver.emitAsUser(eventBus, [\n          createNotebookAction,\n          addNoteAction,\n        ]);\n      });\n\n      it.each([\n        ['content', () => NoteActions.updateContent(note.id, 'content')],\n        [\n          'richContent',\n          () => NoteActions.updateContent(note.id, '\\n', {rich: 'content'}),\n        ],\n        ['name', () => NoteActions.updateName(note.id, 'name')],\n      ])(\n        'should not update %s when there are no changes',\n        async (_text, createAction) => {\n          const action = createAction();\n\n          await driver.emitAsUser(eventBus, [action]);\n          const firstNote = await driver.getNote(note.id);\n\n          await new Promise(resolve => setTimeout(resolve, 1000));\n\n          await driver.emitAsUser(eventBus, [action]);\n          const secondNote = await driver.getNote(note.id);\n\n          expect(firstNote?.dateUpdated).toBe(secondNote?.dateUpdated);\n        },\n      );\n\n      it.each([\n        [\n          'content',\n          () => NoteActions.updateContent(note.id, 'content'),\n          () => NoteActions.updateContent(note.id, 'different'),\n        ],\n        [\n          'richContent',\n          () => NoteActions.updateContent(note.id, '\\n', {rich: 'content'}),\n          () => NoteActions.updateContent(note.id, '\\n', {content: 'rich'}),\n        ],\n        [\n          'name',\n          () => NoteActions.updateContent(note.id, 'name'),\n          () => NoteActions.updateContent(note.id, 'different'),\n        ],\n      ])(\n        'should update %s when there are changes',\n        async (_text, createFirstAction, createSecondAction) => {\n          await driver.emitAsUser(eventBus, [createFirstAction()]);\n\n          const firstNote = await driver.getNote(note.id);\n\n          await new Promise(resolve => setTimeout(resolve, 1000));\n\n          await driver.emitAsUser(eventBus, [createSecondAction()]);\n\n          const secondNote = await driver.getNote(note.id);\n\n          expect(secondNote?.dateUpdated).toBeGreaterThan(\n            firstNote!.dateUpdated,\n          );\n        },\n      );\n    });\n\n    it('move note between notebook', async () => {\n      await driver.emitAsUser(eventBus, [createNotebookAction, addNoteAction]);\n      const [secondNotebookId, createNotebookAction2] =\n        mockBuilder.createNotebookAction();\n\n      await driver.emitAsUser(eventBus, [createNotebookAction2]);\n\n      await driver.emitAsUser(eventBus, [\n        NoteActions.move(note.id, secondNotebookId),\n      ]);\n\n      const notebook = await driver.getNotebookWithNotes(notebookId);\n      expect(notebook.notes).toHaveLength(0);\n\n      const secondNotebook = await driver.getNotebookWithNotes(\n        secondNotebookId,\n      );\n      expect(secondNotebook.notes).toHaveLength(1);\n    });\n\n    describe('note rank/order', () => {\n      let notes: INote[];\n      let createNoteActions: NoteActionT<'note.create'>[];\n      const howManyNotes = 6;\n\n      beforeEach(async () => {\n        const [notebookId2, createNotebookAction2] =\n          mockBuilder.createNotebookAction();\n\n        const notes2 = range(2).map(() => createNote(notebookId2));\n\n        notes = range(howManyNotes).map(() => createNote(notebookId));\n        createNoteActions = notes.map(n => NoteActions.addNote(n.id, n));\n        const createNoteActions2 = notes2.map(n =>\n          NoteActions.addNote(n.id, n),\n        );\n\n        /* creating notes in another notebook, just to make sure reorder is local inside a notebook */\n        await driver.emitAsUser(eventBus, [createNotebookAction2]);\n        await driver.emitAsUser(eventBus, createNoteActions2);\n\n        await driver.emitAsUser(eventBus, [createNotebookAction]);\n        await driver.emitAsUser(eventBus, createNoteActions);\n      });\n\n      it('should create new notes with correct order', async () => {\n        const notebook = await driver.getNotebookWithNotes(notebookId);\n        const doesRankMatchInsertOrder = notes.every(\n          (note, index) =>\n            notebook.notes!.find(n => n.id === note.id)!.rank === index,\n        );\n\n        expect(doesRankMatchInsertOrder).toBeTruthy();\n      });\n\n      const deleteCases = [\n        [0, 'start'],\n        [howManyNotes - 1, 'end'],\n        [3, 'middle'],\n      ] as const;\n\n      deleteCases.forEach(([noteIndexToDelete, testName]) => {\n        it(`on delete should set order of remaining notes correctly, when removing from ${testName}`, async () => {\n          const noteIdToDelete = notes[noteIndexToDelete].id;\n          const deleteAction = NoteActions.deleteNote(noteIdToDelete);\n          await driver.emitAsUser(eventBus, [deleteAction]);\n\n          const filteredNotes = reject(notes, {id: noteIdToDelete});\n\n          const notebook = await driver.getNotebookWithNotes(notebookId);\n          const doesRankMatchInsertOrder = filteredNotes.every(\n            (note, index) =>\n              notebook.notes!.find(n => n.id === note.id)!.rank === index,\n          );\n\n          expect(doesRankMatchInsertOrder).toBeTruthy();\n        });\n      });\n\n      const reorderCases = [\n        [4, 2, '\"from\" greater than \"to\"'],\n        [1, 5, '\"to\" greater than \"from\"'],\n      ] as const;\n\n      reorderCases.forEach(([from, to, testName]) => {\n        it(`reorder notes correctly, when ${testName}`, async () => {\n          const noteIdMove = notes[from].id;\n          const reorderAction = NoteActions.reorderNote(noteIdMove, to);\n          await driver.emitAsUser(eventBus, [reorderAction]);\n\n          const reorderedNotes = reorderPos(notes, from, to);\n          const notebook = await driver.getNotebookWithNotes(notebookId);\n\n          const doesRankMatchInsertOrder = reorderedNotes.every(\n            (note, index) =>\n              notebook.notes!.find(n => n.id === note.id)!.rank === index,\n          );\n\n          expect(doesRankMatchInsertOrder).toBeTruthy();\n        });\n      });\n    });\n  });\n\n  describe('folder tree::', () => {\n    let rootFolderId: string;\n    let createRootFolderAction: any;\n    let notebookId: string;\n    let createNotebookAction: any;\n\n    beforeEach(() => {\n      [rootFolderId, createRootFolderAction] = mockBuilder.createFolderAction(\n        'rootFolder',\n        [],\n      );\n\n      [notebookId, createNotebookAction] = mockBuilder.createNotebookAction([\n        {id: rootFolderId},\n      ]);\n    });\n\n    it('a single folder', async () => {\n      await driver.emitAsUser(eventBus, [createRootFolderAction]);\n\n      const list = await driver.getUserFileTree(defaultUser);\n      expect(list[0].folder!.name).toBe('rootFolder');\n    });\n\n    it('rename folder', async () => {\n      await driver.emitAsUser(eventBus, [createRootFolderAction]);\n      await driver.emitAsUser(eventBus, [\n        FileActions.updateName(rootFolderId, 'a changedName'),\n      ]);\n\n      const list = await driver.getUserFileTree(defaultUser);\n      expect(list[0].folder!.name).toBe('a changedName');\n    });\n\n    it('a notebook inside a single folder', async () => {\n      await driver.emitAsUser(eventBus, [\n        createRootFolderAction,\n        createNotebookAction,\n      ]);\n\n      const list = await driver.getUserFileTree(defaultUser);\n      const notebookTreeItem = list.find(\n        item => item.id === notebookId && item.parentId === rootFolderId,\n      );\n      expect(notebookTreeItem).toBeDefined();\n    });\n\n    it('have multiple notebooks inside a single folder', async () => {\n      const [notebookId2, createNotebookAction2] =\n        mockBuilder.createNotebookAction([{id: rootFolderId}]);\n      await driver.emitAsUser(eventBus, [\n        createRootFolderAction,\n        createNotebookAction,\n        createNotebookAction2,\n      ]);\n\n      const list = await driver.getUserFileTree(defaultUser);\n      const notebookItems = list.filter(\n        item => item.type === FileType.notebook,\n      );\n      expect(notebookItems).toHaveLength(2);\n    });\n\n    it('notebook move', async () => {\n      const [subFolder1, createSubFolder1] = mockBuilder.createFolderAction(\n        'subFolder1',\n        [{id: rootFolderId}],\n      );\n\n      await driver.emitAsUser(eventBus, [\n        createRootFolderAction,\n        createSubFolder1,\n        createNotebookAction,\n      ]);\n\n      await driver.emitAsUser(eventBus, [\n        NotebookActions.moveNotebook(notebookId, [{id: subFolder1, name: ''}]),\n      ]);\n\n      const list = await driver.getUserFileTree(defaultUser);\n      const notebook = list.find(item => item.id === notebookId);\n      expect(notebook!.mpath).toBe(\n        `${rootFolderId}.${subFolder1}.${notebookId}`,\n      );\n    });\n\n    it('folder tree move', async () => {\n      const [subFolder1, createSubFolder1] = mockBuilder.createFolderAction(\n        'subFolder1',\n        [{id: rootFolderId}],\n      );\n\n      const [subFolder2, createSubFolder2] = mockBuilder.createFolderAction(\n        'subFolder2',\n        [{id: subFolder1}],\n      );\n\n      const [subFolder3, createSubFolder3] = mockBuilder.createFolderAction(\n        'subFolder3',\n        [{id: rootFolderId}],\n      );\n\n      const [notebookId, createNotebookAction] =\n        mockBuilder.createNotebookAction([{id: subFolder2}]);\n\n      await driver.emitAsUser(eventBus, [\n        createRootFolderAction,\n        createSubFolder1,\n        createSubFolder2,\n        createSubFolder3,\n        createNotebookAction,\n      ]);\n\n      /**\n       * structure:\n       * rootFolder ->\n       *           folder1 ->\n       *             folder2->\n       *               notebook\n       *           folder3\n       */\n\n      await driver.emitAsUser(eventBus, [\n        FileActions.moveFile(subFolder1, [{id: subFolder3, name: ''}]),\n      ]);\n\n      /**\n       * structure:\n       * rootFolder ->\n       *           folder3 ->\n       *             folder1 ->\n       *               folder2->\n       *                 notebook\n       */\n\n      const list = await driver.getUserFileTree(defaultUser);\n      expect(find(list, {id: subFolder1})).toMatchObject({\n        parentId: subFolder3,\n      });\n      expect(find(list, {id: notebookId})).toMatchObject({\n        mpath: [\n          rootFolderId,\n          subFolder3,\n          subFolder1,\n          subFolder2,\n          notebookId,\n        ].join('.'),\n      });\n      expect(find(list, {id: subFolder2})).toMatchObject({\n        mpath: [rootFolderId, subFolder3, subFolder1, subFolder2].join('.'),\n      });\n    });\n\n    it('delete an empty folder', async () => {\n      const [subFolder1, createSubFolder1] = mockBuilder.createFolderAction(\n        'subFolder1',\n        [{id: rootFolderId}],\n      );\n\n      await driver.emitAsUser(eventBus, [\n        createRootFolderAction,\n        createSubFolder1,\n      ]);\n      const beforeList = await driver.getUserFileTree(defaultUser);\n      expect(beforeList).toHaveLength(2);\n\n      await driver.emitAsUser(eventBus, [FileActions.deleteFile(subFolder1)]);\n\n      const afterList = await driver.getUserFileTree(defaultUser);\n      expect(afterList).toMatchObject([\n        expect.objectContaining({id: rootFolderId}),\n      ]);\n    });\n\n    it('delete notebook favorite after deleting the parent folder', async () => {\n      const [subFolderId, createSubFolder] = mockBuilder.createFolderAction(\n        'subFolder',\n        [{id: rootFolderId}],\n      );\n\n      const [notebookId, createNotebookAction] =\n        mockBuilder.createNotebookAction([{id: subFolderId}]);\n\n      await driver.emitAsUser(eventBus, [\n        createRootFolderAction,\n        createSubFolder,\n        createNotebookAction,\n      ]);\n\n      await driver.emitAsUser(eventBus, [\n        NotebookActions.toggleIsLiked(notebookId, true),\n      ]);\n\n      await driver.emitAsUser(eventBus, [FileActions.deleteFile(subFolderId)]);\n\n      await driver\n        .getFavorite(defaultUser, notebookId, EntityType.Notebook)\n        .and.expectToBeUndefined();\n    });\n  });\n\n  describe('user list::', () => {\n    it('should add user with dateCreated in the past', async () => {\n      const createAction = UserActions.createNewUser('foo', {\n        avatar: '',\n        dateCreated: 1000,\n        dateUpdated: 1000,\n        email: 'foo',\n        id: 'foo',\n        name: '',\n        rootFolder: '',\n      });\n      await driver.emitAsUser(eventBus, [createAction], 'foo');\n      const users = await driver.getUsers();\n      expect(users[0]).toMatchObject({dateCreated: 1000, dateUpdated: 1000});\n    });\n  });\n\n  describe('error handling::', () => {\n    it('should throw an error on invalid action', async () => {\n      const error = await driver\n        .emitAsUser(eventBus, [{type: 'foo'}])\n        .catch(e => e);\n      await new Promise(resolve => setTimeout(resolve, 1000));\n      expect(error instanceof Error).toBe(true);\n    });\n  });\n});\n\nfunction reorderPos<T>(items: T[], from: number, to: number) {\n  const clone = items.slice();\n  const [item] = clone.splice(from, 1);\n  clone.splice(to, 0, item);\n\n  return clone;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/quix-event-bus.ts",
    "content": "import {\n  EventBus,\n  EventBusBuilder,\n  EventBusPlugin,\n} from './infrastructure/event-bus';\n\nimport {Injectable, Inject, Logger} from '@nestjs/common';\nimport {QuixHookNames} from './types';\nimport {IActionStore, DbActionStore} from './infrastructure/action-store';\nimport {NotebookPlugin} from './plugins/notebook-plugin';\nimport {NotePlugin} from './plugins/note-plugin';\nimport {FileTreePlugin} from './plugins/file-tree-plugin';\nimport {FavoritesPlugin} from './plugins/favorites-plugin';\nimport {IAction, IEventData} from './infrastructure/types';\nimport {UserPlugin} from './plugins/user-plugin';\nimport {EventsPlugin} from './plugins/events-plugin';\nimport {DeletedNotebookPlugin} from './plugins/deleted-notebook-plugin';\nimport {TrashBinPlugin} from './plugins/trash-bin-plugin';\nimport {EventsService} from './events.service';\n\n@Injectable()\nexport class QuixEventBus<A extends IAction = IAction> {\n  private bus: EventBus;\n  private logger = new Logger(QuixEventBus.name);\n\n  constructor(\n    @Inject(DbActionStore) private actionStore: IActionStore,\n    @Inject(NotebookPlugin) private notebookPlugin: EventBusPlugin,\n    @Inject(NotePlugin) private notePlugin: EventBusPlugin,\n    @Inject(FileTreePlugin) private fileTreePlugin: EventBusPlugin,\n    @Inject(FavoritesPlugin) private favoritesPlugin: EventBusPlugin,\n    @Inject(UserPlugin) private userPlugin: EventBusPlugin,\n    @Inject(DeletedNotebookPlugin)\n    private deletedNotebookPlugin: EventBusPlugin,\n    @Inject(TrashBinPlugin) private trashBinPlugin: EventBusPlugin,\n    @Inject(EventsPlugin) private eventsPlugin: EventBusPlugin,\n    @Inject(EventsService) private eventsService: EventsService,\n  ) {\n    this.bus = EventBusBuilder()\n      .addPlugin(this.notebookPlugin)\n      .addPlugin(this.deletedNotebookPlugin)\n      .addPlugin(this.trashBinPlugin)\n      .addPlugin(this.notePlugin)\n      .addPlugin(this.fileTreePlugin)\n      .addPlugin(this.favoritesPlugin)\n      .addPlugin(this.userPlugin)\n      .addPlugin(this.eventsPlugin)\n      .addMiddleware(async (action, api, next) => {\n        api.hooks\n          .call(QuixHookNames.VALIDATION, action)\n          .then(() => next())\n          .catch(e => next(e));\n      })\n      .addMiddleware(async (action, api, next) => {\n        if (action.ethereal) {\n          next();\n        } else {\n          this.actionStore\n            .pushAction(action)\n            .then(() => next())\n            .catch(e => next(e));\n        }\n      })\n      .addMiddleware(async (action, api, next) => {\n        api.hooks\n          .call(QuixHookNames.PROJECTION, action)\n          .then(() => next())\n          .catch(e => next(e));\n      })\n      .addMiddleware(async (action, api, next) => {\n        api.hooks\n          .call(QuixHookNames.REACTION, action)\n          .then(async props => {\n            let [reactions] = props;\n\n            if (reactions && Array.isArray(reactions) && reactions.length > 0) {\n              reactions = reactions.map(r => ({...r, syncClients: false}));\n              await this.emit(reactions);\n\n              api.pushLoggedActions(reactions);\n            }\n\n            next();\n          })\n          .catch(e => next(e));\n      })\n      .build();\n  }\n\n  async emit(action: A | A[]) {\n    this.logger.log(`got action ${JSON.stringify(action)}`);\n    if (Array.isArray(action)) {\n      const result = [];\n      for (const a of action) {\n        result.push(...(await this.bus.emit(a)));\n      }\n      this.logger.log(`got ReActions ${JSON.stringify(result)}`);\n      return result;\n    }\n    return this.bus.emit(action);\n  }\n\n  on<T extends string>(type: T, handler: (action: A & {type: T}) => any) {\n    this.bus.on(type, handler);\n    return this;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/event-sourcing/types.ts",
    "content": "export enum QuixHookNames {\n  VALIDATION = 'validation',\n  PROJECTION = 'projection',\n  REACTION = 'reaction',\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/logger/logger.module.ts",
    "content": "import {Module} from '@nestjs/common';\nimport {Logger} from './logger.service';\n\n@Module({\n  providers: [Logger],\n  exports: [Logger],\n})\nexport class LoggerModule {}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/logger/logger.service.ts",
    "content": "import {Logger as BaseLogger} from '@nestjs/common';\n\nexport class Logger extends BaseLogger {}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/proxy-backend/proxy-backend.module.ts",
    "content": "import {MiddlewareConsumer, Module, NestModule} from '@nestjs/common';\nimport httpProxy from 'http-proxy-middleware';\nimport {ConfigService} from '../../config';\n\n@Module({\n  imports: [],\n  controllers: [],\n  providers: [],\n})\nexport class ProxyDbApiBackend implements NestModule {\n  constructor(private configService: ConfigService) {}\n\n  configure(consumer: MiddlewareConsumer) {\n    let backendUrl = this.configService.getEnvSettings().QuixBackendInternalUrl;\n\n    if (['http://', 'https://'].every(s => !backendUrl.startsWith(s))) {\n      backendUrl = 'http://' + backendUrl;\n    }\n\n    consumer\n      .apply(\n        httpProxy({\n          target: backendUrl,\n          changeOrigin: true,\n        }),\n      )\n      .forRoutes('/api/db');\n    consumer\n      .apply(\n        httpProxy({\n          target: backendUrl,\n          changeOrigin: true,\n          pathRewrite: {\n            '^/api/history': '/api/history/executions',\n          },\n        }),\n      )\n      .forRoutes('/api/history');\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/index.ts",
    "content": "export {ISearch} from './types';\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/parser.spec.ts",
    "content": "import {parse} from './parser';\nimport {SearchQuery, SearchTextType} from '@wix/quix-shared';\n\ndescribe('search query parser', () => {\n  describe('basic', () => {\n    it('handle basic text search', () => {\n      const input = 'select 1 from foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle weird characters', () => {\n      const input = 'select $START_TIME from foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '$START_TIME'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle expression wrapped in quotes', () => {\n      const input = '\"select bar from\" foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.PHRASE, text: 'select bar from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle multiple spaces', () => {\n      const input = 'select\\t1    from\\nfoo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n  });\n\n  describe('with special operators', () => {\n    it('handle user operator', () => {\n      const input = 'user:foo@wix.com select 1 from foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n        owner: 'foo@wix.com',\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle user operator without any string', () => {\n      const input = 'user:foo@wix.com';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [],\n        owner: 'foo@wix.com',\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('do not handle user operator in the middle of a sentence', () => {\n      const input = 'select bar user:foo@wix.com from foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: 'bar'},\n          {type: SearchTextType.WORD, text: 'user:foo wix.com'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('do not handle user operator in the middle of a sentence', () => {\n      const input = 'select bar from foo user:foo@wix.com';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: 'bar'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n        owner: 'foo@wix.com',\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle name operator', () => {\n      const input = 'name:anewnotebook select 1 from foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n        name: 'anewnotebook',\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle name operator with spaces', () => {\n      const input = 'name:\"a new notebook\" select 1 from foo';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n        name: 'a new notebook',\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n\n    it('handle type operator', () => {\n      const input = 'type:python select 1 from foo';\n      const input2 = 'select 1 from foo type:python';\n      const expected1: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n        type: 'python',\n      };\n      const expected2: SearchQuery = {...expected1, fullText: input2};\n      expect(parse(input)).toEqual(expected1);\n      expect(parse(input2)).toEqual(expected2);\n    });\n\n    it('multiple operators', () => {\n      const input =\n        'type:python name:\"a new notebook\" select 1 from foo user:foo@wix.com';\n      const expected: SearchQuery = {\n        fullText: input,\n        content: [\n          {type: SearchTextType.WORD, text: 'select'},\n          {type: SearchTextType.WORD, text: '1'},\n          {type: SearchTextType.WORD, text: 'from'},\n          {type: SearchTextType.WORD, text: 'foo'},\n        ],\n        type: 'python',\n        name: 'a new notebook',\n        owner: 'foo@wix.com',\n      };\n      expect(parse(input)).toEqual(expected);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/parser.ts",
    "content": "import {\n  SearchQuery,\n  SearchTypes,\n  SearchTextType,\n  SpecialSearchTypes,\n} from '@wix/quix-shared';\n\nconst createRegExAtBeginningOrEnd = (regex: string | RegExp): RegExp[] => {\n  const source = regex instanceof RegExp ? regex.source : regex;\n  return [new RegExp('^' + source + ' '), new RegExp(source + '$')];\n};\n\nconst searchRegexMap = {\n  [SearchTypes.user]: createRegExAtBeginningOrEnd(/user:([(\\w@\\.-_)]*)/),\n  [SearchTypes.type]: createRegExAtBeginningOrEnd(/type:(\\w*)/),\n  [SearchTypes.noteName]: [\n    ...createRegExAtBeginningOrEnd(/name:([\\w-_\\.]*)/),\n    ...createRegExAtBeginningOrEnd(/name:\"([\\w-_\\. ]*)\"/),\n  ],\n  [SearchTypes.content]: [/(?:([^\\s\"]+)|\"(.+)\")/g],\n};\n\nexport const parse = (s: string): SearchQuery => {\n  s = s.trim();\n  const [partialQuery, updatedString] = getSpecialOperators(s);\n  const query: SearchQuery = {\n    ...partialQuery,\n    fullText: s,\n    [SearchTypes.content]: getTextFromSearchQuery(updatedString),\n  };\n\n  return query;\n};\n\nconst getSpecialOperators = (\n  s: string,\n  operators: SpecialSearchTypes[] = [\n    SearchTypes.noteName,\n    SearchTypes.type,\n    SearchTypes.user,\n  ],\n): [Partial<SearchQuery>, string] => {\n  const query: Partial<SearchQuery> = {};\n\n  operators.some(operator =>\n    searchRegexMap[operator].some(regex => {\n      const match = regex.exec(s);\n\n      if (match && match[1]) {\n        const f = match[1];\n        query[operator] = match[1];\n        s = s.replace(match[0], '');\n        /* do another iteration, to handle other operators */\n        const [partialQuery, updatedString] = getSpecialOperators(\n          s,\n          operators.filter(name => name !== operator),\n        );\n        s = updatedString;\n        Object.assign(query, partialQuery);\n        return true;\n      }\n      return false;\n    }),\n  );\n\n  return [query, s];\n};\n\nconst fullTextSearchSpecialChars = /[+\\-><\\(\\)~*\\/\"@]+/g;\nconst getTextFromSearchQuery = (s: string) => {\n  const result = [];\n  let match = null;\n\n  /* tslint:disable-next-line */\n  while ((match = searchRegexMap[SearchTypes.content][0].exec(s))) {\n    result.push(\n      match[1]\n        ? {\n            type: SearchTextType.WORD,\n            text: match[1].replace(fullTextSearchSpecialChars, ' ').trim(),\n          }\n        : {\n            type: SearchTextType.PHRASE,\n            text: match[2].replace(fullTextSearchSpecialChars, ' ').trim(),\n          },\n    );\n  }\n  return result;\n};\n\nexport const isValidQuery = (query: SearchQuery) =>\n  query[SearchTypes.content].length > 0 ||\n  query[SearchTypes.noteName] ||\n  query[SearchTypes.type] ||\n  query[SearchTypes.user];\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/search.module.ts",
    "content": "import {Module} from '@nestjs/common';\nimport {TypeOrmModule} from '@nestjs/typeorm';\nimport {DbFileTreeNode, DbFolder, DbNote, DbNotebook} from '../../entities';\nimport {ConfigModule} from '../../config/config.module';\nimport {SearchService} from './search';\n@Module({\n  imports: [\n    TypeOrmModule.forFeature([DbFileTreeNode, DbFolder, DbNote, DbNotebook]),\n  ],\n  providers: [SearchService],\n  controllers: [],\n  exports: [SearchService],\n})\nexport class SearchModule {}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/search.spec.ts",
    "content": "import {Test, TestingModule} from '@nestjs/testing';\nimport {getRepositoryToken, TypeOrmModule} from '@nestjs/typeorm';\nimport 'reflect-metadata';\nimport {Repository} from 'typeorm';\nimport uuid from 'uuid/v4';\nimport {ConfigService, ConfigModule} from '../../config';\nimport {DbFileTreeNode, DbFolder, DbNote, DbNotebook} from '../../entities';\nimport {SearchModule} from './search.module';\nimport {SearchService} from './search';\nimport {Chance} from 'chance';\nimport {range} from 'lodash';\nimport {INote} from '@wix/quix-shared';\n\nconst chance = new Chance();\n\ndescribe('Search', () => {\n  jest.setTimeout(60000);\n  let module: TestingModule;\n  let searchService: SearchService;\n  let noteRepo: Repository<DbNote>;\n  let notebookRepo: Repository<DbNotebook>;\n  const defaultUser = 'foo@wix.com';\n  const secondUser = 'bar@wix.com';\n\n  beforeAll(async () => {\n    module = await Test.createTestingModule({\n      imports: [\n        ConfigModule.create(),\n        TypeOrmModule.forRootAsync({\n          imports: [],\n          useFactory: async (configService: ConfigService) =>\n            configService.getDbConnection([\n              DbFileTreeNode,\n              DbFolder,\n              DbNote,\n              DbNotebook,\n            ]),\n          inject: [ConfigService],\n        }),\n        SearchModule,\n      ],\n      providers: [],\n      exports: [],\n    }).compile();\n\n    searchService = module.get(SearchService);\n    noteRepo = module.get(getRepositoryToken(DbNote));\n    notebookRepo = module.get(getRepositoryToken(DbNotebook));\n  });\n\n  beforeEach(async () => {\n    await noteRepo.delete({});\n    await notebookRepo.delete({});\n  });\n\n  const createNotebook = async (user = defaultUser) => {\n    const notebook = new DbNotebook({\n      id: uuid(),\n      owner: user,\n      name: 'new name',\n    } as any);\n    return notebookRepo.save(notebook);\n  };\n\n  const createNote = async (\n    notebookId: string,\n    template: Partial<DbNote> = {},\n  ) => {\n    const base = Object.assign(\n      {\n        id: uuid(),\n        name: 'New Note',\n        owner: defaultUser,\n        textContent: '',\n        type: 'presto',\n      },\n      template,\n    );\n    const note = new DbNote({\n      id: base.id,\n      owner: base.owner,\n      type: base.type,\n      textContent: base.textContent,\n      name: base.name,\n      dateCreated: 1,\n      dateUpdated: 1,\n      notebookId,\n      jsonContent: undefined,\n      richContent: {},\n    });\n    note.rank = 0;\n    return noteRepo.save(note);\n  };\n\n  const createRandomNotes = async (baseString = '', count = 5) => {\n    const {id: notebookId} = await createNotebook();\n    const notes = [];\n    // Due to usage of old TypeORM version, we can't use bulk insert. It can be changed since 0.2.45\n    for (let i = 0; i < count; i++) {\n      const note = await createNote(notebookId, {\n        textContent: baseString + chance.paragraph(),\n      });\n      notes.push(note);\n    }\n\n    return notes;\n  };\n\n  it('should return empty array for empty content', async () => {\n    const [result] = await searchService.search('');\n    expect(result).toHaveLength(0);\n  });\n\n  it('should get note by owner', async () => {\n    const notebook = await createNotebook();\n    const note = await createNote(notebook.id);\n\n    const [result] = await searchService.search(`user:${defaultUser}`);\n    const [badResult] = await searchService.search('user: foo@wix.com');\n\n    expect(result[0].id).toBe(note.id);\n    expect(badResult).toHaveLength(0);\n  });\n\n  it('should get note by content', async () => {\n    const notebook = await createNotebook();\n    const note = await createNote(notebook.id, {\n      textContent: 'select someColumn from someCatalog.someTable',\n    });\n    const note2 = await createNote(notebook.id, {\n      textContent: 'select someColumn from someCatalog.someOtherTable',\n    });\n\n    const [result] = await searchService.search(`someTable`);\n    const [result2] = await searchService.search(`someOtherTable`);\n    const [badResult] = await searchService.search('randomKeyword');\n\n    expect(result[0].id).toBe(note.id);\n    expect(result2[0].id).toBe(note2.id);\n    expect(badResult).toHaveLength(0);\n  });\n\n  it('should actually return a proper note', async () => {\n    const notebook = await createNotebook();\n    const note = await createNote(notebook.id, {\n      textContent: 'select someColumn from someCatalog.someTable',\n    });\n\n    const [result] = await searchService.search(`someTable`);\n\n    expect(result).toHaveLength(1);\n    expect(result[0]).toMatchObject({\n      content: note.textContent,\n      id: note.id,\n    } as Partial<INote>);\n  });\n\n  it('should get note by content, partial keywords', async () => {\n    const notebook = await createNotebook();\n    const note = await createNote(notebook.id, {\n      textContent: 'select someColumn from someCatalog.someTable',\n    });\n    const note2 = await createNote(notebook.id, {\n      textContent: 'select someColumn from someCatalog.someOtherTable',\n    });\n\n    const [notes, length] = await searchService.search(`someCa`);\n    const badResult = await searchService.search('randomKeyword');\n    const [badNotes, badLength] = badResult;\n\n    expect(length).toBe(2);\n    expect(badLength).toBe(0);\n  });\n\n  it('should get note by type', async () => {\n    const notebook = await createNotebook();\n    const note = await createNote(notebook.id, {\n      type: 'python' as any,\n    });\n    const note2 = await createNote(notebook.id, {\n      type: 'presto',\n    });\n\n    const [result] = await searchService.search('type:presto');\n\n    expect(result).toMatchObject([expect.objectContaining({id: note2.id})]);\n  });\n\n  it('should get note by user and type', async () => {\n    const notebook = await createNotebook(defaultUser);\n    const notebook2 = await createNotebook(secondUser);\n    const note = await createNote(notebook.id, {\n      owner: defaultUser,\n    });\n    const note2 = await createNote(notebook2.id, {\n      owner: secondUser,\n      type: 'presto',\n    });\n    const note3 = await createNote(notebook2.id, {\n      owner: secondUser,\n      type: 'python' as any,\n    });\n    const [result] = await searchService.search(\n      `user:${secondUser} type:python`,\n    );\n\n    expect(result).toMatchObject([expect.objectContaining({id: note3.id})]);\n  });\n\n  it('full phrase search', async () => {\n    const notebook = await createNotebook();\n    const note = await createNote(notebook.id, {\n      textContent: 'select col1, col2, col3 from foo where col1 = 1',\n    });\n    const note2 = await createNote(notebook.id, {\n      textContent: 'select col1, col2, col3 from foo where col2 = 1',\n    });\n\n    const [result] = await searchService.search(`col1 = 1`);\n    const [fullResult] = await searchService.search(`\"col1 = 1\"`);\n\n    expect(result).toHaveLength(2);\n    expect(fullResult).toMatchObject([expect.objectContaining({id: note.id})]);\n  });\n\n  describe('pagination', () => {\n    it('should return correct number of results', async () => {\n      await createRandomNotes('searchStringFoo', 20);\n      await createRandomNotes('searchStringBar', 10);\n\n      const [_, count] = await searchService.search('searchStringFoo', 5, 0);\n      expect(count).toBe(20);\n      const [__, count2] = await searchService.search('searchStringBar', 5, 0);\n      expect(count2).toBe(10);\n    });\n\n    it('should handle request outside of range', async () => {\n      await createRandomNotes('searchStringFoo', 20);\n      await createRandomNotes('searchStringBar', 10);\n\n      const [notes, count] = await searchService.search(\n        'searchStringFoo',\n        5,\n        20,\n      );\n      expect(notes).toHaveLength(0);\n    });\n\n    it('should return pages correctly', async () => {\n      let notes = await createRandomNotes('searchStringFoo', 20);\n      await createRandomNotes('searchStringBar', 10);\n\n      let offset = 0;\n      const count = 5;\n      let pagesFetched = 0;\n      while (notes.length) {\n        const [returnedNotes, totalCount] = await searchService.search(\n          'searchStringFoo',\n          count,\n          offset,\n        );\n        pagesFetched++;\n        expect(totalCount).toBe(20);\n        expect(returnedNotes).toHaveLength(count);\n\n        offset += count;\n\n        notes = notes.filter(\n          note => !returnedNotes.find(n => n.id === note.id),\n        );\n      }\n      expect(pagesFetched).toBe(4);\n    });\n  });\n\n  afterAll(() => {\n    module.close();\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/search.ts",
    "content": "import {dbConf} from '../../config/db-conf';\nimport {Repository} from 'typeorm';\nimport {DbNote} from '../../entities';\nimport {isValidQuery, parse} from './parser';\nimport {ISearch} from './types';\nimport {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {convertDbNote} from '../../entities/note/dbnote.entity';\nimport {INote, SearchQuery} from '@wix/quix-shared';\n\n@Injectable()\nexport class SearchService implements ISearch {\n  constructor(@InjectRepository(DbNote) private repo: Repository<DbNote>) {}\n\n  async search(\n    content: string,\n    total = 50,\n    offset = 0,\n  ): Promise<[INote[], number, SearchQuery]> {\n    if (!content) {\n      return [[], 0, {fullText: content, content: []}];\n    }\n\n    const searchQuery = parse(content);\n\n    if (isValidQuery(searchQuery)) {\n      let q = this.repo.createQueryBuilder('note');\n      const where: string[] = [];\n      const whereArgs: any = {};\n\n      if (searchQuery.owner) {\n        where.push('note.owner = :owner');\n        whereArgs.owner = searchQuery.owner;\n      }\n\n      if (searchQuery.type) {\n        where.push('note.type = :type');\n        whereArgs.type = searchQuery.type;\n      }\n\n      if (searchQuery.name) {\n        where.push('note.name = :name');\n        whereArgs.name = searchQuery.name;\n      }\n\n      if (searchQuery.content.length) {\n        where.push(\n          dbConf.fullTextSearch('note.textContent', searchQuery.content),\n        );\n      }\n\n      const whereSql = where.join(' AND ');\n\n      q = q.take(total).skip(offset).where(whereSql, whereArgs);\n\n      const [notes, count] = await q.getManyAndCount();\n      return [notes.map(convertDbNote), count, searchQuery];\n    }\n\n    return [[], 0, {fullText: content, content: []}];\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/search/types.ts",
    "content": "import {INote, SearchQuery} from '@wix/quix-shared';\n\nexport interface ISearch {\n  search(content: string): Promise<[INote[], number, SearchQuery]>;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/autocomplete/autocomplete.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Param,\n  UseGuards,\n} from '@nestjs/common';\n\nimport {AuthGuard} from '../../auth';\nimport {AutocompleteService} from './autocomplete.service';\n\n@Controller('/api/autocomplete')\nexport class AutocompleteController {\n  constructor(private autocompleteService: AutocompleteService) {}\n\n  @Get(':type')\n  @UseGuards(AuthGuard)\n  getAutocompletions(@Param('type') type: string) {\n    return this.autocompleteService.getAutocompletions(type);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/autocomplete/autocomplete.service.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport axios from 'axios';\nimport { isArray } from 'lodash';\nimport { ConfigService } from '../../../config';\n\nexport interface TableAutocompleteItem {\n  value: string;\n  meta: 'table';\n}\n\n@Injectable()\nexport class AutocompleteService {\n  constructor(private configService: ConfigService) {}\n\n  async getAutocompletions(type: string) {\n    let backendUrl = this.configService.getEnvSettings().QuixBackendInternalUrl;\n\n    if (['http://', 'https://'].every(s => !backendUrl.startsWith(s))) {\n      backendUrl = 'http://' + backendUrl;\n    }\n\n    const dbTree = await axios.get(`${backendUrl}/api/db/${type}/explore`);\n\n    return this.flattenTables(dbTree.data);\n  }\n\n  flattenTables(\n    treeNodes: any[],\n    path: string[] = [],\n    tables: TableAutocompleteItem[] = [],\n  ) {\n    if (!isArray(treeNodes)) {\n      return tables;\n    }\n\n    return treeNodes.reduce<TableAutocompleteItem[]>((res, {name, type, children}: any) => {\n      if (type === 'table') {\n        res.push({value: [...path, name].join('.'), meta: type});\n      } else {\n        this.flattenTables(children, [...path, name], res);\n      }\n\n      return res;\n    }, tables);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/deleted-notebooks/deleted-notebook.controller.ts",
    "content": "import { Controller, Get, UseGuards, UseInterceptors } from '@nestjs/common';\nimport { IUser } from '@wix/quix-shared';\nimport { User } from '../../../modules/auth';\nimport { AuthGuard } from '../../auth';\nimport { DemoModeInterceptor } from '../../../common/demo-mode-interceptor';\nimport { DeletedNotebooksService } from './deleted-notebook.service';\n\n@Controller('/api/deletedNotebooks')\n@UseInterceptors(DemoModeInterceptor)\nexport class DeletedNotebooksController {\n  constructor(private deletedNotebooksService: DeletedNotebooksService) { }\n\n  @Get()\n  @UseGuards(AuthGuard)\n  async getUserDeletedNotebooks(@User() user: IUser) {\n    return this.deletedNotebooksService.getDeletedNotebooksForUser(user.email);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/deleted-notebooks/deleted-notebook.service.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {Repository} from 'typeorm';\nimport {IDeletedNotebook} from '@wix/quix-shared';\nimport {DbUser, DbDeletedNotebook} from '../../../entities';\nimport {convertDbDeletedNotebook} from '../../../entities/deleted-notebook/dbdeleted-notebook.entity';\n\n@Injectable()\nexport class DeletedNotebooksService {\n  constructor(\n    @InjectRepository(DbDeletedNotebook)\n    private deletedNotebooksRepo: Repository<DbDeletedNotebook>,\n  ) {}\n\n  async getDeletedNotebooksForUser(user: string): Promise<IDeletedNotebook[]> {\n    const query = this.deletedNotebooksRepo\n      .createQueryBuilder('dn')\n      .leftJoinAndMapOne(\n        'dn.ownerDetails',\n        DbUser,\n        'user',\n        'dn.owner = user.id',\n      )\n      .where('dn.owner = :user', {user})\n      .orderBy({'dn.name': 'ASC'});\n\n    const res = await query.getMany();\n    return res.map(dn => convertDbDeletedNotebook(dn));\n  }\n\n  async getCountDeletedNotebooksForUser(user: string): Promise<number> {\n    return await this.deletedNotebooksRepo.count({owner: user});\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/events.controller.ts",
    "content": "import {\n  Body,\n  Controller,\n  HttpCode,\n  Logger,\n  Post,\n  Query,\n  UseGuards,\n  UsePipes,\n} from '@nestjs/common';\nimport {AuthGuard} from '../auth';\nimport {AnyAction} from '@wix/quix-shared/entities/common/common-types';\nimport {IExternalUser, User} from '../../modules/auth';\nimport {EventsService} from '../../modules/event-sourcing/events.service';\nimport {\n  IAction,\n  IEventData,\n} from '../../modules/event-sourcing/infrastructure/types';\nimport {BaseActionValidation} from '../event-sourcing/base-action-validation';\nimport {QuixEventBus} from '../event-sourcing/quix-event-bus';\n\n@Controller('/api/events')\nexport class EventsController {\n  private readonly logger = new Logger(EventsController.name);\n\n  constructor(\n    private eventBus: QuixEventBus,\n    private eventsService: EventsService,\n  ) {}\n\n  @Post()\n  @UseGuards(AuthGuard)\n  @UsePipes(BaseActionValidation)\n  @HttpCode(200)\n  async pushEvents(\n    @Body() userAction: AnyAction | AnyAction[],\n    @User() user: IExternalUser,\n    @Query('sessionId') sessionId: string,\n  ) {\n    function withUserInfo(action: AnyAction): IAction<IEventData, string> {\n      return {\n        ...action,\n        user: user.email,\n        userId: user.id,\n        sessionId,\n      };\n    }\n\n    let result: IAction<IEventData, string> | IAction<IEventData, string>[] =\n      [];\n\n    try {\n      result = Array.isArray(userAction)\n        ? await this.eventBus.emit(userAction.map(withUserInfo))\n        : await this.eventBus.emit(withUserInfo(userAction));\n    } catch (e: any) {\n      this.logger.error('error emitting event', e);\n      throw e;\n    }\n\n    return {\n      reactions: Array.isArray(result) ? result : [],\n    };\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/events.gateway.ts",
    "content": "import {\n  OnGatewayConnection,\n  OnGatewayDisconnect,\n  SubscribeMessage,\n  WebSocketGateway,\n  WebSocketServer,\n  WsResponse,\n} from '@nestjs/websockets';\nimport {Observable, EMPTY, from} from 'rxjs';\nimport {map} from 'rxjs/operators';\nimport WebSocket, {Server} from 'ws';\nimport {EventsService} from '../../modules/event-sourcing/events.service';\nimport {IAction} from '../../modules/event-sourcing/infrastructure/types';\nimport {AnyAction} from '@wix/quix-shared/entities/common/common-types';\nimport {cloneDeep} from 'lodash';\nimport {LoginService} from '../auth/login.service';\nimport {IncomingMessage} from 'http';\nimport {parse} from 'cookie';\nimport {Inject} from '@nestjs/common';\nimport {AuthOptions, AuthTypes, IExternalUser} from '../auth/types';\nimport {cons} from 'fp-ts/lib/ReadonlyNonEmptyArray';\ninterface ExtendedWebSocket extends WebSocket {\n  userId?: string;\n  sessionId?: string;\n}\n@WebSocketGateway({path: '/subscription'})\nexport class EventsGateway implements OnGatewayDisconnect, OnGatewayConnection {\n  @WebSocketServer()\n  server!: Server;\n\n  constructor(\n    private eventsService: EventsService,\n    private loginService: LoginService,\n    @Inject(AuthOptions) private authOptions: AuthOptions,\n  ) {}\n\n  handleConnection(client: ExtendedWebSocket, msg: IncomingMessage) {\n    let user: IExternalUser | undefined;\n    if (this.authOptions.type === AuthTypes.CUSTOM) {\n      const token = this.authOptions.auth.getTokenFromRequest(msg);\n      user = this.loginService.verify(token);\n    } else {\n      const cookies = parse(msg.headers.cookie || '');\n      const token = cookies[this.authOptions.cookieName];\n      user = this.loginService.verify(token);\n    }\n    if (user) {\n      /* mutating ws client feels weird, but apparently that's the way to go */\n      /* https://github.com/websockets/ws/issues/859 */\n      client.userId = user.id;\n    }\n  }\n\n  handleDisconnect(client: ExtendedWebSocket) {\n    const {userId, sessionId} = client;\n    if (userId && sessionId) {\n      this.eventsService.closeEventStream(sessionId, userId);\n    }\n  }\n\n  @SubscribeMessage('subscribe')\n  onSubscribe(\n    client: ExtendedWebSocket,\n    data: any,\n  ): Observable<WsResponse<any>> | undefined {\n    const {sessionId} = data;\n\n    try {\n      const userId = client.userId;\n      if (!userId) {\n        client.terminate();\n        return;\n      }\n\n      client.sessionId = sessionId;\n\n      return this.eventsService.getEventStream(sessionId, userId).pipe(\n        map((action: IAction) => ({\n          event: 'action',\n          data: this.sanitizeAction(action),\n        })),\n      );\n    } catch (e) {\n      client.close();\n      return;\n    }\n  }\n\n  sanitizeAction(action: IAction): AnyAction {\n    const result = cloneDeep(action);\n    delete (result as any).user;\n    delete result.userId;\n    delete result.sessionId;\n    return result;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/favorites/favorites.controller.ts",
    "content": "import {Controller, Get, UseGuards, UseInterceptors} from '@nestjs/common';\nimport {IUser} from '@wix/quix-shared';\nimport {User} from '../../../modules/auth';\nimport {FavoritesService} from './favorites.service';\nimport {AuthGuard} from '../../auth';\nimport {DemoModeInterceptor} from '../../../common/demo-mode-interceptor';\n\n@Controller('/api/favorites')\n@UseInterceptors(DemoModeInterceptor)\nexport class FavoritesController {\n  constructor(private favoritesListService: FavoritesService) {}\n\n  @Get()\n  @UseGuards(AuthGuard)\n  async getUserFavorites(@User() user: IUser) {\n    return this.favoritesListService.getFavoritesForUser(user.email);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/favorites/favorites.service.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {Repository} from 'typeorm';\nimport {IFile, FileType} from '@wix/quix-shared';\nimport {DbNotebook, DbFavorites, DbUser} from '../../../entities';\nimport {extractOwnerDetails} from '../../../entities/utils';\n\ntype GetFavoritesQueryReturnValue = DbFavorites & {\n  notebook: DbNotebook;\n  notebookOwnerDetails?: DbUser;\n};\n\nfunction favoriteToIFile(fav: GetFavoritesQueryReturnValue): IFile {\n  const {notebook, notebookOwnerDetails} = fav;\n  notebook.ownerDetails = notebookOwnerDetails;\n  const {id, owner, dateCreated, dateUpdated, name} = notebook;\n  const ownerDetails = extractOwnerDetails(notebook);\n\n  return {\n    isLiked: true,\n    ownerDetails,\n    owner,\n    id,\n    dateCreated,\n    dateUpdated,\n    path: [],\n    name,\n    type: FileType.notebook,\n  };\n}\n\n@Injectable()\nexport class FavoritesService {\n  constructor(\n    @InjectRepository(DbFavorites)\n    private favoritesRepo: Repository<DbFavorites>,\n  ) {}\n\n  async getFavoritesForUser(user: string): Promise<IFile[]> {\n    const favoritesQuery = this.favoritesRepo\n      .createQueryBuilder('fav')\n      .innerJoinAndMapOne(\n        'fav.notebook',\n        DbNotebook,\n        'notebook',\n        'fav.entityId = notebook.id',\n      )\n      .leftJoinAndMapOne(\n        'fav.notebookOwnerDetails',\n        DbUser,\n        'user',\n        'notebook.owner = user.id',\n      )\n      .where('fav.owner = :user', {user})\n      .orderBy({'notebook.name': 'ASC'});\n\n    const res = (await favoritesQuery.getMany()) as GetFavoritesQueryReturnValue[];\n\n    return res.map(favoriteToIFile);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/folders/folders.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Param,\n  HttpException,\n  HttpStatus,\n  UseGuards,\n  UseInterceptors,\n} from '@nestjs/common';\nimport {FoldersService} from './folders.service';\nimport {QuixEventBus} from '../../event-sourcing/quix-event-bus';\nimport {IExternalUser, User} from '../../../modules/auth';\nimport {AuthGuard} from '../../auth';\nimport {DemoModeInterceptor} from '../../../common/demo-mode-interceptor';\n\n@Controller('/api')\n@UseGuards(AuthGuard)\n@UseInterceptors(DemoModeInterceptor)\nexport class FoldersController {\n  constructor(\n    private foldersService: FoldersService,\n    private quixEventBus: QuixEventBus,\n  ) {}\n\n  @Get('files')\n  async getFullTree(@User() user: IExternalUser) {\n    const {email} = user;\n    const list = await this.foldersService.getFilesForUser(email);\n\n    return list;\n  }\n\n  @Get('files/:id')\n  async getSpecificFolder(@Param('id') id: string) {\n    const folder = this.foldersService.getFolder(id);\n    if (!folder) {\n      throw new HttpException(`Can't find folder`, HttpStatus.NOT_FOUND);\n    }\n    return folder;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/folders/folders.service.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectEntityManager} from '@nestjs/typeorm';\nimport {DbFileTreeNode, FileTreeRepository, DbUser} from '../../../entities';\nimport {fromNullable, getOrElse, map} from 'fp-ts/lib/Option';\nimport {pipe} from 'fp-ts/lib/pipeable';\nimport {IFile, IFilePathItem} from '@wix/quix-shared/entities/file';\nimport {IFolder} from '@wix/quix-shared/entities/folder';\nimport {EntityManager} from 'typeorm';\nimport {\n  convertListDbNodeToIFileList,\n  convertSingleNodeToIFile,\n  extractPath,\n} from './utils';\n\n@Injectable()\nexport class FoldersService {\n  private fileTreeRepo: FileTreeRepository;\n  constructor(\n    @InjectEntityManager()\n    private entityManager: EntityManager,\n  ) {\n    this.fileTreeRepo = this.entityManager.getCustomRepository(\n      FileTreeRepository,\n    );\n  }\n\n  /**\n   * @returns {Promise<IFile[]>} list of all user folders, in the format client expects.\n   */\n  async getFilesForUser(user: string): Promise<IFile[]> {\n    const query = await this.fileTreeRepo\n      .createQueryBuilder('fileNode')\n      .leftJoinAndSelect('fileNode.notebook', 'notebook')\n      .leftJoinAndSelect('fileNode.folder', 'folder')\n      .leftJoinAndMapOne(\n        'fileNode.ownerDetails',\n        DbUser,\n        'user',\n        'fileNode.owner = user.id',\n      )\n      .where({owner: user});\n\n    const list = await query.getMany();\n\n    return convertListDbNodeToIFileList(list);\n  }\n\n  async getFolder(rootId: string): Promise<IFolder | undefined> {\n    const getFileNodeQuery = this.fileTreeRepo\n      .createQueryBuilder('fileNode')\n      .leftJoinAndSelect('fileNode.notebook', 'notebook')\n      .leftJoinAndSelect('fileNode.folder', 'folder')\n      .leftJoinAndMapOne(\n        'fileNode.ownerDetails',\n        DbUser,\n        'user',\n        'fileNode.owner = user.id',\n      )\n      .where('fileNode.id = :rootId', {rootId});\n\n    const [node, children] = await Promise.all([\n      /* TODO: do this in one query */\n      getFileNodeQuery.getOne(),\n      this.fileTreeRepo.getChildren(rootId),\n    ] as const); /* remove as const when https://github.com/microsoft/TypeScript/issues/34937 is resolved */\n\n    if (node) {\n      const path = await this.computePath(node);\n      const nodeAsFile = convertSingleNodeToIFile(node, path);\n\n      const files = convertListDbNodeToIFileList(children, [nodeAsFile]);\n      return {...nodeAsFile, files};\n    }\n\n    return undefined;\n  }\n\n  computePath(fileNode?: DbFileTreeNode): Promise<IFilePathItem[]> {\n    return pipe(\n      fromNullable(fileNode),\n      map(node => node.mpath.split('.').slice(0, -1)),\n      map(async parentsIds => {\n        if (parentsIds.length > 0) {\n          const parents = await this.fileTreeRepo.getNamesByIds(parentsIds);\n          return extractPath(parentsIds, parents);\n        }\n        return [];\n      }),\n      getOrElse(() => Promise.resolve([] as IFilePathItem[])),\n    );\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/folders/utils.ts",
    "content": "import {FileType, IFile, IFilePathItem} from '@wix/quix-shared/entities/file';\nimport {DbFileTreeNode} from '../../../entities';\nimport {extractOwnerDetails} from '../../../entities/utils';\n\n/**\n * @param list The list dbNodes you want to convert to a IFile\n * @param initialData if you have a parent node already converted to an IFile, this is where you pass it\n */\nexport function convertListDbNodeToIFileList(\n  list: DbFileTreeNode[],\n  initialData: IFile[] = [],\n): IFile[] {\n  const itemMap = new Map(list.map(child => [child.id, child]));\n  const resultMap = new Map(initialData.map(file => [file.id, file]));\n  return list.map(item => convertToIFile(item.id, itemMap, resultMap));\n}\n\n/**\n * given a mapping of DbFileTreeNode items, and a resultCache - return an IFile\n */\nfunction convertToIFile(\n  id: string,\n  noteMap: Map<string, DbFileTreeNode>,\n  resultMap: Map<string, IFile>,\n) {\n  const alreadyConverted = resultMap.get(id);\n  if (alreadyConverted) {\n    return alreadyConverted;\n  }\n\n  const node = noteMap.get(id)!;\n  const {dateCreated, dateUpdated, type, owner} = node;\n\n  let path: IFilePathItem[];\n  if (!node.parentId) {\n    path = [];\n  } else {\n    const parentFile = convertToIFile(node.parentId, noteMap, resultMap);\n    path = parentFile.path.concat([{id: parentFile.id, name: parentFile.name}]);\n  }\n\n  const name =\n    node.type === FileType.folder ? node.folder!.name : node.notebook!.name;\n\n  const result: IFile = {\n    id: node.type === FileType.folder ? id : node.notebookId!,\n    dateCreated,\n    dateUpdated,\n    type,\n    name,\n    owner,\n    ownerDetails: extractOwnerDetails(node),\n    isLiked: false,\n    path,\n  };\n\n  resultMap.set(id, result);\n  return result;\n}\n\nexport function extractPath(\n  parentsIds: string[],\n  parents: DbFileTreeNode[],\n): IFilePathItem[] {\n  try {\n    return parentsIds.map(id => {\n      const item = parents.find(p => p.id === id)!;\n      const name = computeName(item);\n      return {name, id};\n    });\n  } catch (e) {\n    throw new Error('Error in calculation path for notebook');\n  }\n}\n\nexport function dbNodeToFileItem(node: DbFileTreeNode): IFilePathItem {\n  const name = computeName(node);\n  return {id: node.id, name};\n}\n\nexport function computeName(node: DbFileTreeNode): string {\n  const name =\n    node.type === FileType.folder\n      ? node.folder && node.folder.name\n      : node.notebook && node.notebook.name;\n  return name || '';\n}\n\nexport function convertSingleNodeToIFile(\n  node: DbFileTreeNode,\n  path: IFilePathItem[],\n) {\n  const {id, dateCreated, dateUpdated, owner, type} = node;\n  const name = computeName(node);\n\n  const nodeAsFile: IFile = {\n    id,\n    name,\n    path,\n    dateCreated,\n    dateUpdated,\n    owner,\n    ownerDetails: extractOwnerDetails(node),\n    type,\n    isLiked: false,\n  };\n  return nodeAsFile;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/notebooks/notebooks.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Param,\n  HttpException,\n  HttpStatus,\n  UseGuards,\n  UseInterceptors,\n} from '@nestjs/common';\nimport {IUser} from '@wix/quix-shared';\nimport {User} from '../../../modules/auth';\nimport {NotebookService} from './notebooks.service';\nimport {AuthGuard} from '../../auth';\nimport {DemoModeInterceptor} from '../../../common/demo-mode-interceptor';\n\n@Controller('/api/notebook')\n@UseInterceptors(DemoModeInterceptor)\nexport class NotebookController {\n  constructor(private notebookService: NotebookService) {}\n\n  @Get(':id')\n  @UseGuards(AuthGuard)\n  async getNotebook(@User() user: IUser, @Param('id') id: string) {\n    const notebook = await this.notebookService.getNotebook(user.email, id);\n\n    if (!notebook) {\n      throw new HttpException(`Can't find notebook`, HttpStatus.NOT_FOUND);\n    }\n\n    return notebook;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/notebooks/notebooks.service.ts",
    "content": "import {Injectable} from '@nestjs/common';\nimport {InjectRepository} from '@nestjs/typeorm';\nimport {Repository} from 'typeorm';\nimport {INotebook} from '@wix/quix-shared';\nimport {DbNotebook, DbFavorites, DbUser} from '../../../entities';\nimport {FoldersService} from '../folders/folders.service';\nimport {EntityType} from '../../../common/entity-type.enum';\nimport {convertDbNotebook} from '../../../entities/notebook/dbnotebook.entity';\n\n@Injectable()\nexport class NotebookService {\n  constructor(\n    @InjectRepository(DbNotebook) private notebookRepo: Repository<DbNotebook>,\n    @InjectRepository(DbFavorites)\n    private favoritesRepo: Repository<DbFavorites>,\n    private folderService: FoldersService,\n  ) {}\n\n  async getNotebook(\n    user: string,\n    notebookId: string,\n  ): Promise<INotebook | undefined> {\n    const notebookQuery = this.notebookRepo\n      .createQueryBuilder('notebook')\n      .leftJoinAndSelect('notebook.fileNode', 'fileNode')\n      .leftJoinAndSelect('notebook.notes', 'note')\n      .leftJoinAndMapOne(\n        'notebook.ownerDetails',\n        DbUser,\n        'user',\n        'notebook.owner = user.id',\n      )\n      .where('notebook.id = :id', {id: notebookId})\n      .orderBy({'note.rank': 'ASC'});\n\n    const [notebook, favorite] = await Promise.all([\n      notebookQuery.getOne(),\n      this.favoritesRepo.findOne({\n        owner: user,\n        entityId: notebookId,\n      }),\n    ]);\n\n    if (!notebook) {\n      return undefined;\n    }\n\n    const isLiked = !!favorite;\n    const path = await this.folderService.computePath(notebook.fileNode);\n\n    return convertDbNotebook(notebook, path, isLiked);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/search.controller.ts",
    "content": "import {\n  Controller,\n  Get,\n  Param,\n  Query,\n  UseGuards,\n  ParseIntPipe,\n  UseInterceptors,\n} from '@nestjs/common';\nimport {SearchResult} from '@wix/quix-shared';\nimport {AuthGuard} from '../auth';\nimport {SearchService} from '../../modules/search/search';\nimport {DemoModeInterceptor} from '../../common/demo-mode-interceptor';\n\n@Controller('/api/search')\n@UseInterceptors(DemoModeInterceptor)\n@UseGuards(AuthGuard)\nexport class SearchController {\n  constructor(private searchService: SearchService) {}\n\n  @Get('/:term')\n  async doSearch(\n    @Param('term') query: string,\n    @Query('offset', new ParseIntPipe()) offset: number,\n    @Query('total', new ParseIntPipe()) count: number,\n  ): Promise<SearchResult> {\n    const [notes, totalNotesInSearch, term] = await this.searchService.search(\n      query,\n      count,\n      offset,\n    );\n    return {notes, count: totalNotesInSearch, term};\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/user-list.controller.ts",
    "content": "import {Controller, Get, Param, UseGuards} from '@nestjs/common';\nimport {AuthGuard} from '../auth';\nimport {UsersService, User, IExternalUser} from '../../modules/auth';\nimport {ConfigService, EnvSettings} from '../../config';\nimport {sanitizeUserName, sanitizeUserEmail} from '../../common/user-sanitizer';\n\n@Controller('/api/users')\n@UseGuards(AuthGuard)\nexport class UserListController {\n  private env: EnvSettings;\n  constructor(\n    private usersService: UsersService,\n    configService: ConfigService,\n  ) {\n    this.env = configService.getEnvSettings();\n  }\n\n  @Get()\n  async getUsers(@User() user: IExternalUser) {\n    if (this.env.DemoMode) {\n      return (await this.usersService.getListOfUsers()).map(u => {\n        return u.id === user.email\n          ? u\n          : {\n              name: sanitizeUserName(u.name),\n              id: sanitizeUserEmail(u.id),\n              email: sanitizeUserEmail(u.email),\n              avatar: 'http://quix.wix.com/assets/user.svg',\n              rootFolder: u.rootFolder,\n              dateCreated: u.dateCreated,\n              dateUpdated: u.dateUpdated,\n            };\n      });\n    } else {\n      return this.usersService.getListOfUsers();\n    }\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/web-api.driver.ts",
    "content": "import {Test, TestingModule} from '@nestjs/testing';\nimport {\n  getConnectionToken,\n  getRepositoryToken,\n  TypeOrmModule,\n} from '@nestjs/typeorm';\nimport {FileType} from '@wix/quix-shared';\nimport {EntityType} from 'src/common/entity-type.enum';\nimport {ConfigModule, ConfigService} from '../../config/';\nimport {\n  DbAction,\n  DbDeletedNotebook,\n  DbFavorites,\n  DbFileTreeNode,\n  DbFolder,\n  DbNote,\n  DbNotebook,\n  DbUser,\n  FileTreeRepository,\n  NoteRepository,\n} from '../../entities';\nimport {MockDataBuilder} from '../../../test/builder';\nimport {Connection, Repository} from 'typeorm';\nimport uuid from 'uuid';\nimport {AuthModuleConfiguration} from '../auth/auth.module';\nimport {AuthTypes} from '../auth/types';\nimport {DeletedNotebooksService} from './deleted-notebooks/deleted-notebook.service';\nimport {FavoritesService} from './favorites/favorites.service';\nimport {FoldersService} from './folders/folders.service';\nimport {NotebookService} from './notebooks/notebooks.service';\nimport {WebApiModule} from './web-api.module';\nimport {EntityClassOrSchema} from '@nestjs/typeorm/dist/interfaces/entity-class-or-schema.type';\n\nconst defaultEntityDate = new Date('1980-05-21T01:02:03').valueOf();\nexport class WebApiDriver {\n  mockBuilder: MockDataBuilder;\n\n  constructor(\n    public userRepo: Repository<DbUser>,\n    public module: TestingModule,\n    public eventsRepo: Repository<DbAction>,\n    public fileTreeRepo: FileTreeRepository,\n\n    public notebookRepo: Repository<DbNotebook>,\n    public notebookService: NotebookService,\n    public noteRepo: NoteRepository,\n\n    public deletedNotebookRepo: Repository<DbDeletedNotebook>,\n    public deletedNotebookService: DeletedNotebooksService,\n\n    public folderRepo: Repository<DbFolder>,\n    public folderService: FoldersService,\n\n    public favoritesRepo: Repository<DbFavorites>,\n    public favoritesService: FavoritesService,\n\n    private configService: ConfigService,\n    private conn: Connection,\n    private defaultUserId: string,\n  ) {\n    this.mockBuilder = new MockDataBuilder(defaultUserId);\n  }\n\n  static async create(defaultUser: string) {\n    const module = await Test.createTestingModule({\n      imports: [\n        AuthModuleConfiguration.create({\n          type: AuthTypes.FAKE,\n          cookieName: 'foo',\n        }), // consider restructuring web-api module so it won't import auth. feels wrong needing to importing authModule here\n        WebApiModule,\n        ConfigModule.create(),\n        TypeOrmModule.forRootAsync({\n          imports: [],\n          useFactory: async (cs: ConfigService) =>\n            cs.getDbConnection([\n              DbFileTreeNode,\n              DbFolder,\n              DbNote,\n              DbNotebook,\n              DbDeletedNotebook,\n              DbAction,\n              DbUser,\n              DbFavorites,\n            ]),\n          inject: [ConfigService],\n        }),\n      ],\n      providers: [],\n      exports: [],\n    }).compile();\n\n    const getRepository = (entity: EntityClassOrSchema) =>\n      module.get(getRepositoryToken(entity));\n\n    const notebookRepo = getRepository(DbNotebook);\n    const notebookService = module.get(NotebookService);\n\n    const deletedNotebookRepo = getRepository(DbDeletedNotebook);\n\n    const deletedNotebookService = module.get(DeletedNotebooksService);\n\n    const favoritesService = module.get(FavoritesService);\n    const favoritesRepo = getRepository(DbFavorites);\n\n    const noteRepo = getRepository(NoteRepository);\n\n    const folderRepo = getRepository(DbFolder);\n    const folderService = module.get(FoldersService);\n\n    const eventsRepo = getRepository(DbAction);\n    const fileTreeRepo = getRepository(FileTreeRepository);\n\n    const userRepo = getRepository(DbUser);\n    const conn = module.get(getConnectionToken());\n    const configService = module.get(ConfigService);\n\n    return new WebApiDriver(\n      userRepo,\n      module,\n      eventsRepo,\n      fileTreeRepo,\n      notebookRepo,\n      notebookService,\n      noteRepo,\n      deletedNotebookRepo,\n      deletedNotebookService,\n      folderRepo,\n      folderService,\n      favoritesRepo,\n      favoritesService,\n      configService,\n      conn,\n      defaultUser,\n    );\n  }\n\n  async clearDb() {\n    const dbType = this.configService.getDbType();\n    await this.eventsRepo.delete({});\n    await this.noteRepo.delete({});\n    await this.folderRepo.delete({});\n    await this.notebookRepo.delete({});\n    await this.deletedNotebookRepo.delete({});\n    await this.fileTreeRepo.clear();\n    await this.favoritesRepo.clear();\n    await this.userRepo.clear();\n  }\n\n  createUser(props?: Partial<DbUser> | undefined): DbUser {\n    const defaultUser = {\n      id: this.defaultUserId,\n      name: 'some name',\n      avatar: 'http://test-url.quix',\n      rootFolder: 'someId',\n      dateCreated: defaultEntityDate,\n      dateUpdated: defaultEntityDate,\n    };\n    return props ? {...defaultUser, ...props} : defaultUser;\n  }\n\n  createNotebook(notebookName = 'New notebook') {\n    const notebook = new DbNotebook();\n\n    notebook.id = uuid();\n    notebook.owner = this.defaultUserId;\n    notebook.name = notebookName;\n\n    return notebook;\n  }\n\n  createDeletedNotebook(notebookName = 'Deleted notebook') {\n    const deletedNotebook = new DbDeletedNotebook();\n\n    deletedNotebook.id = uuid();\n    deletedNotebook.owner = this.defaultUserId;\n    deletedNotebook.name = notebookName;\n    deletedNotebook.dateDeleted = defaultEntityDate;\n\n    return deletedNotebook;\n  }\n\n  createNotebookNode(notebookName: string) {\n    const notebook = this.createNotebook(notebookName);\n    const notebookNode = new DbFileTreeNode();\n    notebookNode.id = uuid();\n    notebookNode.owner = this.defaultUserId;\n    notebookNode.notebookId = notebook.id;\n    notebookNode.type = FileType.notebook;\n    return [notebookNode, notebook] as const;\n  }\n\n  createNote(noteName: string, notebookId: string) {\n    const note = new DbNote({\n      id: uuid(),\n      owner: this.defaultUserId,\n      name: noteName,\n      textContent: '',\n      jsonContent: undefined,\n      type: 'presto',\n      notebookId,\n      dateCreated: 1,\n      dateUpdated: 1,\n      richContent: {},\n    });\n    return note;\n  }\n\n  createFolderNode(folderName: string) {\n    const folderNode = new DbFileTreeNode();\n    folderNode.id = uuid();\n    folderNode.owner = this.defaultUserId;\n    folderNode.folder = Object.assign(new DbFolder(), {\n      id: folderNode.id,\n      name: folderName,\n      owner: this.defaultUserId,\n    });\n    return folderNode;\n  }\n\n  createFavorite(owner: string, entityId: string, entityType: EntityType) {\n    return Object.assign(new DbFavorites(), {\n      entityId,\n      entityType,\n      owner,\n    });\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/web-api.module.ts",
    "content": "import {Module} from '@nestjs/common';\nimport {TypeOrmModule} from '@nestjs/typeorm';\nimport {\n  DbFileTreeNode,\n  DbFolder,\n  DbNote,\n  DbNotebook,\n  FileTreeRepository,\n  NoteRepository,\n  DbDeletedNotebook,\n  DbUser,\n  DbFavorites,\n} from '../../entities';\nimport {DbAction} from '../event-sourcing/infrastructure/action-store/entities/db-action.entity';\nimport {FoldersController} from './folders/folders.controller';\nimport {FoldersService} from './folders/folders.service';\nimport {NotebookController} from './notebooks/notebooks.controller';\nimport {NotebookService} from './notebooks/notebooks.service';\nimport {AuthModule} from '../auth/auth.module';\nimport {EventSourcingModule} from '../event-sourcing/event-sourcing.module';\nimport {EventsController} from './events.controller';\nimport {SearchController} from './search.controller';\nimport {SearchModule} from '../../modules/search/search.module';\nimport {UserListController} from './user-list.controller';\nimport {FavoritesService} from './favorites/favorites.service';\nimport {FavoritesController} from './favorites/favorites.controller';\nimport {DeletedNotebooksController} from './deleted-notebooks/deleted-notebook.controller';\nimport {EventsGateway} from './events.gateway';\nimport {AutocompleteService} from './autocomplete/autocomplete.service';\nimport {AutocompleteController} from './autocomplete/autocomplete.controller';\nimport {DeletedNotebooksService} from './deleted-notebooks/deleted-notebook.service';\nimport {QuixEventBus} from '../event-sourcing/quix-event-bus';\n\n@Module({\n  imports: [\n    TypeOrmModule.forFeature([\n      DbFileTreeNode,\n      DbFolder,\n      DbNote,\n      DbNotebook,\n      DbAction,\n      FileTreeRepository,\n      NoteRepository,\n      DbDeletedNotebook,\n      DbUser,\n      DbFavorites,\n    ]),\n    AuthModule.create(),\n    EventSourcingModule,\n    SearchModule,\n  ],\n  controllers: [\n    NotebookController,\n    FoldersController,\n    EventsController,\n    SearchController,\n    UserListController,\n    FavoritesController,\n    DeletedNotebooksController,\n    AutocompleteController,\n  ],\n  providers: [\n    NotebookService,\n    FoldersService,\n    FavoritesService,\n    EventsGateway,\n    AutocompleteService,\n    DeletedNotebooksService,\n  ],\n  exports: [],\n})\nexport class WebApiModule {}\n"
  },
  {
    "path": "quix-frontend/service/src/modules/web-api/web-api.spec.ts",
    "content": "/* tslint:disable:no-non-null-assertion */\nimport {FileType} from '@wix/quix-shared';\nimport {range} from 'lodash';\n\nimport {EntityType} from '../../common/entity-type.enum';\nimport {WebApiDriver} from './web-api.driver';\n\njest.setTimeout(60000);\n\ndescribe('web-api module :: ', () => {\n  let driver: WebApiDriver;\n  const defaultUserId = 'quix-default-user@wix.com';\n\n  beforeAll(async () => {\n    driver = await WebApiDriver.create(defaultUserId);\n  });\n\n  beforeEach(async () => await driver.clearDb());\n  afterAll(async () => await driver.module.close());\n\n  describe('foldersService :: ', () => {\n    describe('getPathList', () => {\n      it('get a path list with notebooks inside a folder', async () => {\n        const user = driver.createUser();\n        await driver.userRepo.save(user);\n\n        const notebookName = 'some new notebook';\n        const [notebookNode, notebook] =\n          driver.createNotebookNode(notebookName);\n\n        const folderNode = driver.createFolderNode('folderName');\n        await driver.fileTreeRepo.save(folderNode);\n        notebookNode.parent = folderNode;\n\n        await driver.notebookRepo.save(notebook);\n        await driver.fileTreeRepo.save(notebookNode);\n        const list = await driver.folderService.getFilesForUser(user.id);\n\n        expect(list!.find(i => i.id === notebook.id)!).toMatchObject({\n          id: notebook.id,\n          name: notebookName,\n          path: [{name: 'folderName'}],\n        });\n      });\n\n      it('get a path list, multiple items in root', async () => {\n        const notebookName = 'some new notebook';\n        const [notebookNode, notebook] =\n          driver.createNotebookNode(notebookName);\n        const folderNode = driver.createFolderNode('folderName');\n\n        await driver.fileTreeRepo.save(folderNode);\n        await driver.notebookRepo.save(notebook);\n        await driver.fileTreeRepo.save(notebookNode);\n\n        const list = await driver.folderService.getFilesForUser(defaultUserId);\n        expect(list).toHaveLength(2);\n      });\n\n      it('get a path list, starting from a specific folder', async () => {\n        const notebookName = 'some new notebook';\n        const [notebookNode, notebook] =\n          driver.createNotebookNode(notebookName);\n        const parentFolderNode = driver.createFolderNode('folderName');\n        const subFolderNode = driver.createFolderNode('folderName2');\n        const subSubFolderNode = driver.createFolderNode('folderName3');\n\n        subFolderNode.parent = parentFolderNode;\n        subSubFolderNode.parent = subFolderNode;\n\n        await driver.fileTreeRepo.save(parentFolderNode);\n        await driver.fileTreeRepo.save(subFolderNode);\n        await driver.fileTreeRepo.save(subSubFolderNode);\n\n        await driver.notebookRepo.save(notebook);\n        notebookNode.parent = subSubFolderNode;\n        await driver.fileTreeRepo.save(notebookNode);\n\n        const folder = await driver.folderService.getFolder(subFolderNode.id);\n        const expected = {\n          id: subFolderNode.id,\n          name: 'folderName2',\n          path: [\n            {\n              name: 'folderName',\n              id: parentFolderNode.id,\n            },\n          ],\n          dateCreated: expect.any(Number),\n          dateUpdated: expect.any(Number),\n          ownerDetails: {id: defaultUserId},\n          owner: defaultUserId,\n          type: FileType.folder,\n          files: [\n            {\n              id: subSubFolderNode.id,\n              dateCreated: expect.any(Number),\n              dateUpdated: expect.any(Number),\n              type: FileType.folder,\n              name: 'folderName3',\n              ownerDetails: {id: defaultUserId},\n              owner: defaultUserId,\n              path: [\n                {\n                  name: 'folderName',\n                  id: parentFolderNode.id,\n                },\n                {\n                  id: subFolderNode.id,\n                  name: 'folderName2',\n                },\n              ],\n            },\n          ],\n        };\n\n        expect(folder).toMatchObject(expected);\n      });\n    });\n  });\n\n  describe('notebook service :: ', () => {\n    it('get a notebook, with valid path', async () => {\n      const notebookName = 'some new notebook';\n      const [notebookNode, notebook] = driver.createNotebookNode(notebookName);\n      const folderNode = driver.createFolderNode('folderName');\n      const folderNode2 = driver.createFolderNode('folderName2');\n      folderNode2.parent = folderNode;\n      await driver.fileTreeRepo.save(folderNode);\n      await driver.fileTreeRepo.save(folderNode2);\n      notebookNode.parent = folderNode2;\n\n      await driver.notebookRepo.save(notebook);\n      await driver.fileTreeRepo.save(notebookNode);\n\n      const response = await driver.notebookService.getNotebook(\n        defaultUserId,\n        notebook.id,\n      );\n\n      expect(response!.id).toBe(notebook.id);\n      expect(response!.path).toEqual([\n        {name: 'folderName', id: folderNode.id},\n        {name: 'folderName2', id: folderNode2.id},\n      ]);\n    });\n\n    it('get a notebook, with notes sorted in order', async () => {\n      const notebookName = 'some new notebook';\n      const [notebookNode, notebook] = driver.createNotebookNode(notebookName);\n\n      await driver.notebookRepo.save(notebook);\n      await driver.fileTreeRepo.save(notebookNode);\n\n      const notes = range(5).map(i =>\n        driver.createNote(`note${i}`, notebook.id),\n      );\n      for (const note of notes) {\n        await driver.noteRepo.insertNewWithRank(note);\n      }\n      const from = 3;\n      const to = 1;\n      await driver.noteRepo.reorder(notes[from], to);\n\n      const response = await driver.notebookService.getNotebook(\n        defaultUserId,\n        notebook.id,\n      );\n      expect(response!.notes[to].name).toBe(`note${from}`);\n    });\n\n    it('get a notebook, with favorite indication', async () => {\n      const notebookName = 'some new notebook';\n      const [notebookNode, notebook] = driver.createNotebookNode(notebookName);\n      const favorite = driver.createFavorite(\n        defaultUserId,\n        notebook.id,\n        EntityType.Notebook,\n      );\n\n      await driver.notebookRepo.save(notebook);\n      await driver.fileTreeRepo.save(notebookNode);\n      await driver.favoritesRepo.save(favorite);\n\n      const response = await driver.notebookService.getNotebook(\n        defaultUserId,\n        notebook.id,\n      );\n\n      expect(response!.id).toBe(notebook.id);\n      expect(response!.isLiked).toBe(true);\n    });\n\n    it('get a notebook, with user details', async () => {\n      const notebookName = 'some new notebook';\n      const [notebookNode, notebook] = driver.createNotebookNode(notebookName);\n\n      await driver.userRepo.save({\n        id: defaultUserId,\n        name: 'some name',\n        avatar: 'http://url',\n        rootFolder: 'someId',\n      });\n      await driver.notebookRepo.save(notebook);\n      await driver.fileTreeRepo.save(notebookNode);\n\n      const response = await driver.notebookService.getNotebook(\n        defaultUserId,\n        notebook.id,\n      );\n\n      expect(response!.id).toBe(notebook.id);\n      expect(response!.ownerDetails).toMatchObject({\n        id: defaultUserId,\n        name: 'some name',\n        avatar: 'http://url',\n      });\n    });\n\n    it('get a notebook, even when user does not exist', async () => {\n      const notebookName = 'some new notebook';\n      const [notebookNode, notebook] = driver.createNotebookNode(notebookName);\n\n      await driver.notebookRepo.save(notebook);\n      await driver.fileTreeRepo.save(notebookNode);\n\n      const response = await driver.notebookService.getNotebook(\n        defaultUserId,\n        notebook.id,\n      );\n\n      expect(response!.id).toBe(notebook.id);\n      expect(response!.ownerDetails).toMatchObject({\n        id: defaultUserId,\n        name: '',\n      });\n    });\n  });\n\n  describe('favorites service :: ', () => {\n    it('get favorites per user', async () => {\n      const user = driver.createUser();\n      await driver.userRepo.save(user);\n\n      const user2 = driver.createUser({\n        id: 'secondUser@foo.com',\n        rootFolder: 'someId2',\n        name: '2ndUser',\n      });\n      await driver.userRepo.save(user2);\n\n      const notebook = driver.createNotebook();\n      const favorite = driver.createFavorite(\n        user2.id,\n        notebook.id,\n        EntityType.Notebook,\n      );\n\n      await driver.notebookRepo.save(notebook);\n      await driver.favoritesRepo.save(favorite);\n\n      const response = await driver.favoritesService.getFavoritesForUser(\n        user2.id,\n      );\n\n      expect(response).toEqual([\n        {\n          id: notebook.id,\n          name: notebook.name,\n          type: FileType.notebook,\n          owner: notebook.owner,\n          ownerDetails: expect.objectContaining({\n            id: user.id,\n            name: user.name,\n          }),\n          isLiked: true,\n          path: [],\n          dateCreated: notebook.dateCreated,\n          dateUpdated: notebook.dateUpdated,\n        },\n      ]);\n    });\n  });\n\n  describe('deleted-notebooks service :: ', () => {\n    it('gets all deleted notebooks per user', async () => {\n      const user = driver.createUser();\n      await driver.userRepo.save(user);\n\n      const deletedNotebook = driver.createDeletedNotebook(defaultUserId);\n      await driver.deletedNotebookRepo.save(deletedNotebook);\n\n      const response =\n        await driver.deletedNotebookService.getDeletedNotebooksForUser(\n          defaultUserId,\n        );\n\n      expect(response).toEqual([\n        {\n          id: deletedNotebook.id,\n          name: deletedNotebook.name,\n          owner: deletedNotebook.owner,\n          ownerDetails: expect.objectContaining({\n            id: user.id,\n            name: user.name,\n          }),\n          isLiked: false,\n          path: [],\n          notes: [],\n          dateCreated: deletedNotebook.dateCreated,\n          dateUpdated: deletedNotebook.dateUpdated,\n          dateDeleted: deletedNotebook.dateDeleted,\n        },\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "quix-frontend/service/src/template-engine/velocity.ts",
    "content": "import velocity from 'velocity';\n\nfunction expressEngine() {\n  return function render(template: string, data: any, cb: any) {\n    const vm = new velocity.Engine({\n      template,\n    });\n    cb(null, vm.render(data));\n  };\n}\nexport default expressEngine;\n"
  },
  {
    "path": "quix-frontend/service/src/types/3rd-party/uuid.d.ts",
    "content": "declare module 'uuid/v4' {\n  const fn: () => string;\n  export default fn;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/types/3rd-party/velocity.d.ts",
    "content": "declare module 'velocity' {\n  export class Engine {\n    constructor(options: {template: string});\n    render(data: any): string;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/types/index.ts",
    "content": "export interface Dictionary<T> {\n  [key: string]: T;\n}\n"
  },
  {
    "path": "quix-frontend/service/src/utils/create-schema-helpers.ts",
    "content": "import cluster from 'cluster';\nimport {QUIX_SCHEMA, CURRENT_QUIX_SCHEMA_VERSION} from '../consts';\nimport {Connection} from 'typeorm';\nimport {DbMetadata} from '../entities/version-metadata.entity';\nimport {Logger} from '@nestjs/common';\n\nexport async function checkSchemaVersion(conn: Connection, logger: Logger) {\n  const result = await conn\n    .getRepository(DbMetadata)\n    .findOne({name: QUIX_SCHEMA})\n    .catch(e => {\n      logger.error(e);\n      return undefined;\n    });\n  if (!result || result.version !== CURRENT_QUIX_SCHEMA_VERSION) {\n    logger.error(\n      `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`,\n    );\n    process.exit(-1);\n  }\n}\n\nexport async function createInitialSchemaIfNeeded(\n  conn: Connection,\n  dbName: string,\n  logger: Logger,\n) {\n  try {\n    const versionMetadataTableName = conn.getMetadata(DbMetadata).tableName;\n    const [{cnt: doesTableExist}] = await conn.query(`SELECT count(*) as cnt\n    FROM information_schema.TABLES\n    WHERE (TABLE_SCHEMA = '${dbName}') AND (TABLE_NAME = '${versionMetadataTableName}')`);\n\n    if (doesTableExist === '0') {\n      logger.log(\n        'Looks like this is your first time running quix, setting up initial schema',\n      );\n      await conn.runMigrations();\n    }\n  } catch (e) {\n    logger.error('failed creating initial schema');\n    logger.error(e);\n    process.exit(-1);\n  }\n}\n\nfunction isPm2() {\n  return (\n    'PM2_HOME' in process.env ||\n    'PM2_JSON_PROCESSING' in process.env ||\n    'PM2_CLI' in process.env\n  );\n}\n\nexport function isMasterProcess() {\n  if (isPm2()) {\n    return process.env.pm_id === '0';\n  } else {\n    return cluster.isMaster;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/src/utils/deferred-promise.ts",
    "content": "export function defer<T = any>() {\n  let resolve: any;\n  let reject: any;\n  const promise = new Promise<T>((resolveFn, rejectFn) => {\n    resolve = resolveFn;\n    reject = rejectFn;\n  });\n  return {\n    resolve,\n    reject,\n    resolveByPromise(p: Promise<T>) {\n      p.then(v => resolve(v)).catch(e => reject(e));\n    },\n    promise,\n  } as {\n    resolve: (value?: T | PromiseLike<T>) => void;\n    reject: (reason: any) => void;\n    promise: Promise<T>;\n  };\n}\n"
  },
  {
    "path": "quix-frontend/service/src/utils/retry-promise.ts",
    "content": "export function retry<R>(what: () => Promise<R>) {\n  return {\n    forNTimes: (n: number) => ({\n      andWaitXMilliseconds: async (milliseconds: number) => {\n        let counter = 0;\n        let error: Error | null = null;\n        let result: R = {} as any;\n        while (counter < n) {\n          await what()\n            .then(r => {\n              result = r;\n              error = null;\n            })\n            .catch(e => {\n              error = e;\n              return undefined;\n            });\n          if (error) {\n            counter++;\n            await new Promise(resolve => setTimeout(resolve, milliseconds));\n          } else {\n            return result;\n          }\n        }\n        throw error;\n      },\n    }),\n  };\n}\n"
  },
  {
    "path": "quix-frontend/service/test/app.e2e-spec.ts",
    "content": "/* tslint:disable:no-non-null-assertion */\nimport 'reflect-metadata';\nimport {Test, TestingModule} from '@nestjs/testing';\nimport {AppModule} from './../src/app.module';\nimport {INestApplication, Logger} from '@nestjs/common';\nimport {ConfigService, EnvSettings} from '../src/config';\nimport nock from 'nock';\nimport {IExternalUser} from '../src/modules/auth/types';\nimport {E2EDriver} from './driver';\nimport {E2EMockDataBuilder} from './builder';\nimport cookieParser = require('cookie-parser');\nimport {sanitizeUserEmail} from '../src/common/user-sanitizer';\nimport {getConnectionToken} from '@nestjs/typeorm';\nimport {Connection} from 'typeorm';\nimport WebSocket from 'ws';\nimport './custom-matchers';\nimport {WsAdapter} from '@nestjs/platform-ws';\nimport {serialize as serializeCookie} from 'cookie';\nimport {testingDefaults} from '../src/config/env/static-settings';\n\nlet envSettingsOverride: Partial<EnvSettings> = {};\n\nclass E2EConfigService extends ConfigService {\n  getEnvSettings(): EnvSettings {\n    const env = super.getEnvSettings();\n    return {...env, AutoMigrateDb: false, ...envSettingsOverride};\n  }\n}\n\nconst user1profile: IExternalUser = {\n  email: 'testing@quix.com',\n  id: '111111111',\n  name: 'Testing User',\n};\n\nconst user2profile: IExternalUser = {\n  email: 'secondUser@quix.com',\n  id: '222222222',\n  name: 'second User',\n  avatar: 'http://seconduseravatar.png',\n};\n\ndescribe('Application (e2e)', () => {\n  jest.setTimeout(60000);\n  let app: INestApplication;\n  let driver: E2EDriver;\n  let builder: E2EMockDataBuilder;\n\n  const beforeAndAfter = () => {\n    beforeEach(async () => {\n      const moduleFixture: TestingModule = await Test.createTestingModule({\n        imports: [AppModule],\n      })\n        .overrideProvider(ConfigService)\n        .useClass(E2EConfigService)\n        .compile();\n\n      app = moduleFixture.createNestApplication();\n      app.use(cookieParser());\n      app.useWebSocketAdapter(new WsAdapter(app));\n      await app.init();\n\n      const configService: ConfigService = moduleFixture.get(ConfigService);\n      const conn: Connection = moduleFixture.get(getConnectionToken());\n      if (configService.getDbType() === 'mysql') {\n        await conn.dropDatabase();\n        await conn.synchronize();\n      } else {\n        await conn.dropDatabase();\n        await conn.synchronize();\n      }\n\n      driver = new E2EDriver(app);\n      builder = new E2EMockDataBuilder();\n    });\n\n    afterEach(async () => {\n      envSettingsOverride = {};\n      return app.close();\n    });\n  };\n\n  beforeEach(() => {\n    nock.cleanAll();\n  });\n\n  describe('backend proxy', () => {\n    const fakeBackendHost = 'backend:8081';\n    beforeEach(() => {\n      envSettingsOverride.QuixBackendInternalUrl = fakeBackendHost;\n    });\n    beforeAndAfter();\n\n    it('should proxy requests to the backend', async () => {\n      nock(`http://${fakeBackendHost}`)\n        .get('/api/db/explore')\n        .reply(200, ['mocked']);\n\n      const returned = await driver.get('db/explore');\n      expect(returned).toEqual(['mocked']);\n    });\n  });\n\n  describe('User list', () => {\n    beforeAndAfter();\n\n    beforeEach(() => {\n      driver.addUser('user1', user1profile).addUser('user2', user2profile);\n    });\n\n    it('should add a user on first login', async () => {\n      await driver.doLogin('user1');\n\n      let users = await driver.as('user1').get('users');\n\n      expect(users).toHaveLength(1);\n      await driver.doLogin('user2');\n\n      users = await driver.as('user1').get('users');\n      expect(users).toMatchArrayAnyOrder([\n        {\n          id: user1profile.email,\n          name: user1profile.name,\n          rootFolder: expect.any(String),\n          dateCreated: expect.any(Number),\n          dateUpdated: expect.any(Number),\n        },\n        {\n          id: user2profile.email,\n          name: user2profile.name,\n          rootFolder: expect.any(String),\n          dateCreated: expect.any(Number),\n          dateUpdated: expect.any(Number),\n        },\n      ]);\n      expect(users[0].dateCreated - Date.now()).toBeLessThan(2000); // Within 2 seconds\n    });\n\n    it('should update details on login', async () => {\n      await driver.doLogin('user1');\n\n      driver.addUser('user1', {...user1profile, name: 'new name'});\n\n      await driver.doLogin('user1');\n\n      const users = await driver.as('user1').get('users');\n      expect(users).toMatchArrayAnyOrder([\n        {\n          id: user1profile.email,\n          name: 'new name',\n          rootFolder: expect.any(String),\n          dateCreated: expect.any(Number),\n          dateUpdated: expect.any(Number),\n        },\n      ]);\n    });\n  });\n\n  describe('Demo Mode', () => {\n    beforeEach(() => {\n      envSettingsOverride.DemoMode = true;\n    });\n    beforeAndAfter();\n    beforeEach(() => {\n      driver.addUser('user1', user1profile).addUser('user2', user2profile);\n    });\n\n    const expectObject = (json: object) => ({\n      toNotLeakUserData(user: IExternalUser) {\n        expect(JSON.stringify(json)).toEqual(\n          expect.not.stringContaining(user2profile.email),\n        );\n        expect(JSON.stringify(json)).toEqual(\n          expect.not.stringContaining(user2profile.name!),\n        );\n        expect(JSON.stringify(json)).toEqual(\n          expect.not.stringContaining(user2profile.id!),\n        );\n        expect(JSON.stringify(json)).toEqual(\n          expect.not.stringContaining(user2profile.avatar!),\n        );\n      },\n    });\n\n    it('user list should not contain private information', async () => {\n      await driver.doLogin('user1');\n\n      let users = await driver.as('user1').get('users');\n      expect(users).toHaveLength(1);\n\n      await driver.doLogin('user2');\n      users = await driver.as('user1').get('users');\n      expect(users).toMatchArrayAnyOrder(\n        [\n          {\n            id: expect.stringContaining('**'),\n            name: 'Quix User',\n            rootFolder: expect.any(String),\n          },\n          {\n            id: user1profile.email,\n            name: user1profile.name,\n            rootFolder: expect.any(String),\n          },\n        ],\n        'name',\n      );\n      expectObject(users).toNotLeakUserData(user2profile);\n    });\n\n    it('when fetching other user notebook, user name should be hidden', async () => {\n      await driver.doLogin('user1');\n\n      const [{id: rootFolder}] = await driver.as('user1').get('files');\n      const [notebookId, createAction] = builder.createNotebookAction([\n        {id: rootFolder},\n      ]);\n\n      await driver.as('user1').postEvents(createAction);\n\n      let notebookFromServer = await driver\n        .as('user1')\n        .get('notebook', notebookId);\n\n      expect(notebookFromServer.owner).toBe(user1profile.email);\n\n      notebookFromServer = await driver.as('user2').get('notebook', notebookId);\n\n      expect(notebookFromServer.owner).toBe(\n        sanitizeUserEmail(user1profile.email),\n      );\n      expectObject(notebookFromServer).toNotLeakUserData(user1profile);\n    });\n\n    it('when searching notebooks, sanitize user', async () => {\n      await driver.doLogin('user1');\n\n      const [{id: rootFolder}] = await driver.as('user1').get('files');\n      const [notebookId, createAction] = builder.createNotebookAction([\n        {id: rootFolder},\n      ]);\n\n      await driver.as('user1').postEvents([\n        createAction,\n        builder.createNoteAction(notebookId, {\n          content: 'some query goes here',\n        }),\n      ]);\n\n      let searchResults = await driver\n        .as('user1')\n        .search('\"some query goes here\"');\n      expect(searchResults.notes[0].owner).toBe(user1profile.email);\n\n      searchResults = await driver.as('user2').search('\"some query goes here\"');\n      expect(searchResults.notes[0].owner).toBe(\n        sanitizeUserEmail(user1profile.email),\n      );\n      expectObject(searchResults).toNotLeakUserData(user1profile);\n    });\n  });\n\n  describe('Search', () => {\n    beforeAndAfter();\n    beforeEach(() => {\n      driver.addUser('user1', user1profile);\n    });\n\n    it('when searching notebooks, should receive the search terms back', async () => {\n      await driver.doLogin('user1');\n\n      const [{id: rootFolder}] = await driver.as('user1').get('files');\n      const [notebookId, createAction] = builder.createNotebookAction([\n        {id: rootFolder},\n      ]);\n\n      await driver.as('user1').postEvents([\n        createAction,\n        builder.createNoteAction(notebookId, {\n          content: 'some query goes here',\n          type: 'presto',\n        }),\n        builder.createNoteAction(notebookId, {\n          content: 'diffrent query goes here',\n          type: 'python',\n        }),\n      ]);\n\n      let searchResults1 = await driver\n        .as('user1')\n        .search('type:python \"query goes here\"');\n\n      expect(searchResults1.notes).toHaveLength(1);\n      expect(searchResults1.term.type).toBe('python');\n      expect(searchResults1.term.content[0].text).toBe('query goes here');\n      expect(searchResults1.term.fullText).toBe('type:python \"query goes here\"');\n    });\n  });\n\n  describe('Synchronize sessions', () => {\n    const defaultCookie = testingDefaults.AuthCookieName;\n\n    beforeAndAfter();\n\n    beforeEach(() => {\n      driver.addUser('user1', user1profile).addUser('user2', user2profile);\n    });\n\n    describe('websocket', () => {\n      it(`should close connection if token is not passed in subscription`, async () => {\n        await app.listenAsync(3000);\n\n        const ws1 = new WebSocket('ws://localhost:3000/subscription', {\n          headers: {Cookie: serializeCookie(defaultCookie, 'abc')},\n        });\n        await new Promise(resolve => ws1.on('open', resolve));\n        ws1.send(JSON.stringify({event: 'subscribe', data: {}}));\n        await new Promise(resolve => ws1.on('close', resolve));\n      });\n\n      it(`should send actions only to a single connection`, async () => {\n        await app.listenAsync(3000);\n\n        await driver.doLogin('user1');\n        const token = driver.as('user1').getToken();\n\n        const {ws: ws1, sessionId: sessionId1} = await driver\n          .as('user1')\n          .wsConnect();\n\n        const {ws: ws2, sessionId: sessionId2} = await driver\n          .as('user1')\n          .wsConnect();\n\n        const [{id: rootFolder}] = await driver.as('user1').get('files');\n        const [notebookId, createAction] = builder.createNotebookAction([\n          {id: rootFolder},\n        ]);\n\n        await driver.as('user1').postEvents(createAction, sessionId1);\n\n        expect(driver.getMessages(ws1)).toHaveLength(0);\n\n        expect(driver.getMessages(ws2)).toEqual([\n          {\n            event: 'action',\n            data: createAction,\n          },\n        ]);\n      });\n    });\n  });\n});\n\nfunction resolveIn(n: number = 1000) {\n  return new Promise(resolve => setTimeout(resolve, n));\n}\n"
  },
  {
    "path": "quix-frontend/service/test/builder.ts",
    "content": "import {\n  IFilePathItem,\n  FileActions,\n  FileType,\n} from '@wix/quix-shared/entities/file';\nimport * as uuid from 'uuid';\nimport {\n  INote,\n  createNote,\n  NoteActions,\n  createNotebook,\n  NotebookActions,\n  DeletedNotebookActions,\n  createDeletedNotebook,\n  INotebook,\n  createEmptyIUser,\n  IDeletedNotebook,\n  TrashBinActionTypes,\n  TrashBinActions,\n} from '@wix/quix-shared';\nimport {string} from 'fp-ts';\n\nclass BaseMockDataBuilder<S extends string | never> {\n  constructor(protected defaultUser: S) {}\n\n  createNotebook = createNotebook.bind(this);\n\n  createNotebookAction(\n    path: Partial<IFilePathItem>[] = [],\n    user = this.defaultUser,\n  ) {\n    const id = uuid.v4();\n    const action = {\n      ...NotebookActions.createNotebook(\n        id,\n        createNotebook(path as IFilePathItem[], {id}),\n      ),\n      user,\n    };\n    return [id, action] as const;\n  }\n\n  createDeletedNotebookAction(\n    path: Partial<IFilePathItem>[] = [],\n    user = this.defaultUser,\n  ) {\n    const id = uuid.v4();\n    const action = {\n      ...DeletedNotebookActions.createDeletedNotebook(\n        id,\n        createDeletedNotebook(path as IFilePathItem[], {id}),\n      ),\n      user,\n    };\n    return [id, action] as const;\n  }\n\n  permanentlyDeleteDeletedNotebookAction(\n    user = this.defaultUser,\n    notebookId?: string,\n  ) {\n    notebookId = notebookId || uuid.v4();\n    const action = {\n      ...TrashBinActions.permanentlyDeleteNotebook(notebookId),\n      user,\n    };\n    return [notebookId, action] as const;\n  }\n\n  moveNotebookToTrashBinAction(user = this.defaultUser, notebookId?: string) {\n    const id = notebookId || uuid.v4();\n    const action = {\n      ...TrashBinActions.moveNotebookToTrashBin(id),\n      user,\n      ethereal: true,\n    };\n    return [id, action] as const;\n  }\n\n  restoreNotebookFromTrashBinAction(\n    user = this.defaultUser,\n    restoreFolderId: string,\n    notebookId?: string,\n  ) {\n    const id = notebookId || uuid.v4();\n    const action = {\n      ...TrashBinActions.restoreDeletedNotebook(id, restoreFolderId),\n      user,\n      ethereal: true,\n    };\n    return [id, action] as const;\n  }\n\n  createNoteAction(\n    notebookId: string,\n    note: Partial<INote> = {},\n    user = this.defaultUser,\n  ) {\n    note.id = note.id || uuid.v4();\n    const action = {\n      ...NoteActions.addNote(note.id, createNote(notebookId, note)),\n      user,\n    };\n    return action;\n  }\n\n  createFolderAction(\n    name: string,\n    path: {id: string}[],\n    user = this.defaultUser,\n  ) {\n    const id = uuid.v4();\n    const action = {\n      ...FileActions.createFile(id, {\n        id,\n        type: FileType.folder,\n        name,\n        path: path as IFilePathItem[],\n        isLiked: false,\n        owner: user || '',\n        ownerDetails: createEmptyIUser(user),\n        dateCreated: 0,\n        dateUpdated: 0,\n      }),\n      user,\n    };\n    return [id, action] as const;\n  }\n}\nexport class E2EMockDataBuilder extends BaseMockDataBuilder<never> {\n  constructor() {\n    super(undefined as never);\n  }\n}\n\nexport class MockDataBuilder extends BaseMockDataBuilder<string> {\n  constructor(defaultUser: string) {\n    super(defaultUser);\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/test/custom-matchers.ts",
    "content": "declare global {\n  namespace jest {\n    interface Matchers<R> {\n      toMatchArrayAnyOrder(expected: any, sortBy?: string): R;\n    }\n  }\n}\n\nexpect.extend({\n  toMatchArrayAnyOrder(x: any[], y: any[], z = 'id') {\n    const sortFn = (a: any, b: any) => (a[z] as string).localeCompare(b[z]);\n    const arr1Sorted = x.sort(sortFn);\n    const arr2Sorted = y.sort(sortFn);\n    const diff: any = {};\n    const pass = arr1Sorted.every((item, index) => {\n      const isEqual = this.equals(\n        expect.objectContaining(arr2Sorted[index]),\n        item,\n      );\n      if (!isEqual) {\n        diff.index = index;\n        diff.a = item;\n        diff.b = arr2Sorted[index];\n      }\n      return isEqual;\n    });\n    return {\n      pass,\n      message: () => {\n        if (this.isNot) {\n          return 'Arrays are equal.';\n        } else {\n          return `Items don't match in index ${diff.index}\nExpected:\n${this.utils.printExpected(diff.a)}\nReceived:\n${this.utils.printReceived(diff.b)}\n`;\n        }\n      },\n    };\n  },\n});\n\nexport const dummyVar = 'just to make this a module';\n"
  },
  {
    "path": "quix-frontend/service/test/driver.ts",
    "content": "/* tslint:disable:variable-name */\nimport {INestApplication} from '@nestjs/common';\nimport request from 'supertest';\nimport {IExternalUser} from '../src/modules/auth';\nimport {testingDefaults} from '../src/config/env/static-settings';\nimport {INotebook, INote, IFolder, IFile, IUser} from '@wix/quix-shared';\nimport WebSocket from 'ws';\nimport uuid from 'uuid';\nimport {serialize} from 'cookie';\n\nconst defaultCookie = testingDefaults.AuthCookieName;\n\ninterface GetFunctionTypeHelper {\n  (url: 'users'): Promise<IUser[]>;\n  (url: 'files'): Promise<IFile[]>;\n  (url: 'files', id: string): Promise<IFolder>;\n  (url: 'note', id: string): Promise<INote>;\n  (url: 'notebook', id: string): Promise<INotebook>;\n  (...url: string[]): Promise<any>;\n}\n\nconst createUserCookie = (user: IExternalUser) =>\n  Buffer.from(JSON.stringify(user)).toString('base64');\n\nconst wsMessageLog: WeakMap<WebSocket, string[]> = new WeakMap();\n\nclass HttpHelper {\n  constructor(\n    protected _supertest: request.SuperTest<request.Test>,\n    protected user?: IExternalUser,\n  ) {}\n\n  public getToken() {\n    return this.user ? createUserCookie(this.user) : '';\n  }\n\n  public baseGet(url: string) {\n    let chain = this._supertest.get('/api/' + url);\n    if (this.user) {\n      chain = chain.set(\n        'Cookie',\n        `${defaultCookie}=${createUserCookie(this.user)}`,\n      );\n    }\n    return chain;\n  }\n\n  search = async (term: string, offset = 0, total = 5) =>\n    (\n      await this.baseGet(['search', encodeURIComponent(term)].join('/')).query({\n        offset,\n        total,\n      })\n    ).body;\n\n  get: GetFunctionTypeHelper = async (...url: string[]) =>\n    (await this.baseGet(url.join('/')).expect(200)).body;\n\n  getAndExpectFail = (url: string, errorCode: number) =>\n    this.baseGet(url).expect(errorCode);\n\n  private basePost(url: string, data: any) {\n    let chain = this._supertest.post('/api/' + url);\n    if (this.user) {\n      chain = chain.set('Cookie', [\n        `${defaultCookie}=${createUserCookie(this.user)}`,\n      ]);\n    }\n    return chain.send(data);\n  }\n\n  post = (url: string, data: any) => this.basePost(url, data).expect(200);\n\n  postAndExpectFail = (url: string, data: any, errorCode: number) =>\n    this.basePost(url, data).expect(errorCode);\n\n  postEvents = (data: any, sessionId?: string) => {\n    return this.basePost('events', data)\n      .query({sessionId})\n      .send(data)\n      .expect(200);\n  };\n\n  async wsConnect() {\n    const ws = new WebSocket('ws://localhost:3000/subscription', {\n      headers: this.user\n        ? {Cookie: serialize(defaultCookie, createUserCookie(this.user))}\n        : {},\n    });\n    const sessionId = uuid.v4();\n    await new Promise(resolve => ws.on('open', resolve));\n\n    ws.send(\n      JSON.stringify({\n        event: 'subscribe',\n        data: {token: this.getToken(), sessionId},\n      }),\n    );\n\n    ws.on('message', (data: any) => {\n      const messages = [...(wsMessageLog.get(ws) || []), JSON.parse(data)];\n      wsMessageLog.set(ws, messages);\n    });\n\n    return {ws, sessionId};\n  }\n\n  getMessages(ws: WebSocket): any[] {\n    return wsMessageLog.get(ws) || [];\n  }\n}\n\nexport class E2EDriver extends HttpHelper {\n  private users: Map<string, IExternalUser> = new Map();\n\n  constructor(private app: INestApplication) {\n    super(request(app.getHttpServer()));\n  }\n\n  addUser(nickname: string, up: IExternalUser) {\n    this.users.set(nickname, up);\n    return this;\n  }\n\n  setDefaultUser(nickname: string) {\n    this.user = this.users.get(nickname);\n  }\n\n  as = (username: string) => {\n    const user = this.users.get(username);\n    return new HttpHelper(this._supertest, user);\n  };\n\n  doLogin(nickname: string) {\n    const user = this.users.get(nickname);\n    if (!user) {\n      throw new Error();\n    }\n    return this.get(\n      `authenticate?code=${encodeURIComponent(JSON.stringify(user))}`,\n    );\n  }\n\n  get supertest() {\n    return this._supertest;\n  }\n}\n"
  },
  {
    "path": "quix-frontend/service/test/jest-e2e.js",
    "content": "const path = require('path');\nconst pkgJsonPath = path.resolve(__dirname, '..', 'package.json');\nconst pkgJson = require(pkgJsonPath)\n\nmodule.exports =  {\n  \"moduleFileExtensions\": [\"js\", \"json\", \"ts\"],\n  \"rootDir\": \"../src\",\n  \"roots\": [\"<rootDir>\", \"<rootDir>/../test\"],\n  \"testEnvironment\": \"node\",\n  \"testRegex\": \".e2e-spec.ts$\",\n  \"transform\": {\n    \"^.+\\\\.ts$\": \"ts-jest\"\n  },\n  \"transformIgnorePatterns\": [\"/node_modules/\", \"/quix-frontend\\\\shared/\"],\n}\n"
  },
  {
    "path": "quix-frontend/service/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"references\": [{\n    \"path\": \"../shared\"\n  }],\n  \"include\": [\"src/main.ts\", \"src/types/**/*.ts\", \"src/migrations/*.ts\"],  \n  \"exclude\": [\"node_modules\", \"test\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "quix-frontend/service/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"noErrorTruncation\": true,\n    \"target\": \"esnext\",\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"importHelpers\": true,\n    \"typeRoots\": [\n      \"./node_modules/@types\",\n      \"./src/types/3rd-party\"\n    ]\n  },\n  \"references\": [\n    {\n      \"path\": \"../shared\"\n    }\n  ],\n  \"include\": [\n    \"src/**/*.ts\",\n    \"test/**/*.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}"
  },
  {
    "path": "quix-frontend/service/tslint.json",
    "content": "{\n  \"defaultSeverity\": \"error\",\n  \"extends\": [\n    \"tslint:recommended\",\n    \"tslint-config-prettier\"\n  ],\n  \"jsRules\": {\n    \"no-unused-expression\": true\n  },\n  \"rules\": {\n    \"quotemark\": [\n      true,\n      \"single\"\n    ],\n    \"member-access\": [\n      false\n    ],\n    \"ordered-imports\": [\n      false\n    ],\n    \"member-ordering\": [\n      false\n    ],\n    \"interface-name\": [\n      false\n    ],\n    \"array-type\": false,\n    \"arrow-parens\": false,\n    \"object-literal-sort-keys\": false,\n    \"max-classes-per-file\": false,\n    \"no-non-null-assertion\": true,\n    \"prettier\": true\n  },\n  \"rulesDirectory\": [\n    \"tslint-plugin-prettier\"\n  ]\n}"
  },
  {
    "path": "quix-frontend/shared/.gitignore",
    "content": "node_modules\ndist\ntarget\ncoverage\ntypings\nmaven\nvelocity.private.data.js\ntest/e2e/screenshots\n*npm-debug.log\n.history\n.idea\n*.iml\n.yo-rc.json\n*.js\n*.js.map\n*.d.ts\n*.d.ts.map\ntsconfig.tsbuildinfo"
  },
  {
    "path": "quix-frontend/shared/config-helper/config-helper.ts",
    "content": "import { ModuleEngineType, ModuleComponentType } from './consts';\n\ninterface ComponentConfigurationTypes {\n  [ModuleComponentType.Db]: {};\n  [ModuleComponentType.Note]: {};\n}\n\nexport type ComponentConfiguration = {[K in ModuleComponentType]?: ComponentConfigurationTypes[K]}\n\ninterface ConfigModule {\n  id: string;\n  name: string;\n  components: ComponentConfiguration;\n  syntax: string;\n  engine: ModuleEngineType;\n}\n\nconst defaultConfigData = {\n  modules: [] as ConfigModule[],\n  auth: {\n    googleClientId: '',\n  },\n  clientTopology: {\n    staticsBaseUrl: '',\n    executeBaseUrl: '',\n    apiBasePath: '',\n  },\n  mode: {\n    debug: false,\n    demo: false,\n  }\n}\n\ntype ConfigData = typeof defaultConfigData;\n\nexport class ClientConfigHelper {\n  private readonly config: ConfigData;\n\n  constructor(initialConfig: Partial<ConfigData> = {}) {\n    this.config = {\n      ...defaultConfigData,\n      ...initialConfig\n    };\n  }\n\n  serialize(): string {\n    return JSON.stringify(this.config);\n  }\n\n  static load(input: string | object): ClientConfigHelper {\n    if (typeof input === 'string') {\n      return new ClientConfigHelper(JSON.parse(input));\n    }\n    return new ClientConfigHelper(input);\n  }\n\n  getModule(id: string) {\n    return this.getModules().find(m => m.id === id);\n  }\n\n  getModuleComponent<C extends ModuleComponentType>(id: string, component: C) {\n    const m = this.getModule(id);\n    return m && m.components[component];\n  }\n\n  getModules() {\n    return this.config.modules;\n  }\n\n  addModule(p: ConfigModule) {\n    this.config.modules.push(p);\n    return this;\n  }\n\n  getModulesByComponent(component: ModuleComponentType) {\n    return this.config.modules.filter(p => Object.keys(p.components).includes(component));\n  }\n\n  addModuleComponent<C extends ModuleComponentType>(moduleId: string, component: C, configuration: ComponentConfigurationTypes[C]) {\n    const m = this.getModule(moduleId);\n\n    if (m) {\n      m.components[component] = configuration;\n    }\n\n    return this;\n  }\n\n  getAuth() {\n    return this.config.auth;\n  }\n\n  getClientTopology() {\n    return this.config.clientTopology;\n  }\n\n  getMode() {\n    return this.config.mode;\n  }\n\n  setAuth(auth: ConfigData['auth']) {\n    this.config.auth = {...auth}\n    return this;\n  }\n\n  setClientTopology(clientTopology: ConfigData['clientTopology']) {\n    this.config.clientTopology = {...clientTopology};\n    return this;\n  }\n\n  setMode(mode: ConfigData['mode']) {\n    this.config.mode = {...mode};\n    return this;\n  }\n}"
  },
  {
    "path": "quix-frontend/shared/config-helper/consts.ts",
    "content": "export type TModuleComponentType = 'note' | 'db';\n\nexport enum ModuleComponentType {\n  Note = 'note',\n  Db = 'db',\n}\n\nexport enum ModuleEngineType {\n  Presto = 'presto',\n  Athena = 'athena',\n  Jdbc = 'jdbc',\n  BigQuery = 'bigquery',\n  Python = 'python',\n}\n\nexport const ModuleEngineToSyntaxMap = {\n  presto: 'presto',\n  athena: 'athena',\n  bigquery: 'ansisql',\n  python: 'python'\n}"
  },
  {
    "path": "quix-frontend/shared/entities/common/actions.ts",
    "content": "import {mapValues} from 'lodash';\n\nexport type ExtractActions<T extends Record<string, (...args: any[]) => any>> = {[K in keyof T]: ReturnType<T[K]>}[keyof T];\nexport type ExtractActionTypes<T extends Record<string, (...args: any[]) => any>> = {[K in keyof T]: ReturnType<T[K]>['type']}[keyof T];\nexport const ExtractActionTypes = <T extends Record<string, (...args: any[]) => any>>(actions: T) => {\n  const result: {[K in keyof T]: ReturnType<T[K]>['type']} = mapValues(actions, ((actionCreator: Function) => actionCreator().type)) as any;\n  return result;\n} \n"
  },
  {
    "path": "quix-frontend/shared/entities/common/common-types.ts",
    "content": "import {IUser} from '../user';\n\nexport interface IEntity {\n  id: string;\n  name: string;\n  owner: string\n  ownerDetails?: IUser\n  dateCreated: number;\n  dateUpdated: number;\n}\n\nexport interface BaseAction {\n  type: string;\n  id: string;\n}\n\nexport interface AnyAction extends BaseAction {\n  type: string;\n  [k: string]: any\n}\n\nexport type Reducer<S, A extends BaseAction = AnyAction> = (state: S | undefined, action: A) => (S | undefined);\n\n"
  },
  {
    "path": "quix-frontend/shared/entities/common/create-reducer.spec.ts",
    "content": "import {createReducer, createListReducer} from './create-reducer';\n\ninterface SomeRandomEntity {\n  id: string;\n  name: string;\n  description: string;\n  someNestedObject: {\n    foo: number;\n  }\n}\n\ndescribe('createBaseReducer', () => {\n\n  const entity: SomeRandomEntity = {\n    id: '1',\n    name: 'someName',\n    description: 'words go here',\n    someNestedObject: {\n      foo: 10\n    }\n  }\n\n  it('should handle create actions', () => {\n    const reducer = createReducer<SomeRandomEntity>('someEntity')\n    const action = {\n      type: 'someEntity.create',\n      someEntity: entity,\n      id: '1'\n    }\n    const newState = reducer(undefined, action);\n\n    expect(newState).toEqual(entity);\n    expect(newState).not.toBe(entity);\n  });\n\n  it('should handle delete actions', () => {\n    const reducer = createReducer<SomeRandomEntity>('someEntity')\n    const action = {\n      type: 'someEntity.delete',\n      id: '1'\n    }\n    const newState = reducer(entity, action);\n    expect(newState).toBe(entity);\n  });\n\n  it('should handle update actions', () => {\n    const reducer = createReducer<SomeRandomEntity>('someEntity')\n    const action = {\n      type: 'someEntity.update.name',\n      name: 'newName',\n      id: '1'\n\n    }\n    const newState = reducer(entity, action);\n    expect(newState).toBeDefined;\n    expect(newState!.name).toEqual('newName');\n  });\n\n  it('should handle update actions of deep properties', () => {\n    const reducer = createReducer<SomeRandomEntity>('someEntity')\n    const action = {\n      type: 'someEntity.update.someNestedObject',\n      id: '1',\n      someNestedObject: {\n        foo: 11\n      }\n    }\n    const newState = reducer(entity, action);\n    expect(newState).toBeDefined;\n    expect(newState!.someNestedObject).toEqual({foo: 11});\n  });\n\n  it('should do nothing on unsupported action', () => {\n    const reducer = createReducer<SomeRandomEntity>('someEntity')\n    const action = {\n      type: 'someEntity.someNestedObject.update.foo',\n      foo: 11,\n      id: '1'\n    }\n    const newState = reducer(entity, action);\n    expect(newState).toBe(entity);\n  });\n});\n\n\ndescribe('createListReducer', () => {\n  const entity: SomeRandomEntity = {\n    id: '1',\n    name: 'someName',\n    description: 'words go here',\n    someNestedObject: {\n      foo: 10\n    }\n  }\n  let state: SomeRandomEntity[] = [];\n  const baseReducer = createReducer<SomeRandomEntity>('someEntity')\n\n  beforeEach(() => state = []);\n\n  it('should add item to list', () => {\n    const listReducer = createListReducer('someEntity', baseReducer);\n    const action = {\n      type: 'someEntity.create',\n      someEntity: entity,\n      id: entity.id\n    };\n\n    const newState = listReducer(state, action);\n    expect(newState).toEqual([entity]);\n  });\n\n  it('should remove item from list', () => {\n    const listReducer = createListReducer('someEntity', baseReducer);\n    const action = {\n      type: 'someEntity.delete',\n      id: entity.id\n    };\n    \n    const newState = listReducer([entity], action);\n    expect(newState).toEqual([]);\n  });\n\n  it('should handle updates', () => {\n    const listReducer = createListReducer('someEntity', baseReducer);\n    const action = {\n      type: 'someEntity.update.description',\n      id: entity.id,\n      description: 'newDescription'\n    };\n    \n    const newState = listReducer([entity], action);\n    expect(newState).toMatchObject([{...entity, description: 'newDescription'}])\n  });\n\n});\n"
  },
  {
    "path": "quix-frontend/shared/entities/common/create-reducer.ts",
    "content": "import {Reducer, BaseAction, AnyAction} from './common-types';\nimport {replaceWith} from '../../utils/utils';\n\nconst creatingReducer = <T extends {id: string; dateUpdated?: number}, A extends BaseAction = AnyAction>(\n  entityName: string,\n  entityTransformer = (x: any) => x\n): Reducer<T, A> =>\n  (state, action_) => {\n    const action = action_ as AnyAction;\n\n    switch (action.type) {\n      case `${entityName}.create`: {\n        if (action[entityName]) {\n          const owner = action.user ? {owner: action.user} : {};\n          return {...entityTransformer(action[entityName]), ...owner};\n        }\n\n        break;\n      }\n      default:\n    }\n\n    return state;\n  }\n\nconst deletingReducer = <T extends {id: string; dateUpdated?: number}, A extends BaseAction = AnyAction>(\n  entityName: string\n): Reducer<T, A> =>\n  (state, action_) => {\n    const action = action_ as AnyAction;\n\n    switch (action.type) {\n      case `${entityName}.delete`:\n        return state;\n      default:\n    }\n\n    return state;\n  }\n\nconst updatingReducer = <T extends {id: string; dateUpdated?: number}, A extends BaseAction = AnyAction>(\n  entityName: string\n): Reducer<T, A> =>\n  (state, action_) => {\n    const action = action_ as AnyAction;\n\n    if (action.type.startsWith(`${entityName}.update`) && state && state.id === action.id) {\n      const prop = action.type.split('.')[2];\n\n      if (prop && typeof action[prop] !== 'undefined') {\n        state.dateUpdated = action.dateCreated || Date.now();\n        return {...state as any, [prop]: action[prop]};\n      }\n    }\n\n    return state;\n  }\n\nconst listReducer = <T extends {id: string}, A extends BaseAction = AnyAction>(\n  entityOrMap: string | Record<string, Reducer<T, A>>,\n  reducer: Reducer<T, A> = x => x,\n  options: {\n    createIfNull: boolean;\n    delete: boolean;\n  }\n) => (s: T[], a: A) => {\n  const entityMap = typeof entityOrMap === 'string' ? {[entityOrMap]: reducer} : entityOrMap;\n\n  const fn = (state: T[], action: A) => {\n    const [entityName, actionType] = action.type.split('.');\n    const entityReducer = entityMap[entityName];\n\n    if (!entityReducer) {\n      return state;\n    }\n\n    switch (actionType) {\n      case 'create':\n        state = !state && options.createIfNull ? [] : state;\n        return state && [...state, entityReducer(undefined, action) as T];\n      case 'delete':\n        if (options.delete) {\n          return state && state.filter(item => item.id !== action.id);\n        }\n        break;\n      case 'update':\n        return state && replaceWith(state, {id: action.id}, item => entityReducer(item, action));\n      default:\n    }\n\n    return state;\n  };\n\n  return fn(s, a);\n}\n\nexport const composeReducers = <T extends {id: string}, A extends BaseAction = AnyAction>(\n  ...args: Reducer<T, A>[]\n): Reducer<T, A> => (state, action) => args.reduce((s, reducer) => reducer(s, action), state);\n\nexport const createReducer = <T extends {id: string; dateUpdated?: number}, A extends BaseAction = AnyAction>(\n  entityName: string,\n  entityTransformer = (x: any) => x\n): Reducer<T, A> => composeReducers(\n  creatingReducer(entityName, entityTransformer),\n  deletingReducer(entityName),\n  updatingReducer(entityName),\n);\n\nexport const createClientReducer = <T extends {id: string; dateUpdated?: number}, A extends BaseAction = AnyAction>(\n  entityName: string\n): Reducer<T, A> => composeReducers(\n  updatingReducer(entityName),\n);\n\nexport const createListReducer = <T extends {id: string}, A extends BaseAction = AnyAction>(\n  entityOrMap: string | Record<string, Reducer<T, A>>,\n  reducer: Reducer<T, A> = x => x\n) => listReducer(entityOrMap, reducer, {createIfNull: true, delete: true});\n\nexport const createClientListReducer = <T extends {id: string}, A extends BaseAction = AnyAction>(\n  entityOrMap: string | Record<string, Reducer<T, A>>,\n  reducer: Reducer<T, A> = x => x,\n  options: {\n    delete: boolean;\n  } = {delete: true}\n) => listReducer(entityOrMap, reducer, {createIfNull: false, delete: options.delete});\n"
  },
  {
    "path": "quix-frontend/shared/entities/deleted-notebook/actions.ts",
    "content": "import { IDeletedNotebook } from './types';\nimport { ExtractActionTypes, ExtractActions } from '../common/actions';\n\nexport const DeletedNotebookActions = {\n  createDeletedNotebook: (id: string, deletedNotebook: IDeletedNotebook) => ({\n    type: 'deletedNotebook.create' as const,\n    deletedNotebook,\n    id,\n  }),\n\n  deleteDeletedNotebook: (id: string) => ({\n    type: 'deletedNotebook.delete' as const,\n    id,\n  }),\n\n  restoreDeletedNotebook: (id: string) => ({\n    type: 'deletedNotebook.restore' as const,\n    id,\n  }),\n};\n\nexport type DeletedNotebookActions = ExtractActions<\n  typeof DeletedNotebookActions\n>;\nexport type DeletedNotebookActionTypes = ExtractActionTypes<\n  typeof DeletedNotebookActions\n>;\nexport const DeletedNotebookActionTypes = ExtractActionTypes(\n  DeletedNotebookActions\n);\n"
  },
  {
    "path": "quix-frontend/shared/entities/deleted-notebook/deleted-notebook.ts",
    "content": "import uuid from 'uuid/v4';\nimport {IDeletedNotebook} from './types';\nimport {IFilePathItem} from '../file/types';\nimport {createEmptyIUser} from '../user/user';\nimport {IUser} from '../user';\n\n\nexport const createDeletedNotebook = (path: IFilePathItem[] = [], props: Partial<IDeletedNotebook> = {}, user: IUser = createEmptyIUser('')): IDeletedNotebook => ({\n  id: uuid(),\n  name: 'Deleted notebook',\n  notes: [],\n  isLiked: false,\n  path,\n  owner: user.id,\n  ownerDetails: user,\n  dateCreated: Date.now(),\n  dateUpdated: Date.now(),\n  dateDeleted: Date.now(),\n  ...props\n});\n"
  },
  {
    "path": "quix-frontend/shared/entities/deleted-notebook/index.ts",
    "content": "export { IDeletedNotebook } from './types';\nexport { clientDeletedNotebookListReducer as clientDeletedNotebookReducer, deletedNotebookReducer as deletedNotebookReducer } from './reducer';\nexport { DeletedNotebookActionTypes, DeletedNotebookActions } from './actions'\nexport { createDeletedNotebook } from './deleted-notebook'\n"
  },
  {
    "path": "quix-frontend/shared/entities/deleted-notebook/reducer.ts",
    "content": "import { createClientListReducer, createReducer } from '../common/create-reducer';\nimport { IDeletedNotebook } from './types';\n\nexport const deletedNotebookReducer = \n  createReducer<IDeletedNotebook>('deletedNotebook');\n\nexport const clientDeletedNotebookListReducer =\n  createClientListReducer<IDeletedNotebook>('deletedNotebook');\n\n\n"
  },
  {
    "path": "quix-frontend/shared/entities/deleted-notebook/types.ts",
    "content": "import { INotebook } from '../notebook';\n\nexport interface IDeletedNotebook extends INotebook {\n  dateDeleted: number;\n}\n"
  },
  {
    "path": "quix-frontend/shared/entities/file/actions.ts",
    "content": "import {IFile, IFilePathItem} from './types';\nimport {ExtractActionTypes, ExtractActions} from '../common/actions';\n\nexport const FileActions = {\n  createFile: (id: string, file: IFile) => ({\n    type: 'file.create' as const,\n    id,\n    file\n  }),\n\n  deleteFile: (id: string) => ({\n    type: 'file.delete' as const,\n    id\n  }),\n\n  moveFile: (id: string, newPath: IFilePathItem[]) => ({\n    type: 'file.update.path' as const,\n    id,\n    path: newPath\n  }),\n\n  updateName: (id: string, name: string) => ({\n    type: 'file.update.name' as const,\n    id,\n    name\n  }),\n\n  toggleIsLiked: (id: string, isLiked: boolean) => ({\n    type: 'file.update.isLiked' as const,\n    id,\n    isLiked\n  }),\n}\n\nexport type FileActions = ExtractActions<typeof FileActions>\nexport type FileActionTypes = ExtractActionTypes<typeof FileActions>\nexport const FileActionTypes = ExtractActionTypes(FileActions);\n"
  },
  {
    "path": "quix-frontend/shared/entities/file/file.ts",
    "content": "import uuid from 'uuid/v4';\nimport {IFile, FileType, IFilePathItem} from './types';\nimport {IUser} from '../user';\nimport {createEmptyIUser} from '../user/user';\n\nconst file = (type: FileType, path: IFilePathItem[] = [], props: Partial<IFile> = {}, user: IUser = createEmptyIUser('')): IFile => ({\n  id: uuid(),\n  name: `New ${type}`,\n  type,\n  path,\n  isLiked: false,\n  owner: user.id,\n  ownerDetails: user,\n  dateCreated: Date.now(),\n  dateUpdated: Date.now(),\n  ...props\n})\n\nexport const createFolder = (path: IFilePathItem[] = [], props: Partial<IFile> = {}): IFile => file(FileType.folder, path, props);\nexport const createFile = (path: IFilePathItem[] = [], props: Partial<IFile> = {}): IFile => file(FileType.notebook, path, props);\n"
  },
  {
    "path": "quix-frontend/shared/entities/file/index.ts",
    "content": "export {FileActions, FileActionTypes} from './actions';\nexport {FileType, IFile, IFilePathItem} from './types';\nexport {fileReducer, clientFileReducer, fileListReducer, clientFileListReducer} from './reducer'\nexport {createFile, createFolder} from './file'"
  },
  {
    "path": "quix-frontend/shared/entities/file/reducer.ts",
    "content": "import {last, remove} from 'lodash';\nimport {createReducer, composeReducers, createListReducer, createClientReducer, createClientListReducer} from '../common/create-reducer';\nimport {INotebook, clientNotebookReducer} from '../notebook';\nimport {createFile} from './file';\nimport {IFilePathItem, IFile, FileType} from './types';\nimport {FileActionTypes} from './actions';\n\nconst moveFile = (files: IFile[], id: string, path: IFilePathItem[]) => {\n  const file = files.find(f => f.id === id);\n\n  if (file) {\n    file.path = path;\n\n    if (file.type === FileType.folder) {\n      files.filter(f =>\n        // tslint:disable-next-line: no-non-null-assertion\n        f.path.length && last(f.path)!.id === id).forEach(f => \n          moveFile(files, f.id, [...path, {id: file.id, name: file.name}]));\n    }\n  }\n\n  return files;\n}\n\nconst deleteFile = (files: IFile[], id: string) => {\n  const file = remove(files, {id})[0];\n\n  if (file && file.type === FileType.folder) {\n    files.filter(f => \n      // tslint:disable-next-line: no-non-null-assertion\n      f.path.length && last(f.path)!.id === id).forEach(f => \n        deleteFile(files, f.id));\n  }\n\n  return files;\n}\n\nexport const fileReducer = composeReducers(\n  createReducer('file'),\n  createReducer('notebook', (notebook: INotebook) => createFile(notebook.path, {\n    id: notebook.id,\n    name: notebook.name\n  }))\n);\n\nexport const clientFileReducer = composeReducers(\n  createClientReducer('file'),\n  clientNotebookReducer\n);\n\nexport const fileListReducer = composeReducers(\n  createListReducer('file', fileReducer) as any,\n  createListReducer('notebook', fileReducer) as any\n);\n\nexport const clientFileListReducer = composeReducers(\n  createClientListReducer('file', fileReducer, {delete: false}) as any,\n  createClientListReducer('notebook', fileReducer) as any,\n  ((state: IFile[], action: any) => {\n    switch (action.type) {\n      case FileActionTypes.moveFile:\n        return state && [...moveFile(state, action.id, action.path)];\n      case FileActionTypes.deleteFile:\n        return state && [...deleteFile(state, action.id)];\n      default: \n    }\n\n    return state;\n  }) as any\n);\n"
  },
  {
    "path": "quix-frontend/shared/entities/file/types.ts",
    "content": "import {IEntity} from '../common/common-types';\n\nexport enum FileType {\n  folder = 'folder',\n  notebook = 'notebook'\n}\n\nexport interface IFile extends IEntity {\n  type: FileType;\n  path: IFilePathItem[];\n  isLiked: boolean;\n}\n\nexport interface IFilePathItem {\n  id: string;\n  name: string;\n}\n"
  },
  {
    "path": "quix-frontend/shared/entities/folder/folder.ts",
    "content": "import uuid from 'uuid/v4';\nimport {IFolder} from './types';\nimport {IFilePathItem} from '../file';\nimport {IUser} from '../user';\nimport {createEmptyIUser} from '../user/user';\n\nexport const createFolderPayload = (path: IFilePathItem[] = [], props: Partial<IFolder> = {}, user: IUser = createEmptyIUser('')): IFolder => ({\n  id: uuid(),\n  name: `New folder`,\n  path,\n  files: [],\n  isLiked: false,\n  owner: user.id,\n  ownerDetails: user,\n  dateCreated: Date.now(),\n  dateUpdated: Date.now(),\n  ...props\n});\n"
  },
  {
    "path": "quix-frontend/shared/entities/folder/index.ts",
    "content": "export {IFolder} from './types';\nexport {createFolderPayload} from './folder';"
  },
  {
    "path": "quix-frontend/shared/entities/folder/types.ts",
    "content": "import {IEntity} from '../common/common-types';\nimport {IFilePathItem} from '../file';\n\nexport interface IFolder extends IEntity {\n  path: IFilePathItem[];\n  files: IFilePathItem[];\n  isLiked: boolean;\n}\n"
  },
  {
    "path": "quix-frontend/shared/entities/history/actions.ts",
    "content": "import { IHistory } from './types';\nimport { ExtractActionTypes, ExtractActions } from '../common/actions';\n\nexport const HistoryActions = {\n  createHistory: (id: string, history: IHistory) => ({\n    type: 'history.create' as const,\n    history,\n    id\n  }),\n};\n\nexport type HistoryActions = ExtractActions<typeof HistoryActions>;\nexport type HistoryActionTypes = ExtractActionTypes<typeof HistoryActions>;\nexport const HistoryActionTypes = ExtractActionTypes(HistoryActions);\n"
  },
  {
    "path": "quix-frontend/shared/entities/history/history.ts",
    "content": "import uuid from 'uuid/v4';\nimport { IHistory } from './types';\n\nexport const createHistory = (props: Partial<IHistory> = {}): IHistory => ({\n  id: uuid(),\n  email: 'local@quix.com',\n  query: [],\n  moduleType: 'presto',\n  startedAt: '',\n  ...props\n});\n"
  },
  {
    "path": "quix-frontend/shared/entities/history/index.ts",
    "content": "export { IHistory } from './types';\nexport { createHistory } from './history';\nexport { HistoryActionTypes, HistoryActions } from './actions';\n"
  },
  {
    "path": "quix-frontend/shared/entities/history/types.ts",
    "content": "export interface IHistory {\n  id: string;\n  email: string;\n  query: string[];\n  moduleType: string;\n  startedAt: string;\n}\n"
  },
  {
    "path": "quix-frontend/shared/entities/note/actions.ts",
    "content": "import {ExtractActionTypes, ExtractActions} from '../common/actions';\nimport {INote} from './types';\n\nexport const NoteActions = {\n  updateName: (id: string, name: string) => ({\n    type: 'note.update.name' as const,\n    name,\n    id\n  }),\n\n  updateContent: (id: string, content: any, richContent?: any) => ({\n    type: 'note.update.content' as const,\n    id,\n    content,\n    richContent\n  }),\n\n  move: (id: string, newNotebookId: string) => ({\n    type: 'note.move' as const,\n    id,\n    newNotebookId\n  }),\n\n  addNote: (id: string, note: INote) => {\n    return {\n      type: 'note.create' as const,\n      id,\n      note\n    };\n  },\n\n  deleteNote: (id: string) => ({\n    type: 'note.delete' as const,\n    id\n  }),\n\n  reorderNote: (id: string, to: number) => ({\n    type: 'note.reorder' as const,\n    id,\n    to\n  }),\n}\n\nexport type NoteActions = ExtractActions<typeof NoteActions>;\nexport type NoteActionT<T extends NoteActionTypes> = NoteActions & {type: T};\nexport type NoteActionTypes = ExtractActionTypes<typeof NoteActions>;\nexport const NoteActionTypes = ExtractActionTypes(NoteActions);\n"
  },
  {
    "path": "quix-frontend/shared/entities/note/index.ts",
    "content": "export {NoteActions, NoteActionTypes} from './actions';\nexport {INote, IBaseNote} from './types';\nexport {noteReducer, clientNoteReducer, noteListReducer, clientNoteListReducer} from './reducer'\nexport {createNote} from './note'"
  },
  {
    "path": "quix-frontend/shared/entities/note/note.ts",
    "content": "import uuid from 'uuid/v4';\nimport {INote} from './types';\n\nexport const createNote = (notebookId: string, props: Partial<INote> = {}): INote => ({\n  id: uuid(),\n  notebookId,\n  name: 'New note',\n  type: 'presto',\n  content: '\\n',\n  owner: '',\n  dateCreated: Date.now(),\n  dateUpdated: Date.now(),\n  ...props as any\n});\n"
  },
  {
    "path": "quix-frontend/shared/entities/note/reducer.ts",
    "content": "import { INote } from './types';\nimport {\n  createReducer,\n  createClientReducer,\n  composeReducers,\n  createListReducer,\n  createClientListReducer,\n} from '../common/create-reducer';\nimport { NoteActions, NoteActionTypes } from './actions';\nimport { AnyAction } from '../common/common-types';\n\nconst commonReducer = (state: INote | undefined, action: NoteActions) => {\n  switch (action.type) {\n    case NoteActionTypes.move:\n      return state && { ...state, notebookId: action.newNotebookId };\n    case NoteActionTypes.updateContent:\n      // update of \"plain text\" content happens in the default reducer\n      if (state) {\n        state.dateUpdated = (action as AnyAction).dateCreated || Date.now();\n        return { ...state, richContent: action.richContent };\n      }\n      return state;\n    default:\n      return state;\n  }\n};\n\nexport const noteReducer = composeReducers(\n  commonReducer,\n  createReducer('note')\n);\n\nexport const clientNoteReducer = composeReducers(\n  commonReducer,\n  createClientReducer('note')\n);\n\nexport const noteListReducer = composeReducers(\n  createListReducer('note', createReducer('note')) as any\n);\n\nexport const clientNoteListReducer = composeReducers(\n  createClientListReducer('note', createReducer('note')) as any\n);\n"
  },
  {
    "path": "quix-frontend/shared/entities/note/types.ts",
    "content": "import {IEntity} from '../common/common-types';\n\ntype Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;\n\nexport interface IBaseNote extends Omit<IEntity, 'ownerDetails'> {\n  notebookId: string;\n  type: string;\n  content: string;\n  richContent?: Record<string, any>,\n  owner: string;\n}\n\nexport type INote = IBaseNote;"
  },
  {
    "path": "quix-frontend/shared/entities/notebook/actions.ts",
    "content": "import { INotebook } from './types';\nimport { ExtractActionTypes, ExtractActions } from '../common/actions';\nimport { IFilePathItem } from '../file';\n\nexport const NotebookActions = {\n  createNotebook: (id: string, notebook: INotebook) => ({\n    type: 'notebook.create' as const,\n    notebook,\n    id,\n  }),\n\n  deleteNotebook: (id: string) => ({\n    type: 'notebook.delete' as const,\n    id,\n  }),\n\n  deleteNotebookNotes: (id: string) => ({\n    type: 'notebook.deleteNotes' as const,\n    id,\n  }),\n\n  moveNotebook: (id: string, newPath: IFilePathItem[]) => ({\n    type: 'notebook.update.path' as const,\n    id,\n    path: newPath,\n  }),\n\n  updateName: (id: string, name: string) => ({\n    type: 'notebook.update.name' as const,\n    name,\n    id,\n  }),\n\n  toggleIsLiked: (id: string, isLiked: boolean) => ({\n    type: 'notebook.update.isLiked' as const,\n    id,\n    isLiked,\n  }),\n};\n\nexport type NotebookActions = ExtractActions<typeof NotebookActions>;\nexport type NotebookActionTypes = ExtractActionTypes<typeof NotebookActions>;\nexport const NotebookActionTypes = ExtractActionTypes(NotebookActions);\n"
  },
  {
    "path": "quix-frontend/shared/entities/notebook/index.ts",
    "content": "export {NotebookActions, NotebookActionTypes} from './actions';\nexport {INotebook} from './types';\nexport {notebookReducer, clientNotebookReducer} from './reducer'\nexport {createNotebook, createNotebookWithNote} from './notebook'"
  },
  {
    "path": "quix-frontend/shared/entities/notebook/notebook.ts",
    "content": "import uuid from 'uuid/v4';\nimport {INotebook} from './types';\nimport {createNote} from '../note/note';\nimport {IFilePathItem} from '../file/types';\nimport {createEmptyIUser} from '../user/user';\nimport {IUser} from '../user';\n\n\nexport const createNotebook = (path: IFilePathItem[] = [], props: Partial<INotebook> = {}, user: IUser = createEmptyIUser('')): INotebook => ({\n  id: uuid(),\n  name: 'New notebook',\n  notes: [],\n  isLiked: false,\n  path,\n  owner: user.id,\n  ownerDetails: user,\n  dateCreated: Date.now(),\n  dateUpdated: Date.now(),\n  ...props\n});\n\nexport const createNotebookWithNote = (path: IFilePathItem[] = [], props: Partial<INotebook> = {}) => ((notebook: INotebook): INotebook => ({\n  ...notebook,\n  notes: [createNote(notebook.id)],\n}))(createNotebook(path, props));\n"
  },
  {
    "path": "quix-frontend/shared/entities/notebook/reducer.ts",
    "content": "import {createReducer, createClientReducer} from '../common/create-reducer';\nimport {INotebook} from './types';\n\nexport const notebookReducer = createReducer<INotebook>('notebook');\nexport const clientNotebookReducer = createClientReducer<INotebook>('notebook');\n"
  },
  {
    "path": "quix-frontend/shared/entities/notebook/types.ts",
    "content": "import {INote} from '../note/types';\nimport {IEntity} from '../common/common-types';\nimport {IFilePathItem} from '../file/types';\n\nexport interface INotebook extends IEntity {\n  notes: INote[];\n  path: IFilePathItem[];\n  isLiked: boolean;\n}\n"
  },
  {
    "path": "quix-frontend/shared/entities/trash-bin/actions.ts",
    "content": "import { ExtractActionTypes, ExtractActions } from '../common/actions';\n\nexport const TrashBinActions = {\n  moveNotebookToTrashBin: (id: string) => ({\n    type: 'trashBin.addNotebook' as const,\n    id,\n  }),\n\n  moveFolderToTrashBin: (id: string) => ({\n    type: 'trashBin.addFolderContent' as const,\n    id,\n  }),\n\n  permanentlyDeleteNotebook: (id: string) => ({\n    type: 'trashBin.deleteNotebook' as const,\n    id,\n  }),\n\n  restoreDeletedNotebook: (id: string, folderId: string) => ({\n    type: 'trashBin.restoreNotebook' as const,\n    folderId,\n    id,\n  }),\n};\n\nexport type TrashBinActions = ExtractActions<typeof TrashBinActions>;\nexport type TrashBinActionTypes = ExtractActionTypes<typeof TrashBinActions>;\nexport const TrashBinActionTypes = ExtractActionTypes(TrashBinActions);\n"
  },
  {
    "path": "quix-frontend/shared/entities/trash-bin/index.ts",
    "content": "export { TrashBinActions, TrashBinActionTypes } from './actions';\n"
  },
  {
    "path": "quix-frontend/shared/entities/trash-bin/types.ts",
    "content": ""
  },
  {
    "path": "quix-frontend/shared/entities/user/actions.ts",
    "content": "import {IUser} from './types';\nimport {ExtractActionTypes, ExtractActions} from '../common/actions';\n\nexport const UserActions = {\n  createNewUser: (id: string, user: IUser) => ({\n    type: 'user.create' as const,\n    newUser: user,\n    id,\n  }),\n  updateUser: (id: string, avatar: string, name: string, email: string, changeUserCreated?: Date) => ({\n    type: 'user.update' as const,\n    name,\n    email,\n    avatar,\n    id,\n    changeUserCreated\n  }),\n}\n\nexport type UserActions = ExtractActions<typeof UserActions>\nexport type UserActionTypes = ExtractActionTypes<typeof UserActions>\nexport const UserActionTypes = ExtractActionTypes(UserActions);\n"
  },
  {
    "path": "quix-frontend/shared/entities/user/index.ts",
    "content": "export {IUser} from './types';\nexport {createUser, createEmptyIUser} from './user';\nexport {UserActionTypes, UserActions} from './actions';"
  },
  {
    "path": "quix-frontend/shared/entities/user/types.ts",
    "content": "export interface IUser {\n  email: string;\n  id: string;\n  name: string;\n  avatar: string;\n  rootFolder: string;\n  dateUpdated: number;\n  dateCreated: number;\n}\n"
  },
  {
    "path": "quix-frontend/shared/entities/user/user.ts",
    "content": "import uuid from 'uuid/v4';\nimport {IUser} from './types';\n\nexport const createUser = (props: Partial<IUser> = {}): IUser => ({\n  id: uuid(),\n  name: 'Local User',\n  email: 'local@quix.com',\n  avatar: '',\n  rootFolder: '',\n  dateCreated: 0,\n  dateUpdated: 0,\n  ...props\n});\n\nexport const createEmptyIUser = (userId: string = ''): IUser => ({\n  id: userId,\n  name: '',\n  email: userId,\n  avatar: '',\n  rootFolder: '',\n  dateCreated: 0,\n  dateUpdated: 0,\n});"
  },
  {
    "path": "quix-frontend/shared/index.ts",
    "content": "export { IEntity } from './entities/common/common-types';\nexport { composeReducers } from './entities/common/create-reducer';\n\nexport {\n  INotebook,\n  NotebookActions,\n  NotebookActionTypes,\n  createNotebook,\n  createNotebookWithNote,\n  notebookReducer,\n  clientNotebookReducer,\n} from './entities/notebook';\n\nexport {\n  IDeletedNotebook,\n  DeletedNotebookActions,\n  DeletedNotebookActionTypes,\n  deletedNotebookReducer,\n  clientDeletedNotebookReducer,\n  createDeletedNotebook,\n} from './entities/deleted-notebook';\n\nexport { TrashBinActionTypes, TrashBinActions } from './entities/trash-bin';\n\nexport {\n  IFile,\n  IFilePathItem,\n  FileType,\n  FileActions,\n  FileActionTypes,\n  createFile,\n  createFolder,\n  fileReducer,\n  clientFileReducer,\n  fileListReducer,\n  clientFileListReducer,\n} from './entities/file';\n\nexport { IFolder, createFolderPayload } from './entities/folder';\n\nexport {\n  INote,\n  NoteActions,\n  NoteActionTypes,\n  createNote,\n  noteReducer,\n  clientNoteReducer,\n  noteListReducer,\n  clientNoteListReducer,\n} from './entities/note';\n\nexport {\n  ClientConfigHelper,\n  ComponentConfiguration,\n} from './config-helper/config-helper';\n\nexport {\n  ModuleEngineToSyntaxMap,\n  ModuleEngineType,\n  ModuleComponentType,\n  TModuleComponentType,\n} from './config-helper/consts';\n\nexport {\n  IUser,\n  createEmptyIUser,\n  createUser,\n  UserActionTypes,\n  UserActions,\n} from './entities/user';\n\nexport {\n  IHistory,\n  createHistory,\n  HistoryActionTypes,\n  HistoryActions,\n} from './entities/history';\n\nexport {\n  SearchTypes,\n  SpecialSearchTypes,\n  SearchTextType,\n  ContentSearch,\n  SearchQuery,\n  SearchResult,\n} from './types/search-types';\n"
  },
  {
    "path": "quix-frontend/shared/package.json",
    "content": "{\n  \"name\": \"@wix/quix-shared\",\n  \"version\": \"1.0.16\",\n  \"license\": \"MIT\",\n  \"description\": \"Presto-based notebook manager\",\n  \"author\": {\n    \"name\": \"Anton Podolsky\",\n    \"email\": \"antonp@wix.com\"\n  },\n  \"contributors\": [\n    {\n      \"name\": \"Aviad Hadad\",\n      \"email\": \"aviadh@wix.com\"\n    }\n  ],\n  \"scripts\": {\n    \"test\": \"jest\",\n    \"test:ci\": \"jest\",\n    \"build\": \"tsc -b .\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"files\": [\n    \"*\"\n  ],\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"devDependencies\": {\n    \"@types/jest\": \"^24.0.11\",\n    \"@types/lodash\": \"^4.14.123\",\n    \"@types/uuid\": \"^8.3.0\",\n    \"jest\": \"^26.0.0\",\n    \"ts-jest\": \"^26.0.0\",\n    \"typescript\": \"^4.0.0\"\n  },\n  \"dependencies\": {\n    \"lodash\": \"^4.17.11\",\n    \"tslib\": \"^2.3.0\",\n    \"uuid\": \"^3.3.2\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"./\",\n    \"testRegex\": \".spec.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"coverageDirectory\": \"./coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "quix-frontend/shared/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"target\": \"es5\",\n    \"noUnusedLocals\": true,\n    \"lib\": [\n      \"es2016\"\n    ],\n    \"importHelpers\": true,\n    \"esModuleInterop\": true,\n    \"downlevelIteration\": true,\n    \"composite\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"strict\": true\n  }\n}"
  },
  {
    "path": "quix-frontend/shared/types/search-types.ts",
    "content": "import {INote} from '../entities/note/types';\n\nexport enum SearchTypes {\n  user = \"owner\",\n  type = \"type\",\n  noteName = \"name\",\n  content = \"content\",\n}\n\nexport type SpecialSearchTypes =\n  | SearchTypes.noteName\n  | SearchTypes.type\n  | SearchTypes.user;\n\nexport enum SearchTextType {\n  PHRASE,\n  WORD,\n}\n\nexport interface ContentSearch {\n  type: SearchTextType;\n  text: string;\n}\n\nexport interface SearchQuery {\n  fullText: string;\n  [SearchTypes.content]: ContentSearch[];\n  [SearchTypes.user]?: string;\n  [SearchTypes.noteName]?: string;\n  [SearchTypes.type]?: string;\n}\n\nexport interface SearchResult {\n  notes: INote[];\n  count: number;\n  term: SearchQuery;\n};\n"
  },
  {
    "path": "quix-frontend/shared/utils/utils.ts",
    "content": "import {findIndex} from 'lodash';\n\nexport const replaceWith = (collection: any[], predicate: Record<string, any>, value: (current: any) => any) => {\n  const index = findIndex(collection, predicate);\n\n  if (index === -1) {\n    return collection;\n  }\n\n  collection.splice(index, 1, value(collection[index]));\n\n  return [...collection];\n}\n"
  },
  {
    "path": "terraform/README.md",
    "content": "# Terraform AWS for QUIX-environment\nThis package allows you to easily create your own QUIX on Amazon Web Services with\n[Terraform][https://www.terraform.io/downloads.html] project that builds [VPC\nwith Public and Private Subnets][https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html#VPC_Scenario2_Implementation] from the AWS documentation.\n\n## Getting Started\n\n**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.**\n\n\n# Getting Started\n\n## Pre Reqs\n\nWe use Terraform to automate parts of the infrastructure for your CircleCI Server install, so you will need to install this first:\n\n* [Terraform](https://www.terraform.io/downloads.html)\n\n**Note: This script only supports terraform version 0.12 and higher. Please update to the most recent version before fetching from upstream.**\n\n\n## Installation\n\n### Basic\n\n1. Clone or download this repository\n\n```bash\ngit clone git@github.com:wix/quix.git\n```\n2. Run `terraform init` to install Terraform plugins\n3. Run `terraform apply`\n4. Visit ALB adress supplied at the end of the Terraform output\n5. Follow instructions to setup and configure your installation\n\n### Extra\n\n#### Prepare right [Shared Credentials file for Terraform](https://www.terraform.io/docs/providers/aws/index.html#shared-credentials-file)\n\n  > 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\n  > 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\n  > 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\n  > AWS_PROFILE environment variable:\n\n~/.aws/credentials\n```\n  [default]\n  aws_access_key_id=AKEXAMPLEEXAMPLEEXAMPLE\n  aws_secret_access_key=EXAMPLE/K7MDENG/bPxRfiCYEXAMPLEKEY\n```\n\n~/.aws/config\n```\n  [default]\n  region=us-east-1\n  output=json\n```  \n\n\n### We are using [Terraform S3 BackEnd](https://www.terraform.io/docs/backends/types/s3.html)\n* bucket = \"tf-state-backend-bucket\"\n* key            = \"terraform.tfstate\"\n* dynamodb_table = \"terraform-lock\"\n* region = \"us-east-1\"\n* key = \"example.tfstate\"\n\n## 2. Usage\n### 2.1 Import\n```\nterraform init\n```\n### 2.2 Apply Plan\n```\nterraform plan -out vpc.plan &&  terraform apply \"vpc.plan\"\n```\n\n### Plan\n\n```\nterraform plan -var-file terraform.tfvars\n```\n\n`terraform.tfvars` holds variables which should be overriden with valid ones.\n\n### Apply\n\n```\nterraform apply -var-file terraform.tfvars\n```\n\n### Destroy\n\n```\nterraform destroy -var-file terraform.tfvars\n```\n\n\n## Links\n* [Terraform](http://terraform.io)\n* [Terraform VPC](https://nickcharlton.net/posts/terraform-aws-vpc.html)\n* [scenario_two](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html)\n* [AWS documentation](http://aws.amazon.com/documentation/)\n* [blog_post](https://nickcharlton.net/posts/terraform-aws-vpc.html)\n* [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)\n## Author\n\nCopyright (c) 2019 Valeriy Soloviov <weldpua2008@gmail.com>.\n"
  },
  {
    "path": "terraform/acme_certificate.tf",
    "content": "# ----------------------------------------------------------------\n# Inputs required to do an initial registration (aka create an\n# account) with the ACME provider (Let's Encrypt)\n# ----------------------------------------------------------------\n\n\n\n# Create an on the fly private key for the registration\n# (not the certificate). Could simply be imported as well\nresource \"tls_private_key\" \"acme_registration_private_key\" {\n  count     = var.enable_acme_ssl ? 1 : 0\n  algorithm = \"RSA\"\n}\n\n# Set up a registration using the registration private key\nresource \"acme_registration\" \"reg\" {\n  count           = var.enable_acme_ssl ? 1 : 0\n  account_key_pem = tls_private_key.acme_registration_private_key[0].private_key_pem\n  email_address   = var.acme_registration_email\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\n# ----------------------------------------------------------------\n# Inputs required to request a new cert from ACME provider\n# ----------------------------------------------------------------\n\n# Create a certificate\nresource \"acme_certificate\" \"certificate\" {\n  count                     = var.enable_acme_ssl ? 1 : 0\n  account_key_pem           = tls_private_key.acme_registration_private_key[0].private_key_pem\n  common_name               = var.acme_certificate_common_name\n  subject_alternative_names = [var.dns_domain_name]\n  min_days_remaining        = var.min_days_remaining\n  recursive_nameservers     = [\"8.8.8.8:53\"]\n\n  dns_challenge {\n    provider = \"route53\"\n\n    # Without this explicit config, the ACME provider (which uses lego\n    # under the covers) will look for environment variables to use.\n    # These environment variable names happen to overlap with the names\n    # also required by the native Terraform AWS provider, however is not\n    # guaranteed. You may want to explicitly configure them here if you\n    # would like to use different credentials to those used by the main\n    # Terraform provider\n    config = {\n      AWS_REGION              = var.aws_region\n      AWS_PROFILE             = var.aws_acme_profile\n      AWS_HOSTED_ZONE_ID      = aws_route53_zone.quix.zone_id\n      AWS_TTL                 = 60\n      AWS_PROPAGATION_TIMEOUT = 120\n    }\n  }\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"aws_acm_certificate\" \"cert\" {\n  count = var.enable_ssl ? 1 : 0\n\n  domain_name               = var.dns_domain_name\n  subject_alternative_names = [\"*.${var.dns_domain_name}\"]\n\n  validation_method = \"DNS\"\n\n  tags = merge(\n    {\n      \"Name\" = \"quix-zone\"\n    },\n    var.tags,\n  )\n\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n\nresource \"aws_acm_certificate_validation\" \"cert\" {\n  count = var.enable_ssl ? 1 : 0\n\n  certificate_arn         = aws_acm_certificate.cert[0].arn\n  validation_record_fqdns = [\"${aws_route53_record.cert_validation[0].fqdn}\"]\n}\n\n\nresource \"aws_iam_server_certificate\" \"alb_cert\" {\n  count             = var.enable_acme_ssl ? 1 : 0\n  name              = \"wild-quix-${formatdate(\"YY-MM-DD\", timestamp())}\"\n  certificate_body  = acme_certificate.certificate[0].certificate_pem\n  certificate_chain = acme_certificate.certificate[0].issuer_pem\n  private_key       = acme_certificate.certificate[0].private_key_pem\n\n  lifecycle {\n    create_before_destroy = true\n    ignore_changes = [\n      # Ignore changes to name, e.g. because it's calculating at execution\n      name\n    ]\n\n  }\n}\n"
  },
  {
    "path": "terraform/aws-tf-backend.tf",
    "content": "data \"aws_caller_identity\" \"current\" {}\n\nresource \"aws_s3_bucket\" \"terraform_state\" {\n  bucket = \"terraform-state.quix-oss\"\n  acl    = \"private\"\n\n  versioning {\n    enabled = true\n  }\n  lifecycle {\n    prevent_destroy = true\n  }\n  tags = merge(\n    {\n      Name        = \"TerraformStateBucket\",\n      Description = \"Terraform state locking bucket for account ${data.aws_caller_identity.current.account_id}.\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_dynamodb_table\" \"tf_backend_state_lock_table\" {\n  # count = true\n  name           = var.tf_dynamodb_lock_table_name\n  read_capacity  = var.tf_lock_table_read_capacity\n  write_capacity = var.tf_lock_table_write_capacity\n  hash_key       = \"LockID\"\n\n  attribute {\n    name = \"LockID\"\n    type = \"S\"\n  }\n\n  tags = merge(\n    {\n      Description = \"Terraform state locking table for account ${data.aws_caller_identity.current.account_id}.\"\n    },\n    var.tags,\n  )\n  lifecycle {\n    prevent_destroy = true\n  }\n}\n"
  },
  {
    "path": "terraform/ecs.tf",
    "content": "/*\n * ECS Cluster for Quix\n *\n */\nresource \"aws_ecs_cluster\" \"main\" {\n  name = \"quix-ecs-cluster\"\n  tags = merge(\n    {\n      \"Name\" = \"alb-tg-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_cloudwatch_log_group\" \"quix-logs\" {\n  name              = \"quix-logs\"\n  retention_in_days = \"14\"\n}\n\n# You can use\n# Presto ALB http://${aws_alb.presto.dns_name}:${var.presto_port}/v1\nlocals {\n  backend_url = \"http%{if var.enable_acme_ssl != false || var.enable_ssl != false}s%{endif}://${var.dns_domain_name}:${var.backend_public_port}\"\n}\n\nresource \"aws_ecs_task_definition\" \"quix\" {\n  family                   = \"quix\"\n  network_mode             = \"awsvpc\"\n  requires_compatibilities = [\"FARGATE\"]\n  cpu                      = var.fargate_cpu * 16\n  memory                   = var.fargate_memory * 32\n  execution_role_arn       = aws_iam_role.ecs_task_role.arn\n  container_definitions    = <<DEFINITION\n[\n  {\n      \"ulimits\": [\n        {\n          \"name\": \"nofile\",\n          \"hardLimit\": 65536,\n          \"softLimit\": 65536\n        },\n        {\n          \"name\": \"nproc\",\n          \"hardLimit\": 2048,\n          \"softLimit\": 2048\n        },\n        {\n          \"name\": \"memlock\",\n          \"hardLimit\": -1,\n          \"softLimit\": -1\n        }\n      ],\n    \"essential\": false,\n    \"cpu\": ${var.fargate_cpu * 8},\n    \"image\": \"${var.quix_backend_image}\",\n    \"memory\": ${var.fargate_memory * 8},\n    \"name\": \"quix-backend\",\n    \"networkMode\": \"awsvpc\",\n    \"portMappings\": [\n      {\n        \"containerPort\": ${var.backend_port},\n        \"hostPort\": ${var.backend_port}\n      }\n    ],\n    \"logConfiguration\": {\n        \"logDriver\": \"awslogs\",\n        \"options\": {\n            \"awslogs-group\": \"${aws_cloudwatch_log_group.quix-logs.name}\",\n            \"awslogs-region\": \"${var.aws_region}\",\n            \"awslogs-stream-prefix\": \"backend\"\n        }\n    },\n    \"environment\": [\n        {\n           \"name\": \"DEMO_MODE\",\n           \"value\": \"true\"\n        },\n        {\n           \"name\": \"MODULES\",\n           \"value\": \"presto\"\n        },\n        {\n            \"name\": \"MODULES_PRESTO_API\",\n            \"value\": \"http://localhost:${var.presto_port}/v1\"\n         },\n        {\n         \"name\": \"MODULES_PRESTO_CATALOG\",\n         \"value\": \"system\"\n        },\n        {\n          \"name\": \"MODULES_PRESTO_SCHEMA\",\n          \"value\": \"runtime\"\n        },\n        {\n           \"name\": \"MODULES_PRESTO_SOURCE\",\n           \"value\": \"quix\"\n       },\n\n       {\n         \"name\": \"BACKEND_INTERNAL_URL\",\n         \"value\": \"http://localhost:${var.backend_port}\"\n       },\n       {\n        \"name\": \"BACKEND_PUBLIC_URL\",\n        \"value\": \"${local.backend_url}\"\n       },\n       {\n         \"name\": \"DB_NAME\",\n         \"value\": \"${aws_ssm_parameter.dbname.value}\"\n       },\n       {\n         \"name\": \"DB_USER\",\n         \"value\": \"${aws_ssm_parameter.dbuser.value}\"\n       },\n       {\n         \"name\": \"DB_PASS\",\n         \"value\": \"${aws_ssm_parameter.dbpwd.value}\"\n       },\n       {\n         \"name\": \"DB_HOST\",\n         \"value\": \"${aws_ssm_parameter.dbhost.value}\"\n        } %{if var.enable_google_sso == true},\n        {\n            \"name\": \"AUTH_TYPE\",\n            \"value\": \"google\"\n        },\n        {\n            \"name\": \"AUTH_COOKIE\",\n            \"value\": \"${var.auth_cookie}\"\n        },\n        {\n            \"name\": \"GOOGLE_SSO_SECRET\",\n            \"value\": \"${aws_ssm_parameter.google_sso_client_secret.value}\"\n        },\n        {\n            \"name\": \"GOOGLE_SSO_CLIENT_ID\",\n            \"value\": \"${aws_ssm_parameter.google_sso_client_id.value}\"\n        },\n        {\n            \"name\": \"AUTH_SECRET\",\n            \"value\": \"${aws_ssm_parameter.auth_secret.value}\"\n        }\n        %{endif}\n    ]\n},\n{\n  \"essential\": true,\n  \"cpu\": ${var.fargate_cpu},\n  \"image\": \"${var.quix_frontend_image}\",\n  \"memory\": ${var.fargate_memory},\n  \"name\": \"quix-frontend\",\n  \"networkMode\": \"awsvpc\",\n  \"portMappings\": [\n    {\n      \"containerPort\": ${var.frontend_port},\n      \"hostPort\": ${var.frontend_port}\n    }\n  ],\n  \"logConfiguration\": {\n      \"logDriver\": \"awslogs\",\n      \"options\": {\n          \"awslogs-group\": \"${aws_cloudwatch_log_group.quix-logs.name}\",\n          \"awslogs-region\": \"${var.aws_region}\",\n          \"awslogs-stream-prefix\": \"frontend\"\n      }\n  },\n  \"environment\": [\n      {\n         \"name\": \"DEMO_MODE\",\n         \"value\": \"true\"\n      },\n      {\n         \"name\": \"MODULES\",\n         \"value\": \"presto\"\n      },\n      {\n        \"name\": \"BACKEND_INTERNAL_URL\",\n        \"value\": \"http://localhost:${var.backend_port}\"\n      },\n      {\n       \"name\": \"BACKEND_PUBLIC_URL\",\n       \"value\": \"${local.backend_url}\"\n      },\n      {\n          \"name\": \"MODULES_PRESTO_API\",\n          \"value\": \"http://localhost:${var.presto_port}/v1\"\n       },\n      {\n       \"name\": \"MODULES_PRESTO_CATALOG\",\n       \"value\": \"system\"\n      },\n      {\n        \"name\": \"MODULES_PRESTO_SCHEMA\",\n        \"value\": \"runtime\"\n      },\n      {\n         \"name\": \"MODULES_PRESTO_SOURCE\",\n         \"value\": \"quix\"\n      },\n      {\n       \"name\": \"DB_NAME\",\n       \"value\": \"${aws_ssm_parameter.dbname.value}\"\n      },\n      {\n       \"name\": \"DB_USER\",\n       \"value\": \"${aws_ssm_parameter.dbuser.value}\"\n      },\n      {\n       \"name\": \"DB_PASS\",\n       \"value\": \"${aws_ssm_parameter.dbpwd.value}\"\n      },\n      {\n       \"name\": \"DB_HOST\",\n       \"value\": \"${aws_ssm_parameter.dbhost.value}\"\n      }%{if var.enable_google_sso == true},\n      {\n          \"name\": \"AUTH_TYPE\",\n          \"value\": \"google\"\n      },\n      {\n          \"name\": \"AUTH_COOKIE\",\n          \"value\": \"${var.auth_cookie}\"\n      },\n      {\n          \"name\": \"GOOGLE_SSO_SECRET\",\n          \"value\": \"${aws_ssm_parameter.google_sso_client_secret.value}\"\n      },\n      {\n          \"name\": \"GOOGLE_SSO_CLIENT_ID\",\n          \"value\": \"${aws_ssm_parameter.google_sso_client_id.value}\"\n      },\n      {\n          \"name\": \"AUTH_SECRET\",\n          \"value\": \"${aws_ssm_parameter.auth_secret.value}\"\n      }\n      %{endif}\n  ]\n}\n%{if var.create_separate_presto != true}\n,{\n\n  \"essential\": true,\n  \"cpu\": ${var.fargate_cpu},\n  \"image\": \"${var.presto_image}\",\n  \"memory\": ${var.fargate_memory * 8},\n  \"name\": \"presto\",\n  \"networkMode\": \"awsvpc\",\n  \"logConfiguration\": {\n      \"logDriver\": \"awslogs\",\n      \"options\": {\n          \"awslogs-group\": \"${aws_cloudwatch_log_group.quix-logs.name}\",\n          \"awslogs-region\": \"${var.aws_region}\",\n          \"awslogs-stream-prefix\": \"presto\"\n      }\n  },\n  \"ulimits\": [\n    {\n      \"name\": \"nofile\",\n      \"hardLimit\": 65536,\n      \"softLimit\": 65536\n    },\n    {\n      \"name\": \"nproc\",\n      \"hardLimit\": 2048,\n      \"softLimit\": 2048\n    },\n    {\n      \"name\": \"memlock\",\n      \"hardLimit\": -1,\n      \"softLimit\": -1\n    }\n  ],\n  \"portMappings\": [\n    {\n      \"containerPort\": ${var.presto_port},\n      \"hostPort\": ${var.presto_port}\n    }\n  ]\n}%{endif}\n]\nDEFINITION\n}\n\n/*\nThe amount (in MiB) of memory used by the task.\n\nIf using the EC2 launch type, this field is optional and any value can be used.\nIf a task-level memory value is specified then the container-level memory value is optional.\nIf using the Fargate launch type, this field is required and you must use one of\nthe following values, which determines your range of valid values for the cpu parameter:\n\n512 (0.5 GB), 1024 (1 GB), 2048 (2 GB) - Available cpu values: 256 (.25 vCPU)\n1024 (1 GB), 2048 (2 GB), 3072 (3 GB), 4096 (4 GB) - Available cpu values: 512 (.5 vCPU)\n2048 (2 GB), 3072 (3 GB), 4096 (4 GB), 5120 (5 GB), 6144 (6 GB), 7168 (7 GB), 8192 (8 GB) - Available cpu values: 1024 (1 vCPU)\nBetween 4096 (4 GB) and 16384 (16 GB) in increments of 1024 (1 GB) - Available cpu values: 2048 (2 vCPU)\nBetween 8192 (8 GB) and 30720 (30 GB) in increments of 1024 (1 GB) - Available cpu values: 4096 (4 vCPU)\n*/\nresource \"aws_ecs_service\" \"quix\" {\n  name            = \"ecs-service-quix\"\n  cluster         = aws_ecs_cluster.main.id\n  task_definition = aws_ecs_task_definition.quix.arn\n  desired_count   = \"1\"\n  launch_type     = \"FARGATE\"\n\n  network_configuration {\n    security_groups = [aws_security_group.ecs_tasks.id, ]\n    subnets         = aws_subnet.private.*.id\n  }\n\n  load_balancer {\n    target_group_arn = aws_alb_target_group.frontend.id\n    container_name   = \"quix-frontend\"\n    container_port   = var.frontend_port\n  }\n  load_balancer {\n    target_group_arn = aws_alb_target_group.backend.id\n    container_name   = \"quix-backend\"\n    container_port   = var.backend_port\n  }\n  /*\n    dedicated ALB for presto\n  load_balancer {\n    target_group_arn = aws_alb_target_group.presto.id\n    container_name   = \"presto\"\n    container_port   = var.presto_port\n  }\n */\n}\n#####\n# Presto Only Service\nresource \"aws_ecs_task_definition\" \"presto\" {\n  count                    = var.create_separate_presto ? 1 : 0\n  family                   = \"presto\"\n  network_mode             = \"awsvpc\"\n  requires_compatibilities = [\"FARGATE\"]\n  cpu                      = var.fargate_cpu * 4\n  memory                   = var.fargate_memory * 8\n  execution_role_arn       = aws_iam_role.ecs_task_role.arn\n  container_definitions    = <<DEFINITION\n[\n{\n  \"essential\": true,\n  \"cpu\": ${var.fargate_cpu},\n  \"image\": \"${var.presto_image}\",\n  \"memory\": ${var.fargate_memory * 8},\n  \"name\": \"presto\",\n  \"networkMode\": \"awsvpc\",\n  \"logConfiguration\": {\n      \"logDriver\": \"awslogs\",\n      \"options\": {\n          \"awslogs-group\": \"${aws_cloudwatch_log_group.quix-logs.name}\",\n          \"awslogs-region\": \"${var.aws_region}\",\n          \"awslogs-stream-prefix\": \"presto\"\n      }\n  },\n  \"ulimits\": [\n    {\n      \"name\": \"nofile\",\n      \"hardLimit\": 65536,\n      \"softLimit\": 65536\n    },\n    {\n      \"name\": \"nproc\",\n      \"hardLimit\": 2048,\n      \"softLimit\": 2048\n    },\n    {\n      \"name\": \"memlock\",\n      \"hardLimit\": -1,\n      \"softLimit\": -1\n    }\n  ],\n  \"portMappings\": [\n    {\n      \"containerPort\": ${var.presto_port},\n      \"hostPort\": ${var.presto_port}\n    }\n  ]\n}\n]\nDEFINITION\n}\n\nresource \"aws_ecs_service\" \"presto\" {\n  count           = var.create_separate_presto ? 1 : 0\n  name            = \"ecs-service-presto\"\n  cluster         = aws_ecs_cluster.main.id\n  task_definition = aws_ecs_task_definition.presto[0].arn\n  desired_count   = \"1\"\n  launch_type     = \"FARGATE\"\n\n  network_configuration {\n    security_groups = [aws_security_group.ecs_tasks.id]\n    subnets         = aws_subnet.private.*.id\n  }\n\n\n  load_balancer {\n    target_group_arn = aws_alb_target_group.presto[0].id\n    container_name   = \"presto\"\n    container_port   = var.presto_port\n  }\n}\n"
  },
  {
    "path": "terraform/iam.tf",
    "content": "/*\n    IAM Settings\n*/\ndata \"aws_iam_policy_document\" \"task-assume-role-policy\" {\n  statement {\n    actions = [\"sts:AssumeRole\"]\n\n    principals {\n      type        = \"Service\"\n      identifiers = [\"ecs-tasks.amazonaws.com\"]\n    }\n  }\n}\n\nresource \"aws_iam_role\" \"ecs_task_role\" {\n  name               = \"ecs_task_role\"\n  path               = \"/system/\"\n  assume_role_policy = data.aws_iam_policy_document.task-assume-role-policy.json\n}\n\nresource \"aws_iam_policy_attachment\" \"ecs_task_role_attach\" {\n  name       = \"ecs-task-role-attach\"\n  roles      = [\"${aws_iam_role.ecs_task_role.name}\"]\n  policy_arn = \"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy\"\n}\n\ndata \"aws_iam_policy_document\" \"autoscaling-assume-role-policy\" {\n  statement {\n    actions = [\"sts:AssumeRole\"]\n\n    principals {\n      type        = \"Service\"\n      identifiers = [\"application-autoscaling.amazonaws.com\"]\n    }\n  }\n}\n\nresource \"aws_iam_role\" \"ecs_autoscale_role\" {\n  name               = \"ecs_autoscale_role\"\n  path               = \"/system/\"\n  assume_role_policy = data.aws_iam_policy_document.autoscaling-assume-role-policy.json\n}\n\nresource \"aws_iam_policy_attachment\" \"ecs_autoscale_role_attach\" {\n  name       = \"ecs-autoscale-role-attach\"\n  roles      = [\"${aws_iam_role.ecs_autoscale_role.name}\"]\n  policy_arn = \"arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole\"\n}\n"
  },
  {
    "path": "terraform/initialize.tf",
    "content": "/*\n    Initialize the remote state with these values.\n    Only need to run this once via terraform init.\n*/\n\nterraform {\n  backend \"s3\" {\n    bucket  = \"terraform-state.quix-oss\"\n    key     = \"quix.tfstate\"\n    region  = \"us-east-1\"\n    encrypt = \"true\"\n    profile = \"quix\"\n    // no lock we are creating dynamodb tables for locking in this global config\n    // we are only run this rarely so skip locking\n    dynamodb_table = \"terraform-lock\"\n\n  }\n}\n"
  },
  {
    "path": "terraform/lb.tf",
    "content": "/*\nApplication Load Balancers configuration.\nThe load balancer distributes incoming application traffic across multiple targets,\nsuch as EC2 instances, ECS container instances.\n*/\nresource \"aws_alb\" \"main\" {\n  name            = \"ecs-quix-alb\"\n  subnets         = aws_subnet.public.*.id\n  security_groups = [aws_security_group.lb.id]\n  tags = merge(\n    {\n      \"Name\" = \"alb-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_alb_listener\" \"frontend_ssl\" {\n  load_balancer_arn = aws_alb.main.id\n  port              = \"443\"\n  protocol          = \"HTTPS\"\n  ssl_policy        = \"ELBSecurityPolicy-2016-08\"\n  certificate_arn   = aws_acm_certificate.cert[0].arn\n\n  default_action {\n    target_group_arn = aws_alb_target_group.frontend.id\n    type             = \"forward\"\n  }\n}\n\n\nresource \"aws_alb_listener\" \"backend_ssl\" {\n  load_balancer_arn = aws_alb.main.id\n  port              = var.backend_public_port\n  protocol          = \"HTTPS\"\n  ssl_policy        = \"ELBSecurityPolicy-2016-08\"\n  certificate_arn   = aws_acm_certificate.cert[0].arn\n\n  default_action {\n    target_group_arn = aws_alb_target_group.backend.id\n    type             = \"forward\"\n  }\n}\n\nresource \"aws_alb_target_group\" \"frontend\" {\n  name        = \"ecs-quix-frontend-alb-tg\"\n  port        = var.frontend_port\n  protocol    = \"HTTP\"\n  vpc_id      = aws_vpc.main.id\n  target_type = \"ip\"\n  tags = merge(\n    {\n      \"Name\" = \"alb-tg-frontend-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_alb_listener\" \"frontend\" {\n  load_balancer_arn = aws_alb.main.id\n  port              = var.frontend_port\n  protocol          = \"HTTP\"\n\n  default_action {\n    target_group_arn = aws_alb_target_group.frontend.id\n    type             = \"forward\"\n  }\n}\n\n\nresource \"aws_alb_target_group\" \"backend\" {\n  name        = \"ecs-quix-backend-alb-tg\"\n  port        = var.backend_port\n  protocol    = \"HTTP\"\n  vpc_id      = aws_vpc.main.id\n  target_type = \"ip\"\n  tags = merge(\n    {\n      \"Name\" = \"alb-tg-backend-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n  health_check {\n    healthy_threshold   = 2\n    unhealthy_threshold = 10\n    timeout             = \"5\"\n    port                = var.backend_port\n    path                = \"/health/keep_alive\"\n    protocol            = \"HTTP\"\n    interval            = 10\n    matcher             = \"200-499\"\n  }\n}\n\nresource \"aws_alb_listener\" \"frontend_http\" {\n  load_balancer_arn = aws_alb.main.id\n  port              = 80\n  protocol          = \"HTTP\"\n\n  default_action {\n    type = \"redirect\"\n\n    redirect {\n      port        = \"443\"\n      protocol    = \"HTTPS\"\n      status_code = \"HTTP_301\"\n    }\n  }\n}\n\nresource \"aws_alb_listener\" \"backend\" {\n  load_balancer_arn = aws_alb.main.id\n  port              = var.backend_port\n  protocol          = \"HTTP\"\n\n  default_action {\n    target_group_arn = aws_alb_target_group.backend.id\n    type             = \"forward\"\n  }\n}\n\n\nresource \"aws_alb\" \"presto\" {\n  count           = var.create_separate_presto ? 1 : 0\n  name            = \"ecs-quix-presto-alb\"\n  subnets         = aws_subnet.private.*.id\n  security_groups = [aws_security_group.presto_lb.id]\n  internal        = true\n  tags = merge(\n    {\n      \"Name\" = \"alb-presto-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n  # depends_on = [aws_security_group.presto_lb]\n}\n\nresource \"aws_alb_target_group\" \"presto\" {\n  count       = var.create_separate_presto ? 1 : 0\n  name        = \"ecs-quix-presto-alb-tg\"\n  port        = var.presto_port\n  protocol    = \"HTTP\"\n  vpc_id      = aws_vpc.main.id\n  target_type = \"ip\"\n  tags = merge(\n    {\n      \"Name\" = \"alb-tg-presto-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n  health_check {\n    healthy_threshold   = 2\n    unhealthy_threshold = 5\n    timeout             = \"5\"\n    port                = var.presto_port\n    path                = \"/\"\n    protocol            = \"HTTP\"\n    interval            = 10\n    matcher             = \"200-499\"\n  }\n}\n\nresource \"aws_alb_listener\" \"presto\" {\n  count             = var.create_separate_presto ? 1 : 0\n  load_balancer_arn = aws_alb.presto[0].id\n  port              = var.presto_port\n  protocol          = \"HTTP\"\n\n  default_action {\n    target_group_arn = aws_alb_target_group.presto[0].id\n    type             = \"forward\"\n  }\n}\n"
  },
  {
    "path": "terraform/outputs.tf",
    "content": "output \"vpc-id\" {\n  value = aws_vpc.main.id\n}\n\noutput \"account_id\" {\n  value = data.aws_caller_identity.current.account_id\n}\n\noutput \"caller_arn\" {\n  value = data.aws_caller_identity.current.arn\n}\n\noutput \"caller_user\" {\n  value = data.aws_caller_identity.current.user_id\n}\n\noutput \"quix_alb\" {\n  value = aws_alb.main.dns_name\n}\n\noutput \"presto_alb_url\" {\n  value = \"http://${var.create_separate_presto ? aws_alb.presto[0].dns_name : \"\"}:${var.presto_port}/v1\"\n}\n\noutput \"fqdn_domain_name\" {\n  value = aws_route53_record.www-quix.fqdn\n}\n"
  },
  {
    "path": "terraform/parameter_store.tf",
    "content": "/*\nSSM parameters in AWS Systems Manager Parameter Store\n*/\nresource \"aws_ssm_parameter\" \"dbhost\" {\n  name  = \"quix-rds-host\"\n  type  = \"String\"\n  value = aws_db_instance.quix-rds.address\n\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-dbhost\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_ssm_parameter\" \"dbuser\" {\n  name  = \"quix-rds-user\"\n  type  = \"String\"\n  value = aws_db_instance.quix-rds.username\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-dbuser\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_ssm_parameter\" \"dbpwd\" {\n  name  = \"quix-rds-password\"\n  type  = \"SecureString\"\n  value = aws_db_instance.quix-rds.password\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-dbpwd\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_ssm_parameter\" \"dbname\" {\n  name  = \"quix-rds-name\"\n  type  = \"String\"\n  value = aws_db_instance.quix-rds.name\n\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-dbname\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_ssm_parameter\" \"dbport\" {\n  name  = \"quix-rds-port\"\n  type  = \"String\"\n  value = aws_db_instance.quix-rds.port\n\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-dbport\"\n    },\n    var.tags,\n  )\n}\n\n\nresource \"aws_ssm_parameter\" \"google_sso_client_id\" {\n  name  = \"google_sso_client_id\"\n  type  = \"String\"\n  value = \"google_sso_client_id\"\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-sso_id\"\n    },\n    var.tags,\n  )\n\n  lifecycle {\n    ignore_changes = [\n      # Ignore changes to value, e.g. because updated manually\n      value,\n    ]\n  }\n  overwrite = false\n}\n\nresource \"aws_ssm_parameter\" \"google_sso_client_secret\" {\n  name      = \"google_sso_client_secret\"\n  type      = \"String\"\n  value     = \"google_sso_client_secret\"\n  overwrite = false\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-sso_sec\"\n    },\n    var.tags,\n  )\n  lifecycle {\n    ignore_changes = [\n      # Ignore changes to value, e.g. because updated manually\n      value,\n    ]\n  }\n}\n\nresource \"aws_ssm_parameter\" \"auth_secret\" {\n  name      = \"auth_secret\"\n  type      = \"String\"\n  value     = \"somekeygoeshere\"\n  overwrite = false\n  tags = merge(\n    {\n      \"Name\" = \"${var.vpc_name}-auth_secret\"\n    },\n    var.tags,\n  )\n  lifecycle {\n    ignore_changes = [\n      # Ignore changes to value, e.g. because updated manually\n      value,\n    ]\n  }\n}\n"
  },
  {
    "path": "terraform/provider.tf",
    "content": "provider \"aws\" {\n  version = \"~> 2.0\"\n  region  = \"us-east-1\"\n  profile = \"quix\"\n}\n\nprovider \"acme\" {\n  server_url = \"https://acme-v02.api.letsencrypt.org/directory\"\n}\n"
  },
  {
    "path": "terraform/rds.tf",
    "content": "/*\nCreates an Amazon RDS DB instance.\n*/\nresource \"aws_db_subnet_group\" \"quix-rds-group\" {\n  name        = \"subnet_group\"\n  description = \"subnet group for RDS\"\n  # subnet_ids  = [\"${element(aws_subnet.private.ids, 0)}\", \"${element(aws_subnet.private.ids, 1)}\"]\n  subnet_ids = aws_subnet.private.*.id\n}\n\nresource \"random_password\" \"password\" {\n  length           = 16\n  special          = true\n  override_special = \"_%@\"\n}\n\nresource \"aws_db_instance\" \"quix-rds\" {\n  allocated_storage          = 20\n  storage_type               = \"gp2\"\n  engine                     = \"mysql\"\n  engine_version             = \"5.7.22\"\n  instance_class             = \"db.t2.micro\"\n  name                       = \"quix\"\n  username                   = \"quix\"\n  password                   = random_password.password.result\n  auto_minor_version_upgrade = false\n  storage_encrypted          = false\n  apply_immediately          = true\n\n  vpc_security_group_ids = [\"${aws_security_group.ecs_tasks.id}\"]\n  db_subnet_group_name   = aws_db_subnet_group.quix-rds-group.id\n  skip_final_snapshot    = true\n  tags = merge(\n    {\n      \"Name\" = \"quix-rds\"\n    },\n    var.tags,\n  )\n}\n"
  },
  {
    "path": "terraform/route_53.tf",
    "content": "/*\nAWS ROUTE53 : Domain creation\n\nThis assumes that you have already setup AWS as your DNS provider, and\ncreated a hosted zone again the main domain, e.g against example.com.\nThis datasource simply looks up the zone details to use in the creation\nof the additional sub domain records.\n*/\nresource \"aws_route53_zone\" \"quix\" {\n  # count              = var.enable_ssl ? 1: 0\n  name = var.dns_domain_name\n  tags = merge(\n    {\n      \"Name\" = \"quix-zone\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_route53_record\" \"at-quix\" {\n  # count              = var.enable_ssl ? 1: 0\n  zone_id         = aws_route53_zone.quix.zone_id\n  name            = \"@\"\n  type            = \"CNAME\"\n  ttl             = \"60\"\n  records         = [\"${aws_alb.main.dns_name}\"]\n  allow_overwrite = \"true\"\n}\n\nresource \"aws_route53_record\" \"star-quix\" {\n  # count              = var.enable_ssl ? 1: 0\n  zone_id         = aws_route53_zone.quix.zone_id\n  name            = \"*\"\n  type            = \"CNAME\"\n  ttl             = \"60\"\n  records         = [\"${aws_alb.main.dns_name}\"]\n  allow_overwrite = \"true\"\n}\n\nresource \"aws_route53_record\" \"alias_route53_record\" {\n  zone_id = aws_route53_zone.quix.zone_id\n  name    = var.dns_domain_name\n  type    = \"A\"\n  alias {\n    name                   = aws_alb.main.dns_name\n    zone_id                = aws_alb.main.zone_id\n    evaluate_target_health = true\n  }\n  allow_overwrite = \"true\"\n}\n\nresource \"aws_route53_record\" \"www-quix\" {\n  # count              = var.enable_ssl ? 1: 0\n  zone_id         = aws_route53_zone.quix.zone_id\n  name            = \"www\"\n  type            = \"CNAME\"\n  ttl             = \"60\"\n  records         = [\"${aws_alb.main.dns_name}\"]\n  allow_overwrite = \"true\"\n\n}\n\nresource \"aws_route53_record\" \"www2-quix\" {\n  # count              = var.enable_ssl ? 1: 0\n  zone_id         = aws_route53_zone.quix.zone_id\n  name            = \"www2\"\n  type            = \"CNAME\"\n  ttl             = \"60\"\n  records         = [\"${aws_alb.main.dns_name}\"]\n  allow_overwrite = \"true\"\n\n}\n\nresource \"aws_route53_record\" \"cert_validation\" {\n  count   = var.enable_ssl ? 1 : 0\n  name    = aws_acm_certificate.cert[0].domain_validation_options.0.resource_record_name\n  type    = aws_acm_certificate.cert[0].domain_validation_options.0.resource_record_type\n  zone_id = aws_route53_zone.quix.id\n  records = [\"${aws_acm_certificate.cert[0].domain_validation_options.0.resource_record_value}\"]\n  ttl     = 60\n}\n"
  },
  {
    "path": "terraform/security_groups.tf",
    "content": "/*\nSpecifies AWS security groups\n*/\n\n// Security group for ALB\nresource \"aws_security_group\" \"lb\" {\n  name        = \"ecs-alb-main\"\n  description = \"controls access to the ALB Main\"\n  vpc_id      = aws_vpc.main.id\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.backend_port\n    to_port     = var.backend_port\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.frontend_port\n    to_port     = var.frontend_port\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.presto_port\n    to_port     = var.presto_port\n    cidr_blocks = [\"10.0.0.0/8\"]\n  }\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = 80\n    to_port     = 80\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = 443\n    to_port     = 443\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.backend_public_port\n    to_port     = var.backend_public_port\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n\n  egress {\n    from_port   = 0\n    to_port     = 0\n    protocol    = \"-1\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  # lifecycle {\n  #     create_before_destroy = true\n  # }\n}\n\n// Security group for ALB Presto\nresource \"aws_security_group\" \"presto_lb\" {\n  name        = \"ecs-alb-presto\"\n  description = \"controls access to the ALB Presto\"\n  vpc_id      = aws_vpc.main.id\n  ingress {\n    protocol        = \"tcp\"\n    from_port       = var.presto_port\n    to_port         = var.presto_port\n    cidr_blocks     = [\"10.0.0.0/8\"]\n    security_groups = [aws_security_group.ecs_tasks.id]\n\n  }\n  egress {\n    from_port   = 0\n    to_port     = 0\n    protocol    = \"-1\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  # lifecycle {\n  #     create_before_destroy = true\n  # }\n\n}\n\n\n// Traffic to the ECS Cluster should only come from the ALB\nresource \"aws_security_group\" \"ecs_tasks\" {\n  name        = \"tf-ecs-tasks\"\n  description = \"allow inbound access from the ALB only\"\n  vpc_id      = aws_vpc.main.id\n\n  ingress {\n    from_port   = 3306\n    to_port     = 3306\n    protocol    = \"tcp\"\n    cidr_blocks = [\"10.0.0.0/8\"]\n  }\n\n  ingress {\n    from_port   = 5432\n    to_port     = 5432\n    protocol    = \"tcp\"\n    cidr_blocks = [\"10.0.0.0/8\"]\n  }\n  ingress {\n    from_port   = 6379\n    to_port     = 6379\n    protocol    = \"tcp\"\n    cidr_blocks = [\"10.0.0.0/8\"]\n  }\n\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.backend_port\n    to_port     = var.backend_port\n    cidr_blocks = [\"10.0.0.0/8\"]\n\n    # security_groups = [aws_security_group.lb.id]\n  }\n\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.presto_port\n    to_port     = var.presto_port\n    cidr_blocks = [\"10.0.0.0/8\"]\n\n    # security_groups = [aws_security_group.lb.id]\n  }\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = var.frontend_port\n    to_port     = var.frontend_port\n    cidr_blocks = [\"10.0.0.0/8\"]\n\n    # security_groups = [aws_security_group.lb.id]\n  }\n\n  ingress {\n    protocol    = \"tcp\"\n    from_port   = \"80\"\n    to_port     = \"80\"\n    cidr_blocks = [\"10.0.0.0/8\"]\n\n    # security_groups = [aws_security_group.lb.id]\n  }\n  egress {\n    protocol    = \"-1\"\n    from_port   = 0\n    to_port     = 0\n    cidr_blocks = [\"0.0.0.0/0\"]\n  }\n  # lifecycle {\n  #     create_before_destroy = true\n  # }\n\n}\n"
  },
  {
    "path": "terraform/variables.tf",
    "content": "variable \"aws_key_name\" {\n  default = \"valeriys\"\n}\n\nvariable \"vpc_name\" {\n  description = \"VPC Name\"\n  default     = \"quix\"\n}\n\nvariable \"aws_region\" {\n  description = \"EC2 Region for the VPC\"\n  default     = \"us-east-1\"\n}\n\nvariable \"aws_availability_zone\" {\n  default = \"us-east-1a\"\n}\n\nvariable \"az_count\" {\n  description = \"Number of AZs to cover in a given AWS region\"\n  default     = \"2\"\n}\n\nvariable \"fargate_cpu\" {\n  description = \"Fargate instance CPU units to provision (1 vCPU = 1024 CPU units)\"\n  default     = \"256\"\n}\n\nvariable \"fargate_memory\" {\n  description = \"Fargate instance memory to provision (in MiB)\"\n  default     = \"512\"\n}\n\nvariable \"quix_backend_image\" {\n  description = \"Docker image for backend to run in the ECS cluster\"\n  default     = \"wixquix/quix-backend:release-v1\"\n\n}\n\nvariable \"quix_frontend_image\" {\n  description = \"Docker image for frontend to run in the ECS cluster\"\n  default     = \"wixquix/quix-frontend:release-v1\"\n}\n\nvariable \"presto_image\" {\n  description = \"Docker image for Presto to run in the ECS cluster\"\n  default     = \"starburstdata/presto:latest\"\n}\n\nvariable \"backend_port\" {\n  description = \"Port exposed by the docker image of backend\"\n  default     = 8081\n}\n\nvariable \"frontend_port\" {\n  description = \"Port exposed by the docker image of frontend\"\n  default     = 3000\n}\n\nvariable \"presto_port\" {\n  description = \"Port exposed by the docker image of presto\"\n  default     = 8080\n}\nvariable \"mapPublicIP\" {\n  default = true\n}\n\nvariable \"tags\" {\n  default = {\n    ManagedByTerraform = true\n    Terraform          = true\n    Project            = \"Quix\"\n    Environment        = \"production\"\n\n  }\n  type        = map(string)\n  description = \"A mapping of tags to assign to all resources.\"\n}\n\n\nvariable \"tf_dynamodb_lock_table_enabled\" {\n  default     = 1\n  description = \"Affects terraform-aws-backend module behavior. Set to false or 0 to prevent this module from creating the DynamoDB table to use for terraform state locking and consistency. More info on locking for aws/s3 backends: https://www.terraform.io/docs/backends/types/s3.html. More information about how terraform handles booleans here: https://www.terraform.io/docs/configuration/variables.html\"\n}\n\nvariable \"tf_dynamodb_lock_table_name\" {\n  default = \"terraform-lock\"\n}\n\nvariable \"tf_lock_table_read_capacity\" {\n  default = 1\n}\n\nvariable \"tf_lock_table_write_capacity\" {\n  default = 1\n}\n\nvariable \"create_separate_presto\" {\n  description = \"Defines if we need to create Presto ECS & talk to it via ALB\"\n  default     = false\n}\n\n/*\n    Let's Encrypt Account Registration Config via ACME\n*/\nvariable \"enable_ssl\" {\n  description = \"Defines if we need to enable SSL for ALB\"\n  default     = true\n}\n\nvariable \"enable_acme_ssl\" {\n  description = \"Defines if we need to enable SSL for ALB via ACME\"\n  default     = false\n}\n\nvariable \"enable_google_sso\" {\n  description = \"Defines if we need to enable Google SSO\"\n  default     = true\n}\n\nvariable \"auth_cookie\" {\n  description = \"Defines AUTH_COOKIE\"\n  default     = \"__quixuser\"\n}\n\nvariable \"backend_public_port\" {\n  default = \"8443\"\n}\n\nvariable \"dns_domain_name\" {\n  default = \"quix-demo.io\"\n}\n\nvariable \"acme_server_url\" {\n  default = \"https://acme.api.letsencrypt.org/directory\"\n}\n\nvariable \"acme_registration_email\" {\n  default = \"quix@quix-demo.io\"\n}\n\nvariable \"aws_acme_profile\" {\n  default = \"quix\"\n}\n\nvariable \"acme_account_key_pem\" {\n  default = \"\"\n}\n\nvariable \"acme_certificate_common_name\" {\n  description = \"Domain for letsencrypt\"\n  default     = \"*.quix-demo.io\"\n}\n\nvariable \"min_days_remaining\" {\n  description = \"The minimum amount of days remaining on the expiration of a certificate before a renewal is attempted\"\n  default     = 14\n}\n\nvariable \"acme_challenge_aws_access_key_id\" { default = \"\" }\nvariable \"acme_challenge_aws_secret_access_key\" { default = \"\" }\n"
  },
  {
    "path": "terraform/versions.tf",
    "content": "// It's important to have the correct terraform versiosn,\n// all versions at https://releases.hashicorp.com/terraform/\nterraform {\n  required_version = \">= 0.12\"\n}\n"
  },
  {
    "path": "terraform/vpc.tf",
    "content": "# Declare the data source\ndata \"aws_availability_zones\" \"available\" {\n  state = \"available\"\n  # blacklisted_names = [\n  #     \"us-east-1e\",\n  #     \"us-east-1f\",\n  #     \"us-east-1d\",\n  #     \"us-east-1c\"\n  # ]\n}\n\nresource \"aws_vpc\" \"main\" {\n  cidr_block = \"10.0.0.0/16\"\n  # instance_tenancy = \"dedicated\"\n\n  tags = merge(\n    {\n      \"Name\" = var.vpc_name\n    },\n    var.tags,\n  )\n}\n\n# Create var.az_count public subnets, each in a different AZ\nresource \"aws_subnet\" \"public\" {\n  count             = var.az_count\n  vpc_id            = aws_vpc.main.id\n  availability_zone = data.aws_availability_zones.available.names[count.index]\n\n  cidr_block = element(\n    cidrsubnets(aws_vpc.main.cidr_block, 4, 4, 8, 4),\n    2 + count.index,\n  )\n\n  # ipv6_cidr_block                 = cidrsubnet(aws_vpc.network.ipv6_cidr_block, 8, count.index)\n  map_public_ip_on_launch = true\n\n  # assign_ipv6_address_on_creation = true\n\n  tags = {\n    \"Name\" = \"main-public-${count.index}\"\n  }\n}\n\n# Create var.az_count private subnets, each in a different AZ\nresource \"aws_subnet\" \"private\" {\n  count = var.az_count\n\n  vpc_id            = aws_vpc.main.id\n  availability_zone = data.aws_availability_zones.available.names[count.index]\n  cidr_block = element(\n    cidrsubnets(aws_vpc.main.cidr_block, 4, 4, 8, 4),\n    count.index,\n  )\n  tags = {\n    \"Name\" = \"main-private-${count.index}\"\n  }\n}\n\n# IGW for the public subnet\nresource \"aws_internet_gateway\" \"gw\" {\n  vpc_id = aws_vpc.main.id\n\n  tags = merge(\n    {\n      \"Name\" = var.vpc_name\n    },\n    var.tags,\n  )\n}\n\n# Route the public subnet traffic through the IGW\nresource \"aws_route\" \"internet_access\" {\n  route_table_id         = aws_vpc.main.main_route_table_id\n  destination_cidr_block = \"0.0.0.0/0\"\n  gateway_id             = aws_internet_gateway.gw.id\n}\n\n# Create a NAT gateway with an EIP for each private subnet to get internet connectivity\nresource \"aws_eip\" \"gw\" {\n  count      = var.az_count\n  vpc        = true\n  depends_on = [aws_internet_gateway.gw]\n  tags = merge(\n    {\n      \"Name\" = \"eip-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n}\n\nresource \"aws_nat_gateway\" \"gw\" {\n  count         = var.az_count\n  subnet_id     = element(aws_subnet.public.*.id, count.index)\n  allocation_id = element(aws_eip.gw.*.id, count.index)\n  tags = merge(\n    {\n      \"Name\" = \"nat-gw-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n}\n\n# Create a new route table for the private subnets\n# And make it route non-local traffic through the NAT gateway to the internet\nresource \"aws_route_table\" \"private\" {\n  count  = var.az_count\n  vpc_id = aws_vpc.main.id\n\n  route {\n    cidr_block     = \"0.0.0.0/0\"\n    nat_gateway_id = element(aws_nat_gateway.gw.*.id, count.index)\n  }\n  tags = merge(\n    {\n      \"Name\" = \"route-table-private-${var.vpc_name}\"\n    },\n    var.tags,\n  )\n}\n\n# Explicitely associate the newly created route tables to the private subnets (so they don't default to the main route table)\nresource \"aws_route_table_association\" \"private\" {\n  count          = var.az_count\n  subnet_id      = element(aws_subnet.private.*.id, count.index)\n  route_table_id = element(aws_route_table.private.*.id, count.index)\n}\n"
  }
]